extractedLnx/linux-2.6.37/drivers/staging/brcm80211/sys/wlc_mac80211.c_wlc_d11hdrs_mac80211.c
static u16 BCMFASTPATH
wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
void *p, struct scb *scb, uint frag,
uint nfrags, uint queue, uint next_frag_len,
wsec_key_t *key, ratespec_t rspec_override)
{
struct dot11_header *h;
d11txh_t *txh;
u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
osl_t *osh;
int len, phylen, rts_phylen;
u16 fc, type, frameid, mch, phyctl, xfts, mainrates;
u16 seq = 0, mcl = 0, status = 0;
ratespec_t rspec[2] = { WLC_RATE_1M, WLC_RATE_1M }, rts_rspec[2] = {
WLC_RATE_1M, WLC_RATE_1M};
bool use_rts = false;
bool use_cts = false;
bool use_rifs = false;
bool short_preamble[2] = { false, false };
u8 preamble_type[2] = { WLC_LONG_PREAMBLE, WLC_LONG_PREAMBLE };
u8 rts_preamble_type[2] = { WLC_LONG_PREAMBLE, WLC_LONG_PREAMBLE };
u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
struct dot11_rts_frame *rts = NULL;
bool qos;
uint ac;
u32 rate_val[2];
bool hwtkmic = false;
u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
#ifdef WLANTSEL
#define ANTCFG_NONE 0xFF
u8 antcfg = ANTCFG_NONE;
u8 fbantcfg = ANTCFG_NONE;
#endif
uint phyctl1_stf = 0;
u16 durid = 0;
struct ieee80211_tx_rate *txrate[2];
int k;
struct ieee80211_tx_info *tx_info;
bool is_mcs[2];
u16 mimo_txbw;
u8 mimo_preamble_type;
frameid = 0;
ASSERT(queue < NFIFO);
osh = wlc->osh;
/* locate 802.11 MAC header */
h = (struct dot11_header *)PKTDATA(p);
fc = ltoh16(h->fc);
type = FC_TYPE(fc);
qos = (type == FC_TYPE_DATA && FC_SUBTYPE_ANY_QOS(FC_SUBTYPE(fc)));
/* compute length of frame in bytes for use in PLCP computations */
len = pkttotlen(osh, p);
phylen = len + DOT11_FCS_LEN;
/* If WEP enabled, add room in phylen for the additional bytes of
* ICV which MAC generates. We do NOT add the additional bytes to
* the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN
* in this case
*/
if (key) {
phylen += key->icv_len;
}
/* Get tx_info */
tx_info = IEEE80211_SKB_CB(p);
ASSERT(tx_info);
/* add PLCP */
plcp = PKTPUSH(p, D11_PHY_HDR_LEN);
/* add Broadcom tx descriptor header */
txh = (d11txh_t *) PKTPUSH(p, D11_TXH_LEN);
bzero((char *)txh, D11_TXH_LEN);
/* setup frameid */
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
/* non-AP STA should never use BCMC queue */
ASSERT(queue != TX_BCMC_FIFO);
if (queue == TX_BCMC_FIFO) {
WL_ERROR(("wl%d: %s: ASSERT queue == TX_BCMC!\n",
WLCWLUNIT(wlc), __func__));
frameid = bcmc_fid_generate(wlc, NULL, txh);
} else {
/* Increment the counter for first fragment */
if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
SCB_SEQNUM(scb, PKTPRIO(p))++;
}
/* extract fragment number from frame first */
seq = ltoh16(seq) & FRAGNUM_MASK;
seq |= (SCB_SEQNUM(scb, PKTPRIO(p)) << SEQNUM_SHIFT);
h->seq = htol16(seq);
frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
(queue & TXFID_QUEUE_MASK);
}
}
frameid |= queue & TXFID_QUEUE_MASK;
/* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
if (SCB_PS(scb) || ((fc & FC_KIND_MASK) == FC_BEACON))
mcl |= TXC_IGNOREPMQ;
ASSERT(hw->max_rates <= IEEE80211_TX_MAX_RATES);
ASSERT(hw->max_rates == 2);
txrate[0] = tx_info->control.rates;
txrate[1] = txrate[0] + 1;
ASSERT(txrate[0]->idx >= 0);
/* if rate control algorithm didn't give us a fallback rate, use the primary rate */
if (txrate[1]->idx < 0) {
txrate[1] = txrate[0];
}
#ifdef WLC_HIGH_ONLY
/* Double protection , just in case */
if (txrate[0]->idx > HIGHEST_SINGLE_STREAM_MCS)
txrate[0]->idx = HIGHEST_SINGLE_STREAM_MCS;
if (txrate[1]->idx > HIGHEST_SINGLE_STREAM_MCS)
txrate[1]->idx = HIGHEST_SINGLE_STREAM_MCS;
#endif
for (k = 0; k < hw->max_rates; k++) {
is_mcs[k] =
txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
if (!is_mcs[k]) {
ASSERT(!(tx_info->flags & IEEE80211_TX_CTL_AMPDU));
if ((txrate[k]->idx >= 0)
&& (txrate[k]->idx <
hw->wiphy->bands[tx_info->band]->n_bitrates)) {
rate_val[k] =
hw->wiphy->bands[tx_info->band]->
bitrates[txrate[k]->idx].hw_value;
short_preamble[k] =
txrate[k]->
flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
true : false;
} else {
ASSERT((txrate[k]->idx >= 0) &&
(txrate[k]->idx <
hw->wiphy->bands[tx_info->band]->
n_bitrates));
rate_val[k] = WLC_RATE_1M;
}
} else {
rate_val[k] = txrate[k]->idx;
}
/* Currently only support same setting for primay and fallback rates.
* Unify flags for each rate into a single value for the frame
*/
use_rts |=
txrate[k]->
flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
use_cts |=
txrate[k]->
flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
if (is_mcs[k])
rate_val[k] |= NRATE_MCS_INUSE;
rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]);
/* (1) RATE: determine and validate primary rate and fallback rates */
if (!RSPEC_ACTIVE(rspec[k])) {
ASSERT(RSPEC_ACTIVE(rspec[k]));
rspec[k] = WLC_RATE_1M;
} else {
if (WLANTSEL_ENAB(wlc) && !ETHER_ISMULTI(&h->a1)) {
/* set tx antenna config */
wlc_antsel_antcfg_get(wlc->asi, false, false, 0,
0, &antcfg, &fbantcfg);
}
}
}
phyctl1_stf = wlc->stf->ss_opmode;
if (N_ENAB(wlc->pub)) {
for (k = 0; k < hw->max_rates; k++) {
/* apply siso/cdd to single stream mcs's or ofdm if rspec is auto selected */
if (((IS_MCS(rspec[k]) &&
IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
IS_OFDM(rspec[k]))
&& ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
|| !(rspec[k] & RSPEC_OVERRIDE))) {
rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
/* For SISO MCS use STBC if possible */
if (IS_MCS(rspec[k])
&& WLC_STF_SS_STBC_TX(wlc, scb)) {
u8 stc;
ASSERT(WLC_STBC_CAP_PHY(wlc));
stc = 1; /* Nss for single stream is always 1 */
rspec[k] |=
(PHY_TXC1_MODE_STBC <<
RSPEC_STF_SHIFT) | (stc <<
RSPEC_STC_SHIFT);
} else
rspec[k] |=
(phyctl1_stf << RSPEC_STF_SHIFT);
}
/* Is the phy configured to use 40MHZ frames? If so then pick the desired txbw */
if (CHSPEC_WLC_BW(wlc->chanspec) == WLC_40_MHZ) {
/* default txbw is 20in40 SB */
mimo_ctlchbw = mimo_txbw =
CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
if (IS_MCS(rspec[k])) {
/* mcs 32 must be 40b/w DUP */
if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
mimo_txbw =
PHY_TXC1_BW_40MHZ_DUP;
/* use override */
} else if (wlc->mimo_40txbw != AUTO)
mimo_txbw = wlc->mimo_40txbw;
/* else check if dst is using 40 Mhz */
else if (scb->flags & SCB_IS40)
mimo_txbw = PHY_TXC1_BW_40MHZ;
} else if (IS_OFDM(rspec[k])) {
if (wlc->ofdm_40txbw != AUTO)
mimo_txbw = wlc->ofdm_40txbw;
} else {
ASSERT(IS_CCK(rspec[k]));
if (wlc->cck_40txbw != AUTO)
mimo_txbw = wlc->cck_40txbw;
}
} else {
/* mcs32 is 40 b/w only.
* This is possible for probe packets on a STA during SCAN
*/
if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
/* mcs 0 */
rspec[k] = RSPEC_MIMORATE;
}
mimo_txbw = PHY_TXC1_BW_20MHZ;
}
/* Set channel width */
rspec[k] &= ~RSPEC_BW_MASK;
if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
else
rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
/* Set Short GI */
#ifdef NOSGIYET
if (IS_MCS(rspec[k])
&& (txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
rspec[k] |= RSPEC_SHORT_GI;
else if (!(txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
rspec[k] &= ~RSPEC_SHORT_GI;
#else
rspec[k] &= ~RSPEC_SHORT_GI;
#endif
mimo_preamble_type = WLC_MM_PREAMBLE;
if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
mimo_preamble_type = WLC_GF_PREAMBLE;
if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
&& (!IS_MCS(rspec[k]))) {
WL_ERROR(("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n", WLCWLUNIT(wlc), __func__));
ASSERT(0 && "Rate mismatch");
}
if (IS_MCS(rspec[k])) {
preamble_type[k] = mimo_preamble_type;
/* if SGI is selected, then forced mm for single stream */
if ((rspec[k] & RSPEC_SHORT_GI)
&& IS_SINGLE_STREAM(rspec[k] &
RSPEC_RATE_MASK)) {
preamble_type[k] = WLC_MM_PREAMBLE;
}
}
/* mimo bw field MUST now be valid in the rspec (it affects duration calculations) */
ASSERT(VALID_RATE_DBG(wlc, rspec[0]));
/* should be better conditionalized */
if (!IS_MCS(rspec[0])
&& (tx_info->control.rates[0].
flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
preamble_type[k] = WLC_SHORT_PREAMBLE;
ASSERT(!IS_MCS(rspec[0])
|| WLC_IS_MIMO_PREAMBLE(preamble_type[k]));
}
} else {
for (k = 0; k < hw->max_rates; k++) {
/* Set ctrlchbw as 20Mhz */
ASSERT(!IS_MCS(rspec[k]));
rspec[k] &= ~RSPEC_BW_MASK;
rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
/* for nphy, stf of ofdm frames must follow policies */
if (WLCISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
rspec[k] &= ~RSPEC_STF_MASK;
rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
}
}
}
/* Reset these for use with AMPDU's */
txrate[0]->count = 0;
txrate[1]->count = 0;
/* (3) PLCP: determine PLCP header and MAC duration, fill d11txh_t */
wlc_compute_plcp(wlc, rspec[0], phylen, plcp);
wlc_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
bcopy(plcp_fallback, (char *)&txh->FragPLCPFallback,
sizeof(txh->FragPLCPFallback));
/* Length field now put in CCK FBR CRC field */
if (IS_CCK(rspec[1])) {
txh->FragPLCPFallback[4] = phylen & 0xff;
txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
}
/* MIMO-RATE: need validation ?? */
mainrates =
IS_OFDM(rspec[0]) ? D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) plcp) :
plcp[0];
/* DUR field for main rate */
if ((fc != FC_PS_POLL) && !ETHER_ISMULTI(&h->a1) && !use_rifs) {
durid =
wlc_compute_frame_dur(wlc, rspec[0], preamble_type[0],
next_frag_len);
h->durid = htol16(durid);
} else if (use_rifs) {
/* NAV protect to end of next max packet size */
durid =
(u16) wlc_calc_frame_time(wlc, rspec[0],
preamble_type[0],
DOT11_MAX_FRAG_LEN);
durid += RIFS_11N_TIME;
h->durid = htol16(durid);
}
/* DUR field for fallback rate */
if (fc == FC_PS_POLL)
txh->FragDurFallback = h->durid;
else if (ETHER_ISMULTI(&h->a1) || use_rifs)
txh->FragDurFallback = 0;
else {
durid = wlc_compute_frame_dur(wlc, rspec[1],
preamble_type[1], next_frag_len);
txh->FragDurFallback = htol16(durid);
}
/* (4) MAC-HDR: MacTxControlLow */
if (frag == 0)
mcl |= TXC_STARTMSDU;
if (!ETHER_ISMULTI(&h->a1))
mcl |= TXC_IMMEDACK;
if (BAND_5G(wlc->band->bandtype))
mcl |= TXC_FREQBAND_5G;
if (CHSPEC_IS40(WLC_BAND_PI_RADIO_CHANSPEC))
mcl |= TXC_BW_40;
/* set AMIC bit if using hardware TKIP MIC */
if (hwtkmic)
mcl |= TXC_AMIC;
txh->MacTxControlLow = htol16(mcl);
/* MacTxControlHigh */
mch = 0;
/* Set fallback rate preamble type */
if ((preamble_type[1] == WLC_SHORT_PREAMBLE) ||
(preamble_type[1] == WLC_GF_PREAMBLE)) {
ASSERT((preamble_type[1] == WLC_GF_PREAMBLE) ||
(!IS_MCS(rspec[1])));
if (RSPEC2RATE(rspec[1]) != WLC_RATE_1M)
mch |= TXC_PREAMBLE_DATA_FB_SHORT;
}
/* MacFrameControl */
bcopy((char *)&h->fc, (char *)&txh->MacFrameControl, sizeof(u16));
txh->TxFesTimeNormal = htol16(0);
txh->TxFesTimeFallback = htol16(0);
/* TxFrameRA */
bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETHER_ADDR_LEN);
/* TxFrameID */
txh->TxFrameID = htol16(frameid);
/* TxStatus, Note the case of recreating the first frag of a suppressed frame
* then we may need to reset the retry cnt's via the status reg
*/
txh->TxStatus = htol16(status);
if (D11REV_GE(wlc->pub->corerev, 16)) {
/* extra fields for ucode AMPDU aggregation, the new fields are added to
* the END of previous structure so that it's compatible in driver.
* In old rev ucode, these fields should be ignored
*/
txh->MaxNMpdus = htol16(0);
txh->MaxABytes_MRT = htol16(0);
txh->MaxABytes_FBR = htol16(0);
txh->MinMBytes = htol16(0);
}
/* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration, furnish d11txh_t */
/* RTS PLCP header and RTS frame */
if (use_rts || use_cts) {
if (use_rts && use_cts)
use_cts = false;
for (k = 0; k < 2; k++) {
rts_rspec[k] = wlc_rspec_to_rts_rspec(wlc, rspec[k],
false,
mimo_ctlchbw);
}
if (!IS_OFDM(rts_rspec[0]) &&
!((RSPEC2RATE(rts_rspec[0]) == WLC_RATE_1M) ||
(wlc->PLCPHdr_override == WLC_PLCP_LONG))) {
rts_preamble_type[0] = WLC_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
}
if (!IS_OFDM(rts_rspec[1]) &&
!((RSPEC2RATE(rts_rspec[1]) == WLC_RATE_1M) ||
(wlc->PLCPHdr_override == WLC_PLCP_LONG))) {
rts_preamble_type[1] = WLC_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_FB_SHORT;
}
/* RTS/CTS additions to MacTxControlLow */
if (use_cts) {
txh->MacTxControlLow |= htol16(TXC_SENDCTS);
} else {
txh->MacTxControlLow |= htol16(TXC_SENDRTS);
txh->MacTxControlLow |= htol16(TXC_LONGFRAME);
}
/* RTS PLCP header */
ASSERT(IS_ALIGNED((unsigned long)txh->RTSPhyHeader, sizeof(u16)));
rts_plcp = txh->RTSPhyHeader;
if (use_cts)
rts_phylen = DOT11_CTS_LEN + DOT11_FCS_LEN;
else
rts_phylen = DOT11_RTS_LEN + DOT11_FCS_LEN;
wlc_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
/* fallback rate version of RTS PLCP header */
wlc_compute_plcp(wlc, rts_rspec[1], rts_phylen,
rts_plcp_fallback);
bcopy(rts_plcp_fallback, (char *)&txh->RTSPLCPFallback,
sizeof(txh->RTSPLCPFallback));
/* RTS frame fields... */
rts = (struct dot11_rts_frame *)&txh->rts_frame;
durid = wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
rspec[0], rts_preamble_type[0],
preamble_type[0], phylen, false);
rts->durid = htol16(durid);
/* fallback rate version of RTS DUR field */
durid = wlc_compute_rtscts_dur(wlc, use_cts,
rts_rspec[1], rspec[1],
rts_preamble_type[1],
preamble_type[1], phylen, false);
txh->RTSDurFallback = htol16(durid);
if (use_cts) {
rts->fc = htol16(FC_CTS);
bcopy((char *)&h->a2, (char *)&rts->ra, ETHER_ADDR_LEN);
} else {
rts->fc = htol16((u16) FC_RTS);
bcopy((char *)&h->a1, (char *)&rts->ra,
2 * ETHER_ADDR_LEN);
}
/* mainrate
* low 8 bits: main frag rate/mcs,
* high 8 bits: rts/cts rate/mcs
*/
mainrates |= (IS_OFDM(rts_rspec[0]) ?
D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) rts_plcp) :
rts_plcp[0]) << 8;
} else {
bzero((char *)txh->RTSPhyHeader, D11_PHY_HDR_LEN);
bzero((char *)&txh->rts_frame, sizeof(struct dot11_rts_frame));
bzero((char *)txh->RTSPLCPFallback,
sizeof(txh->RTSPLCPFallback));
txh->RTSDurFallback = 0;
}
#ifdef SUPPORT_40MHZ
/* add null delimiter count */
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec)) {
txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
wlc_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
}
#endif
/* Now that RTS/RTS FB preamble types are updated, write the final value */
txh->MacTxControlHigh = htol16(mch);
/* MainRates (both the rts and frag plcp rates have been calculated now) */
txh->MainRates = htol16(mainrates);
/* XtraFrameTypes */
xfts = FRAMETYPE(rspec[1], wlc->mimoft);
xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
xfts |=
CHSPEC_CHANNEL(WLC_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT;
txh->XtraFrameTypes = htol16(xfts);
/* PhyTxControlWord */
phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
if ((preamble_type[0] == WLC_SHORT_PREAMBLE) ||
(preamble_type[0] == WLC_GF_PREAMBLE)) {
ASSERT((preamble_type[0] == WLC_GF_PREAMBLE)
|| !IS_MCS(rspec[0]));
if (RSPEC2RATE(rspec[0]) != WLC_RATE_1M)
phyctl |= PHY_TXC_SHORT_HDR;
WLCNTINCR(wlc->pub->_cnt->txprshort);
}
/* phytxant is properly bit shifted */
phyctl |= wlc_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
txh->PhyTxControlWord = htol16(phyctl);
/* PhyTxControlWord_1 */
if (WLC_PHY_11N_CAP(wlc->band)) {
u16 phyctl1 = 0;
phyctl1 = wlc_phytxctl1_calc(wlc, rspec[0]);
txh->PhyTxControlWord_1 = htol16(phyctl1);
phyctl1 = wlc_phytxctl1_calc(wlc, rspec[1]);
txh->PhyTxControlWord_1_Fbr = htol16(phyctl1);
if (use_rts || use_cts) {
phyctl1 = wlc_phytxctl1_calc(wlc, rts_rspec[0]);
txh->PhyTxControlWord_1_Rts = htol16(phyctl1);
phyctl1 = wlc_phytxctl1_calc(wlc, rts_rspec[1]);
txh->PhyTxControlWord_1_FbrRts = htol16(phyctl1);
}
/*
* For mcs frames, if mixedmode(overloaded with long preamble) is going to be set,
* fill in non-zero MModeLen and/or MModeFbrLen
* it will be unnecessary if they are separated
*/
if (IS_MCS(rspec[0]) && (preamble_type[0] == WLC_MM_PREAMBLE)) {
u16 mmodelen =
wlc_calc_lsig_len(wlc, rspec[0], phylen);
txh->MModeLen = htol16(mmodelen);
}
if (IS_MCS(rspec[1]) && (preamble_type[1] == WLC_MM_PREAMBLE)) {
u16 mmodefbrlen =
wlc_calc_lsig_len(wlc, rspec[1], phylen);
txh->MModeFbrLen = htol16(mmodefbrlen);
}
}
if (IS_MCS(rspec[0]))
ASSERT(IS_MCS(rspec[1]));
ASSERT(!IS_MCS(rspec[0]) ||
((preamble_type[0] == WLC_MM_PREAMBLE) == (txh->MModeLen != 0)));
ASSERT(!IS_MCS(rspec[1]) ||
((preamble_type[1] == WLC_MM_PREAMBLE) ==
(txh->MModeFbrLen != 0)));
ac = wme_fifo2ac[queue];
if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
uint frag_dur, dur, dur_fallback;
ASSERT(!ETHER_ISMULTI(&h->a1));
/* WME: Update TXOP threshold */
if ((!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) && (frag == 0)) {
frag_dur =
wlc_calc_frame_time(wlc, rspec[0], preamble_type[0],
phylen);
if (rts) {
/* 1 RTS or CTS-to-self frame */
dur =
wlc_calc_cts_time(wlc, rts_rspec[0],
rts_preamble_type[0]);
dur_fallback =
wlc_calc_cts_time(wlc, rts_rspec[1],
rts_preamble_type[1]);
/* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
dur += ltoh16(rts->durid);
dur_fallback += ltoh16(txh->RTSDurFallback);
} else if (use_rifs) {
dur = frag_dur;
dur_fallback = 0;
} else {
/* frame + SIFS + ACK */
dur = frag_dur;
dur +=
wlc_compute_frame_dur(wlc, rspec[0],
preamble_type[0], 0);
dur_fallback =
wlc_calc_frame_time(wlc, rspec[1],
preamble_type[1],
phylen);
dur_fallback +=
wlc_compute_frame_dur(wlc, rspec[1],
preamble_type[1], 0);
}
/* NEED to set TxFesTimeNormal (hard) */
txh->TxFesTimeNormal = htol16((u16) dur);
/* NEED to set fallback rate version of TxFesTimeNormal (hard) */
txh->TxFesTimeFallback = htol16((u16) dur_fallback);
/* update txop byte threshold (txop minus intraframe overhead) */
if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
{
uint newfragthresh;
newfragthresh =
wlc_calc_frame_len(wlc, rspec[0],
preamble_type[0],
(wlc->
edcf_txop[ac] -
(dur -
frag_dur)));
/* range bound the fragthreshold */
if (newfragthresh < DOT11_MIN_FRAG_LEN)
newfragthresh =
DOT11_MIN_FRAG_LEN;
else if (newfragthresh >
wlc->usr_fragthresh)
newfragthresh =
wlc->usr_fragthresh;
/* update the fragthresh and do txc update */
if (wlc->fragthresh[queue] !=
(u16) newfragthresh) {
wlc->fragthresh[queue] =
(u16) newfragthresh;
}
}
} else
WL_ERROR(("wl%d: %s txop invalid for rate %d\n",
wlc->pub->unit, fifo_names[queue],
RSPEC2RATE(rspec[0])));
if (dur > wlc->edcf_txop[ac])
WL_ERROR(("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__, fifo_names[queue], phylen, wlc->fragthresh[queue], dur, wlc->edcf_txop[ac]));
}
}
return 0;
}
Generated by GNU enscript 1.6.4.