Home | History | Annotate | Download | only in ath5k
      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