]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/wireless/iwlwifi/iwl-core.c
iwlwifi: Add power level support
[karo-tx-linux.git] / drivers / net / wireless / iwlwifi / iwl-core.c
1 /******************************************************************************
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>
32 #include <net/mac80211.h>
33
34 struct iwl_priv; /* FIXME: remove */
35 #include "iwl-debug.h"
36 #include "iwl-eeprom.h"
37 #include "iwl-4965.h" /* FIXME: remove */
38 #include "iwl-core.h"
39 #include "iwl-rfkill.h"
40 #include "iwl-power.h"
41
42
43 MODULE_DESCRIPTION("iwl core");
44 MODULE_VERSION(IWLWIFI_VERSION);
45 MODULE_AUTHOR(DRV_COPYRIGHT);
46 MODULE_LICENSE("GPL");
47
48 #ifdef CONFIG_IWLWIFI_DEBUG
49 u32 iwl_debug_level;
50 EXPORT_SYMBOL(iwl_debug_level);
51 #endif
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
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 {
196         if (!iwl_get_channel_info(priv, band, channel)) {
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
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 {
260         int ret;
261         switch (notify) {
262         case IWLCORE_INIT_EVT:
263                 ret = iwl_rfkill_init(priv);
264                 if (ret)
265                         IWL_ERROR("Unable to initialize RFKILL system. "
266                                   "Ignoring error: %d\n", ret);
267                 iwl_power_initialize(priv);
268                 break;
269         case IWLCORE_START_EVT:
270                 iwl_power_update_mode(priv, 1);
271                 break;
272         case IWLCORE_STOP_EVT:
273                 break;
274         case IWLCORE_REMOVE_EVT:
275                 iwl_rfkill_unregister(priv);
276                 break;
277         }
278
279         return 0;
280 }
281 EXPORT_SYMBOL(iwlcore_low_level_notify);
282
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);
295