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" |
df48c323 | 40 | |
1d0a082d | 41 | |
df48c323 TW |
42 | MODULE_DESCRIPTION("iwl core"); |
43 | MODULE_VERSION(IWLWIFI_VERSION); | |
44 | MODULE_AUTHOR(DRV_COPYRIGHT); | |
712b6cf5 | 45 | MODULE_LICENSE("GPL"); |
df48c323 | 46 | |
0a6857e7 TW |
47 | #ifdef CONFIG_IWLWIFI_DEBUG |
48 | u32 iwl_debug_level; | |
49 | EXPORT_SYMBOL(iwl_debug_level); | |
df48c323 | 50 | #endif |
1d0a082d AK |
51 | |
52 | /* This function both allocates and initializes hw and priv. */ | |
53 | struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, | |
54 | struct ieee80211_ops *hw_ops) | |
55 | { | |
56 | struct iwl_priv *priv; | |
57 | ||
58 | /* mac80211 allocates memory for this device instance, including | |
59 | * space for this driver's private structure */ | |
60 | struct ieee80211_hw *hw = | |
61 | ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); | |
62 | if (hw == NULL) { | |
63 | IWL_ERROR("Can not allocate network device\n"); | |
64 | goto out; | |
65 | } | |
66 | ||
67 | priv = hw->priv; | |
68 | priv->hw = hw; | |
69 | ||
70 | out: | |
71 | return hw; | |
72 | } | |
73 | EXPORT_SYMBOL(iwl_alloc_all); | |
74 | ||
bf85ea4f AK |
75 | /** |
76 | * iwlcore_clear_stations_table - Clear the driver's station table | |
77 | * | |
78 | * NOTE: This does not clear or otherwise alter the device's station table. | |
79 | */ | |
80 | void iwlcore_clear_stations_table(struct iwl_priv *priv) | |
81 | { | |
82 | unsigned long flags; | |
83 | ||
84 | spin_lock_irqsave(&priv->sta_lock, flags); | |
85 | ||
86 | priv->num_stations = 0; | |
87 | memset(priv->stations, 0, sizeof(priv->stations)); | |
88 | ||
89 | spin_unlock_irqrestore(&priv->sta_lock, flags); | |
90 | } | |
91 | EXPORT_SYMBOL(iwlcore_clear_stations_table); | |
92 | ||
93 | void iwlcore_reset_qos(struct iwl_priv *priv) | |
94 | { | |
95 | u16 cw_min = 15; | |
96 | u16 cw_max = 1023; | |
97 | u8 aifs = 2; | |
98 | u8 is_legacy = 0; | |
99 | unsigned long flags; | |
100 | int i; | |
101 | ||
102 | spin_lock_irqsave(&priv->lock, flags); | |
103 | priv->qos_data.qos_active = 0; | |
104 | ||
105 | if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { | |
106 | if (priv->qos_data.qos_enable) | |
107 | priv->qos_data.qos_active = 1; | |
108 | if (!(priv->active_rate & 0xfff0)) { | |
109 | cw_min = 31; | |
110 | is_legacy = 1; | |
111 | } | |
112 | } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { | |
113 | if (priv->qos_data.qos_enable) | |
114 | priv->qos_data.qos_active = 1; | |
115 | } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { | |
116 | cw_min = 31; | |
117 | is_legacy = 1; | |
118 | } | |
119 | ||
120 | if (priv->qos_data.qos_active) | |
121 | aifs = 3; | |
122 | ||
123 | priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); | |
124 | priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); | |
125 | priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; | |
126 | priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; | |
127 | priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; | |
128 | ||
129 | if (priv->qos_data.qos_active) { | |
130 | i = 1; | |
131 | priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); | |
132 | priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); | |
133 | priv->qos_data.def_qos_parm.ac[i].aifsn = 7; | |
134 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | |
135 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
136 | ||
137 | i = 2; | |
138 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
139 | cpu_to_le16((cw_min + 1) / 2 - 1); | |
140 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
141 | cpu_to_le16(cw_max); | |
142 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | |
143 | if (is_legacy) | |
144 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
145 | cpu_to_le16(6016); | |
146 | else | |
147 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
148 | cpu_to_le16(3008); | |
149 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
150 | ||
151 | i = 3; | |
152 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
153 | cpu_to_le16((cw_min + 1) / 4 - 1); | |
154 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
155 | cpu_to_le16((cw_max + 1) / 2 - 1); | |
156 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | |
157 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
158 | if (is_legacy) | |
159 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
160 | cpu_to_le16(3264); | |
161 | else | |
162 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | |
163 | cpu_to_le16(1504); | |
164 | } else { | |
165 | for (i = 1; i < 4; i++) { | |
166 | priv->qos_data.def_qos_parm.ac[i].cw_min = | |
167 | cpu_to_le16(cw_min); | |
168 | priv->qos_data.def_qos_parm.ac[i].cw_max = | |
169 | cpu_to_le16(cw_max); | |
170 | priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; | |
171 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | |
172 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | |
173 | } | |
174 | } | |
175 | IWL_DEBUG_QOS("set QoS to default \n"); | |
176 | ||
177 | spin_unlock_irqrestore(&priv->lock, flags); | |
178 | } | |
179 | EXPORT_SYMBOL(iwlcore_reset_qos); | |
180 | ||
181 | /** | |
182 | * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON | |
183 | * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz | |
184 | * @channel: Any channel valid for the requested phymode | |
185 | ||
186 | * In addition to setting the staging RXON, priv->phymode is also set. | |
187 | * | |
188 | * NOTE: Does not commit to the hardware; it sets appropriate bit fields | |
189 | * in the staging RXON flag structure based on the phymode | |
190 | */ | |
191 | int iwlcore_set_rxon_channel(struct iwl_priv *priv, | |
192 | enum ieee80211_band band, | |
193 | u16 channel) | |
194 | { | |
8622e705 | 195 | if (!iwl_get_channel_info(priv, band, channel)) { |
bf85ea4f AK |
196 | IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", |
197 | channel, band); | |
198 | return -EINVAL; | |
199 | } | |
200 | ||
201 | if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && | |
202 | (priv->band == band)) | |
203 | return 0; | |
204 | ||
205 | priv->staging_rxon.channel = cpu_to_le16(channel); | |
206 | if (band == IEEE80211_BAND_5GHZ) | |
207 | priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; | |
208 | else | |
209 | priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; | |
210 | ||
211 | priv->band = band; | |
212 | ||
213 | IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); | |
214 | ||
215 | return 0; | |
216 | } | |
217 | EXPORT_SYMBOL(iwlcore_set_rxon_channel); | |
218 | ||
219 | static void iwlcore_init_hw(struct iwl_priv *priv) | |
220 | { | |
221 | struct ieee80211_hw *hw = priv->hw; | |
222 | hw->rate_control_algorithm = "iwl-4965-rs"; | |
223 | ||
224 | /* Tell mac80211 and its clients (e.g. Wireless Extensions) | |
225 | * the range of signal quality values that we'll provide. | |
226 | * Negative values for level/noise indicate that we'll provide dBm. | |
227 | * For WE, at least, non-0 values here *enable* display of values | |
228 | * in app (iwconfig). */ | |
229 | hw->max_rssi = -20; /* signal level, negative indicates dBm */ | |
230 | hw->max_noise = -20; /* noise level, negative indicates dBm */ | |
231 | hw->max_signal = 100; /* link quality indication (%) */ | |
232 | ||
233 | /* Tell mac80211 our Tx characteristics */ | |
234 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; | |
235 | ||
236 | /* Default value; 4 EDCA QOS priorities */ | |
237 | hw->queues = 4; | |
238 | #ifdef CONFIG_IWL4965_HT | |
239 | /* Enhanced value; more queues, to support 11n aggregation */ | |
240 | hw->queues = 16; | |
241 | #endif /* CONFIG_IWL4965_HT */ | |
242 | } | |
243 | ||
244 | int iwl_setup(struct iwl_priv *priv) | |
245 | { | |
246 | int ret = 0; | |
247 | iwlcore_init_hw(priv); | |
248 | ret = priv->cfg->ops->lib->init_drv(priv); | |
249 | return ret; | |
250 | } | |
251 | EXPORT_SYMBOL(iwl_setup); | |
252 | ||
c8381fdc MA |
253 | /* Low level driver call this function to update iwlcore with |
254 | * driver status. | |
255 | */ | |
256 | int iwlcore_low_level_notify(struct iwl_priv *priv, | |
257 | enum iwlcore_card_notify notify) | |
258 | { | |
03d29c68 | 259 | int ret; |
c8381fdc MA |
260 | switch (notify) { |
261 | case IWLCORE_INIT_EVT: | |
03d29c68 MA |
262 | ret = iwl_rfkill_init(priv); |
263 | if (ret) | |
264 | IWL_ERROR("Unable to initialize RFKILL system. " | |
265 | "Ignoring error: %d\n", ret); | |
c8381fdc MA |
266 | break; |
267 | case IWLCORE_START_EVT: | |
268 | break; | |
269 | case IWLCORE_STOP_EVT: | |
270 | break; | |
271 | case IWLCORE_REMOVE_EVT: | |
ad97edd2 | 272 | iwl_rfkill_unregister(priv); |
c8381fdc MA |
273 | break; |
274 | } | |
275 | ||
276 | return 0; | |
277 | } | |
278 | EXPORT_SYMBOL(iwlcore_low_level_notify); | |
279 |