/* * Detects if there is any priority bt traffic */ static void ath_detect_bt_priority(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) btcoex->bt_priority_cnt++; if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, "BT scan detected"); sc->sc_flags |= (SC_OP_BT_SCAN | SC_OP_BT_PRIORITY_DETECTED); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, "BT priority traffic detected"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; } btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; } }
/* This is done for the currently configured channel */ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->curchan) return true; if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) return true; if (currCal == NULL) return true; if (currCal->calState != CAL_DONE) { ath_print(common, ATH_DBG_CALIBRATE, "Calibration state incorrect, %d\n", currCal->calState); return true; } if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) return true; ath_print(common, ATH_DBG_CALIBRATE, "Resetting Cal %d state for channel %u\n", currCal->calData->calType, conf->channel->center_freq); ah->curchan->CalValid &= ~currCal->calData->calType; currCal->calState = CAL_WAITING; return false; }
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, enum ath9k_tx_queue_subtype subtype) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; int qnum; memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype; qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; qi.tqi_physCompBuf = 0; qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); if (qnum == -1) return false; if (qnum >= ARRAY_SIZE(priv->hwq_map)) { ath_print(common, ATH_DBG_FATAL, "qnum %u out of range, max %u!\n", qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); ath9k_hw_releasetxqueue(ah, qnum); return false; } priv->hwq_map[subtype] = qnum; return true; }
bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) { u32 macHi, macLo; u32 unicast_flag = AR_KEYTABLE_VALID; void *ah = common->ah; if (entry >= common->keymax) { ath_print(common, ATH_DBG_FATAL, "keychache entry %u out of range\n", entry); return false; } if (mac != NULL) { /* * AR_KEYTABLE_VALID indicates that the address is a unicast * address, which must match the transmitter address for * decrypting frames. * Not setting this bit allows the hardware to use the key * for multicast frame decryption. */ if (mac[0] & 0x01) unicast_flag = 0; macHi = (mac[5] << 8) | mac[4]; macLo = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; macLo >>= 1; macLo |= (macHi & 1) << 31; macHi >>= 1; } else {
bool ath_hw_keyreset(struct ath_common *common, u16 entry) { u32 keyType; void *ah = common->ah; if (entry >= common->keymax) { ath_print(common, ATH_DBG_FATAL, "keychache entry %u out of range\n", entry); return false; } keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); if (keyType == AR_KEYTABLE_TYPE_TKIP) { u16 micentry = entry + 64; REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); } return true; }
static void ath9k_init_crypto(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; /* Get the hardware key cache size. */ common->keymax = sc->sc_ah->caps.keycache_size; if (common->keymax > ATH_KEYMAX) { ath_print(common, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", ATH_KEYMAX, common->keymax); common->keymax = ATH_KEYMAX; } /* * Reset the key cache since some parts do not * reset the contents on initial power up. */ for (i = 0; i < common->keymax; i++) ath9k_hw_keyreset(sc->sc_ah, (u16) i); /* * Check whether the separate key cache entries * are required to handle both tx+rx MIC keys. * With split mic keys the number of stations is limited * to 27 otherwise 59. */ if (!(sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)) common->splitmic = 1; }
static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; u32 rsp_status; int r; mutex_lock(&priv->wmi->multi_write_mutex); /* Store the register/value */ priv->wmi->multi_write[priv->wmi->multi_write_idx].reg = cpu_to_be32(reg_offset); priv->wmi->multi_write[priv->wmi->multi_write_idx].val = cpu_to_be32(val); priv->wmi->multi_write_idx++; /* If the buffer is full, send it out. */ if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, (u8 *) &priv->wmi->multi_write, sizeof(struct register_write) * priv->wmi->multi_write_idx, (u8 *) &rsp_status, sizeof(rsp_status), 100); if (unlikely(r)) { ath_print(common, ATH_DBG_WMI, "REGISTER WRITE FAILED, multi len: %d\n", priv->wmi->multi_write_idx); } priv->wmi->multi_write_idx = 0; } mutex_unlock(&priv->wmi->multi_write_mutex); }
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; int qnum; memset(&qi, 0, sizeof(qi)); ATH9K_HTC_INIT_TXQ(subtype); qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); if (qnum == -1) return false; if (qnum >= ARRAY_SIZE(priv->hwq_map)) { ath_print(common, ATH_DBG_FATAL, "qnum %u out of range, max %u!\n", qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); ath9k_hw_releasetxqueue(ah, qnum); return false; } priv->hwq_map[subtype] = qnum; return true; }
void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_tx_info *tx_info; if (!skb) return; if (ep_id == priv->mgmt_ep) { skb_pull(skb, sizeof(struct tx_mgmt_hdr)); } else if ((ep_id == priv->data_bk_ep) || (ep_id == priv->data_be_ep) || (ep_id == priv->data_vi_ep) || (ep_id == priv->data_vo_ep)) { skb_pull(skb, sizeof(struct tx_frame_hdr)); } else { ath_print(common, ATH_DBG_FATAL, "Unsupported TX EPID: %d\n", ep_id); dev_kfree_skb_any(skb); return; } tx_info = IEEE80211_SKB_CB(skb); if (txok) tx_info->flags |= IEEE80211_TX_STAT_ACK; skb_queue_tail(&priv->tx_queue, skb); tasklet_schedule(&priv->tx_tasklet); }
/* * Configures appropriate weight based on stomp type. */ static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, enum ath_stomp_type stomp_type) { struct ath_hw *ah = sc->sc_ah; switch (stomp_type) { case ATH_BTCOEX_STOMP_ALL: ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_ALL_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_LOW: ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_NONE: ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_NONE_WLAN_WGHT); break; default: ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Invalid Stomptype\n"); break; } ath9k_hw_btcoex_enable(ah); }
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath9k_platform_data *pdata = sc->dev->platform_data; if (pdata) { if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { ath_print(common, ATH_DBG_FATAL, "%s: eeprom read failed, offset %08x " "is out of range\n", __func__, off); } *data = pdata->eeprom_data[off]; } else { struct ath_hw *ah = (struct ath_hw *) common->ah; common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); if (!ath9k_hw_wait(ah, AR_EEPROM_STATUS_DATA, AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, AH_WAIT_TIMEOUT)) { return false; } *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), AR_EEPROM_STATUS_DATA_VAL); } return true; }
/* * This function will modify certain transmit queue properties depending on * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max */ int ath_beaconq_config(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi, qi_be; struct ath_txq *txq; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ txq = sc->tx.txq_map[WME_AC_BE]; ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; qi.tqi_cwmin = 4*qi_be.tqi_cwmin; qi.tqi_cwmax = qi_be.tqi_cwmax; } if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { ath_print(common, ATH_DBG_FATAL, "Unable to update h/w beacon queue parameters\n"); return 0; } else { ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); return 1; } }
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; cur_conf->beacon_interval = bss_conf->beacon_int; if (cur_conf->beacon_interval == 0) cur_conf->beacon_interval = 100; cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; switch (vif->type) { case NL80211_IFTYPE_STATION: ath9k_htc_beacon_config_sta(priv, cur_conf); break; case NL80211_IFTYPE_ADHOC: ath9k_htc_beacon_config_adhoc(priv, cur_conf); break; default: ath_print(common, ATH_DBG_CONFIG, "Unsupported beaconing mode\n"); return; } }
/* Currently, only for IBSS */ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) { struct ath_hw *ah = priv->ah; struct ath9k_tx_queue_info qi, qi_be; int qnum = priv->hwq_map[WME_AC_BE]; memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); ath9k_hw_get_txq_props(ah, qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; /* For WIFI Beacon Distribution * Long slot time : 2x cwmin * Short slot time : 4x cwmin */ if (ah->slottime == ATH9K_SLOT_TIME_20) qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else qi.tqi_cwmin = 4*qi_be.tqi_cwmin; qi.tqi_cwmax = qi_be.tqi_cwmax; if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, "Unable to update beacon queue %u!\n", qnum); } else { ath9k_hw_resettxqueue(ah, priv->beaconq); } }
static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, struct htc_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; u32 nexttbtt, intval; __be32 htc_imask = 0; int ret; u8 cmd_rsp; intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; nexttbtt = intval; intval |= ATH9K_BEACON_ENA; if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; ath_print(common, ATH_DBG_BEACON, "IBSS Beacon config, intval: %d, imask: 0x%x\n", bss_conf->beacon_interval, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); priv->bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); }
static void ath9k_regwrite_flush(void *hw_priv) { struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; u32 rsp_status; int r; mutex_lock(&priv->wmi->multi_write_mutex); if (priv->wmi->multi_write_idx) { r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, (u8 *) &priv->wmi->multi_write, sizeof(struct register_write) * priv->wmi->multi_write_idx, (u8 *) &rsp_status, sizeof(rsp_status), 100); if (unlikely(r)) { ath_print(common, ATH_DBG_WMI, "REGISTER WRITE FAILED, multi len: %d\n", priv->wmi->multi_write_idx); } priv->wmi->multi_write_idx = 0; } mutex_unlock(&priv->wmi->multi_write_mutex); }
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo) { struct ath_hw *ah = priv->ah; int error = 0; struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, qnum, &qi); qi.tqi_aifs = qinfo->tqi_aifs; qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ qi.tqi_cwmax = qinfo->tqi_cwmax; qi.tqi_burstTime = qinfo->tqi_burstTime; qi.tqi_readyTime = qinfo->tqi_readyTime; if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { ath9k_hw_resettxqueue(ah, qnum); } return error; }
static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; aniState = ah->curani; aniState->listenTime = 0; if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; ath_print(common, ATH_DBG_ANI, "OFDM Trigger is too high for hw counters\n"); } else { aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; } if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; ath_print(common, ATH_DBG_ANI, "CCK Trigger is too high for hw counters\n"); } else { aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; } ath_print(common, ATH_DBG_ANI, "Writing ofdmbase=%u cckbase=%u\n", aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); DISABLE_REGWRITE_BUFFER(ah); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
void ath9k_hw_ani_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); int i; ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; ah->ani[i].ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; ah->ani[i].cckWeakSigThreshold = ATH9K_ANI_CCK_WEAK_SIG_THR; ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ah->ani[i].ofdmPhyErrBase = AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; ah->ani[i].cckPhyErrBase = AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } ath_print(common, ATH_DBG_ANI, "Setting OfdmErrBase = 0x%08x\n", ah->ani[0].ofdmPhyErrBase); ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", ah->ani[0].cckPhyErrBase); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); REGWRITE_BUFFER_FLUSH(ah); DISABLE_REGWRITE_BUFFER(ah); ath9k_enable_mib_counters(ah); ah->aniperiod = ATH9K_ANI_PERIOD; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; }
void ath9k_hw_ani_disable(struct ath_hw *ah) { ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n"); ath9k_hw_disable_mib_counters(ah); REG_WRITE(ah, AR_PHY_ERR_1, 0); REG_WRITE(ah, AR_PHY_ERR_2, 0); }
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = sc->beacon.cabq; ath_print(common, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n"); dev_kfree_skb_any(skb); } }
/* caller must hold wiphy_lock */ void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) { struct ath_softc *sc = aphy->sc; aphy->idle = idle; ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, "Marking %s as %s\n", wiphy_name(aphy->hw->wiphy), idle ? "idle" : "not-idle"); }
void ath9k_wmi_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; struct ath_common *common = ath9k_hw_common(priv->ah); struct wmi_cmd_hdr *hdr; struct wmi_swba *swba_hdr; enum wmi_event_id event; struct sk_buff *skb; void *wmi_event; unsigned long flags; #ifdef CONFIG_ATH9K_HTC_DEBUGFS __be32 txrate; #endif spin_lock_irqsave(&priv->wmi->wmi_lock, flags); skb = priv->wmi->wmi_skb; spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); hdr = (struct wmi_cmd_hdr *) skb->data; event = be16_to_cpu(hdr->command_id); wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); ath_print(common, ATH_DBG_WMI, "WMI Event: 0x%x\n", event); switch (event) { case WMI_TGT_RDY_EVENTID: break; case WMI_SWBA_EVENTID: swba_hdr = (struct wmi_swba *) wmi_event; ath9k_htc_swba(priv, swba_hdr->beacon_pending); break; case WMI_FATAL_EVENTID: break; case WMI_TXTO_EVENTID: break; case WMI_BMISS_EVENTID: break; case WMI_WLAN_TXCOMP_EVENTID: break; case WMI_DELBA_EVENTID: break; case WMI_TXRATE_EVENTID: #ifdef CONFIG_ATH9K_HTC_DEBUGFS txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; priv->debug.txrate = be32_to_cpu(txrate); #endif break; default: break; } kfree_skb(skb); }
static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u8 tx_streams, rx_streams; int i, max_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SM_PS | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; if (AR_SREV_9300_20_OR_LATER(ah)) max_streams = 3; else max_streams = 2; if (AR_SREV_9280_10_OR_LATER(ah)) { if (max_streams >= 2) ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); } /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams); rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams); ath_print(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); if (tx_streams != rx_streams) { ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } for (i = 0; i < rx_streams; i++) ht_info->mcs.rx_mask[i] = 0xff; ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; }
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf) { if (nf > ATH9K_NF_TOO_LOW) { ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "noise floor value detected (%d) is " "lower than what we think is a " "reasonable value (%d)\n", nf, ATH9K_NF_TOO_LOW); return false; } return true; }
/* Freeze the MIB counters, get the stats and then clear them */ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n"); REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); }
static void ath9k_init_crypto(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; /* Get the hardware key cache size. */ common->keymax = sc->sc_ah->caps.keycache_size; if (common->keymax > ATH_KEYMAX) { ath_print(common, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", ATH_KEYMAX, common->keymax); common->keymax = ATH_KEYMAX; } /* * Reset the key cache since some parts do not * reset the contents on initial power up. */ for (i = 0; i < common->keymax; i++) ath9k_hw_keyreset(sc->sc_ah, (u16) i); if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL)) { /* * Whether we should enable h/w TKIP MIC. * XXX: if we don't support WME TKIP MIC, then we wouldn't * report WMM capable, so it's always safe to turn on * TKIP MIC in this case. */ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); } /* * Check whether the separate key cache entries * are required to handle both tx+rx MIC keys. * With split mic keys the number of stations is limited * to 27 otherwise 59. */ if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL) && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_MIC, NULL) && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT, 0, NULL)) common->splitmic = 1; /* turn on mcast key search if possible */ if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 1, 1, NULL); }
static int ath9k_init_queues(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) sc->tx.hwq_map[i] = -1; sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); if (sc->beacon.beaconq == -1) { ath_print(common, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); goto err; } sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { ath_print(common, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); goto err; } sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for BK traffic\n"); goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for BE traffic\n"); goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for VI traffic\n"); goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for VO traffic\n"); goto err; } return 0; err: for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); return -EIO; }
int16_t ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); int16_t nf, nfThresh; int16_t nfarray[NUM_NF_READINGS] = { 0 }; struct ath9k_nfcal_hist *h; struct ieee80211_channel *c = chan->chan; chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { ath_print(common, ATH_DBG_CALIBRATE, "NF did not complete in calibration window\n"); nf = 0; chan->rawNoiseFloor = nf; return chan->rawNoiseFloor; } else { ath9k_hw_do_getnf(ah, nfarray); nf = nfarray[0]; if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) && nf > nfThresh) { ath_print(common, ATH_DBG_CALIBRATE, "noise floor failed detected; " "detected %d, threshold %d\n", nf, nfThresh); chan->channelFlags |= CHANNEL_CW_INT; } } h = ah->nfCalHist; ath9k_hw_update_nfcal_hist_buffer(h, nfarray); chan->rawNoiseFloor = h[0].privNF; return chan->rawNoiseFloor; }
static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, struct ath9k_keyval *hk, const u8 *addr, bool authenticator) { struct ath_hw *ah = common->ah; const u8 *key_rxmic; const u8 *key_txmic; key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; if (addr == NULL) { /* * Group key installation - only two key cache entries are used * regardless of splitmic capability since group key is only * used either for TX or RX. */ if (authenticator) { memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); } else { memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); } return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); } if (!common->splitmic) { /* TX and RX keys share the same key cache entry. */ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); } /* Separate key cache entries for TX and RX */ /* TX key goes at first index, RX key at +32. */ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ ath_print(common, ATH_DBG_FATAL, "Setting TX MIC Key Failed\n"); return 0; } memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); /* XXX delete tx key on failure? */ return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); }