|
@@ -168,23 +168,169 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
|
|
|
+{
|
|
|
+ int checksum;
|
|
|
+
|
|
|
+ checksum = ads->info + ads->link
|
|
|
+ + ads->data0 + ads->ctl3
|
|
|
+ + ads->data1 + ads->ctl5
|
|
|
+ + ads->data2 + ads->ctl7
|
|
|
+ + ads->data3 + ads->ctl9;
|
|
|
+
|
|
|
+ return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum;
|
|
|
+}
|
|
|
+
|
|
|
static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
|
|
|
bool is_firstseg, bool is_lastseg,
|
|
|
const void *ds0, dma_addr_t buf_addr,
|
|
|
unsigned int qcu)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+ unsigned int descid = 0;
|
|
|
+
|
|
|
+ ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) |
|
|
|
+ (1 << AR_TxRxDesc_S) |
|
|
|
+ (1 << AR_CtrlStat_S) |
|
|
|
+ (qcu << AR_TxQcuNum_S) | 0x17;
|
|
|
+
|
|
|
+ ads->data0 = buf_addr;
|
|
|
+ ads->data1 = 0;
|
|
|
+ ads->data2 = 0;
|
|
|
+ ads->data3 = 0;
|
|
|
+
|
|
|
+ ads->ctl3 = (seglen << AR_BufLen_S);
|
|
|
+ ads->ctl3 &= AR_BufLen;
|
|
|
+
|
|
|
+ /* Fill in pointer checksum and descriptor id */
|
|
|
+ ads->ctl10 = ar9003_calc_ptr_chksum(ads);
|
|
|
+ ads->ctl10 |= (descid << AR_TxDescId_S);
|
|
|
+
|
|
|
+ if (is_firstseg) {
|
|
|
+ ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore);
|
|
|
+ } else if (is_lastseg) {
|
|
|
+ ads->ctl11 = 0;
|
|
|
+ ads->ctl12 = 0;
|
|
|
+ ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13;
|
|
|
+ ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14;
|
|
|
+ } else {
|
|
|
+ /* XXX Intermediate descriptor in a multi-descriptor frame.*/
|
|
|
+ ads->ctl11 = 0;
|
|
|
+ ads->ctl12 = AR_TxMore;
|
|
|
+ ads->ctl13 = 0;
|
|
|
+ ads->ctl14 = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
|
|
|
struct ath_tx_status *ts)
|
|
|
{
|
|
|
+ struct ar9003_txs *ads;
|
|
|
+
|
|
|
+ ads = &ah->ts_ring[ah->ts_tail];
|
|
|
+
|
|
|
+ if ((ads->status8 & AR_TxDone) == 0)
|
|
|
+ return -EINPROGRESS;
|
|
|
+
|
|
|
+ ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
|
|
|
+
|
|
|
+ if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
|
|
|
+ (MS(ads->ds_info, AR_TxRxDesc) != 1)) {
|
|
|
+ ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
|
|
|
+ "Tx Descriptor error %x\n", ads->ds_info);
|
|
|
+ memset(ads, 0, sizeof(*ads));
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ ts->qid = MS(ads->ds_info, AR_TxQcuNum);
|
|
|
+ ts->desc_id = MS(ads->status1, AR_TxDescId);
|
|
|
+ ts->ts_seqnum = MS(ads->status8, AR_SeqNum);
|
|
|
+ ts->ts_tstamp = ads->status4;
|
|
|
+ ts->ts_status = 0;
|
|
|
+ ts->ts_flags = 0;
|
|
|
+
|
|
|
+ if (ads->status3 & AR_ExcessiveRetries)
|
|
|
+ ts->ts_status |= ATH9K_TXERR_XRETRY;
|
|
|
+ if (ads->status3 & AR_Filtered)
|
|
|
+ ts->ts_status |= ATH9K_TXERR_FILT;
|
|
|
+ if (ads->status3 & AR_FIFOUnderrun) {
|
|
|
+ ts->ts_status |= ATH9K_TXERR_FIFO;
|
|
|
+ ath9k_hw_updatetxtriglevel(ah, true);
|
|
|
+ }
|
|
|
+ if (ads->status8 & AR_TxOpExceeded)
|
|
|
+ ts->ts_status |= ATH9K_TXERR_XTXOP;
|
|
|
+ if (ads->status3 & AR_TxTimerExpired)
|
|
|
+ ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
|
|
|
+
|
|
|
+ if (ads->status3 & AR_DescCfgErr)
|
|
|
+ ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
|
|
|
+ if (ads->status3 & AR_TxDataUnderrun) {
|
|
|
+ ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
|
|
|
+ ath9k_hw_updatetxtriglevel(ah, true);
|
|
|
+ }
|
|
|
+ if (ads->status3 & AR_TxDelimUnderrun) {
|
|
|
+ ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
|
|
|
+ ath9k_hw_updatetxtriglevel(ah, true);
|
|
|
+ }
|
|
|
+ if (ads->status2 & AR_TxBaStatus) {
|
|
|
+ ts->ts_flags |= ATH9K_TX_BA;
|
|
|
+ ts->ba_low = ads->status5;
|
|
|
+ ts->ba_high = ads->status6;
|
|
|
+ }
|
|
|
+
|
|
|
+ ts->ts_rateindex = MS(ads->status8, AR_FinalTxIdx);
|
|
|
+
|
|
|
+ ts->ts_rssi = MS(ads->status7, AR_TxRSSICombined);
|
|
|
+ ts->ts_rssi_ctl0 = MS(ads->status2, AR_TxRSSIAnt00);
|
|
|
+ ts->ts_rssi_ctl1 = MS(ads->status2, AR_TxRSSIAnt01);
|
|
|
+ ts->ts_rssi_ctl2 = MS(ads->status2, AR_TxRSSIAnt02);
|
|
|
+ ts->ts_rssi_ext0 = MS(ads->status7, AR_TxRSSIAnt10);
|
|
|
+ ts->ts_rssi_ext1 = MS(ads->status7, AR_TxRSSIAnt11);
|
|
|
+ ts->ts_rssi_ext2 = MS(ads->status7, AR_TxRSSIAnt12);
|
|
|
+ ts->ts_shortretry = MS(ads->status3, AR_RTSFailCnt);
|
|
|
+ ts->ts_longretry = MS(ads->status3, AR_DataFailCnt);
|
|
|
+ ts->ts_virtcol = MS(ads->status3, AR_VirtRetryCnt);
|
|
|
+ ts->ts_antenna = 0;
|
|
|
+
|
|
|
+ ts->tid = MS(ads->status8, AR_TxTid);
|
|
|
+
|
|
|
+ memset(ads, 0, sizeof(*ads));
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
|
|
|
- u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
|
|
|
- u32 keyIx, enum ath9k_key_type keyType, u32 flags)
|
|
|
+ u32 pktlen, enum ath9k_pkt_type type, u32 txpower,
|
|
|
+ u32 keyIx, enum ath9k_key_type keyType, u32 flags)
|
|
|
{
|
|
|
-
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+
|
|
|
+ txpower += ah->txpower_indexoffset;
|
|
|
+ if (txpower > 63)
|
|
|
+ txpower = 63;
|
|
|
+
|
|
|
+ ads->ctl11 = (pktlen & AR_FrameLen)
|
|
|
+ | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
|
|
|
+ | SM(txpower, AR_XmitPower)
|
|
|
+ | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
|
|
|
+ | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
|
|
|
+ | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
|
|
|
+ | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
|
|
|
+
|
|
|
+ ads->ctl12 =
|
|
|
+ (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
|
|
|
+ | SM(type, AR_FrameType)
|
|
|
+ | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
|
|
|
+ | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
|
|
|
+ | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
|
|
|
+
|
|
|
+ ads->ctl17 = SM(keyType, AR_EncrType);
|
|
|
+ ads->ctl18 = 0;
|
|
|
+ ads->ctl19 = AR_Not_Sounding;
|
|
|
+
|
|
|
+ ads->ctl20 = 0;
|
|
|
+ ads->ctl21 = 0;
|
|
|
+ ads->ctl22 = 0;
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
|
@@ -194,41 +340,119 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
|
|
struct ath9k_11n_rate_series series[],
|
|
|
u32 nseries, u32 flags)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+ struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds;
|
|
|
+ u_int32_t ctl11;
|
|
|
+
|
|
|
+ if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
|
|
|
+ ctl11 = ads->ctl11;
|
|
|
+
|
|
|
+ if (flags & ATH9K_TXDESC_RTSENA) {
|
|
|
+ ctl11 &= ~AR_CTSEnable;
|
|
|
+ ctl11 |= AR_RTSEnable;
|
|
|
+ } else {
|
|
|
+ ctl11 &= ~AR_RTSEnable;
|
|
|
+ ctl11 |= AR_CTSEnable;
|
|
|
+ }
|
|
|
+
|
|
|
+ ads->ctl11 = ctl11;
|
|
|
+ } else {
|
|
|
+ ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable));
|
|
|
+ }
|
|
|
|
|
|
+ ads->ctl13 = set11nTries(series, 0)
|
|
|
+ | set11nTries(series, 1)
|
|
|
+ | set11nTries(series, 2)
|
|
|
+ | set11nTries(series, 3)
|
|
|
+ | (durUpdateEn ? AR_DurUpdateEna : 0)
|
|
|
+ | SM(0, AR_BurstDur);
|
|
|
+
|
|
|
+ ads->ctl14 = set11nRate(series, 0)
|
|
|
+ | set11nRate(series, 1)
|
|
|
+ | set11nRate(series, 2)
|
|
|
+ | set11nRate(series, 3);
|
|
|
+
|
|
|
+ ads->ctl15 = set11nPktDurRTSCTS(series, 0)
|
|
|
+ | set11nPktDurRTSCTS(series, 1);
|
|
|
+
|
|
|
+ ads->ctl16 = set11nPktDurRTSCTS(series, 2)
|
|
|
+ | set11nPktDurRTSCTS(series, 3);
|
|
|
+
|
|
|
+ ads->ctl18 = set11nRateFlags(series, 0)
|
|
|
+ | set11nRateFlags(series, 1)
|
|
|
+ | set11nRateFlags(series, 2)
|
|
|
+ | set11nRateFlags(series, 3)
|
|
|
+ | SM(rtsctsRate, AR_RTSCTSRate);
|
|
|
+ ads->ctl19 = AR_Not_Sounding;
|
|
|
+
|
|
|
+ last_ads->ctl13 = ads->ctl13;
|
|
|
+ last_ads->ctl14 = ads->ctl14;
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
|
|
|
u32 aggrLen)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+
|
|
|
+ ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
|
|
|
|
|
|
+ ads->ctl17 &= ~AR_AggrLen;
|
|
|
+ ads->ctl17 |= SM(aggrLen, AR_AggrLen);
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
|
|
|
u32 numDelims)
|
|
|
{
|
|
|
-
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+ unsigned int ctl17;
|
|
|
+
|
|
|
+ ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We use a stack variable to manipulate ctl6 to reduce uncached
|
|
|
+ * read modify, modfiy, write.
|
|
|
+ */
|
|
|
+ ctl17 = ads->ctl17;
|
|
|
+ ctl17 &= ~AR_PadDelim;
|
|
|
+ ctl17 |= SM(numDelims, AR_PadDelim);
|
|
|
+ ads->ctl17 = ctl17;
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
|
|
|
+ ads->ctl12 |= AR_IsAggr;
|
|
|
+ ads->ctl12 &= ~AR_MoreAggr;
|
|
|
+ ads->ctl17 &= ~AR_PadDelim;
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
|
|
|
+ ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
|
|
|
u32 burstDuration)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
+
|
|
|
+ ads->ctl13 &= ~AR_BurstDur;
|
|
|
+ ads->ctl13 |= SM(burstDuration, AR_BurstDur);
|
|
|
|
|
|
}
|
|
|
|
|
|
static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
|
|
|
- u32 vmf)
|
|
|
+ u32 vmf)
|
|
|
{
|
|
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
|
|
|
|
|
+ if (vmf)
|
|
|
+ ads->ctl11 |= AR_VirtMoreFrag;
|
|
|
+ else
|
|
|
+ ads->ctl11 &= ~AR_VirtMoreFrag;
|
|
|
}
|
|
|
|
|
|
void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
|