/** * ath5k_hw_set_rx_filter - Set rx filter * * @ah: The &struct ath5k_hw * @filter: RX filter mask (see reg.h) * * Sets RX filter register and also handles PHY error filter * register on 5212 and newer chips so that we have proper PHY * error reporting. */ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) { u32 data = 0; ATH5K_TRACE(ah->ah_sc); /* Set PHY error filter register on 5212*/ if (ah->ah_version == AR5K_AR5212) { if (filter & AR5K_RX_FILTER_RADARERR) data |= AR5K_PHY_ERR_FIL_RADAR; if (filter & AR5K_RX_FILTER_PHYERR) data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; } /* * The AR5210 uses promiscous mode to detect radar activity */ if (ah->ah_version == AR5K_AR5210 && (filter & AR5K_RX_FILTER_RADARERR)) { filter &= ~AR5K_RX_FILTER_RADARERR; filter |= AR5K_RX_FILTER_PROM; } /*Zero length DMA*/ if (data) AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); else AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); /*Write RX Filter register*/ ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); /*Write PHY error filter register on 5212*/ if (ah->ah_version == AR5K_AR5212) ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); }
/* * Proccess the rx status descriptor on 5212 */ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_error *rx_err; ATH5K_TRACE(ah->ah_sc); rx_status = &desc->ud.ds_rx.u.rx_stat; /* Overlay on error */ rx_err = &desc->ud.ds_rx.u.rx_err; /* No frame received / not ready */ if (unlikely(!(rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; /* * Frame receive status */ rs->rs_datalen = rx_status->rx_status_0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); rs->rs_more = !!(rx_status->rx_status_0 & AR5K_5212_RX_DESC_STATUS0_MORE); rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); rs->rs_status = 0; rs->rs_phyerr = 0; /* * Key table status */ if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else rs->rs_keyix = AR5K_RXKEYIX_INVALID; /* * Receive/descriptor errors */ if (!(rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); } if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) rs->rs_status |= AR5K_RXERR_DECRYPT; if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) rs->rs_status |= AR5K_RXERR_MIC; } return 0; }
/* * Proccess a tx status descriptor on 5212 */ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_tx_status *ts) { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; ATH5K_TRACE(ah->ah_sc); tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; /* No frame has been send or error */ if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) return -EINPROGRESS; /* * Get descriptor status */ ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_SEQ_NUM); ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = (tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; ts->ts_status = 0; ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); /* The longretry counter has the number of un-acked retries * for the final rate. To get the total number of retries * we have to add the retry counters for the other rates * as well */ ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; switch (ts->ts_final_idx) { case 3: ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ts->ts_longretry += ts->ts_retry[2]; /* fall through */ case 2: ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[1]; /* fall through */ case 1: ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[0]; /* fall through */ case 0: ts->ts_rate[0] = tx_ctl->tx_control_3 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; break; } /* TX error */ if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ts->ts_status |= AR5K_TXERR_XRETRY; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ts->ts_status |= AR5K_TXERR_FIFO; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) ts->ts_status |= AR5K_TXERR_FILT; } return 0; }
/* * Initialize the 4-word tx control descriptor on 5212 */ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; ATH5K_TRACE(ah->ah_sc); tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { ATH5K_ERR(ah->ah_sc, "zero retries\n"); WARN_ON(1); return -EINVAL; } if (unlikely(tx_rate0 == 0)) { ATH5K_ERR(ah->ah_sc, "zero rate\n"); WARN_ON(1); return -EINVAL; } /* Clear descriptor */ memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); /* Setup control descriptor */ /* Verify and set frame length */ /* remove padding we might have added before */ frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ /* NB: beacon's BufLen must be a multiple of 4 bytes */ if (type == AR5K_PKT_TYPE_BEACON) pkt_len = roundup(pkt_len, 4); if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); _TX_FLAGS(0, CTSENA); _TX_FLAGS(1, NOACK); #undef _TX_FLAGS /* * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); } /* * RTS/CTS */ if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; tx_ctl->tx_control_2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } return 0; }
/* * Set beacon timers */ int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state) { u32 cfp_period, next_cfp, dtim, interval, next_beacon; /* * TODO: should be changed through *state * review struct ath5k_beacon_state struct * * XXX: These are used for cfp period bellow, are they * ok ? Is it O.K. for tsf here to be 0 or should we use * get_tsf ? */ u32 dtim_count = 0; /* XXX */ u32 cfp_count = 0; /* XXX */ u32 tsf = 0; /* XXX */ ATH5K_TRACE(ah->ah_sc); /* Return on an invalid beacon state */ if (state->bs_interval < 1) return -EINVAL; interval = state->bs_interval; dtim = state->bs_dtim_period; /* * PCF support? */ if (state->bs_cfp_period > 0) { /* * Enable PCF mode and set the CFP * (Contention Free Period) and timer registers */ cfp_period = state->bs_cfp_period * state->bs_dtim_period * state->bs_interval; next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * state->bs_interval; AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, AR5K_CFP_DUR); ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : next_cfp)) << 3, AR5K_TIMER2); } else { /* Disable PCF mode */ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); } /* * Enable the beacon timer register */ ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); /* * Start the beacon timers */ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, AR5K_BEACON_PERIOD), AR5K_BEACON); /* * Write new beacon miss threshold, if it appears to be valid * XXX: Figure out right values for min <= bs_bmiss_threshold <= max * and return if its not in range. We can test this by reading value and * setting value to a largest value and seeing which values register. */ AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, state->bs_bmiss_threshold); /* * Set sleep control register * XXX: Didn't find this in 5210 code but since this register * exists also in ar5k's 5210 headers i leave it as common code. */ AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, (state->bs_sleep_duration - 3) << 3); /* * Set enhanced sleep registers on 5212 */ if (ah->ah_version == AR5K_AR5212) { if (state->bs_sleep_duration > state->bs_interval && roundup(state->bs_sleep_duration, interval) == state->bs_sleep_duration) interval = state->bs_sleep_duration; if (state->bs_sleep_duration > dtim && (dtim == 0 || roundup(state->bs_sleep_duration, dtim) == state->bs_sleep_duration)) dtim = state->bs_sleep_duration; if (interval > dtim) return -EINVAL; next_beacon = interval == dtim ? state->bs_next_dtim : state->bs_next_beacon; ath5k_hw_reg_write(ah, AR5K_REG_SM((state->bs_next_dtim - 3) << 3, AR5K_SLEEP0_NEXT_DTIM) | AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | AR5K_SLEEP0_ENH_SLEEP_EN | AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, AR5K_SLEEP1_NEXT_TIM) | AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); ath5k_hw_reg_write(ah, AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); } return 0; }
/* * Initialize beacon timers */ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) { u32 timer1, timer2, timer3; ATH5K_TRACE(ah->ah_sc); /* * Set the additional timers by mode */ switch (ah->ah_op_mode) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: /* In STA mode timer1 is used as next wakeup * timer and timer2 as next CFP duration start * timer. Both in 1/8TUs. */ /* TODO: PCF handling */ if (ah->ah_version == AR5K_AR5210) { timer1 = 0xffffffff; timer2 = 0xffffffff; } else { timer1 = 0x0000ffff; timer2 = 0x0007ffff; } /* Mark associated AP as PCF incapable for now */ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); break; case NL80211_IFTYPE_ADHOC: AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); default: /* On non-STA modes timer1 is used as next DMA * beacon alert (DBA) timer and timer2 as next * software beacon alert. Both in 1/8TUs. */ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; break; } /* Timer3 marks the end of our ATIM window * a zero length window is not allowed because * we 'll get no beacons */ timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); /* * Set the beacon register and enable all timers. */ /* When in AP or Mesh Point mode zero timer0 to start TSF */ if (ah->ah_op_mode == NL80211_IFTYPE_AP || ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT) ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); /* Force a TSF reset if requested and enable beacons */ if (interval & AR5K_BEACON_RESET_TSF) ath5k_hw_reset_tsf(ah); ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | AR5K_BEACON_ENABLE), AR5K_BEACON); /* Flush any pending BMISS interrupts on ISR by * performing a clear-on-write operation on PISR * register for the BMISS bit (writing a bit on * ISR togles a reset for that bit and leaves * the rest bits intact) */ if (ah->ah_version == AR5K_AR5210) ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); else ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); /* TODO: Set enchanced sleep registers on AR5212 * based on vif->bss_conf params, until then * disable power save reporting.*/ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); }
/** * ath5k_hw_get_tsf32 - Get a 32bit TSF * * @ah: The &struct ath5k_hw * * Returns lower 32 bits of current TSF */ u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); return ath5k_hw_reg_read(ah, AR5K_TSF_L32); }
/** * ath5k_hw_set_opmode - Set PCU operating mode * * @ah: The &struct ath5k_hw * * Initialize PCU for the various operating modes (AP/STA etc) * * NOTE: ah->ah_op_mode must be set before calling this. */ int ath5k_hw_set_opmode(struct ath5k_hw *ah) { struct ath_common *common = ath5k_hw_common(ah); u32 pcu_reg, beacon_reg, low_id, high_id; /* Preserve rest settings */ pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); beacon_reg = 0; ATH5K_TRACE(ah->ah_sc); switch (ah->ah_op_mode) { case NL80211_IFTYPE_ADHOC: pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_ADHOC; if (ah->ah_version == AR5K_AR5210) pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; else AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_AP; if (ah->ah_version == AR5K_AR5210) pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; else AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); break; case NL80211_IFTYPE_STATION: pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); case NL80211_IFTYPE_MONITOR: pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_NO_PSPOLL : 0); break; default: return -EINVAL; } /* * Set PCU registers */ low_id = get_unaligned_le32(common->macaddr); high_id = get_unaligned_le16(common->macaddr + 4); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); /* * Set Beacon Control Register on 5210 */ if (ah->ah_version == AR5K_AR5210) ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); return 0; }
/** * at5k_hw_stop_rx_pcu - Stop RX engine * * @ah: The &struct ath5k_hw * * Stops RX engine on PCU * * TODO: Detach ANI here */ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); }
/** * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec * * @ah: The &struct ath5k_hw */ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); }
/* * Set a key entry on the table */ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac) { unsigned int i; int keylen; __le32 key_v[5] = {}; __le32 key0 = 0, key1 = 0; __le32 *rxmic, *txmic; int keytype; u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; bool is_tkip; const u8 *key_ptr; ATH5K_TRACE(ah->ah_sc); is_tkip = (key->alg == ALG_TKIP); /* * key->keylen comes in from mac80211 in bytes. * TKIP is 128 bit + 128 bit mic */ keylen = (is_tkip) ? (128 / 8) : key->keylen; if (entry > AR5K_KEYTABLE_SIZE || (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; if (unlikely(keylen > 16)) return -EOPNOTSUPP; keytype = ath5k_keycache_type(key); if (keytype < 0) return keytype; /* * each key block is 6 bytes wide, written as pairs of * alternating 32 and 16 bit le values. */ key_ptr = key->key; for (i = 0; keylen >= 6; keylen -= 6) { memcpy(&key_v[i], key_ptr, 6); i += 2; key_ptr += 6; } if (keylen) memcpy(&key_v[i], key_ptr, keylen); /* intentionally corrupt key until mic is installed */ if (is_tkip) { key0 = key_v[0] = ~key_v[0]; key1 = key_v[1] = ~key_v[1]; } for (i = 0; i < ARRAY_SIZE(key_v); i++) ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), AR5K_KEYTABLE_OFF(entry, i)); ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); if (is_tkip) { /* Install rx/tx MIC */ rxmic = (__le32 *) &key->key[16]; txmic = (__le32 *) &key->key[24]; if (ah->ah_combined_mic) { key_v[0] = rxmic[0]; key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); key_v[2] = rxmic[1]; key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); key_v[4] = txmic[1]; } else {
/** * ath5k_hw_get_lladdr - Get station id * * @ah: The &struct ath5k_hw * @mac: The card's mac address * * Initialize ah->ah_sta_id using the mac address provided * (just a memcpy). * * TODO: Remove it once we merge ath5k_softc and ath5k_hw */ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) { ATH5K_TRACE(ah->ah_sc); memcpy(mac, ah->ah_sta_id, ETH_ALEN); }