Beispiel #1
0
/*
 * 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;
	}
}
Beispiel #2
0
/* 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;
}
Beispiel #4
0
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 {
Beispiel #5
0
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;
}
Beispiel #6
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);

	/*
	 * 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;
}
Beispiel #7
0
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);
}
Beispiel #8
0
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;
}
Beispiel #9
0
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);
}
Beispiel #10
0
/*
 * 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);
}
Beispiel #11
0
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;
}
Beispiel #12
0
/*
 *  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;
	}
}
Beispiel #13
0
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;
	}
}
Beispiel #14
0
/* 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);
	}
}
Beispiel #15
0
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);
}
Beispiel #16
0
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);
}
Beispiel #17
0
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;
}
Beispiel #18
0
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;
}
Beispiel #19
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;
}
Beispiel #20
0
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);
}
Beispiel #21
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);
	}
}
Beispiel #22
0
/* 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");
}
Beispiel #23
0
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);
}
Beispiel #24
0
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;
}
Beispiel #25
0
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;
}
Beispiel #26
0
/* 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);
}
Beispiel #27
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);

}
Beispiel #28
0
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;
}
Beispiel #29
0
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;
}
Beispiel #30
0
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);
}