Commit | Line | Data |
---|---|---|
df48c323 | 1 | /****************************************************************************** |
df48c323 TW |
2 | * |
3 | * GPL LICENSE SUMMARY | |
4 | * | |
5 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of version 2 of the GNU General Public License as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | |
19 | * USA | |
20 | * | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * Contact Information: | |
25 | * Tomas Winkler <tomas.winkler@intel.com> | |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
27 | *****************************************************************************/ | |
28 | ||
29 | #include <linux/kernel.h> | |
30 | #include <linux/module.h> | |
31 | #include <linux/version.h> | |
1d0a082d | 32 | #include <net/mac80211.h> |
df48c323 | 33 | |
712b6cf5 | 34 | struct iwl_priv; /* FIXME: remove */ |
0a6857e7 | 35 | #include "iwl-debug.h" |
6bc913bd | 36 | #include "iwl-eeprom.h" |
fee1247a | 37 | #include "iwl-4965.h" /* FIXME: remove */ |
df48c323 | 38 | #include "iwl-core.h" |
ad97edd2 | 39 | #include "iwl-rfkill.h" |
5da4b55f | 40 | #include "iwl-power.h" |
df48c323 | 41 | |
1d0a082d | 42 | |
df48c323 TW |
43 | MODULE_DESCRIPTION("iwl core"); |
44 | MODULE_VERSION(IWLWIFI_VERSION); | |
45 | MODULE_AUTHOR(DRV_COPYRIGHT); | |
712b6cf5 | 46 | MODULE_LICENSE("GPL"); |
df48c323 | 47 | |
0a6857e7 TW |
48 | #ifdef CONFIG_IWLWIFI_DEBUG |
49 | u32 iwl_debug_level; | |
50 | EXPORT_SYMBOL(iwl_debug_level); | |
df48c323 | 51 | #endif |
1d0a082d AK |
52 | |
53 | /* This function both allocates and initializes hw and priv. */ | |
54 | struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, | |
55 | struct ieee80211_ops *hw_ops) | |
56 | { | |
57 | struct iwl_priv *priv; | |
58 | ||
59 | /* mac80211 allocates memory for this device instance, including | |
60 | * space for this driver's private structure */ | |
61 | struct ieee80211_hw *hw = | |
62 | ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); | |
63 | if (hw == NULL) { | |
64 | IWL_ERROR("Can not allocate network device\n"); | |
65 | goto out; | |
66 | } | |
67 | ||
68 | priv = hw->priv; | |
69 | priv->hw = hw; | |
70 | ||
71 | out: | |
72 | return hw; | |
73 | } | |
74 | EXPORT_SYMBOL(iwl_alloc_all); | |
75 | ||
bf85ea4f AK |
76 | /** |
77 | * iwlcore_clear_stations_table - Clear the driver's station table | |
78 | * | |
79 | * NOTE: This does not clear or otherwise alter the device's station table. | |
80 | */ | |
81 | void iwlcore_clear_stations_table(struct iwl_priv *priv) | |
82 | { | |
83 | unsigned long flags; | |
84 | ||
85 | spin_lock_irqsave(&priv->sta_lock, flags); | |
86 | ||
87 | priv->num_stations = 0; | |
88 | memset(priv->stations, 0, sizeof(priv->stations)); | |
89 | ||
90 | spin_unlock_irqrestore(&priv->sta_lock, flags); | |
91 | } | |
92 | EXPORT_SYMBOL(iwlcore_clear_stations_table); | |
93 | ||
94 | void iwlcore_reset_qos(struct iwl_priv *priv) | |
95 | { | |
96 | u16 cw_min = 15; | |
97 | u16 cw_max = 1023; | |
98 | u8 aifs = 2; | |
99 | u8 is_legacy = 0; | |
100 | unsigned long flags; | |
101 | int i; | |
102 | ||
103 | spin_lock_irqsave(&priv->lock, flags); | |
104 | priv->qos_data.qos_active = 0; | |
105 | ||
106 | if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { | |
107 | if (priv->qos_data.qos_enable) | |
108 | priv->qos_data.qos_active = 1; | |
109 | if (!(priv->active_rate & 0xfff0)) { | |
110 | cw_min = 31; | |
111 | is_legacy = 1; | |
112 | } | |
113 | } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { | |
114 | if (priv->qos_data.qos_enable) | |
115 | priv->qos_data.qos_active = 1; | |
116 | } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { | |
117 | cw_min = 31; | |
118 | is_legacy = 1; | |
119 | } | |
120 | ||
121 | if (priv->qos_data.qos_active) | |
122 | aifs = 3; | |
123 | ||
124 | priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); | |
125 | priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); | |
126 | priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; | |
127 | priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; | |
128 | priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; | |
129 | ||
130 | if (priv->qos_data.qos_active) { | |
131 | i = 1; | |
132 | priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); | |
133 | priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); | |
134 | priv->qos_data.def_qos_parm.ac[i].aifsn = 7; | |
135 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | |
136 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
137 | ||
138 | i = 2; | |
139 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
140 | cpu_to_le16((cw_min + 1) / 2 - 1); | |
141 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
142 | cpu_to_le16(cw_max); | |
143 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | |
144 | if (is_legacy) | |
145 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
146 | cpu_to_le16(6016); | |
147 | else | |
148 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
149 | cpu_to_le16(3008); | |
150 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
151 | ||
152 | i = 3; | |
153 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
154 | cpu_to_le16((cw_min + 1) / 4 - 1); | |
155 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
156 | cpu_to_le16((cw_max + 1) / 2 - 1); | |
157 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | |
158 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
159 | if (is_legacy) | |
160 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
161 | cpu_to_le16(3264); | |
162 | else | |
163 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
164 | cpu_to_le16(1504); | |
165 | } else { | |
166 | for (i = 1; i < 4; i++) { | |
167 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
168 | cpu_to_le16(cw_min); | |
169 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
170 | cpu_to_le16(cw_max); | |
171 | priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; | |
172 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | |
173 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
174 | } | |
175 | } | |
176 | IWL_DEBUG_QOS("set QoS to default \n"); | |
177 | ||
178 | spin_unlock_irqrestore(&priv->lock, flags); | |
179 | } | |
180 | EXPORT_SYMBOL(iwlcore_reset_qos); | |
181 | ||
182 | /** | |
183 | * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON | |
184 | * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz | |
185 | * @channel: Any channel valid for the requested phymode | |
186 | ||
187 | * In addition to setting the staging RXON, priv->phymode is also set. | |
188 | * | |
189 | * NOTE: Does not commit to the hardware; it sets appropriate bit fields | |
190 | * in the staging RXON flag structure based on the phymode | |
191 | */ | |
192 | int iwlcore_set_rxon_channel(struct iwl_priv *priv, | |
193 | enum ieee80211_band band, | |
194 | u16 channel) | |
195 | { | |
8622e705 | 196 | if (!iwl_get_channel_info(priv, band, channel)) { |
bf85ea4f AK |
197 | IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", |
198 | channel, band); | |
199 | return -EINVAL; | |
200 | } | |
201 | ||
202 | if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && | |
203 | (priv->band == band)) | |
204 | return 0; | |
205 | ||
206 | priv->staging_rxon.channel = cpu_to_le16(channel); | |
207 | if (band == IEEE80211_BAND_5GHZ) | |
208 | priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; | |
209 | else | |
210 | priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; | |
211 | ||
212 | priv->band = band; | |
213 | ||
214 | IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); | |
215 | ||
216 | return 0; | |
217 | } | |
218 | EXPORT_SYMBOL(iwlcore_set_rxon_channel); | |
219 | ||
220 | static void iwlcore_init_hw(struct iwl_priv *priv) | |
221 | { | |
222 | struct ieee80211_hw *hw = priv->hw; | |
223 | hw->rate_control_algorithm = "iwl-4965-rs"; | |
224 | ||
225 | /* Tell mac80211 and its clients (e.g. Wireless Extensions) | |
226 | * the range of signal quality values that we'll provide. | |
227 | * Negative values for level/noise indicate that we'll provide dBm. | |
228 | * For WE, at least, non-0 values here *enable* display of values | |
229 | * in app (iwconfig). */ | |
230 | hw->max_rssi = -20; /* signal level, negative indicates dBm */ | |
231 | hw->max_noise = -20; /* noise level, negative indicates dBm */ | |
232 | hw->max_signal = 100; /* link quality indication (%) */ | |
233 | ||
234 | /* Tell mac80211 our Tx characteristics */ | |
235 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; | |
236 | ||
237 | /* Default value; 4 EDCA QOS priorities */ | |
238 | hw->queues = 4; | |
239 | #ifdef CONFIG_IWL4965_HT | |
240 | /* Enhanced value; more queues, to support 11n aggregation */ | |
241 | hw->queues = 16; | |
242 | #endif /* CONFIG_IWL4965_HT */ | |
243 | } | |
244 | ||
245 | int iwl_setup(struct iwl_priv *priv) | |
246 | { | |
247 | int ret = 0; | |
248 | iwlcore_init_hw(priv); | |
249 | ret = priv->cfg->ops->lib->init_drv(priv); | |
250 | return ret; | |
251 | } | |
252 | EXPORT_SYMBOL(iwl_setup); | |
253 | ||
c8381fdc MA |
254 | /* Low level driver call this function to update iwlcore with |
255 | * driver status. | |
256 | */ | |
257 | int iwlcore_low_level_notify(struct iwl_priv *priv, | |
258 | enum iwlcore_card_notify notify) | |
259 | { | |
03d29c68 | 260 | int ret; |
c8381fdc MA |
261 | switch (notify) { |
262 | case IWLCORE_INIT_EVT: | |
03d29c68 MA |
263 | ret = iwl_rfkill_init(priv); |
264 | if (ret) | |
265 | IWL_ERROR("Unable to initialize RFKILL system. " | |
266 | "Ignoring error: %d\n", ret); | |
5da4b55f | 267 | iwl_power_initialize(priv); |
c8381fdc MA |
268 | break; |
269 | case IWLCORE_START_EVT: | |
5da4b55f | 270 | iwl_power_update_mode(priv, 1); |
c8381fdc MA |
271 | break; |
272 | case IWLCORE_STOP_EVT: | |
273 | break; | |
274 | case IWLCORE_REMOVE_EVT: | |
ad97edd2 | 275 | iwl_rfkill_unregister(priv); |
c8381fdc MA |
276 | break; |
277 | } | |
278 | ||
279 | return 0; | |
280 | } | |
281 | EXPORT_SYMBOL(iwlcore_low_level_notify); | |
282 | ||
49ea8596 EG |
283 | int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) |
284 | { | |
285 | u32 stat_flags = 0; | |
286 | struct iwl_host_cmd cmd = { | |
287 | .id = REPLY_STATISTICS_CMD, | |
288 | .meta.flags = flags, | |
289 | .len = sizeof(stat_flags), | |
290 | .data = (u8 *) &stat_flags, | |
291 | }; | |
292 | return iwl_send_cmd(priv, &cmd); | |
293 | } | |
294 | EXPORT_SYMBOL(iwl_send_statistics_request); | |
7e8c519e | 295 |