Commit 2b63a41d authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k_hw: add a new API for setting tx descriptors

Instead of using lots of different functions with long argument lists,
pull all the necessary information from one struct. This makes the code
easier to read and eliminates the need for copying data between multiple
linked descriptors.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 60f8cc60
...@@ -170,6 +170,106 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -170,6 +170,106 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
return true; return true;
} }
static void
ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
{
struct ar5416_desc *ads = AR5416DESC(ds);
u32 ctl1, ctl6;
ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
ACCESS_ONCE(ads->ds_link) = i->link;
ACCESS_ONCE(ads->ds_data) = i->buf_addr[0];
ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore);
ctl6 = SM(i->keytype, AR_EncrType);
if (AR_SREV_9285(ah)) {
ads->ds_ctl8 = 0;
ads->ds_ctl9 = 0;
ads->ds_ctl10 = 0;
ads->ds_ctl11 = 0;
}
if ((i->is_first || i->is_last) &&
i->aggr != AGGR_BUF_MIDDLE && i->aggr != AGGR_BUF_LAST) {
ACCESS_ONCE(ads->ds_ctl2) = set11nTries(i->rates, 0)
| set11nTries(i->rates, 1)
| set11nTries(i->rates, 2)
| set11nTries(i->rates, 3)
| (i->dur_update ? AR_DurUpdateEna : 0)
| SM(0, AR_BurstDur);
ACCESS_ONCE(ads->ds_ctl3) = set11nRate(i->rates, 0)
| set11nRate(i->rates, 1)
| set11nRate(i->rates, 2)
| set11nRate(i->rates, 3);
} else {
ACCESS_ONCE(ads->ds_ctl2) = 0;
ACCESS_ONCE(ads->ds_ctl3) = 0;
}
if (!i->is_first) {
ACCESS_ONCE(ads->ds_ctl0) = 0;
ACCESS_ONCE(ads->ds_ctl1) = ctl1;
ACCESS_ONCE(ads->ds_ctl6) = ctl6;
return;
}
ctl1 |= (i->keyix != ATH9K_TXKEYIX_INVALID ? SM(i->keyix, AR_DestIdx) : 0)
| SM(i->type, AR_FrameType)
| (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
| (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
| (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
switch (i->aggr) {
case AGGR_BUF_FIRST:
ctl6 |= SM(i->aggr_len, AR_AggrLen);
/* fall through */
case AGGR_BUF_MIDDLE:
ctl1 |= AR_IsAggr | AR_MoreAggr;
ctl6 |= SM(i->ndelim, AR_PadDelim);
break;
case AGGR_BUF_LAST:
ctl1 |= AR_IsAggr;
break;
case AGGR_BUF_NONE:
break;
}
ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(i->txpower, AR_XmitPower)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable :
(i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0));
ACCESS_ONCE(ads->ds_ctl1) = ctl1;
ACCESS_ONCE(ads->ds_ctl6) = ctl6;
if (i->aggr == AGGR_BUF_MIDDLE || i->aggr == AGGR_BUF_LAST)
return;
ACCESS_ONCE(ads->ds_ctl4) = set11nPktDurRTSCTS(i->rates, 0)
| set11nPktDurRTSCTS(i->rates, 1);
ACCESS_ONCE(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2)
| set11nPktDurRTSCTS(i->rates, 3);
ACCESS_ONCE(ads->ds_ctl7) = set11nRateFlags(i->rates, 0)
| set11nRateFlags(i->rates, 1)
| set11nRateFlags(i->rates, 2)
| set11nRateFlags(i->rates, 3)
| SM(i->rtscts_rate, AR_RTSCTSRate);
}
static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
bool is_firstseg, bool is_lastseg, bool is_firstseg, bool is_lastseg,
const void *ds0, dma_addr_t buf_addr, const void *ds0, dma_addr_t buf_addr,
...@@ -433,6 +533,7 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ...@@ -433,6 +533,7 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
ops->rx_enable = ar9002_hw_rx_enable; ops->rx_enable = ar9002_hw_rx_enable;
ops->set_desc_link = ar9002_hw_set_desc_link; ops->set_desc_link = ar9002_hw_set_desc_link;
ops->get_isr = ar9002_hw_get_isr; ops->get_isr = ar9002_hw_get_isr;
ops->set_txdesc = ar9002_set_txdesc;
ops->fill_txdesc = ar9002_hw_fill_txdesc; ops->fill_txdesc = ar9002_hw_fill_txdesc;
ops->proc_txdesc = ar9002_hw_proc_txdesc; ops->proc_txdesc = ar9002_hw_proc_txdesc;
ops->set11n_txdesc = ar9002_hw_set11n_txdesc; ops->set11n_txdesc = ar9002_hw_set11n_txdesc;
......
...@@ -21,6 +21,132 @@ static void ar9003_hw_rx_enable(struct ath_hw *hw) ...@@ -21,6 +21,132 @@ static void ar9003_hw_rx_enable(struct ath_hw *hw)
REG_WRITE(hw, AR_CR, 0); REG_WRITE(hw, AR_CR, 0);
} }
static void
ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
{
struct ar9003_txc *ads = ds;
int checksum = 0;
u32 val, ctl12, ctl17;
val = (ATHEROS_VENDOR_ID << AR_DescId_S) |
(1 << AR_TxRxDesc_S) |
(1 << AR_CtrlStat_S) |
(i->qcu << AR_TxQcuNum_S) | 0x17;
checksum += val;
ACCESS_ONCE(ads->info) = val;
checksum += i->link;
ACCESS_ONCE(ads->link) = i->link;
checksum += i->buf_addr[0];
ACCESS_ONCE(ads->data0) = i->buf_addr[0];
checksum += i->buf_addr[1];
ACCESS_ONCE(ads->data1) = i->buf_addr[1];
checksum += i->buf_addr[2];
ACCESS_ONCE(ads->data2) = i->buf_addr[2];
checksum += i->buf_addr[3];
ACCESS_ONCE(ads->data3) = i->buf_addr[3];
checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen);
ACCESS_ONCE(ads->ctl3) = val;
checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen);
ACCESS_ONCE(ads->ctl5) = val;
checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen);
ACCESS_ONCE(ads->ctl7) = val;
checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen);
ACCESS_ONCE(ads->ctl9) = val;
checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff);
ACCESS_ONCE(ads->ctl10) = checksum;
if (i->is_first || i->is_last) {
ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0)
| set11nTries(i->rates, 1)
| set11nTries(i->rates, 2)
| set11nTries(i->rates, 3)
| (i->dur_update ? AR_DurUpdateEna : 0)
| SM(0, AR_BurstDur);
ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0)
| set11nRate(i->rates, 1)
| set11nRate(i->rates, 2)
| set11nRate(i->rates, 3);
} else {
ACCESS_ONCE(ads->ctl13) = 0;
ACCESS_ONCE(ads->ctl14) = 0;
}
ads->ctl20 = 0;
ads->ctl21 = 0;
ads->ctl22 = 0;
ctl17 = SM(i->keytype, AR_EncrType);
if (!i->is_first) {
ACCESS_ONCE(ads->ctl11) = 0;
ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore;
ACCESS_ONCE(ads->ctl15) = 0;
ACCESS_ONCE(ads->ctl16) = 0;
ACCESS_ONCE(ads->ctl17) = ctl17;
ACCESS_ONCE(ads->ctl18) = 0;
ACCESS_ONCE(ads->ctl19) = 0;
return;
}
ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(i->txpower, AR_XmitPower)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0)
| (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable :
(i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0));
ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ?
SM(i->keyix, AR_DestIdx) : 0)
| SM(i->type, AR_FrameType)
| (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
| (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
| (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
ctl17 |= (i->flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0);
switch (i->aggr) {
case AGGR_BUF_FIRST:
ctl17 |= SM(i->aggr_len, AR_AggrLen);
/* fall through */
case AGGR_BUF_MIDDLE:
ctl12 |= AR_IsAggr | AR_MoreAggr;
ctl17 |= SM(i->ndelim, AR_PadDelim);
break;
case AGGR_BUF_LAST:
ctl12 |= AR_IsAggr;
break;
case AGGR_BUF_NONE:
break;
}
val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S;
ctl12 |= SM(val, AR_PAPRDChainMask);
ACCESS_ONCE(ads->ctl12) = ctl12;
ACCESS_ONCE(ads->ctl17) = ctl17;
ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0)
| set11nPktDurRTSCTS(i->rates, 1);
ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2)
| set11nPktDurRTSCTS(i->rates, 3);
ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0)
| set11nRateFlags(i->rates, 1)
| set11nRateFlags(i->rates, 2)
| set11nRateFlags(i->rates, 3)
| SM(i->rtscts_rate, AR_RTSCTSRate);
ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding;
}
static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
{ {
int checksum; int checksum;
...@@ -471,6 +597,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ...@@ -471,6 +597,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
ops->rx_enable = ar9003_hw_rx_enable; ops->rx_enable = ar9003_hw_rx_enable;
ops->set_desc_link = ar9003_hw_set_desc_link; ops->set_desc_link = ar9003_hw_set_desc_link;
ops->get_isr = ar9003_hw_get_isr; ops->get_isr = ar9003_hw_get_isr;
ops->set_txdesc = ar9003_set_txdesc;
ops->fill_txdesc = ar9003_hw_fill_txdesc; ops->fill_txdesc = ar9003_hw_fill_txdesc;
ops->proc_txdesc = ar9003_hw_proc_txdesc; ops->proc_txdesc = ar9003_hw_proc_txdesc;
ops->set11n_txdesc = ar9003_hw_set11n_txdesc; ops->set11n_txdesc = ar9003_hw_set11n_txdesc;
......
...@@ -54,6 +54,12 @@ static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -54,6 +54,12 @@ static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
return ath9k_hw_ops(ah)->get_isr(ah, masked); return ath9k_hw_ops(ah)->get_isr(ah, masked);
} }
static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_info *i)
{
return ath9k_hw_ops(ah)->set_txdesc(ah, ds, i);
}
static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen, static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen,
bool is_firstseg, bool is_lastseg, bool is_firstseg, bool is_lastseg,
const void *ds0, dma_addr_t buf_addr, const void *ds0, dma_addr_t buf_addr,
......
...@@ -616,6 +616,8 @@ struct ath_hw_ops { ...@@ -616,6 +616,8 @@ struct ath_hw_ops {
u8 rxchainmask, u8 rxchainmask,
bool longcal); bool longcal);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked); bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
void (*set_txdesc)(struct ath_hw *ah, void *ds,
struct ath_tx_info *i);
void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen, void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen,
bool is_firstseg, bool is_is_lastseg, bool is_firstseg, bool is_is_lastseg,
const void *ds0, dma_addr_t buf_addr, const void *ds0, dma_addr_t buf_addr,
......
...@@ -263,7 +263,11 @@ struct ath_desc { ...@@ -263,7 +263,11 @@ struct ath_desc {
#define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_VMF 0x0100
#define ATH9K_TXDESC_FRAG_IS_ON 0x0200 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200
#define ATH9K_TXDESC_LOWRXCHAIN 0x0400 #define ATH9K_TXDESC_LOWRXCHAIN 0x0400
#define ATH9K_TXDESC_LDPC 0x00010000 #define ATH9K_TXDESC_LDPC 0x0800
#define ATH9K_TXDESC_CLRDMASK 0x1000
#define ATH9K_TXDESC_PAPRD 0x70000
#define ATH9K_TXDESC_PAPRD_S 16
#define ATH9K_RXDESC_INTREQ 0x0020 #define ATH9K_RXDESC_INTREQ 0x0020
...@@ -660,6 +664,13 @@ struct ath9k_11n_rate_series { ...@@ -660,6 +664,13 @@ struct ath9k_11n_rate_series {
u32 RateFlags; u32 RateFlags;
}; };
enum aggr_type {
AGGR_BUF_NONE,
AGGR_BUF_FIRST,
AGGR_BUF_MIDDLE,
AGGR_BUF_LAST,
};
enum ath9k_key_type { enum ath9k_key_type {
ATH9K_KEY_TYPE_CLEAR, ATH9K_KEY_TYPE_CLEAR,
ATH9K_KEY_TYPE_WEP, ATH9K_KEY_TYPE_WEP,
...@@ -667,6 +678,33 @@ enum ath9k_key_type { ...@@ -667,6 +678,33 @@ enum ath9k_key_type {
ATH9K_KEY_TYPE_TKIP, ATH9K_KEY_TYPE_TKIP,
}; };
struct ath_tx_info {
u8 qcu;
bool is_first;
bool is_last;
enum aggr_type aggr;
u8 ndelim;
u16 aggr_len;
dma_addr_t link;
int pkt_len;
u32 flags;
dma_addr_t buf_addr[4];
int buf_len[4];
struct ath9k_11n_rate_series rates[4];
u8 rtscts_rate;
bool dur_update;
enum ath9k_pkt_type type;
enum ath9k_key_type keytype;
u8 keyix;
u8 txpower;
};
struct ath_hw; struct ath_hw;
struct ath9k_channel; struct ath9k_channel;
enum ath9k_int; enum ath9k_int;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment