/* * Read from eeprom */ bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) { struct ath5k_hw *ah = (struct ath5k_hw *) common->ah; u32 status, timeout; /* * Initialize EEPROM access */ if (ah->ah_version == AR5K_AR5210) { AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); } else { ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_READ); } for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_RDDONE) { if (status & AR5K_EEPROM_STAT_RDERR) return -EIO; *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & 0xffff); return 0; } udelay(15); } return -ETIMEDOUT; }
static int ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, struct ath5k_ani_state *as) { unsigned int ofdm_err, cck_err; if (!ah->ah_capabilities.cap_has_phyerr_counters) return 0; ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1); cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2); ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, AR5K_PHYERR_CNT1); ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, AR5K_PHYERR_CNT2); ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err); cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err); if (ofdm_err <= 0 && cck_err <= 0) return 0; if (ofdm_err > 0) { as->ofdm_errors += ofdm_err; as->sum_ofdm_errors += ofdm_err; } if (cck_err > 0) { as->cck_errors += cck_err; as->sum_cck_errors += cck_err; } return 1; }
/** * ath5k_hw_get_tsf64 - Get the full 64bit TSF * * @ah: The &struct ath5k_hw * * Returns the current TSF */ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { u32 tsf_lower, tsf_upper1, tsf_upper2; int i; /* * While reading TSF upper and then lower part, the clock is still * counting (or jumping in case of IBSS merge) so we might get * inconsistent values. To avoid this, we read the upper part again * and check it has not been changed. We make the hypothesis that a * maximum of 3 changes can happens in a row (we use 10 as a safe * value). * * Impact on performance is pretty small, since in most cases, only * 3 register reads are needed. */ tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); for (i = 0; i < ATH5K_MAX_TSF_READ; i++) { tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32); tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); if (tsf_upper2 == tsf_upper1) break; tsf_upper1 = tsf_upper2; } WARN_ON( i == ATH5K_MAX_TSF_READ ); return (((u64)tsf_upper1 << 32) | tsf_lower); }
/** * ath5k_hw_update - Update mib counters (mac layer statistics) * * @ah: The &struct ath5k_hw * @stats: The &struct ieee80211_low_level_stats we use to track * statistics on the driver * * Reads MIB counters from PCU and updates sw statistics. Must be * called after a MIB interrupt. */ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats) { ATH5K_TRACE(ah->ah_sc); /* Read-And-Clear */ stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); /* XXX: Should we use this to track beacon count ? * -we read it anyway to clear the register */ ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); /* Reset profile count registers on 5212*/ if (ah->ah_version == AR5K_AR5212) { ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); } /* TODO: Handle ANI stats */ }
static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) { u32 status, timeout; ATH5K_TRACE(ah->ah_sc); if (ah->ah_version == AR5K_AR5210) { AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); } else { ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_READ); } for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_RDDONE) { if (status & AR5K_EEPROM_STAT_RDERR) return -EIO; *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & 0xffff); return 0; } udelay(15); } return -ETIMEDOUT; }
/** * ath5k_hw_get_tsf64 - Get the full 64bit TSF * * @ah: The &struct ath5k_hw * * Returns the current TSF */ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); ATH5K_TRACE(ah->ah_sc); return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); }
static int ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) { int listen; /* freeze */ ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); /* read */ as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); /* clear */ ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); /* un-freeze */ ath5k_hw_reg_write(ah, 0, AR5K_MIBC); /* TODO: where does 44000 come from? (11g clock rate?) */ listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; if (as->pfc_cycles == 0 || listen < 0) return 0; return listen; }
/** * ath5k_hw_post - Power On Self Test helper function * * @ah: The &struct ath5k_hw */ static int ath5k_hw_post(struct ath5k_hw *ah) { static const u32 static_pattern[4] = { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) }; int i, c; u16 cur_reg; u32 var_pattern; u32 init_val; u32 cur_val; for (c = 0; c < 2; c++) { cur_reg = regs[c]; /* Save previous value */ init_val = ath5k_hw_reg_read(ah, cur_reg); for (i = 0; i < 256; i++) { var_pattern = i << 16 | i; ath5k_hw_reg_write(ah, var_pattern, cur_reg); cur_val = ath5k_hw_reg_read(ah, cur_reg); if (cur_val != var_pattern) { ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); return -EAGAIN; } /* Found on ndiswrapper dumps */ var_pattern = 0x0039080f; ath5k_hw_reg_write(ah, var_pattern, cur_reg); } for (i = 0; i < 4; i++) { var_pattern = static_pattern[i]; ath5k_hw_reg_write(ah, var_pattern, cur_reg); cur_val = ath5k_hw_reg_read(ah, cur_reg); if (cur_val != var_pattern) { ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); return -EAGAIN; } /* Found on ndiswrapper dumps */ var_pattern = 0x003b080f; ath5k_hw_reg_write(ah, var_pattern, cur_reg); } /* Restore previous value */ ath5k_hw_reg_write(ah, init_val, cur_reg); } return 0; }
/** * ath5k_hw_update - Update MIB counters (mac layer statistics) * * @ah: The &struct ath5k_hw * * Reads MIB counters from PCU and updates sw statistics. Is called after a * MIB interrupt, because one of these counters might have reached their maximum * and triggered the MIB interrupt, to let us read and clear the counter. * * Is called in interrupt context! */ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) { struct ath5k_statistics *stats = &ah->ah_sc->stats; /* Read-And-Clear */ stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK); stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); }
/** * ath5k_hw_set_opmode - Set PCU operating mode * * @ah: The &struct ath5k_hw * * Initialize PCU for the various operating modes (AP/STA etc) * * For gPXE we always assume STA mode. */ int ath5k_hw_set_opmode(struct ath5k_hw *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; pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); /* * Set PCU registers */ low_id = AR5K_LOW_ID(ah->ah_sta_id); high_id = AR5K_HIGH_ID(ah->ah_sta_id); 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; }
/* * Write initial register dump */ static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, const struct ath5k_ini *ini_regs, bool skip_pcu) { unsigned int i; /* Write initial registers */ for (i = 0; i < size; i++) { /* Skip PCU registers if * requested */ if (skip_pcu && ini_regs[i].ini_register >= AR5K_PCU_MIN && ini_regs[i].ini_register <= AR5K_PCU_MAX) continue; switch (ini_regs[i].ini_mode) { case AR5K_INI_READ: /* Cleared on read */ ath5k_hw_reg_read(ah, ini_regs[i].ini_register); break; case AR5K_INI_WRITE: default: AR5K_REG_WAIT(i); ath5k_hw_reg_write(ah, ini_regs[i].ini_value, ini_regs[i].ini_register); } } }
/** * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec * * @ah: The &struct ath5k_hw */ unsigned int ath5k_hw_get_ack_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_ACK)); }
/** * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch) * @ah: The &struct ath5k_hw * @gpio: The GPIO pin to use * @interrupt_level: True to generate interrupt on active pin (high) * * This function is used to set up the GPIO interrupt for the hw RFKill switch. * That switch is connected to a GPIO pin and it's number is stored on EEPROM. * It can either open or close the circuit to indicate that we should disable * RF/Wireless to save power (we also get that from EEPROM). */ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level) { u32 data; if (gpio >= AR5K_NUM_GPIO) return; /* * Set the GPIO interrupt */ data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); ath5k_hw_reg_write(ah, interrupt_level ? data : (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); ah->ah_imr |= AR5K_IMR_GPIO; /* Enable GPIO interrupts */ AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); }
/** * ath5k_hw_num_tx_pending() - Get number of pending frames for a given queue * @ah: The &struct ath5k_hw * @queue: One of enum ath5k_tx_queue_id */ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { u32 pending; AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* Return if queue is declared inactive */ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) return false; /* XXX: How about AR5K_CFG_TXCNT ? */ if (ah->ah_version == AR5K_AR5210) return false; pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue)); pending &= AR5K_QCU_STS_FRMPENDCNT; /* It's possible to have no frames pending even if TXE * is set. To indicate that q has not stopped return * true */ if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) return true; return pending; }
/* * Wait for beacon queue to finish */ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) { unsigned int i; int ret; ATH5K_TRACE(ah->ah_sc); /* 5210 doesn't have QCU*/ if (ah->ah_version == AR5K_AR5210) { /* * Wait for beaconn queue to finish by checking * Control Register and Beacon Status Register. */ for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) || !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) break; udelay(10); } /* Timeout... */ if (i <= 0) { /* * Re-schedule the beacon queue */ ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, AR5K_BCR); return -EIO; } ret = 0; } else { /*5211/5212*/ ret = ath5k_hw_register_timeout(ah, AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), AR5K_QCU_STS_FRMPENDCNT, 0, false); if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) return -EIO; } return ret; }
/* * Check if a table entry is valid */ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) { ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); /* Check the validation flag at the end of the entry */ return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & AR5K_KEYTABLE_VALID; }
/** * ath5k_hw_get_rx_filter - Get current rx filter * * @ah: The &struct ath5k_hw * * Returns the RX filter by reading rx filter and * phy error filter registers. RX filter is used * to set the allowed frame types that PCU will accept * and pass to the driver. For a list of frame types * check out reg.h. */ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) { u32 data, filter = 0; filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); /*Radar detection for 5212*/ if (ah->ah_version == AR5K_AR5212) { data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); if (data & AR5K_PHY_ERR_FIL_RADAR) filter |= AR5K_RX_FILTER_RADARERR; if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) filter |= AR5K_RX_FILTER_PHYERR; } return filter; }
/* * Get GPIO state */ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return 0xffffffff; /* GPIO input magic */ return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & 0x1; }
/* * Set GPIO outputs */ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return -EINVAL; ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); return 0; }
/* * Set GPIO inputs */ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) { ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return -EINVAL; ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); return 0; }
/** * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters * @ah: The &struct ath5k_hw * @as: The &struct ath5k_ani_state * * Clear the PHY error counters as soon as possible, since this might be called * from a MIB interrupt and we want to make sure we don't get interrupted again. * Add the count of CCK and OFDM errors to our internal state, so it can be used * by the algorithm later. * * Will be called from interrupt and tasklet context. * Returns 0 if both counters are zero. */ static int ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, struct ath5k_ani_state *as) { unsigned int ofdm_err, cck_err; if (!ah->ah_capabilities.cap_has_phyerr_counters) return 0; ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1); cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2); /* reset counters first, we might be in a hurry (interrupt) */ ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, AR5K_PHYERR_CNT1); ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, AR5K_PHYERR_CNT2); ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err); cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err); /* sometimes both can be zero, especially when there is a superfluous * second interrupt. detect that here and return an error. */ if (ofdm_err <= 0 && cck_err <= 0) return 0; /* avoid negative values should one of the registers overflow */ if (ofdm_err > 0) { as->ofdm_errors += ofdm_err; as->sum_ofdm_errors += ofdm_err; } if (cck_err > 0) { as->cck_errors += cck_err; as->sum_cck_errors += cck_err; } return 1; }
/** * ath5k_hw_reset_tsf - Force a TSF reset * * @ah: The &struct ath5k_hw * * Forces a TSF reset on PCU */ void ath5k_hw_reset_tsf(struct ath5k_hw *ah) { u32 val; val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; /* * Each write to the RESET_TSF bit toggles a hardware internal * signal to reset TSF, but if left high it will cause a TSF reset * on the next chip reset as well. Thus we always write the value * twice to clear the signal. */ ath5k_hw_reg_write(ah, val, AR5K_BEACON); ath5k_hw_reg_write(ah, val, AR5K_BEACON); }
/* * Set GPIO state */ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) { u32 data; if (gpio >= AR5K_NUM_GPIO) return -EINVAL; /* GPIO output magic */ data = ath5k_hw_reg_read(ah, AR5K_GPIODO); data &= ~(1 << gpio); data |= (val & 1) << gpio; ath5k_hw_reg_write(ah, data, AR5K_GPIODO); return 0; }
/** * ath5k_hw_set_lladdr - Set station id * * @ah: The &struct ath5k_hw * @mac: The card's mac address * * Set station id on hw using the provided mac address */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { u32 low_id, high_id; u32 pcu_reg; /* Set new station ID */ memcpy(ah->ah_sta_id, mac, ETH_ALEN); pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; low_id = AR5K_LOW_ID(mac); high_id = AR5K_HIGH_ID(mac); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); return 0; }
/* * Reset a key entry on the table */ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) { unsigned int i, type; u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); /* Reset associated MIC entry if TKIP * is enabled located at offset (entry + 64) */ if (type == AR5K_KEYTABLE_TYPE_TKIP) { AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(micentry, i)); } /* * Set NULL encryption on AR5212+ * * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 * * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ if (ah->ah_version >= AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); if (type == AR5K_KEYTABLE_TYPE_TKIP) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(micentry)); } } return 0; }
/** * ath5k_hw_set_lladdr - Set station id * * @ah: The &struct ath5k_hw * @mac: The card's mac address * * Set station id on hw using the provided mac address */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; u32 pcu_reg; /* Set new station ID */ memcpy(common->macaddr, mac, ETH_ALEN); pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; low_id = get_unaligned_le32(mac); high_id = get_unaligned_le16(mac + 4); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); return 0; }
/** * ath5k_ani_print_counters() - Print ANI counters * @ah: The &struct ath5k_hw * * Used for debugging ANI */ void ath5k_ani_print_counters(struct ath5k_hw *ah) { /* clears too */ printk(KERN_NOTICE "ACK fail\t%d\n", ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); printk(KERN_NOTICE "RTS fail\t%d\n", ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); printk(KERN_NOTICE "RTS success\t%d\n", ath5k_hw_reg_read(ah, AR5K_RTS_OK)); printk(KERN_NOTICE "FCS error\t%d\n", ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); /* no clear */ printk(KERN_NOTICE "tx\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); printk(KERN_NOTICE "rx\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); printk(KERN_NOTICE "busy\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); printk(KERN_NOTICE "cycles\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n", ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n", ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n", ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n", ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); }
/* * 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; }
/** * 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; }
/** * 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); }