| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | * Atheros AR9170 driver | 
|  | 3 | * | 
|  | 4 | * mac80211 interaction code | 
|  | 5 | * | 
|  | 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | 
|  | 7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | 
|  | 8 | * | 
|  | 9 | * This program is free software; you can redistribute it and/or modify | 
|  | 10 | * it under the terms of the GNU General Public License as published by | 
|  | 11 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 12 | * (at your option) any later version. | 
|  | 13 | * | 
|  | 14 | * This program is distributed in the hope that it will be useful, | 
|  | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 17 | * GNU General Public License for more details. | 
|  | 18 | * | 
|  | 19 | * You should have received a copy of the GNU General Public License | 
|  | 20 | * along with this program; see the file COPYING.  If not, see | 
|  | 21 | * http://www.gnu.org/licenses/. | 
|  | 22 | * | 
|  | 23 | * This file incorporates work covered by the following copyright and | 
|  | 24 | * permission notice: | 
|  | 25 | *    Copyright (c) 2007-2008 Atheros Communications, Inc. | 
|  | 26 | * | 
|  | 27 | *    Permission to use, copy, modify, and/or distribute this software for any | 
|  | 28 | *    purpose with or without fee is hereby granted, provided that the above | 
|  | 29 | *    copyright notice and this permission notice appear in all copies. | 
|  | 30 | * | 
|  | 31 | *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
|  | 32 | *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
|  | 33 | *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 
|  | 34 | *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
|  | 35 | *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
|  | 36 | *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 
|  | 37 | *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
|  | 38 | */ | 
|  | 39 |  | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 40 | #include <linux/init.h> | 
|  | 41 | #include <linux/module.h> | 
|  | 42 | #include <linux/etherdevice.h> | 
|  | 43 | #include <net/mac80211.h> | 
|  | 44 | #include "ar9170.h" | 
|  | 45 | #include "hw.h" | 
|  | 46 | #include "cmd.h" | 
|  | 47 |  | 
|  | 48 | static int modparam_nohwcrypt; | 
|  | 49 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 
|  | 50 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 51 |  | 
|  | 52 | #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {	\ | 
|  | 53 | .bitrate	= (_bitrate),			\ | 
|  | 54 | .flags		= (_flags),			\ | 
|  | 55 | .hw_value	= (_hw_rate) | (_txpidx) << 4,	\ | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | static struct ieee80211_rate __ar9170_ratetable[] = { | 
|  | 59 | RATE(10, 0, 0, 0), | 
|  | 60 | RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), | 
|  | 61 | RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), | 
|  | 62 | RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), | 
|  | 63 | RATE(60, 0xb, 0, 0), | 
|  | 64 | RATE(90, 0xf, 0, 0), | 
|  | 65 | RATE(120, 0xa, 0, 0), | 
|  | 66 | RATE(180, 0xe, 0, 0), | 
|  | 67 | RATE(240, 0x9, 0, 0), | 
|  | 68 | RATE(360, 0xd, 1, 0), | 
|  | 69 | RATE(480, 0x8, 2, 0), | 
|  | 70 | RATE(540, 0xc, 3, 0), | 
|  | 71 | }; | 
|  | 72 | #undef RATE | 
|  | 73 |  | 
|  | 74 | #define ar9170_g_ratetable	(__ar9170_ratetable + 0) | 
|  | 75 | #define ar9170_g_ratetable_size	12 | 
|  | 76 | #define ar9170_a_ratetable	(__ar9170_ratetable + 4) | 
|  | 77 | #define ar9170_a_ratetable_size	8 | 
|  | 78 |  | 
|  | 79 | /* | 
|  | 80 | * NB: The hw_value is used as an index into the ar9170_phy_freq_params | 
|  | 81 | *     array in phy.c so that we don't have to do frequency lookups! | 
|  | 82 | */ | 
|  | 83 | #define CHAN(_freq, _idx) {		\ | 
|  | 84 | .center_freq	= (_freq),	\ | 
|  | 85 | .hw_value	= (_idx),	\ | 
|  | 86 | .max_power	= 18, /* XXX */	\ | 
|  | 87 | } | 
|  | 88 |  | 
|  | 89 | static struct ieee80211_channel ar9170_2ghz_chantable[] = { | 
|  | 90 | CHAN(2412,  0), | 
|  | 91 | CHAN(2417,  1), | 
|  | 92 | CHAN(2422,  2), | 
|  | 93 | CHAN(2427,  3), | 
|  | 94 | CHAN(2432,  4), | 
|  | 95 | CHAN(2437,  5), | 
|  | 96 | CHAN(2442,  6), | 
|  | 97 | CHAN(2447,  7), | 
|  | 98 | CHAN(2452,  8), | 
|  | 99 | CHAN(2457,  9), | 
|  | 100 | CHAN(2462, 10), | 
|  | 101 | CHAN(2467, 11), | 
|  | 102 | CHAN(2472, 12), | 
|  | 103 | CHAN(2484, 13), | 
|  | 104 | }; | 
|  | 105 |  | 
|  | 106 | static struct ieee80211_channel ar9170_5ghz_chantable[] = { | 
|  | 107 | CHAN(4920, 14), | 
|  | 108 | CHAN(4940, 15), | 
|  | 109 | CHAN(4960, 16), | 
|  | 110 | CHAN(4980, 17), | 
|  | 111 | CHAN(5040, 18), | 
|  | 112 | CHAN(5060, 19), | 
|  | 113 | CHAN(5080, 20), | 
|  | 114 | CHAN(5180, 21), | 
|  | 115 | CHAN(5200, 22), | 
|  | 116 | CHAN(5220, 23), | 
|  | 117 | CHAN(5240, 24), | 
|  | 118 | CHAN(5260, 25), | 
|  | 119 | CHAN(5280, 26), | 
|  | 120 | CHAN(5300, 27), | 
|  | 121 | CHAN(5320, 28), | 
|  | 122 | CHAN(5500, 29), | 
|  | 123 | CHAN(5520, 30), | 
|  | 124 | CHAN(5540, 31), | 
|  | 125 | CHAN(5560, 32), | 
|  | 126 | CHAN(5580, 33), | 
|  | 127 | CHAN(5600, 34), | 
|  | 128 | CHAN(5620, 35), | 
|  | 129 | CHAN(5640, 36), | 
|  | 130 | CHAN(5660, 37), | 
|  | 131 | CHAN(5680, 38), | 
|  | 132 | CHAN(5700, 39), | 
|  | 133 | CHAN(5745, 40), | 
|  | 134 | CHAN(5765, 41), | 
|  | 135 | CHAN(5785, 42), | 
|  | 136 | CHAN(5805, 43), | 
|  | 137 | CHAN(5825, 44), | 
|  | 138 | CHAN(5170, 45), | 
|  | 139 | CHAN(5190, 46), | 
|  | 140 | CHAN(5210, 47), | 
|  | 141 | CHAN(5230, 48), | 
|  | 142 | }; | 
|  | 143 | #undef CHAN | 
|  | 144 |  | 
|  | 145 | static struct ieee80211_supported_band ar9170_band_2GHz = { | 
|  | 146 | .channels	= ar9170_2ghz_chantable, | 
|  | 147 | .n_channels	= ARRAY_SIZE(ar9170_2ghz_chantable), | 
|  | 148 | .bitrates	= ar9170_g_ratetable, | 
|  | 149 | .n_bitrates	= ar9170_g_ratetable_size, | 
|  | 150 | }; | 
|  | 151 |  | 
|  | 152 | #ifdef AR9170_QUEUE_DEBUG | 
|  | 153 | /* | 
|  | 154 | * In case some wants works with AR9170's crazy tx_status queueing techniques. | 
|  | 155 | * He might need this rather useful probing function. | 
|  | 156 | * | 
|  | 157 | * NOTE: caller must hold the queue's spinlock! | 
|  | 158 | */ | 
|  | 159 |  | 
|  | 160 | static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) | 
|  | 161 | { | 
|  | 162 | struct ar9170_tx_control *txc = (void *) skb->data; | 
|  | 163 | struct ieee80211_hdr *hdr = (void *)txc->frame_data; | 
|  | 164 |  | 
|  | 165 | printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " | 
|  | 166 | "mac_control:%04x, phy_control:%08x]\n", | 
|  | 167 | wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), | 
|  | 168 | ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), | 
|  | 169 | le32_to_cpu(txc->phy_control)); | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, | 
|  | 173 | struct sk_buff_head *queue) | 
|  | 174 | { | 
|  | 175 | struct sk_buff *skb; | 
|  | 176 | int i = 0; | 
|  | 177 |  | 
|  | 178 | printk(KERN_DEBUG "---[ cut here ]---\n"); | 
|  | 179 | printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", | 
|  | 180 | wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); | 
|  | 181 |  | 
|  | 182 | skb_queue_walk(queue, skb) { | 
|  | 183 | struct ar9170_tx_control *txc = (void *) skb->data; | 
|  | 184 | struct ieee80211_hdr *hdr = (void *)txc->frame_data; | 
|  | 185 |  | 
|  | 186 | printk(KERN_DEBUG "index:%d => \n", i); | 
|  | 187 | ar9170_print_txheader(ar, skb); | 
|  | 188 | } | 
|  | 189 | printk(KERN_DEBUG "---[ end ]---\n"); | 
|  | 190 | } | 
|  | 191 | #endif /* AR9170_QUEUE_DEBUG */ | 
|  | 192 |  | 
|  | 193 | static struct ieee80211_supported_band ar9170_band_5GHz = { | 
|  | 194 | .channels	= ar9170_5ghz_chantable, | 
|  | 195 | .n_channels	= ARRAY_SIZE(ar9170_5ghz_chantable), | 
|  | 196 | .bitrates	= ar9170_a_ratetable, | 
|  | 197 | .n_bitrates	= ar9170_a_ratetable_size, | 
|  | 198 | }; | 
|  | 199 |  | 
|  | 200 | void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, | 
|  | 201 | bool valid_status, u16 tx_status) | 
|  | 202 | { | 
|  | 203 | struct ieee80211_tx_info *txinfo; | 
|  | 204 | unsigned int retries = 0, queue = skb_get_queue_mapping(skb); | 
|  | 205 | unsigned long flags; | 
|  | 206 |  | 
|  | 207 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | 
|  | 208 | ar->tx_stats[queue].len--; | 
|  | 209 | if (ieee80211_queue_stopped(ar->hw, queue)) | 
|  | 210 | ieee80211_wake_queue(ar->hw, queue); | 
|  | 211 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | 
|  | 212 |  | 
|  | 213 | txinfo = IEEE80211_SKB_CB(skb); | 
|  | 214 | ieee80211_tx_info_clear_status(txinfo); | 
|  | 215 |  | 
|  | 216 | switch (tx_status) { | 
|  | 217 | case AR9170_TX_STATUS_RETRY: | 
|  | 218 | retries = 2; | 
|  | 219 | case AR9170_TX_STATUS_COMPLETE: | 
|  | 220 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | 
|  | 221 | break; | 
|  | 222 |  | 
|  | 223 | case AR9170_TX_STATUS_FAILED: | 
|  | 224 | retries = ar->hw->conf.long_frame_max_tx_count; | 
|  | 225 | break; | 
|  | 226 |  | 
|  | 227 | default: | 
|  | 228 | printk(KERN_ERR "%s: invalid tx_status response (%x).\n", | 
|  | 229 | wiphy_name(ar->hw->wiphy), tx_status); | 
|  | 230 | break; | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | if (valid_status) | 
|  | 234 | txinfo->status.rates[0].count = retries + 1; | 
|  | 235 |  | 
|  | 236 | skb_pull(skb, sizeof(struct ar9170_tx_control)); | 
|  | 237 | ieee80211_tx_status_irqsafe(ar->hw, skb); | 
|  | 238 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 239 |  | 
|  | 240 | static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, | 
|  | 241 | const u8 *mac, | 
|  | 242 | const u32 queue, | 
|  | 243 | struct sk_buff_head *q) | 
|  | 244 | { | 
|  | 245 | unsigned long flags; | 
|  | 246 | struct sk_buff *skb; | 
|  | 247 |  | 
|  | 248 | spin_lock_irqsave(&q->lock, flags); | 
|  | 249 | skb_queue_walk(q, skb) { | 
|  | 250 | struct ar9170_tx_control *txc = (void *) skb->data; | 
|  | 251 | struct ieee80211_hdr *hdr = (void *) txc->frame_data; | 
|  | 252 | u32 txc_queue = (le32_to_cpu(txc->phy_control) & | 
|  | 253 | AR9170_TX_PHY_QOS_MASK) >> | 
|  | 254 | AR9170_TX_PHY_QOS_SHIFT; | 
|  | 255 |  | 
|  | 256 | if  ((queue != txc_queue) || | 
|  | 257 | (compare_ether_addr(ieee80211_get_DA(hdr), mac))) | 
|  | 258 | continue; | 
|  | 259 |  | 
|  | 260 | __skb_unlink(skb, q); | 
|  | 261 | spin_unlock_irqrestore(&q->lock, flags); | 
|  | 262 | return skb; | 
|  | 263 | } | 
|  | 264 | spin_unlock_irqrestore(&q->lock, flags); | 
|  | 265 | return NULL; | 
|  | 266 | } | 
|  | 267 |  | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 268 | static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, | 
|  | 269 | const u32 queue) | 
|  | 270 | { | 
|  | 271 | struct ieee80211_sta *sta; | 
|  | 272 | struct sk_buff *skb; | 
|  | 273 |  | 
|  | 274 | /* | 
|  | 275 | * Unfortunately, the firmware does not tell to which (queued) frame | 
|  | 276 | * this transmission status report belongs to. | 
|  | 277 | * | 
|  | 278 | * So we have to make risky guesses - with the scarce information | 
|  | 279 | * the firmware provided (-> destination MAC, and phy_control) - | 
|  | 280 | * and hope that we picked the right one... | 
|  | 281 | */ | 
|  | 282 | rcu_read_lock(); | 
|  | 283 | sta = ieee80211_find_sta(ar->hw, mac); | 
|  | 284 |  | 
|  | 285 | if (likely(sta)) { | 
|  | 286 | struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 287 | skb = skb_dequeue(&sta_priv->tx_status[queue]); | 
|  | 288 | rcu_read_unlock(); | 
|  | 289 | if (likely(skb)) | 
|  | 290 | return skb; | 
|  | 291 | } else | 
|  | 292 | rcu_read_unlock(); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 293 |  | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 294 | /* scan the waste queue for candidates */ | 
|  | 295 | skb = ar9170_find_skb_in_queue(ar, mac, queue, | 
|  | 296 | &ar->global_tx_status_waste); | 
|  | 297 | if (!skb) { | 
|  | 298 | /* so it still _must_ be in the global list. */ | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 299 | skb = ar9170_find_skb_in_queue(ar, mac, queue, | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 300 | &ar->global_tx_status); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 301 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 302 |  | 
|  | 303 | #ifdef AR9170_QUEUE_DEBUG | 
|  | 304 | if (unlikely((!skb) && net_ratelimit())) { | 
|  | 305 | printk(KERN_ERR "%s: ESS:[%pM] does not have any " | 
|  | 306 | "outstanding frames in this queue (%d).\n", | 
|  | 307 | wiphy_name(ar->hw->wiphy), mac, queue); | 
|  | 308 | } | 
|  | 309 | #endif /* AR9170_QUEUE_DEBUG */ | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 310 | return skb; | 
|  | 311 | } | 
|  | 312 |  | 
|  | 313 | /* | 
|  | 314 | * This worker tries to keep the global tx_status queue empty. | 
|  | 315 | * So we can guarantee that incoming tx_status reports for | 
|  | 316 | * unregistered stations are always synced with the actual | 
|  | 317 | * frame - which we think - belongs to. | 
|  | 318 | */ | 
|  | 319 |  | 
|  | 320 | static void ar9170_tx_status_janitor(struct work_struct *work) | 
|  | 321 | { | 
|  | 322 | struct ar9170 *ar = container_of(work, struct ar9170, | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 323 | tx_status_janitor.work); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 324 | struct sk_buff *skb; | 
|  | 325 |  | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 326 | if (unlikely(!IS_STARTED(ar))) | 
|  | 327 | return ; | 
|  | 328 |  | 
|  | 329 | mutex_lock(&ar->mutex); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 330 | /* recycle the garbage back to mac80211... one by one. */ | 
|  | 331 | while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { | 
|  | 332 | #ifdef AR9170_QUEUE_DEBUG | 
|  | 333 | printk(KERN_DEBUG "%s: dispose queued frame =>\n", | 
|  | 334 | wiphy_name(ar->hw->wiphy)); | 
|  | 335 | ar9170_print_txheader(ar, skb); | 
|  | 336 | #endif /* AR9170_QUEUE_DEBUG */ | 
|  | 337 | ar9170_handle_tx_status(ar, skb, false, | 
|  | 338 | AR9170_TX_STATUS_FAILED); | 
|  | 339 | } | 
|  | 340 |  | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 341 | while ((skb = skb_dequeue(&ar->global_tx_status))) { | 
|  | 342 | #ifdef AR9170_QUEUE_DEBUG | 
|  | 343 | printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", | 
|  | 344 | wiphy_name(ar->hw->wiphy)); | 
|  | 345 |  | 
|  | 346 | ar9170_print_txheader(ar, skb); | 
|  | 347 | #endif /* AR9170_QUEUE_DEBUG */ | 
|  | 348 | skb_queue_tail(&ar->global_tx_status_waste, skb); | 
|  | 349 | } | 
|  | 350 |  | 
|  | 351 | /* recall the janitor in 100ms - if there's garbage in the can. */ | 
|  | 352 | if (skb_queue_len(&ar->global_tx_status_waste) > 0) | 
|  | 353 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, | 
|  | 354 | msecs_to_jiffies(100)); | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 355 |  | 
|  | 356 | mutex_unlock(&ar->mutex); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 357 | } | 
|  | 358 |  | 
|  | 359 | static void ar9170_handle_command_response(struct ar9170 *ar, | 
|  | 360 | void *buf, u32 len) | 
|  | 361 | { | 
|  | 362 | struct ar9170_cmd_response *cmd = (void *) buf; | 
|  | 363 |  | 
|  | 364 | if ((cmd->type & 0xc0) != 0xc0) { | 
|  | 365 | ar->callback_cmd(ar, len, buf); | 
|  | 366 | return; | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | /* hardware event handlers */ | 
|  | 370 | switch (cmd->type) { | 
|  | 371 | case 0xc1: { | 
|  | 372 | /* | 
|  | 373 | * TX status notification: | 
|  | 374 | * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 | 
|  | 375 | * | 
|  | 376 | * XX always 81 | 
|  | 377 | * YY always 00 | 
|  | 378 | * M1-M6 is the MAC address | 
|  | 379 | * R1-R4 is the transmit rate | 
|  | 380 | * S1-S2 is the transmit status | 
|  | 381 | */ | 
|  | 382 |  | 
|  | 383 | struct sk_buff *skb; | 
|  | 384 | u32 queue = (le32_to_cpu(cmd->tx_status.rate) & | 
|  | 385 | AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; | 
|  | 386 |  | 
|  | 387 | skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); | 
|  | 388 | if (unlikely(!skb)) | 
|  | 389 | return ; | 
|  | 390 |  | 
|  | 391 | ar9170_handle_tx_status(ar, skb, true, | 
|  | 392 | le16_to_cpu(cmd->tx_status.status)); | 
|  | 393 | break; | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | case 0xc0: | 
|  | 397 | /* | 
|  | 398 | * pre-TBTT event | 
|  | 399 | */ | 
|  | 400 | if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) | 
|  | 401 | queue_work(ar->hw->workqueue, &ar->beacon_work); | 
|  | 402 | break; | 
|  | 403 |  | 
|  | 404 | case 0xc2: | 
|  | 405 | /* | 
|  | 406 | * (IBSS) beacon send notification | 
|  | 407 | * bytes: 04 c2 XX YY B4 B3 B2 B1 | 
|  | 408 | * | 
|  | 409 | * XX always 80 | 
|  | 410 | * YY always 00 | 
|  | 411 | * B1-B4 "should" be the number of send out beacons. | 
|  | 412 | */ | 
|  | 413 | break; | 
|  | 414 |  | 
|  | 415 | case 0xc3: | 
|  | 416 | /* End of Atim Window */ | 
|  | 417 | break; | 
|  | 418 |  | 
|  | 419 | case 0xc4: | 
|  | 420 | case 0xc5: | 
|  | 421 | /* BlockACK events */ | 
|  | 422 | break; | 
|  | 423 |  | 
|  | 424 | case 0xc6: | 
|  | 425 | /* Watchdog Interrupt */ | 
|  | 426 | break; | 
|  | 427 |  | 
|  | 428 | case 0xc9: | 
|  | 429 | /* retransmission issue / SIFS/EIFS collision ?! */ | 
|  | 430 | break; | 
|  | 431 |  | 
|  | 432 | default: | 
|  | 433 | printk(KERN_INFO "received unhandled event %x\n", cmd->type); | 
|  | 434 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); | 
|  | 435 | break; | 
|  | 436 | } | 
|  | 437 | } | 
|  | 438 |  | 
|  | 439 | /* | 
|  | 440 | * If the frame alignment is right (or the kernel has | 
|  | 441 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | 
|  | 442 | * is only a single MPDU in the USB frame, then we can | 
|  | 443 | * submit to mac80211 the SKB directly. However, since | 
|  | 444 | * there may be multiple packets in one SKB in stream | 
|  | 445 | * mode, and we need to observe the proper ordering, | 
|  | 446 | * this is non-trivial. | 
|  | 447 | */ | 
|  | 448 | static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | 
|  | 449 | { | 
|  | 450 | struct sk_buff *skb; | 
|  | 451 | struct ar9170_rx_head *head = (void *)buf; | 
|  | 452 | struct ar9170_rx_tail *tail; | 
|  | 453 | struct ieee80211_rx_status status; | 
|  | 454 | int mpdu_len, i; | 
|  | 455 | u8 error, antennas = 0, decrypt; | 
|  | 456 | __le16 fc; | 
|  | 457 | int reserved; | 
|  | 458 |  | 
|  | 459 | if (unlikely(!IS_STARTED(ar))) | 
|  | 460 | return ; | 
|  | 461 |  | 
|  | 462 | /* Received MPDU */ | 
|  | 463 | mpdu_len = len; | 
|  | 464 | mpdu_len -= sizeof(struct ar9170_rx_head); | 
|  | 465 | mpdu_len -= sizeof(struct ar9170_rx_tail); | 
|  | 466 | BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); | 
|  | 467 | BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); | 
|  | 468 |  | 
|  | 469 | if (mpdu_len <= FCS_LEN) | 
|  | 470 | return; | 
|  | 471 |  | 
|  | 472 | tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); | 
|  | 473 |  | 
|  | 474 | for (i = 0; i < 3; i++) | 
|  | 475 | if (tail->rssi[i] != 0x80) | 
|  | 476 | antennas |= BIT(i); | 
|  | 477 |  | 
|  | 478 | /* post-process RSSI */ | 
|  | 479 | for (i = 0; i < 7; i++) | 
|  | 480 | if (tail->rssi[i] & 0x80) | 
|  | 481 | tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; | 
|  | 482 |  | 
|  | 483 | memset(&status, 0, sizeof(status)); | 
|  | 484 |  | 
|  | 485 | status.band = ar->channel->band; | 
|  | 486 | status.freq = ar->channel->center_freq; | 
|  | 487 | status.signal = ar->noise[0] + tail->rssi_combined; | 
|  | 488 | status.noise = ar->noise[0]; | 
|  | 489 | status.antenna = antennas; | 
|  | 490 |  | 
|  | 491 | switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { | 
|  | 492 | case AR9170_RX_STATUS_MODULATION_CCK: | 
|  | 493 | if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) | 
|  | 494 | status.flag |= RX_FLAG_SHORTPRE; | 
|  | 495 | switch (head->plcp[0]) { | 
|  | 496 | case 0x0a: | 
|  | 497 | status.rate_idx = 0; | 
|  | 498 | break; | 
|  | 499 | case 0x14: | 
|  | 500 | status.rate_idx = 1; | 
|  | 501 | break; | 
|  | 502 | case 0x37: | 
|  | 503 | status.rate_idx = 2; | 
|  | 504 | break; | 
|  | 505 | case 0x6e: | 
|  | 506 | status.rate_idx = 3; | 
|  | 507 | break; | 
|  | 508 | default: | 
|  | 509 | if ((!ar->sniffer_enabled) && (net_ratelimit())) | 
|  | 510 | printk(KERN_ERR "%s: invalid plcp cck rate " | 
|  | 511 | "(%x).\n", wiphy_name(ar->hw->wiphy), | 
|  | 512 | head->plcp[0]); | 
|  | 513 | return; | 
|  | 514 | } | 
|  | 515 | break; | 
|  | 516 | case AR9170_RX_STATUS_MODULATION_OFDM: | 
|  | 517 | switch (head->plcp[0] & 0xF) { | 
|  | 518 | case 0xB: | 
|  | 519 | status.rate_idx = 0; | 
|  | 520 | break; | 
|  | 521 | case 0xF: | 
|  | 522 | status.rate_idx = 1; | 
|  | 523 | break; | 
|  | 524 | case 0xA: | 
|  | 525 | status.rate_idx = 2; | 
|  | 526 | break; | 
|  | 527 | case 0xE: | 
|  | 528 | status.rate_idx = 3; | 
|  | 529 | break; | 
|  | 530 | case 0x9: | 
|  | 531 | status.rate_idx = 4; | 
|  | 532 | break; | 
|  | 533 | case 0xD: | 
|  | 534 | status.rate_idx = 5; | 
|  | 535 | break; | 
|  | 536 | case 0x8: | 
|  | 537 | status.rate_idx = 6; | 
|  | 538 | break; | 
|  | 539 | case 0xC: | 
|  | 540 | status.rate_idx = 7; | 
|  | 541 | break; | 
|  | 542 | default: | 
|  | 543 | if ((!ar->sniffer_enabled) && (net_ratelimit())) | 
|  | 544 | printk(KERN_ERR "%s: invalid plcp ofdm rate " | 
|  | 545 | "(%x).\n", wiphy_name(ar->hw->wiphy), | 
|  | 546 | head->plcp[0]); | 
|  | 547 | return; | 
|  | 548 | } | 
|  | 549 | if (status.band == IEEE80211_BAND_2GHZ) | 
|  | 550 | status.rate_idx += 4; | 
|  | 551 | break; | 
|  | 552 | case AR9170_RX_STATUS_MODULATION_HT: | 
|  | 553 | case AR9170_RX_STATUS_MODULATION_DUPOFDM: | 
|  | 554 | /* XXX */ | 
|  | 555 |  | 
|  | 556 | if (net_ratelimit()) | 
|  | 557 | printk(KERN_ERR "%s: invalid modulation\n", | 
|  | 558 | wiphy_name(ar->hw->wiphy)); | 
|  | 559 | return; | 
|  | 560 | } | 
|  | 561 |  | 
|  | 562 | error = tail->error; | 
|  | 563 |  | 
|  | 564 | if (error & AR9170_RX_ERROR_MMIC) { | 
|  | 565 | status.flag |= RX_FLAG_MMIC_ERROR; | 
|  | 566 | error &= ~AR9170_RX_ERROR_MMIC; | 
|  | 567 | } | 
|  | 568 |  | 
|  | 569 | if (error & AR9170_RX_ERROR_PLCP) { | 
|  | 570 | status.flag |= RX_FLAG_FAILED_PLCP_CRC; | 
|  | 571 | error &= ~AR9170_RX_ERROR_PLCP; | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | if (error & AR9170_RX_ERROR_FCS) { | 
|  | 575 | status.flag |= RX_FLAG_FAILED_FCS_CRC; | 
|  | 576 | error &= ~AR9170_RX_ERROR_FCS; | 
|  | 577 | } | 
|  | 578 |  | 
|  | 579 | decrypt = ar9170_get_decrypt_type(tail); | 
|  | 580 | if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && | 
|  | 581 | decrypt != AR9170_ENC_ALG_NONE) | 
|  | 582 | status.flag |= RX_FLAG_DECRYPTED; | 
|  | 583 |  | 
|  | 584 | /* ignore wrong RA errors */ | 
|  | 585 | error &= ~AR9170_RX_ERROR_WRONG_RA; | 
|  | 586 |  | 
|  | 587 | if (error & AR9170_RX_ERROR_DECRYPT) { | 
|  | 588 | error &= ~AR9170_RX_ERROR_DECRYPT; | 
|  | 589 |  | 
|  | 590 | /* | 
|  | 591 | * Rx decryption is done in place, | 
|  | 592 | * the original data is lost anyway. | 
|  | 593 | */ | 
|  | 594 | return ; | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | /* drop any other error frames */ | 
|  | 598 | if ((error) && (net_ratelimit())) { | 
|  | 599 | printk(KERN_DEBUG "%s: errors: %#x\n", | 
|  | 600 | wiphy_name(ar->hw->wiphy), error); | 
|  | 601 | return; | 
|  | 602 | } | 
|  | 603 |  | 
|  | 604 | buf += sizeof(struct ar9170_rx_head); | 
|  | 605 | fc = *(__le16 *)buf; | 
|  | 606 |  | 
|  | 607 | if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) | 
|  | 608 | reserved = 32 + 2; | 
|  | 609 | else | 
|  | 610 | reserved = 32; | 
|  | 611 |  | 
|  | 612 | skb = dev_alloc_skb(mpdu_len + reserved); | 
|  | 613 | if (!skb) | 
|  | 614 | return; | 
|  | 615 |  | 
|  | 616 | skb_reserve(skb, reserved); | 
|  | 617 | memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); | 
|  | 618 | ieee80211_rx_irqsafe(ar->hw, skb, &status); | 
|  | 619 | } | 
|  | 620 |  | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 621 | void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) | 
|  | 622 | { | 
|  | 623 | unsigned int i, tlen, resplen; | 
|  | 624 | u8 *tbuf, *respbuf; | 
|  | 625 |  | 
|  | 626 | tbuf = skb->data; | 
|  | 627 | tlen = skb->len; | 
|  | 628 |  | 
|  | 629 | while (tlen >= 4) { | 
|  | 630 | int clen = tbuf[1] << 8 | tbuf[0]; | 
|  | 631 | int wlen = (clen + 3) & ~3; | 
|  | 632 |  | 
|  | 633 | /* | 
|  | 634 | * parse stream (if any) | 
|  | 635 | */ | 
|  | 636 | if (tbuf[2] != 0 || tbuf[3] != 0x4e) { | 
|  | 637 | printk(KERN_ERR "%s: missing tag!\n", | 
|  | 638 | wiphy_name(ar->hw->wiphy)); | 
|  | 639 | return ; | 
|  | 640 | } | 
|  | 641 | if (wlen > tlen - 4) { | 
|  | 642 | printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", | 
|  | 643 | wiphy_name(ar->hw->wiphy), clen, wlen, tlen); | 
|  | 644 | print_hex_dump(KERN_DEBUG, "data: ", | 
|  | 645 | DUMP_PREFIX_OFFSET, | 
|  | 646 | 16, 1, tbuf, tlen, true); | 
|  | 647 | return ; | 
|  | 648 | } | 
|  | 649 | resplen = clen; | 
|  | 650 | respbuf = tbuf + 4; | 
|  | 651 | tbuf += wlen + 4; | 
|  | 652 | tlen -= wlen + 4; | 
|  | 653 |  | 
|  | 654 | i = 0; | 
|  | 655 |  | 
|  | 656 | /* weird thing, but this is the same in the original driver */ | 
|  | 657 | while (resplen > 2 && i < 12 && | 
|  | 658 | respbuf[0] == 0xff && respbuf[1] == 0xff) { | 
|  | 659 | i += 2; | 
|  | 660 | resplen -= 2; | 
|  | 661 | respbuf += 2; | 
|  | 662 | } | 
|  | 663 |  | 
|  | 664 | if (resplen < 4) | 
|  | 665 | continue; | 
|  | 666 |  | 
|  | 667 | /* found the 6 * 0xffff marker? */ | 
|  | 668 | if (i == 12) | 
|  | 669 | ar9170_handle_command_response(ar, respbuf, resplen); | 
|  | 670 | else | 
|  | 671 | ar9170_handle_mpdu(ar, respbuf, resplen); | 
|  | 672 | } | 
|  | 673 |  | 
|  | 674 | if (tlen) | 
|  | 675 | printk(KERN_ERR "%s: buffer remains!\n", | 
|  | 676 | wiphy_name(ar->hw->wiphy)); | 
|  | 677 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 678 |  | 
|  | 679 | #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop)		\ | 
|  | 680 | do {									\ | 
|  | 681 | queue.aifs = ai_fs;						\ | 
|  | 682 | queue.cw_min = cwmin;						\ | 
|  | 683 | queue.cw_max = cwmax;						\ | 
|  | 684 | queue.txop = _txop;						\ | 
|  | 685 | } while (0) | 
|  | 686 |  | 
|  | 687 | static int ar9170_op_start(struct ieee80211_hw *hw) | 
|  | 688 | { | 
|  | 689 | struct ar9170 *ar = hw->priv; | 
|  | 690 | int err, i; | 
|  | 691 |  | 
|  | 692 | mutex_lock(&ar->mutex); | 
|  | 693 |  | 
|  | 694 | /* reinitialize queues statistics */ | 
|  | 695 | memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); | 
|  | 696 | for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) | 
|  | 697 | ar->tx_stats[i].limit = 8; | 
|  | 698 |  | 
|  | 699 | /* reset QoS defaults */ | 
|  | 700 | AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023,  0); /* BEST EFFORT*/ | 
|  | 701 | AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023,  0); /* BACKGROUND */ | 
|  | 702 | AR9170_FILL_QUEUE(ar->edcf[2], 2, 7,    15, 94); /* VIDEO */ | 
|  | 703 | AR9170_FILL_QUEUE(ar->edcf[3], 2, 3,     7, 47); /* VOICE */ | 
|  | 704 | AR9170_FILL_QUEUE(ar->edcf[4], 2, 3,     7,  0); /* SPECIAL */ | 
|  | 705 |  | 
|  | 706 | err = ar->open(ar); | 
|  | 707 | if (err) | 
|  | 708 | goto out; | 
|  | 709 |  | 
|  | 710 | err = ar9170_init_mac(ar); | 
|  | 711 | if (err) | 
|  | 712 | goto out; | 
|  | 713 |  | 
|  | 714 | err = ar9170_set_qos(ar); | 
|  | 715 | if (err) | 
|  | 716 | goto out; | 
|  | 717 |  | 
|  | 718 | err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); | 
|  | 719 | if (err) | 
|  | 720 | goto out; | 
|  | 721 |  | 
|  | 722 | err = ar9170_init_rf(ar); | 
|  | 723 | if (err) | 
|  | 724 | goto out; | 
|  | 725 |  | 
|  | 726 | /* start DMA */ | 
|  | 727 | err = ar9170_write_reg(ar, 0x1c3d30, 0x100); | 
|  | 728 | if (err) | 
|  | 729 | goto out; | 
|  | 730 |  | 
|  | 731 | ar->state = AR9170_STARTED; | 
|  | 732 |  | 
|  | 733 | out: | 
|  | 734 | mutex_unlock(&ar->mutex); | 
|  | 735 | return err; | 
|  | 736 | } | 
|  | 737 |  | 
|  | 738 | static void ar9170_op_stop(struct ieee80211_hw *hw) | 
|  | 739 | { | 
|  | 740 | struct ar9170 *ar = hw->priv; | 
|  | 741 |  | 
|  | 742 | if (IS_STARTED(ar)) | 
|  | 743 | ar->state = AR9170_IDLE; | 
|  | 744 |  | 
|  | 745 | mutex_lock(&ar->mutex); | 
|  | 746 |  | 
|  | 747 | cancel_delayed_work_sync(&ar->tx_status_janitor); | 
|  | 748 | cancel_work_sync(&ar->filter_config_work); | 
|  | 749 | cancel_work_sync(&ar->beacon_work); | 
|  | 750 | skb_queue_purge(&ar->global_tx_status_waste); | 
|  | 751 | skb_queue_purge(&ar->global_tx_status); | 
|  | 752 |  | 
|  | 753 | if (IS_ACCEPTING_CMD(ar)) { | 
|  | 754 | ar9170_set_leds_state(ar, 0); | 
|  | 755 |  | 
|  | 756 | /* stop DMA */ | 
|  | 757 | ar9170_write_reg(ar, 0x1c3d30, 0); | 
|  | 758 | ar->stop(ar); | 
|  | 759 | } | 
|  | 760 |  | 
|  | 761 | mutex_unlock(&ar->mutex); | 
|  | 762 | } | 
|  | 763 |  | 
|  | 764 | int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 
|  | 765 | { | 
|  | 766 | struct ar9170 *ar = hw->priv; | 
|  | 767 | struct ieee80211_hdr *hdr; | 
|  | 768 | struct ar9170_tx_control *txc; | 
|  | 769 | struct ieee80211_tx_info *info; | 
|  | 770 | struct ieee80211_rate *rate = NULL; | 
|  | 771 | struct ieee80211_tx_rate *txrate; | 
|  | 772 | unsigned int queue = skb_get_queue_mapping(skb); | 
|  | 773 | unsigned long flags = 0; | 
|  | 774 | struct ar9170_sta_info *sta_info = NULL; | 
|  | 775 | u32 power, chains; | 
|  | 776 | u16 keytype = 0; | 
|  | 777 | u16 len, icv = 0; | 
|  | 778 | int err; | 
|  | 779 | bool tx_status; | 
|  | 780 |  | 
|  | 781 | if (unlikely(!IS_STARTED(ar))) | 
|  | 782 | goto err_free; | 
|  | 783 |  | 
|  | 784 | hdr = (void *)skb->data; | 
|  | 785 | info = IEEE80211_SKB_CB(skb); | 
|  | 786 | len = skb->len; | 
|  | 787 |  | 
|  | 788 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | 
|  | 789 | if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { | 
|  | 790 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | 
|  | 791 | return NETDEV_TX_OK; | 
|  | 792 | } | 
|  | 793 |  | 
|  | 794 | ar->tx_stats[queue].len++; | 
|  | 795 | ar->tx_stats[queue].count++; | 
|  | 796 | if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) | 
|  | 797 | ieee80211_stop_queue(hw, queue); | 
|  | 798 |  | 
|  | 799 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | 
|  | 800 |  | 
|  | 801 | txc = (void *)skb_push(skb, sizeof(*txc)); | 
|  | 802 |  | 
|  | 803 | tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || | 
|  | 804 | ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); | 
|  | 805 |  | 
|  | 806 | if (info->control.hw_key) { | 
|  | 807 | icv = info->control.hw_key->icv_len; | 
|  | 808 |  | 
|  | 809 | switch (info->control.hw_key->alg) { | 
|  | 810 | case ALG_WEP: | 
|  | 811 | keytype = AR9170_TX_MAC_ENCR_RC4; | 
|  | 812 | break; | 
|  | 813 | case ALG_TKIP: | 
|  | 814 | keytype = AR9170_TX_MAC_ENCR_RC4; | 
|  | 815 | break; | 
|  | 816 | case ALG_CCMP: | 
|  | 817 | keytype = AR9170_TX_MAC_ENCR_AES; | 
|  | 818 | break; | 
|  | 819 | default: | 
|  | 820 | WARN_ON(1); | 
|  | 821 | goto err_dequeue; | 
|  | 822 | } | 
|  | 823 | } | 
|  | 824 |  | 
|  | 825 | /* Length */ | 
|  | 826 | txc->length = cpu_to_le16(len + icv + 4); | 
|  | 827 |  | 
|  | 828 | txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | | 
|  | 829 | AR9170_TX_MAC_BACKOFF); | 
|  | 830 | txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << | 
|  | 831 | AR9170_TX_MAC_QOS_SHIFT); | 
|  | 832 | txc->mac_control |= cpu_to_le16(keytype); | 
|  | 833 | txc->phy_control = cpu_to_le32(0); | 
|  | 834 |  | 
|  | 835 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | 
|  | 836 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); | 
|  | 837 |  | 
|  | 838 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | 
|  | 839 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); | 
|  | 840 |  | 
|  | 841 | txrate = &info->control.rates[0]; | 
|  | 842 |  | 
|  | 843 | if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) | 
|  | 844 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); | 
|  | 845 | else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) | 
|  | 846 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); | 
|  | 847 |  | 
|  | 848 | if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) | 
|  | 849 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); | 
|  | 850 |  | 
|  | 851 | if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) | 
|  | 852 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); | 
|  | 853 |  | 
|  | 854 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 
|  | 855 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); | 
|  | 856 | /* this works because 40 MHz is 2 and dup is 3 */ | 
|  | 857 | if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) | 
|  | 858 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); | 
|  | 859 |  | 
|  | 860 | if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) | 
|  | 861 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); | 
|  | 862 |  | 
|  | 863 | if (txrate->flags & IEEE80211_TX_RC_MCS) { | 
|  | 864 | u32 r = txrate->idx; | 
|  | 865 | u8 *txpower; | 
|  | 866 |  | 
|  | 867 | r <<= AR9170_TX_PHY_MCS_SHIFT; | 
|  | 868 | if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) | 
|  | 869 | goto err_dequeue; | 
|  | 870 | txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); | 
|  | 871 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); | 
|  | 872 |  | 
|  | 873 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | 
|  | 874 | if (info->band == IEEE80211_BAND_5GHZ) | 
|  | 875 | txpower = ar->power_5G_ht40; | 
|  | 876 | else | 
|  | 877 | txpower = ar->power_2G_ht40; | 
|  | 878 | } else { | 
|  | 879 | if (info->band == IEEE80211_BAND_5GHZ) | 
|  | 880 | txpower = ar->power_5G_ht20; | 
|  | 881 | else | 
|  | 882 | txpower = ar->power_2G_ht20; | 
|  | 883 | } | 
|  | 884 |  | 
|  | 885 | power = txpower[(txrate->idx) & 7]; | 
|  | 886 | } else { | 
|  | 887 | u8 *txpower; | 
|  | 888 | u32 mod; | 
|  | 889 | u32 phyrate; | 
|  | 890 | u8 idx = txrate->idx; | 
|  | 891 |  | 
|  | 892 | if (info->band != IEEE80211_BAND_2GHZ) { | 
|  | 893 | idx += 4; | 
|  | 894 | txpower = ar->power_5G_leg; | 
|  | 895 | mod = AR9170_TX_PHY_MOD_OFDM; | 
|  | 896 | } else { | 
|  | 897 | if (idx < 4) { | 
|  | 898 | txpower = ar->power_2G_cck; | 
|  | 899 | mod = AR9170_TX_PHY_MOD_CCK; | 
|  | 900 | } else { | 
|  | 901 | mod = AR9170_TX_PHY_MOD_OFDM; | 
|  | 902 | txpower = ar->power_2G_ofdm; | 
|  | 903 | } | 
|  | 904 | } | 
|  | 905 |  | 
|  | 906 | rate = &__ar9170_ratetable[idx]; | 
|  | 907 |  | 
|  | 908 | phyrate = rate->hw_value & 0xF; | 
|  | 909 | power = txpower[(rate->hw_value & 0x30) >> 4]; | 
|  | 910 | phyrate <<= AR9170_TX_PHY_MCS_SHIFT; | 
|  | 911 |  | 
|  | 912 | txc->phy_control |= cpu_to_le32(mod); | 
|  | 913 | txc->phy_control |= cpu_to_le32(phyrate); | 
|  | 914 | } | 
|  | 915 |  | 
|  | 916 | power <<= AR9170_TX_PHY_TX_PWR_SHIFT; | 
|  | 917 | power &= AR9170_TX_PHY_TX_PWR_MASK; | 
|  | 918 | txc->phy_control |= cpu_to_le32(power); | 
|  | 919 |  | 
|  | 920 | /* set TX chains */ | 
|  | 921 | if (ar->eeprom.tx_mask == 1) { | 
|  | 922 | chains = AR9170_TX_PHY_TXCHAIN_1; | 
|  | 923 | } else { | 
|  | 924 | chains = AR9170_TX_PHY_TXCHAIN_2; | 
|  | 925 |  | 
|  | 926 | /* >= 36M legacy OFDM - use only one chain */ | 
|  | 927 | if (rate && rate->bitrate >= 360) | 
|  | 928 | chains = AR9170_TX_PHY_TXCHAIN_1; | 
|  | 929 | } | 
|  | 930 | txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); | 
|  | 931 |  | 
|  | 932 | if (tx_status) { | 
|  | 933 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); | 
|  | 934 | /* | 
|  | 935 | * WARNING: | 
|  | 936 | * Putting the QoS queue bits into an unexplored territory is | 
|  | 937 | * certainly not elegant. | 
|  | 938 | * | 
|  | 939 | * In my defense: This idea provides a reasonable way to | 
|  | 940 | * smuggle valuable information to the tx_status callback. | 
|  | 941 | * Also, the idea behind this bit-abuse came straight from | 
|  | 942 | * the original driver code. | 
|  | 943 | */ | 
|  | 944 |  | 
|  | 945 | txc->phy_control |= | 
|  | 946 | cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); | 
|  | 947 |  | 
|  | 948 | if (info->control.sta) { | 
|  | 949 | sta_info = (void *) info->control.sta->drv_priv; | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 950 | skb_queue_tail(&sta_info->tx_status[queue], skb); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 951 | } else { | 
|  | 952 | skb_queue_tail(&ar->global_tx_status, skb); | 
|  | 953 |  | 
|  | 954 | queue_delayed_work(ar->hw->workqueue, | 
|  | 955 | &ar->tx_status_janitor, | 
|  | 956 | msecs_to_jiffies(100)); | 
|  | 957 | } | 
|  | 958 | } | 
|  | 959 |  | 
|  | 960 | err = ar->tx(ar, skb, tx_status, 0); | 
|  | 961 | if (unlikely(tx_status && err)) { | 
|  | 962 | if (info->control.sta) | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 963 | skb_unlink(skb, &sta_info->tx_status[queue]); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 964 | else | 
|  | 965 | skb_unlink(skb, &ar->global_tx_status); | 
|  | 966 | } | 
|  | 967 |  | 
|  | 968 | return NETDEV_TX_OK; | 
|  | 969 |  | 
|  | 970 | err_dequeue: | 
|  | 971 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | 
|  | 972 | ar->tx_stats[queue].len--; | 
|  | 973 | ar->tx_stats[queue].count--; | 
|  | 974 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | 
|  | 975 |  | 
|  | 976 | err_free: | 
|  | 977 | dev_kfree_skb(skb); | 
|  | 978 | return NETDEV_TX_OK; | 
|  | 979 | } | 
|  | 980 |  | 
|  | 981 | static int ar9170_op_add_interface(struct ieee80211_hw *hw, | 
|  | 982 | struct ieee80211_if_init_conf *conf) | 
|  | 983 | { | 
|  | 984 | struct ar9170 *ar = hw->priv; | 
|  | 985 | int err = 0; | 
|  | 986 |  | 
|  | 987 | mutex_lock(&ar->mutex); | 
|  | 988 |  | 
|  | 989 | if (ar->vif) { | 
|  | 990 | err = -EBUSY; | 
|  | 991 | goto unlock; | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | ar->vif = conf->vif; | 
|  | 995 | memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN); | 
|  | 996 |  | 
|  | 997 | if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { | 
|  | 998 | ar->rx_software_decryption = true; | 
|  | 999 | ar->disable_offload = true; | 
|  | 1000 | } | 
|  | 1001 |  | 
|  | 1002 | ar->cur_filter = 0; | 
|  | 1003 | ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; | 
|  | 1004 | err = ar9170_update_frame_filter(ar); | 
|  | 1005 | if (err) | 
|  | 1006 | goto unlock; | 
|  | 1007 |  | 
|  | 1008 | err = ar9170_set_operating_mode(ar); | 
|  | 1009 |  | 
|  | 1010 | unlock: | 
|  | 1011 | mutex_unlock(&ar->mutex); | 
|  | 1012 | return err; | 
|  | 1013 | } | 
|  | 1014 |  | 
|  | 1015 | static void ar9170_op_remove_interface(struct ieee80211_hw *hw, | 
|  | 1016 | struct ieee80211_if_init_conf *conf) | 
|  | 1017 | { | 
|  | 1018 | struct ar9170 *ar = hw->priv; | 
|  | 1019 |  | 
|  | 1020 | mutex_lock(&ar->mutex); | 
|  | 1021 | ar->vif = NULL; | 
|  | 1022 | ar->want_filter = 0; | 
|  | 1023 | ar9170_update_frame_filter(ar); | 
|  | 1024 | ar9170_set_beacon_timers(ar); | 
|  | 1025 | dev_kfree_skb(ar->beacon); | 
|  | 1026 | ar->beacon = NULL; | 
|  | 1027 | ar->sniffer_enabled = false; | 
|  | 1028 | ar->rx_software_decryption = false; | 
|  | 1029 | ar9170_set_operating_mode(ar); | 
|  | 1030 | mutex_unlock(&ar->mutex); | 
|  | 1031 | } | 
|  | 1032 |  | 
|  | 1033 | static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) | 
|  | 1034 | { | 
|  | 1035 | struct ar9170 *ar = hw->priv; | 
|  | 1036 | int err = 0; | 
|  | 1037 |  | 
|  | 1038 | mutex_lock(&ar->mutex); | 
|  | 1039 |  | 
|  | 1040 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { | 
|  | 1041 | /* TODO */ | 
|  | 1042 | err = 0; | 
|  | 1043 | } | 
|  | 1044 |  | 
|  | 1045 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { | 
|  | 1046 | /* TODO */ | 
|  | 1047 | err = 0; | 
|  | 1048 | } | 
|  | 1049 |  | 
|  | 1050 | if (changed & IEEE80211_CONF_CHANGE_PS) { | 
|  | 1051 | /* TODO */ | 
|  | 1052 | err = 0; | 
|  | 1053 | } | 
|  | 1054 |  | 
|  | 1055 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 
|  | 1056 | /* TODO */ | 
|  | 1057 | err = 0; | 
|  | 1058 | } | 
|  | 1059 |  | 
|  | 1060 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | 
|  | 1061 | /* | 
|  | 1062 | * is it long_frame_max_tx_count or short_frame_max_tx_count? | 
|  | 1063 | */ | 
|  | 1064 |  | 
|  | 1065 | err = ar9170_set_hwretry_limit(ar, | 
|  | 1066 | ar->hw->conf.long_frame_max_tx_count); | 
|  | 1067 | if (err) | 
|  | 1068 | goto out; | 
|  | 1069 | } | 
|  | 1070 |  | 
|  | 1071 | if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { | 
|  | 1072 | err = ar9170_set_beacon_timers(ar); | 
|  | 1073 | if (err) | 
|  | 1074 | goto out; | 
|  | 1075 | } | 
|  | 1076 |  | 
|  | 1077 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 
|  | 1078 | err = ar9170_set_channel(ar, hw->conf.channel, | 
|  | 1079 | AR9170_RFI_NONE, AR9170_BW_20); | 
|  | 1080 | if (err) | 
|  | 1081 | goto out; | 
|  | 1082 | /* adjust slot time for 5 GHz */ | 
|  | 1083 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) | 
|  | 1084 | err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, | 
|  | 1085 | 9 << 10); | 
|  | 1086 | } | 
|  | 1087 |  | 
|  | 1088 | out: | 
|  | 1089 | mutex_unlock(&ar->mutex); | 
|  | 1090 | return err; | 
|  | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | static int ar9170_op_config_interface(struct ieee80211_hw *hw, | 
|  | 1094 | struct ieee80211_vif *vif, | 
|  | 1095 | struct ieee80211_if_conf *conf) | 
|  | 1096 | { | 
|  | 1097 | struct ar9170 *ar = hw->priv; | 
|  | 1098 | int err = 0; | 
|  | 1099 |  | 
|  | 1100 | mutex_lock(&ar->mutex); | 
|  | 1101 |  | 
|  | 1102 | if (conf->changed & IEEE80211_IFCC_BSSID) { | 
|  | 1103 | memcpy(ar->bssid, conf->bssid, ETH_ALEN); | 
|  | 1104 | err = ar9170_set_operating_mode(ar); | 
|  | 1105 | } | 
|  | 1106 |  | 
|  | 1107 | if (conf->changed & IEEE80211_IFCC_BEACON) { | 
|  | 1108 | err = ar9170_update_beacon(ar); | 
|  | 1109 |  | 
|  | 1110 | if (err) | 
|  | 1111 | goto out; | 
|  | 1112 | err = ar9170_set_beacon_timers(ar); | 
|  | 1113 | } | 
|  | 1114 |  | 
|  | 1115 | out: | 
|  | 1116 | mutex_unlock(&ar->mutex); | 
|  | 1117 | return err; | 
|  | 1118 | } | 
|  | 1119 |  | 
|  | 1120 | static void ar9170_set_filters(struct work_struct *work) | 
|  | 1121 | { | 
|  | 1122 | struct ar9170 *ar = container_of(work, struct ar9170, | 
|  | 1123 | filter_config_work); | 
|  | 1124 | int err; | 
|  | 1125 |  | 
|  | 1126 | mutex_lock(&ar->mutex); | 
|  | 1127 | if (unlikely(!IS_STARTED(ar))) | 
|  | 1128 | goto unlock; | 
|  | 1129 |  | 
|  | 1130 | if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { | 
|  | 1131 | err = ar9170_set_operating_mode(ar); | 
|  | 1132 | if (err) | 
|  | 1133 | goto unlock; | 
|  | 1134 | } | 
|  | 1135 |  | 
|  | 1136 | if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { | 
|  | 1137 | err = ar9170_update_multicast(ar); | 
|  | 1138 | if (err) | 
|  | 1139 | goto unlock; | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) | 
|  | 1143 | err = ar9170_update_frame_filter(ar); | 
|  | 1144 |  | 
|  | 1145 | unlock: | 
|  | 1146 | mutex_unlock(&ar->mutex); | 
|  | 1147 | } | 
|  | 1148 |  | 
|  | 1149 | static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | 
|  | 1150 | unsigned int changed_flags, | 
|  | 1151 | unsigned int *new_flags, | 
|  | 1152 | int mc_count, struct dev_mc_list *mclist) | 
|  | 1153 | { | 
|  | 1154 | struct ar9170 *ar = hw->priv; | 
|  | 1155 |  | 
|  | 1156 | /* mask supported flags */ | 
|  | 1157 | *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | | 
|  | 1158 | FIF_PROMISC_IN_BSS; | 
|  | 1159 |  | 
|  | 1160 | /* | 
|  | 1161 | * We can support more by setting the sniffer bit and | 
|  | 1162 | * then checking the error flags, later. | 
|  | 1163 | */ | 
|  | 1164 |  | 
|  | 1165 | if (changed_flags & FIF_ALLMULTI) { | 
|  | 1166 | if (*new_flags & FIF_ALLMULTI) { | 
|  | 1167 | ar->want_mc_hash = ~0ULL; | 
|  | 1168 | } else { | 
|  | 1169 | u64 mchash; | 
|  | 1170 | int i; | 
|  | 1171 |  | 
|  | 1172 | /* always get broadcast frames */ | 
|  | 1173 | mchash = 1ULL << (0xff>>2); | 
|  | 1174 |  | 
|  | 1175 | for (i = 0; i < mc_count; i++) { | 
|  | 1176 | if (WARN_ON(!mclist)) | 
|  | 1177 | break; | 
|  | 1178 | mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); | 
|  | 1179 | mclist = mclist->next; | 
|  | 1180 | } | 
|  | 1181 | ar->want_mc_hash = mchash; | 
|  | 1182 | } | 
|  | 1183 | ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; | 
|  | 1184 | } | 
|  | 1185 |  | 
|  | 1186 | if (changed_flags & FIF_CONTROL) { | 
|  | 1187 | u32 filter = AR9170_MAC_REG_FTF_PSPOLL | | 
|  | 1188 | AR9170_MAC_REG_FTF_RTS | | 
|  | 1189 | AR9170_MAC_REG_FTF_CTS | | 
|  | 1190 | AR9170_MAC_REG_FTF_ACK | | 
|  | 1191 | AR9170_MAC_REG_FTF_CFE | | 
|  | 1192 | AR9170_MAC_REG_FTF_CFE_ACK; | 
|  | 1193 |  | 
|  | 1194 | if (*new_flags & FIF_CONTROL) | 
|  | 1195 | ar->want_filter = ar->cur_filter | filter; | 
|  | 1196 | else | 
|  | 1197 | ar->want_filter = ar->cur_filter & ~filter; | 
|  | 1198 |  | 
|  | 1199 | ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; | 
|  | 1200 | } | 
|  | 1201 |  | 
|  | 1202 | if (changed_flags & FIF_PROMISC_IN_BSS) { | 
|  | 1203 | ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; | 
|  | 1204 | ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; | 
|  | 1205 | } | 
|  | 1206 |  | 
|  | 1207 | if (likely(IS_STARTED(ar))) | 
|  | 1208 | queue_work(ar->hw->workqueue, &ar->filter_config_work); | 
|  | 1209 | } | 
|  | 1210 |  | 
|  | 1211 | static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, | 
|  | 1212 | struct ieee80211_vif *vif, | 
|  | 1213 | struct ieee80211_bss_conf *bss_conf, | 
|  | 1214 | u32 changed) | 
|  | 1215 | { | 
|  | 1216 | struct ar9170 *ar = hw->priv; | 
|  | 1217 | int err = 0; | 
|  | 1218 |  | 
|  | 1219 | mutex_lock(&ar->mutex); | 
|  | 1220 |  | 
|  | 1221 | ar9170_regwrite_begin(ar); | 
|  | 1222 |  | 
|  | 1223 | if (changed & BSS_CHANGED_ASSOC) { | 
|  | 1224 | ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; | 
|  | 1225 |  | 
|  | 1226 | #ifndef CONFIG_AR9170_LEDS | 
|  | 1227 | /* enable assoc LED. */ | 
|  | 1228 | err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); | 
|  | 1229 | #endif /* CONFIG_AR9170_LEDS */ | 
|  | 1230 | } | 
|  | 1231 |  | 
|  | 1232 | if (changed & BSS_CHANGED_HT) { | 
|  | 1233 | /* TODO */ | 
|  | 1234 | err = 0; | 
|  | 1235 | } | 
|  | 1236 |  | 
|  | 1237 | if (changed & BSS_CHANGED_ERP_SLOT) { | 
|  | 1238 | u32 slottime = 20; | 
|  | 1239 |  | 
|  | 1240 | if (bss_conf->use_short_slot) | 
|  | 1241 | slottime = 9; | 
|  | 1242 |  | 
|  | 1243 | ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); | 
|  | 1244 | } | 
|  | 1245 |  | 
|  | 1246 | if (changed & BSS_CHANGED_BASIC_RATES) { | 
|  | 1247 | u32 cck, ofdm; | 
|  | 1248 |  | 
|  | 1249 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { | 
|  | 1250 | ofdm = bss_conf->basic_rates; | 
|  | 1251 | cck = 0; | 
|  | 1252 | } else { | 
|  | 1253 | /* four cck rates */ | 
|  | 1254 | cck = bss_conf->basic_rates & 0xf; | 
|  | 1255 | ofdm = bss_conf->basic_rates >> 4; | 
|  | 1256 | } | 
|  | 1257 | ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, | 
|  | 1258 | ofdm << 8 | cck); | 
|  | 1259 | } | 
|  | 1260 |  | 
|  | 1261 | ar9170_regwrite_finish(); | 
|  | 1262 | err = ar9170_regwrite_result(); | 
|  | 1263 | mutex_unlock(&ar->mutex); | 
|  | 1264 | } | 
|  | 1265 |  | 
|  | 1266 | static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) | 
|  | 1267 | { | 
|  | 1268 | struct ar9170 *ar = hw->priv; | 
|  | 1269 | int err; | 
|  | 1270 | u32 tsf_low; | 
|  | 1271 | u32 tsf_high; | 
|  | 1272 | u64 tsf; | 
|  | 1273 |  | 
|  | 1274 | mutex_lock(&ar->mutex); | 
|  | 1275 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low); | 
|  | 1276 | if (!err) | 
|  | 1277 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high); | 
|  | 1278 | mutex_unlock(&ar->mutex); | 
|  | 1279 |  | 
|  | 1280 | if (WARN_ON(err)) | 
|  | 1281 | return 0; | 
|  | 1282 |  | 
|  | 1283 | tsf = tsf_high; | 
|  | 1284 | tsf = (tsf << 32) | tsf_low; | 
|  | 1285 | return tsf; | 
|  | 1286 | } | 
|  | 1287 |  | 
|  | 1288 | static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 
|  | 1289 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | 
|  | 1290 | struct ieee80211_key_conf *key) | 
|  | 1291 | { | 
|  | 1292 | struct ar9170 *ar = hw->priv; | 
|  | 1293 | int err = 0, i; | 
|  | 1294 | u8 ktype; | 
|  | 1295 |  | 
|  | 1296 | if ((!ar->vif) || (ar->disable_offload)) | 
|  | 1297 | return -EOPNOTSUPP; | 
|  | 1298 |  | 
|  | 1299 | switch (key->alg) { | 
|  | 1300 | case ALG_WEP: | 
|  | 1301 | if (key->keylen == LEN_WEP40) | 
|  | 1302 | ktype = AR9170_ENC_ALG_WEP64; | 
|  | 1303 | else | 
|  | 1304 | ktype = AR9170_ENC_ALG_WEP128; | 
|  | 1305 | break; | 
|  | 1306 | case ALG_TKIP: | 
|  | 1307 | ktype = AR9170_ENC_ALG_TKIP; | 
|  | 1308 | break; | 
|  | 1309 | case ALG_CCMP: | 
|  | 1310 | ktype = AR9170_ENC_ALG_AESCCMP; | 
|  | 1311 | break; | 
|  | 1312 | default: | 
|  | 1313 | return -EOPNOTSUPP; | 
|  | 1314 | } | 
|  | 1315 |  | 
|  | 1316 | mutex_lock(&ar->mutex); | 
|  | 1317 | if (cmd == SET_KEY) { | 
|  | 1318 | if (unlikely(!IS_STARTED(ar))) { | 
|  | 1319 | err = -EOPNOTSUPP; | 
|  | 1320 | goto out; | 
|  | 1321 | } | 
|  | 1322 |  | 
|  | 1323 | /* group keys need all-zeroes address */ | 
|  | 1324 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 
|  | 1325 | sta = NULL; | 
|  | 1326 |  | 
|  | 1327 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | 
|  | 1328 | for (i = 0; i < 64; i++) | 
|  | 1329 | if (!(ar->usedkeys & BIT(i))) | 
|  | 1330 | break; | 
|  | 1331 | if (i == 64) { | 
|  | 1332 | ar->rx_software_decryption = true; | 
|  | 1333 | ar9170_set_operating_mode(ar); | 
|  | 1334 | err = -ENOSPC; | 
|  | 1335 | goto out; | 
|  | 1336 | } | 
|  | 1337 | } else { | 
|  | 1338 | i = 64 + key->keyidx; | 
|  | 1339 | } | 
|  | 1340 |  | 
|  | 1341 | key->hw_key_idx = i; | 
|  | 1342 |  | 
|  | 1343 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, | 
|  | 1344 | key->key, min_t(u8, 16, key->keylen)); | 
|  | 1345 | if (err) | 
|  | 1346 | goto out; | 
|  | 1347 |  | 
|  | 1348 | if (key->alg == ALG_TKIP) { | 
|  | 1349 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, | 
|  | 1350 | ktype, 1, key->key + 16, 16); | 
|  | 1351 | if (err) | 
|  | 1352 | goto out; | 
|  | 1353 |  | 
|  | 1354 | /* | 
|  | 1355 | * hardware is not capable generating the MMIC | 
|  | 1356 | * for fragmented frames! | 
|  | 1357 | */ | 
|  | 1358 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 
|  | 1359 | } | 
|  | 1360 |  | 
|  | 1361 | if (i < 64) | 
|  | 1362 | ar->usedkeys |= BIT(i); | 
|  | 1363 |  | 
|  | 1364 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 
|  | 1365 | } else { | 
|  | 1366 | if (unlikely(!IS_STARTED(ar))) { | 
|  | 1367 | /* The device is gone... together with the key ;-) */ | 
|  | 1368 | err = 0; | 
|  | 1369 | goto out; | 
|  | 1370 | } | 
|  | 1371 |  | 
|  | 1372 | err = ar9170_disable_key(ar, key->hw_key_idx); | 
|  | 1373 | if (err) | 
|  | 1374 | goto out; | 
|  | 1375 |  | 
|  | 1376 | if (key->hw_key_idx < 64) { | 
|  | 1377 | ar->usedkeys &= ~BIT(key->hw_key_idx); | 
|  | 1378 | } else { | 
|  | 1379 | err = ar9170_upload_key(ar, key->hw_key_idx, NULL, | 
|  | 1380 | AR9170_ENC_ALG_NONE, 0, | 
|  | 1381 | NULL, 0); | 
|  | 1382 | if (err) | 
|  | 1383 | goto out; | 
|  | 1384 |  | 
|  | 1385 | if (key->alg == ALG_TKIP) { | 
|  | 1386 | err = ar9170_upload_key(ar, key->hw_key_idx, | 
|  | 1387 | NULL, | 
|  | 1388 | AR9170_ENC_ALG_NONE, 1, | 
|  | 1389 | NULL, 0); | 
|  | 1390 | if (err) | 
|  | 1391 | goto out; | 
|  | 1392 | } | 
|  | 1393 |  | 
|  | 1394 | } | 
|  | 1395 | } | 
|  | 1396 |  | 
|  | 1397 | ar9170_regwrite_begin(ar); | 
|  | 1398 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); | 
|  | 1399 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); | 
|  | 1400 | ar9170_regwrite_finish(); | 
|  | 1401 | err = ar9170_regwrite_result(); | 
|  | 1402 |  | 
|  | 1403 | out: | 
|  | 1404 | mutex_unlock(&ar->mutex); | 
|  | 1405 |  | 
|  | 1406 | return err; | 
|  | 1407 | } | 
|  | 1408 |  | 
|  | 1409 | static void ar9170_sta_notify(struct ieee80211_hw *hw, | 
|  | 1410 | struct ieee80211_vif *vif, | 
|  | 1411 | enum sta_notify_cmd cmd, | 
|  | 1412 | struct ieee80211_sta *sta) | 
|  | 1413 | { | 
|  | 1414 | struct ar9170 *ar = hw->priv; | 
|  | 1415 | struct ar9170_sta_info *info = (void *) sta->drv_priv; | 
|  | 1416 | struct sk_buff *skb; | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1417 | unsigned int i; | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1418 |  | 
|  | 1419 | switch (cmd) { | 
|  | 1420 | case STA_NOTIFY_ADD: | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1421 | for (i = 0; i < ar->hw->queues; i++) | 
|  | 1422 | skb_queue_head_init(&info->tx_status[i]); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1423 | break; | 
|  | 1424 |  | 
|  | 1425 | case STA_NOTIFY_REMOVE: | 
|  | 1426 |  | 
|  | 1427 | /* | 
|  | 1428 | * transfer all outstanding frames that need a tx_status | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1429 | * reports to the global tx_status queue | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1430 | */ | 
|  | 1431 |  | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1432 | for (i = 0; i < ar->hw->queues; i++) { | 
|  | 1433 | while ((skb = skb_dequeue(&info->tx_status[i]))) { | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1434 | #ifdef AR9170_QUEUE_DEBUG | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1435 | printk(KERN_DEBUG "%s: queueing frame in " | 
|  | 1436 | "global tx_status queue =>\n", | 
|  | 1437 | wiphy_name(ar->hw->wiphy)); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1438 |  | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1439 | ar9170_print_txheader(ar, skb); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1440 | #endif /* AR9170_QUEUE_DEBUG */ | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1441 | skb_queue_tail(&ar->global_tx_status, skb); | 
|  | 1442 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1443 | } | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1444 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, | 
|  | 1445 | msecs_to_jiffies(100)); | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1446 | break; | 
|  | 1447 |  | 
|  | 1448 | default: | 
|  | 1449 | break; | 
|  | 1450 | } | 
|  | 1451 | } | 
|  | 1452 |  | 
|  | 1453 | static int ar9170_get_stats(struct ieee80211_hw *hw, | 
|  | 1454 | struct ieee80211_low_level_stats *stats) | 
|  | 1455 | { | 
|  | 1456 | struct ar9170 *ar = hw->priv; | 
|  | 1457 | u32 val; | 
|  | 1458 | int err; | 
|  | 1459 |  | 
|  | 1460 | mutex_lock(&ar->mutex); | 
|  | 1461 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); | 
|  | 1462 | ar->stats.dot11ACKFailureCount += val; | 
|  | 1463 |  | 
|  | 1464 | memcpy(stats, &ar->stats, sizeof(*stats)); | 
|  | 1465 | mutex_unlock(&ar->mutex); | 
|  | 1466 |  | 
|  | 1467 | return 0; | 
|  | 1468 | } | 
|  | 1469 |  | 
|  | 1470 | static int ar9170_get_tx_stats(struct ieee80211_hw *hw, | 
|  | 1471 | struct ieee80211_tx_queue_stats *tx_stats) | 
|  | 1472 | { | 
|  | 1473 | struct ar9170 *ar = hw->priv; | 
|  | 1474 |  | 
|  | 1475 | spin_lock_bh(&ar->tx_stats_lock); | 
|  | 1476 | memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); | 
|  | 1477 | spin_unlock_bh(&ar->tx_stats_lock); | 
|  | 1478 |  | 
|  | 1479 | return 0; | 
|  | 1480 | } | 
|  | 1481 |  | 
|  | 1482 | static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, | 
|  | 1483 | const struct ieee80211_tx_queue_params *param) | 
|  | 1484 | { | 
|  | 1485 | struct ar9170 *ar = hw->priv; | 
|  | 1486 | int ret; | 
|  | 1487 |  | 
|  | 1488 | mutex_lock(&ar->mutex); | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1489 | if ((param) && !(queue > ar->hw->queues)) { | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1490 | memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], | 
|  | 1491 | param, sizeof(*param)); | 
|  | 1492 |  | 
|  | 1493 | ret = ar9170_set_qos(ar); | 
|  | 1494 | } else | 
|  | 1495 | ret = -EINVAL; | 
|  | 1496 |  | 
|  | 1497 | mutex_unlock(&ar->mutex); | 
|  | 1498 | return ret; | 
|  | 1499 | } | 
|  | 1500 |  | 
|  | 1501 | static const struct ieee80211_ops ar9170_ops = { | 
|  | 1502 | .start			= ar9170_op_start, | 
|  | 1503 | .stop			= ar9170_op_stop, | 
|  | 1504 | .tx			= ar9170_op_tx, | 
|  | 1505 | .add_interface		= ar9170_op_add_interface, | 
|  | 1506 | .remove_interface	= ar9170_op_remove_interface, | 
|  | 1507 | .config			= ar9170_op_config, | 
|  | 1508 | .config_interface	= ar9170_op_config_interface, | 
|  | 1509 | .configure_filter	= ar9170_op_configure_filter, | 
|  | 1510 | .conf_tx		= ar9170_conf_tx, | 
|  | 1511 | .bss_info_changed	= ar9170_op_bss_info_changed, | 
|  | 1512 | .get_tsf		= ar9170_op_get_tsf, | 
|  | 1513 | .set_key		= ar9170_set_key, | 
|  | 1514 | .sta_notify		= ar9170_sta_notify, | 
|  | 1515 | .get_stats		= ar9170_get_stats, | 
|  | 1516 | .get_tx_stats		= ar9170_get_tx_stats, | 
|  | 1517 | }; | 
|  | 1518 |  | 
|  | 1519 | void *ar9170_alloc(size_t priv_size) | 
|  | 1520 | { | 
|  | 1521 | struct ieee80211_hw *hw; | 
|  | 1522 | struct ar9170 *ar; | 
|  | 1523 | int i; | 
|  | 1524 |  | 
|  | 1525 | hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); | 
|  | 1526 | if (!hw) | 
|  | 1527 | return ERR_PTR(-ENOMEM); | 
|  | 1528 |  | 
|  | 1529 | ar = hw->priv; | 
|  | 1530 | ar->hw = hw; | 
|  | 1531 |  | 
|  | 1532 | mutex_init(&ar->mutex); | 
|  | 1533 | spin_lock_init(&ar->cmdlock); | 
|  | 1534 | spin_lock_init(&ar->tx_stats_lock); | 
|  | 1535 | skb_queue_head_init(&ar->global_tx_status); | 
|  | 1536 | skb_queue_head_init(&ar->global_tx_status_waste); | 
|  | 1537 | INIT_WORK(&ar->filter_config_work, ar9170_set_filters); | 
|  | 1538 | INIT_WORK(&ar->beacon_work, ar9170_new_beacon); | 
|  | 1539 | INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); | 
|  | 1540 |  | 
|  | 1541 | /* all hw supports 2.4 GHz, so set channel to 1 by default */ | 
|  | 1542 | ar->channel = &ar9170_2ghz_chantable[0]; | 
|  | 1543 |  | 
|  | 1544 | /* first part of wiphy init */ | 
|  | 1545 | ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 
|  | 1546 | BIT(NL80211_IFTYPE_WDS) | | 
|  | 1547 | BIT(NL80211_IFTYPE_ADHOC); | 
|  | 1548 | ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | | 
|  | 1549 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 
|  | 1550 | IEEE80211_HW_SIGNAL_DBM | | 
|  | 1551 | IEEE80211_HW_NOISE_DBM; | 
|  | 1552 |  | 
| Christian Lamparter | 4a48e2a | 2009-03-23 12:15:43 +0100 | [diff] [blame] | 1553 | ar->hw->queues = __AR9170_NUM_TXQ; | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1554 | ar->hw->extra_tx_headroom = 8; | 
|  | 1555 | ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); | 
|  | 1556 |  | 
|  | 1557 | ar->hw->max_rates = 1; | 
|  | 1558 | ar->hw->max_rate_tries = 3; | 
|  | 1559 |  | 
|  | 1560 | for (i = 0; i < ARRAY_SIZE(ar->noise); i++) | 
|  | 1561 | ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ | 
|  | 1562 |  | 
|  | 1563 | return ar; | 
|  | 1564 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1565 |  | 
|  | 1566 | static int ar9170_read_eeprom(struct ar9170 *ar) | 
|  | 1567 | { | 
|  | 1568 | #define RW	8	/* number of words to read at once */ | 
|  | 1569 | #define RB	(sizeof(u32) * RW) | 
|  | 1570 | DECLARE_MAC_BUF(mbuf); | 
|  | 1571 | u8 *eeprom = (void *)&ar->eeprom; | 
|  | 1572 | u8 *addr = ar->eeprom.mac_address; | 
|  | 1573 | __le32 offsets[RW]; | 
|  | 1574 | int i, j, err, bands = 0; | 
|  | 1575 |  | 
|  | 1576 | BUILD_BUG_ON(sizeof(ar->eeprom) & 3); | 
|  | 1577 |  | 
|  | 1578 | BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); | 
|  | 1579 | #ifndef __CHECKER__ | 
|  | 1580 | /* don't want to handle trailing remains */ | 
|  | 1581 | BUILD_BUG_ON(sizeof(ar->eeprom) % RB); | 
|  | 1582 | #endif | 
|  | 1583 |  | 
|  | 1584 | for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { | 
|  | 1585 | for (j = 0; j < RW; j++) | 
|  | 1586 | offsets[j] = cpu_to_le32(AR9170_EEPROM_START + | 
|  | 1587 | RB * i + 4 * j); | 
|  | 1588 |  | 
|  | 1589 | err = ar->exec_cmd(ar, AR9170_CMD_RREG, | 
|  | 1590 | RB, (u8 *) &offsets, | 
|  | 1591 | RB, eeprom + RB * i); | 
|  | 1592 | if (err) | 
|  | 1593 | return err; | 
|  | 1594 | } | 
|  | 1595 |  | 
|  | 1596 | #undef RW | 
|  | 1597 | #undef RB | 
|  | 1598 |  | 
|  | 1599 | if (ar->eeprom.length == cpu_to_le16(0xFFFF)) | 
|  | 1600 | return -ENODATA; | 
|  | 1601 |  | 
|  | 1602 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { | 
|  | 1603 | ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; | 
|  | 1604 | bands++; | 
|  | 1605 | } | 
|  | 1606 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { | 
|  | 1607 | ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; | 
|  | 1608 | bands++; | 
|  | 1609 | } | 
|  | 1610 | /* | 
|  | 1611 | * I measured this, a bandswitch takes roughly | 
|  | 1612 | * 135 ms and a frequency switch about 80. | 
|  | 1613 | * | 
|  | 1614 | * FIXME: measure these values again once EEPROM settings | 
|  | 1615 | *	  are used, that will influence them! | 
|  | 1616 | */ | 
|  | 1617 | if (bands == 2) | 
|  | 1618 | ar->hw->channel_change_time = 135 * 1000; | 
|  | 1619 | else | 
|  | 1620 | ar->hw->channel_change_time = 80 * 1000; | 
|  | 1621 |  | 
|  | 1622 | /* second part of wiphy init */ | 
|  | 1623 | SET_IEEE80211_PERM_ADDR(ar->hw, addr); | 
|  | 1624 |  | 
|  | 1625 | return bands ? 0 : -EINVAL; | 
|  | 1626 | } | 
|  | 1627 |  | 
|  | 1628 | int ar9170_register(struct ar9170 *ar, struct device *pdev) | 
|  | 1629 | { | 
|  | 1630 | int err; | 
|  | 1631 |  | 
|  | 1632 | /* try to read EEPROM, init MAC addr */ | 
|  | 1633 | err = ar9170_read_eeprom(ar); | 
|  | 1634 | if (err) | 
|  | 1635 | goto err_out; | 
|  | 1636 |  | 
|  | 1637 | err = ieee80211_register_hw(ar->hw); | 
|  | 1638 | if (err) | 
|  | 1639 | goto err_out; | 
|  | 1640 |  | 
|  | 1641 | err = ar9170_init_leds(ar); | 
|  | 1642 | if (err) | 
|  | 1643 | goto err_unreg; | 
|  | 1644 |  | 
|  | 1645 | #ifdef CONFIG_AR9170_LEDS | 
|  | 1646 | err = ar9170_register_leds(ar); | 
|  | 1647 | if (err) | 
|  | 1648 | goto err_unreg; | 
|  | 1649 | #endif /* CONFIG_AR9170_LEDS */ | 
|  | 1650 |  | 
|  | 1651 | dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", | 
|  | 1652 | wiphy_name(ar->hw->wiphy)); | 
|  | 1653 |  | 
|  | 1654 | return err; | 
|  | 1655 |  | 
|  | 1656 | err_unreg: | 
|  | 1657 | ieee80211_unregister_hw(ar->hw); | 
|  | 1658 |  | 
|  | 1659 | err_out: | 
|  | 1660 | return err; | 
|  | 1661 | } | 
| Christian Lamparter | e9348cd | 2009-03-21 23:05:13 +0100 | [diff] [blame] | 1662 |  | 
|  | 1663 | void ar9170_unregister(struct ar9170 *ar) | 
|  | 1664 | { | 
|  | 1665 | #ifdef CONFIG_AR9170_LEDS | 
|  | 1666 | ar9170_unregister_leds(ar); | 
|  | 1667 | #endif /* CONFIG_AR9170_LEDS */ | 
|  | 1668 |  | 
|  | 1669 | ieee80211_unregister_hw(ar->hw); | 
|  | 1670 | mutex_destroy(&ar->mutex); | 
|  | 1671 | } |