Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | * |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 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> |
Assaf Krauss | 1d0a082 | 2008-03-14 10:38:48 -0700 | [diff] [blame] | 32 | #include <net/mac80211.h> |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 33 | |
Tomas Winkler | 712b6cf | 2008-03-12 16:58:52 -0700 | [diff] [blame] | 34 | struct iwl_priv; /* FIXME: remove */ |
Tomas Winkler | 0a6857e | 2008-03-12 16:58:49 -0700 | [diff] [blame] | 35 | #include "iwl-debug.h" |
Assaf Krauss | 6bc913b | 2008-03-11 16:17:18 -0700 | [diff] [blame] | 36 | #include "iwl-eeprom.h" |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 37 | #include "iwl-core.h" |
| 38 | |
Assaf Krauss | 1d0a082 | 2008-03-14 10:38:48 -0700 | [diff] [blame] | 39 | #include "iwl-4965.h" /* FIXME: remove */ |
| 40 | |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 41 | MODULE_DESCRIPTION("iwl core"); |
| 42 | MODULE_VERSION(IWLWIFI_VERSION); |
| 43 | MODULE_AUTHOR(DRV_COPYRIGHT); |
Tomas Winkler | 712b6cf | 2008-03-12 16:58:52 -0700 | [diff] [blame] | 44 | MODULE_LICENSE("GPL"); |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 45 | |
Tomas Winkler | 0a6857e | 2008-03-12 16:58:49 -0700 | [diff] [blame] | 46 | #ifdef CONFIG_IWLWIFI_DEBUG |
| 47 | u32 iwl_debug_level; |
| 48 | EXPORT_SYMBOL(iwl_debug_level); |
Tomas Winkler | df48c32 | 2008-03-06 10:40:19 -0800 | [diff] [blame] | 49 | #endif |
Assaf Krauss | 1d0a082 | 2008-03-14 10:38:48 -0700 | [diff] [blame] | 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 | |
Assaf Krauss | bf85ea4 | 2008-03-14 10:38:49 -0700 | [diff] [blame] | 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 | { |
Assaf Krauss | 8622e70 | 2008-03-21 13:53:43 -0700 | [diff] [blame^] | 194 | if (!iwl_get_channel_info(priv, band, channel)) { |
Assaf Krauss | bf85ea4 | 2008-03-14 10:38:49 -0700 | [diff] [blame] | 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 | |