1 /* 2 * Copyright (c) 2004-2008 Reyk Floeter <reyk (at) openbsd.org> 3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm (at) gmail.com> 4 * Copyright (c) 2007-2008 Matthew W. S. Bell <mentor (at) madwifi.org> 5 * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof (at) winlab.rutgers.edu> 6 * Copyright (c) 2007-2008 Pavel Roskin <proski (at) gnu.org> 7 * Copyright (c) 2007-2008 Jiri Slaby <jirislaby (at) gmail.com> 8 * 9 * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj (at) rwcr.net>. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 */ 24 25 FILE_LICENCE ( MIT ); 26 27 /*********************************\ 28 * Protocol Control Unit Functions * 29 \*********************************/ 30 31 #include "ath5k.h" 32 #include "reg.h" 33 #include "base.h" 34 35 /*******************\ 36 * Generic functions * 37 \*******************/ 38 39 /** 40 * ath5k_hw_set_opmode - Set PCU operating mode 41 * 42 * @ah: The &struct ath5k_hw 43 * 44 * Initialize PCU for the various operating modes (AP/STA etc) 45 * 46 * For gPXE we always assume STA mode. 47 */ 48 int ath5k_hw_set_opmode(struct ath5k_hw *ah) 49 { 50 u32 pcu_reg, beacon_reg, low_id, high_id; 51 52 53 /* Preserve rest settings */ 54 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; 55 pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP 56 | AR5K_STA_ID1_KEYSRCH_MODE 57 | (ah->ah_version == AR5K_AR5210 ? 58 (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); 59 60 beacon_reg = 0; 61 62 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE 63 | (ah->ah_version == AR5K_AR5210 ? 64 AR5K_STA_ID1_PWR_SV : 0); 65 66 /* 67 * Set PCU registers 68 */ 69 low_id = AR5K_LOW_ID(ah->ah_sta_id); 70 high_id = AR5K_HIGH_ID(ah->ah_sta_id); 71 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); 72 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); 73 74 /* 75 * Set Beacon Control Register on 5210 76 */ 77 if (ah->ah_version == AR5K_AR5210) 78 ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); 79 80 return 0; 81 } 82 83 /** 84 * ath5k_hw_set_ack_bitrate - set bitrate for ACKs 85 * 86 * @ah: The &struct ath5k_hw 87 * @high: Flag to determine if we want to use high transmition rate 88 * for ACKs or not 89 * 90 * If high flag is set, we tell hw to use a set of control rates based on 91 * the current transmition rate (check out control_rates array inside reset.c). 92 * If not hw just uses the lowest rate available for the current modulation 93 * scheme being used (1Mbit for CCK and 6Mbits for OFDM). 94 */ 95 void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high) 96 { 97 if (ah->ah_version != AR5K_AR5212) 98 return; 99 else { 100 u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; 101 if (high) 102 AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); 103 else 104 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); 105 } 106 } 107 108 109 /******************\ 110 * ACK/CTS Timeouts * 111 \******************/ 112 113 /** 114 * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec 115 * 116 * @ah: The &struct ath5k_hw 117 */ 118 unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) 119 { 120 return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, 121 AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); 122 } 123 124 /** 125 * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU 126 * 127 * @ah: The &struct ath5k_hw 128 * @timeout: Timeout in usec 129 */ 130 int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) 131 { 132 if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), 133 ah->ah_turbo) <= timeout) 134 return -EINVAL; 135 136 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, 137 ath5k_hw_htoclock(timeout, ah->ah_turbo)); 138 139 return 0; 140 } 141 142 /** 143 * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec 144 * 145 * @ah: The &struct ath5k_hw 146 */ 147 unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) 148 { 149 return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, 150 AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); 151 } 152 153 /** 154 * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU 155 * 156 * @ah: The &struct ath5k_hw 157 * @timeout: Timeout in usec 158 */ 159 int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) 160 { 161 if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), 162 ah->ah_turbo) <= timeout) 163 return -EINVAL; 164 165 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, 166 ath5k_hw_htoclock(timeout, ah->ah_turbo)); 167 168 return 0; 169 } 170 171 172 /****************\ 173 * BSSID handling * 174 \****************/ 175 176 /** 177 * ath5k_hw_get_lladdr - Get station id 178 * 179 * @ah: The &struct ath5k_hw 180 * @mac: The card's mac address 181 * 182 * Initialize ah->ah_sta_id using the mac address provided 183 * (just a memcpy). 184 * 185 * TODO: Remove it once we merge ath5k_softc and ath5k_hw 186 */ 187 void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) 188 { 189 memcpy(mac, ah->ah_sta_id, ETH_ALEN); 190 } 191 192 /** 193 * ath5k_hw_set_lladdr - Set station id 194 * 195 * @ah: The &struct ath5k_hw 196 * @mac: The card's mac address 197 * 198 * Set station id on hw using the provided mac address 199 */ 200 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) 201 { 202 u32 low_id, high_id; 203 u32 pcu_reg; 204 205 /* Set new station ID */ 206 memcpy(ah->ah_sta_id, mac, ETH_ALEN); 207 208 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; 209 210 low_id = AR5K_LOW_ID(mac); 211 high_id = AR5K_HIGH_ID(mac); 212 213 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); 214 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); 215 216 return 0; 217 } 218 219 /** 220 * ath5k_hw_set_associd - Set BSSID for association 221 * 222 * @ah: The &struct ath5k_hw 223 * @bssid: BSSID 224 * @assoc_id: Assoc id 225 * 226 * Sets the BSSID which trigers the "SME Join" operation 227 */ 228 void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) 229 { 230 u32 low_id, high_id; 231 232 /* 233 * Set simple BSSID mask on 5212 234 */ 235 if (ah->ah_version == AR5K_AR5212) { 236 ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), 237 AR5K_BSS_IDM0); 238 ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), 239 AR5K_BSS_IDM1); 240 } 241 242 /* 243 * Set BSSID which triggers the "SME Join" operation 244 */ 245 low_id = AR5K_LOW_ID(bssid); 246 high_id = AR5K_HIGH_ID(bssid); 247 ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); 248 ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << 249 AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); 250 } 251 252 /** 253 * ath5k_hw_set_bssid_mask - filter out bssids we listen 254 * 255 * @ah: the &struct ath5k_hw 256 * @mask: the bssid_mask, a u8 array of size ETH_ALEN 257 * 258 * BSSID masking is a method used by AR5212 and newer hardware to inform PCU 259 * which bits of the interface's MAC address should be looked at when trying 260 * to decide which packets to ACK. In station mode and AP mode with a single 261 * BSS every bit matters since we lock to only one BSS. In AP mode with 262 * multiple BSSes (virtual interfaces) not every bit matters because hw must 263 * accept frames for all BSSes and so we tweak some bits of our mac address 264 * in order to have multiple BSSes. 265 * 266 * NOTE: This is a simple filter and does *not* filter out all 267 * relevant frames. Some frames that are not for us might get ACKed from us 268 * by PCU because they just match the mask. 269 * 270 * When handling multiple BSSes you can get the BSSID mask by computing the 271 * set of ~ ( MAC XOR BSSID ) for all bssids we handle. 272 * 273 * When you do this you are essentially computing the common bits of all your 274 * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with 275 * the MAC address to obtain the relevant bits and compare the result with 276 * (frame's BSSID & mask) to see if they match. 277 */ 278 /* 279 * Simple example: on your card you have have two BSSes you have created with 280 * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. 281 * There is another BSSID-03 but you are not part of it. For simplicity's sake, 282 * assuming only 4 bits for a mac address and for BSSIDs you can then have: 283 * 284 * \ 285 * MAC: 0001 | 286 * BSSID-01: 0100 | --> Belongs to us 287 * BSSID-02: 1001 | 288 * / 289 * ------------------- 290 * BSSID-03: 0110 | --> External 291 * ------------------- 292 * 293 * Our bssid_mask would then be: 294 * 295 * On loop iteration for BSSID-01: 296 * ~(0001 ^ 0100) -> ~(0101) 297 * -> 1010 298 * bssid_mask = 1010 299 * 300 * On loop iteration for BSSID-02: 301 * bssid_mask &= ~(0001 ^ 1001) 302 * bssid_mask = (1010) & ~(0001 ^ 1001) 303 * bssid_mask = (1010) & ~(1001) 304 * bssid_mask = (1010) & (0110) 305 * bssid_mask = 0010 306 * 307 * A bssid_mask of 0010 means "only pay attention to the second least 308 * significant bit". This is because its the only bit common 309 * amongst the MAC and all BSSIDs we support. To findout what the real 310 * common bit is we can simply "&" the bssid_mask now with any BSSID we have 311 * or our MAC address (we assume the hardware uses the MAC address). 312 * 313 * Now, suppose there's an incoming frame for BSSID-03: 314 * 315 * IFRAME-01: 0110 316 * 317 * An easy eye-inspeciton of this already should tell you that this frame 318 * will not pass our check. This is beacuse the bssid_mask tells the 319 * hardware to only look at the second least significant bit and the 320 * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB 321 * as 1, which does not match 0. 322 * 323 * So with IFRAME-01 we *assume* the hardware will do: 324 * 325 * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; 326 * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; 327 * --> allow = (0010) == 0000 ? 1 : 0; 328 * --> allow = 0 329 * 330 * Lets now test a frame that should work: 331 * 332 * IFRAME-02: 0001 (we should allow) 333 * 334 * allow = (0001 & 1010) == 1010 335 * 336 * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; 337 * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; 338 * --> allow = (0010) == (0010) 339 * --> allow = 1 340 * 341 * Other examples: 342 * 343 * IFRAME-03: 0100 --> allowed 344 * IFRAME-04: 1001 --> allowed 345 * IFRAME-05: 1101 --> allowed but its not for us!!! 346 * 347 */ 348 int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) 349 { 350 u32 low_id, high_id; 351 352 /* Cache bssid mask so that we can restore it 353 * on reset */ 354 memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); 355 if (ah->ah_version == AR5K_AR5212) { 356 low_id = AR5K_LOW_ID(mask); 357 high_id = AR5K_HIGH_ID(mask); 358 359 ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); 360 ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); 361 362 return 0; 363 } 364 365 return -EIO; 366 } 367 368 369 /************\ 370 * RX Control * 371 \************/ 372 373 /** 374 * ath5k_hw_start_rx_pcu - Start RX engine 375 * 376 * @ah: The &struct ath5k_hw 377 * 378 * Starts RX engine on PCU so that hw can process RXed frames 379 * (ACK etc). 380 * 381 * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma 382 * TODO: Init ANI here 383 */ 384 void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) 385 { 386 AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); 387 } 388 389 /** 390 * at5k_hw_stop_rx_pcu - Stop RX engine 391 * 392 * @ah: The &struct ath5k_hw 393 * 394 * Stops RX engine on PCU 395 * 396 * TODO: Detach ANI here 397 */ 398 void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) 399 { 400 AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); 401 } 402 403 /* 404 * Set multicast filter 405 */ 406 void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) 407 { 408 /* Set the multicat filter */ 409 ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); 410 ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); 411 } 412 413 /** 414 * ath5k_hw_get_rx_filter - Get current rx filter 415 * 416 * @ah: The &struct ath5k_hw 417 * 418 * Returns the RX filter by reading rx filter and 419 * phy error filter registers. RX filter is used 420 * to set the allowed frame types that PCU will accept 421 * and pass to the driver. For a list of frame types 422 * check out reg.h. 423 */ 424 u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) 425 { 426 u32 data, filter = 0; 427 428 filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); 429 430 /*Radar detection for 5212*/ 431 if (ah->ah_version == AR5K_AR5212) { 432 data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); 433 434 if (data & AR5K_PHY_ERR_FIL_RADAR) 435 filter |= AR5K_RX_FILTER_RADARERR; 436 if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) 437 filter |= AR5K_RX_FILTER_PHYERR; 438 } 439 440 return filter; 441 } 442 443 /** 444 * ath5k_hw_set_rx_filter - Set rx filter 445 * 446 * @ah: The &struct ath5k_hw 447 * @filter: RX filter mask (see reg.h) 448 * 449 * Sets RX filter register and also handles PHY error filter 450 * register on 5212 and newer chips so that we have proper PHY 451 * error reporting. 452 */ 453 void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) 454 { 455 u32 data = 0; 456 457 /* Set PHY error filter register on 5212*/ 458 if (ah->ah_version == AR5K_AR5212) { 459 if (filter & AR5K_RX_FILTER_RADARERR) 460 data |= AR5K_PHY_ERR_FIL_RADAR; 461 if (filter & AR5K_RX_FILTER_PHYERR) 462 data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; 463 } 464 465 /* 466 * The AR5210 uses promiscous mode to detect radar activity 467 */ 468 if (ah->ah_version == AR5K_AR5210 && 469 (filter & AR5K_RX_FILTER_RADARERR)) { 470 filter &= ~AR5K_RX_FILTER_RADARERR; 471 filter |= AR5K_RX_FILTER_PROM; 472 } 473 474 /*Zero length DMA (phy error reporting) */ 475 if (data) 476 AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); 477 else 478 AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); 479 480 /*Write RX Filter register*/ 481 ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); 482 483 /*Write PHY error filter register on 5212*/ 484 if (ah->ah_version == AR5K_AR5212) 485 ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); 486 487 } 488 489 /*********************\ 490 * Key table functions * 491 \*********************/ 492 493 /* 494 * Reset a key entry on the table 495 */ 496 int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) 497 { 498 unsigned int i, type; 499 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; 500 501 type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); 502 503 for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) 504 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); 505 506 /* Reset associated MIC entry if TKIP 507 * is enabled located at offset (entry + 64) */ 508 if (type == AR5K_KEYTABLE_TYPE_TKIP) { 509 for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) 510 ath5k_hw_reg_write(ah, 0, 511 AR5K_KEYTABLE_OFF(micentry, i)); 512 } 513 514 /* 515 * Set NULL encryption on AR5212+ 516 * 517 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) 518 * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 519 * 520 * Note2: Windows driver (ndiswrapper) sets this to 521 * 0x00000714 instead of 0x00000007 522 */ 523 if (ah->ah_version >= AR5K_AR5211) { 524 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 525 AR5K_KEYTABLE_TYPE(entry)); 526 527 if (type == AR5K_KEYTABLE_TYPE_TKIP) { 528 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 529 AR5K_KEYTABLE_TYPE(micentry)); 530 } 531 } 532 533 return 0; 534 } 535