diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-core.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 216 |
1 files changed, 211 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9ca539861db2..da51349cbd8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -29,17 +29,223 @@ | |||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/version.h> | 31 | #include <linux/version.h> |
32 | #include <net/mac80211.h> | ||
32 | 33 | ||
33 | #include "iwl-4965-debug.h" | 34 | struct iwl_priv; /* FIXME: remove */ |
35 | #include "iwl-debug.h" | ||
34 | #include "iwl-eeprom.h" | 36 | #include "iwl-eeprom.h" |
35 | #include "iwl-core.h" | 37 | #include "iwl-core.h" |
36 | 38 | ||
39 | #include "iwl-4965.h" /* FIXME: remove */ | ||
40 | |||
37 | MODULE_DESCRIPTION("iwl core"); | 41 | MODULE_DESCRIPTION("iwl core"); |
38 | MODULE_VERSION(IWLWIFI_VERSION); | 42 | MODULE_VERSION(IWLWIFI_VERSION); |
39 | MODULE_AUTHOR(DRV_COPYRIGHT); | 43 | MODULE_AUTHOR(DRV_COPYRIGHT); |
40 | MODULE_LICENSE("GPL/BSD"); | 44 | MODULE_LICENSE("GPL"); |
41 | 45 | ||
42 | #ifdef CONFIG_IWL4965_DEBUG | 46 | #ifdef CONFIG_IWLWIFI_DEBUG |
43 | u32 iwl4965_debug_level; | 47 | u32 iwl_debug_level; |
44 | EXPORT_SYMBOL(iwl4965_debug_level); | 48 | EXPORT_SYMBOL(iwl_debug_level); |
45 | #endif | 49 | #endif |
50 | |||
51 | /* This function both allocates and initializes hw and priv. */ | ||
52 | struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, | ||
53 | struct ieee80211_ops *hw_ops) | ||
54 | { | ||
55 | struct iwl_priv *priv; | ||
56 | |||
57 | /* mac80211 allocates memory for this device instance, including | ||
58 | * space for this driver's private structure */ | ||
59 | struct ieee80211_hw *hw = | ||
60 | ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); | ||
61 | if (hw == NULL) { | ||
62 | IWL_ERROR("Can not allocate network device\n"); | ||
63 | goto out; | ||
64 | } | ||
65 | |||
66 | priv = hw->priv; | ||
67 | priv->hw = hw; | ||
68 | |||
69 | out: | ||
70 | return hw; | ||
71 | } | ||
72 | EXPORT_SYMBOL(iwl_alloc_all); | ||
73 | |||
74 | /** | ||
75 | * iwlcore_clear_stations_table - Clear the driver's station table | ||
76 | * | ||
77 | * NOTE: This does not clear or otherwise alter the device's station table. | ||
78 | */ | ||
79 | void iwlcore_clear_stations_table(struct iwl_priv *priv) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | |||
83 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
84 | |||
85 | priv->num_stations = 0; | ||
86 | memset(priv->stations, 0, sizeof(priv->stations)); | ||
87 | |||
88 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
89 | } | ||
90 | EXPORT_SYMBOL(iwlcore_clear_stations_table); | ||
91 | |||
92 | void iwlcore_reset_qos(struct iwl_priv *priv) | ||
93 | { | ||
94 | u16 cw_min = 15; | ||
95 | u16 cw_max = 1023; | ||
96 | u8 aifs = 2; | ||
97 | u8 is_legacy = 0; | ||
98 | unsigned long flags; | ||
99 | int i; | ||
100 | |||
101 | spin_lock_irqsave(&priv->lock, flags); | ||
102 | priv->qos_data.qos_active = 0; | ||
103 | |||
104 | if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { | ||
105 | if (priv->qos_data.qos_enable) | ||
106 | priv->qos_data.qos_active = 1; | ||
107 | if (!(priv->active_rate & 0xfff0)) { | ||
108 | cw_min = 31; | ||
109 | is_legacy = 1; | ||
110 | } | ||
111 | } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { | ||
112 | if (priv->qos_data.qos_enable) | ||
113 | priv->qos_data.qos_active = 1; | ||
114 | } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { | ||
115 | cw_min = 31; | ||
116 | is_legacy = 1; | ||
117 | } | ||
118 | |||
119 | if (priv->qos_data.qos_active) | ||
120 | aifs = 3; | ||
121 | |||
122 | priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); | ||
123 | priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); | ||
124 | priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; | ||
125 | priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; | ||
126 | priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; | ||
127 | |||
128 | if (priv->qos_data.qos_active) { | ||
129 | i = 1; | ||
130 | priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); | ||
131 | priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); | ||
132 | priv->qos_data.def_qos_parm.ac[i].aifsn = 7; | ||
133 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | ||
134 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | ||
135 | |||
136 | i = 2; | ||
137 | priv->qos_data.def_qos_parm.ac[i].cw_min = | ||
138 | cpu_to_le16((cw_min + 1) / 2 - 1); | ||
139 | priv->qos_data.def_qos_parm.ac[i].cw_max = | ||
140 | cpu_to_le16(cw_max); | ||
141 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | ||
142 | if (is_legacy) | ||
143 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | ||
144 | cpu_to_le16(6016); | ||
145 | else | ||
146 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | ||
147 | cpu_to_le16(3008); | ||
148 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | ||
149 | |||
150 | i = 3; | ||
151 | priv->qos_data.def_qos_parm.ac[i].cw_min = | ||
152 | cpu_to_le16((cw_min + 1) / 4 - 1); | ||
153 | priv->qos_data.def_qos_parm.ac[i].cw_max = | ||
154 | cpu_to_le16((cw_max + 1) / 2 - 1); | ||
155 | priv->qos_data.def_qos_parm.ac[i].aifsn = 2; | ||
156 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | ||
157 | if (is_legacy) | ||
158 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | ||
159 | cpu_to_le16(3264); | ||
160 | else | ||
161 | priv->qos_data.def_qos_parm.ac[i].edca_txop = | ||
162 | cpu_to_le16(1504); | ||
163 | } else { | ||
164 | for (i = 1; i < 4; i++) { | ||
165 | priv->qos_data.def_qos_parm.ac[i].cw_min = | ||
166 | cpu_to_le16(cw_min); | ||
167 | priv->qos_data.def_qos_parm.ac[i].cw_max = | ||
168 | cpu_to_le16(cw_max); | ||
169 | priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; | ||
170 | priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; | ||
171 | priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; | ||
172 | } | ||
173 | } | ||
174 | IWL_DEBUG_QOS("set QoS to default \n"); | ||
175 | |||
176 | spin_unlock_irqrestore(&priv->lock, flags); | ||
177 | } | ||
178 | EXPORT_SYMBOL(iwlcore_reset_qos); | ||
179 | |||
180 | /** | ||
181 | * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON | ||
182 | * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz | ||
183 | * @channel: Any channel valid for the requested phymode | ||
184 | |||
185 | * In addition to setting the staging RXON, priv->phymode is also set. | ||
186 | * | ||
187 | * NOTE: Does not commit to the hardware; it sets appropriate bit fields | ||
188 | * in the staging RXON flag structure based on the phymode | ||
189 | */ | ||
190 | int iwlcore_set_rxon_channel(struct iwl_priv *priv, | ||
191 | enum ieee80211_band band, | ||
192 | u16 channel) | ||
193 | { | ||
194 | if (!iwl_get_channel_info(priv, band, channel)) { | ||
195 | IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", | ||
196 | channel, band); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && | ||
201 | (priv->band == band)) | ||
202 | return 0; | ||
203 | |||
204 | priv->staging_rxon.channel = cpu_to_le16(channel); | ||
205 | if (band == IEEE80211_BAND_5GHZ) | ||
206 | priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; | ||
207 | else | ||
208 | priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; | ||
209 | |||
210 | priv->band = band; | ||
211 | |||
212 | IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | EXPORT_SYMBOL(iwlcore_set_rxon_channel); | ||
217 | |||
218 | static void iwlcore_init_hw(struct iwl_priv *priv) | ||
219 | { | ||
220 | struct ieee80211_hw *hw = priv->hw; | ||
221 | hw->rate_control_algorithm = "iwl-4965-rs"; | ||
222 | |||
223 | /* Tell mac80211 and its clients (e.g. Wireless Extensions) | ||
224 | * the range of signal quality values that we'll provide. | ||
225 | * Negative values for level/noise indicate that we'll provide dBm. | ||
226 | * For WE, at least, non-0 values here *enable* display of values | ||
227 | * in app (iwconfig). */ | ||
228 | hw->max_rssi = -20; /* signal level, negative indicates dBm */ | ||
229 | hw->max_noise = -20; /* noise level, negative indicates dBm */ | ||
230 | hw->max_signal = 100; /* link quality indication (%) */ | ||
231 | |||
232 | /* Tell mac80211 our Tx characteristics */ | ||
233 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; | ||
234 | |||
235 | /* Default value; 4 EDCA QOS priorities */ | ||
236 | hw->queues = 4; | ||
237 | #ifdef CONFIG_IWL4965_HT | ||
238 | /* Enhanced value; more queues, to support 11n aggregation */ | ||
239 | hw->queues = 16; | ||
240 | #endif /* CONFIG_IWL4965_HT */ | ||
241 | } | ||
242 | |||
243 | int iwl_setup(struct iwl_priv *priv) | ||
244 | { | ||
245 | int ret = 0; | ||
246 | iwlcore_init_hw(priv); | ||
247 | ret = priv->cfg->ops->lib->init_drv(priv); | ||
248 | return ret; | ||
249 | } | ||
250 | EXPORT_SYMBOL(iwl_setup); | ||
251 | |||