Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2008-08-29 14:02:13 -07:00
commit 143b11c03c
84 changed files with 7736 additions and 6741 deletions

View file

@ -144,6 +144,7 @@ struct ath_desc {
#define ATH9K_TXDESC_EXT_AND_CTL 0x0080
#define ATH9K_TXDESC_VMF 0x0100
#define ATH9K_TXDESC_FRAG_IS_ON 0x0200
#define ATH9K_TXDESC_CAB 0x0400
#define ATH9K_RXDESC_INTREQ 0x0020
@ -564,8 +565,6 @@ enum ath9k_cipher {
#define CTL_5GHT40 8
#define AR_EEPROM_MAC(i) (0x1d+(i))
#define EEP_SCALE 100
#define EEP_DELTA 10
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
@ -606,9 +605,6 @@ struct ath9k_country_entry {
#define REG_CLR_BIT(_a, _r, _f) \
REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
#define ATH9K_COMP_BUF_MAX_SIZE 9216
#define ATH9K_COMP_BUF_ALIGN_SIZE 512
#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
#define INIT_AIFS 2
@ -632,12 +628,6 @@ struct ath9k_country_entry {
(IEEE80211_WEP_IVLEN + \
IEEE80211_WEP_KIDLEN + \
IEEE80211_WEP_CRCLEN))
#define IEEE80211_MAX_LEN (2300 + FCS_LEN + \
(IEEE80211_WEP_IVLEN + \
IEEE80211_WEP_KIDLEN + \
IEEE80211_WEP_CRCLEN))
#define MAX_REG_ADD_COUNT 129
#define MAX_RATE_POWER 63
enum ath9k_power_mode {
@ -707,13 +697,6 @@ enum phytype {
};
#define PHY_CCK PHY_DS
enum start_adhoc_option {
START_ADHOC_NO_11A,
START_ADHOC_PER_11D,
START_ADHOC_IN_11A,
START_ADHOC_IN_11B,
};
enum ath9k_tp_scale {
ATH9K_TP_SCALE_MAX = 0,
ATH9K_TP_SCALE_50,
@ -769,14 +752,11 @@ struct ath9k_node_stats {
#define ATH9K_RSSI_EP_MULTIPLIER (1<<7)
enum ath9k_gpio_output_mux_type {
ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT,
ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES
};
#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
enum {
ATH9K_RESET_POWER_ON,
@ -790,19 +770,20 @@ struct ath_hal {
u32 ah_magic;
u16 ah_devid;
u16 ah_subvendorid;
struct ath_softc *ah_sc;
void __iomem *ah_sh;
u16 ah_countryCode;
u32 ah_macVersion;
u16 ah_macRev;
u16 ah_phyRev;
u16 ah_analog5GhzRev;
u16 ah_analog2GhzRev;
u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE];
u32 ah_flags;
void __iomem *ah_sh;
struct ath_softc *ah_sc;
enum ath9k_opmode ah_opmode;
struct ath9k_ops_config ah_config;
struct ath9k_hw_capabilities ah_caps;
u16 ah_countryCode;
u32 ah_flags;
int16_t ah_powerLimit;
u16 ah_maxPowerLevel;
u32 ah_tpScale;
@ -812,15 +793,16 @@ struct ath_hal {
u16 ah_currentRD5G;
u16 ah_currentRD2G;
char ah_iso[4];
enum start_adhoc_option ah_adHocMode;
bool ah_commonMode;
struct ath9k_channel ah_channels[150];
u32 ah_nchan;
struct ath9k_channel *ah_curchan;
u32 ah_nchan;
u16 ah_rfsilent;
bool ah_rfkillEnabled;
bool ah_isPciExpress;
u16 ah_txTrigLevel;
#ifndef ATH_NF_PER_CHAN
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
#endif
@ -853,7 +835,7 @@ bool ath9k_regd_init_channels(struct ath_hal *ah,
u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
enum ath9k_int ints);
bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
bool ath9k_hw_reset(struct ath_hal *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode,
u8 txchainmask, u8 rxchainmask,
@ -1018,4 +1000,7 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah,
bool ath9k_get_channel_edges(struct ath_hal *ah,
u16 flags, u16 *low,
u16 *high);
void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
u32 ah_signal_type);
void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
#endif

View file

@ -33,7 +33,7 @@ static int ath_beaconq_config(struct ath_softc *sc)
struct ath9k_tx_queue_info qi;
ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi);
if (sc->sc_opmode == ATH9K_M_HOSTAP) {
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
/* Always burst out beacon and CAB traffic. */
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
@ -85,7 +85,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
flags = ATH9K_TXDESC_NOACK;
if (sc->sc_opmode == ATH9K_M_IBSS &&
if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
ds->ds_link = bf->bf_daddr; /* self-linked */
flags |= ATH9K_TXDESC_VEOL;
@ -111,24 +111,24 @@ static void ath_beacon_setup(struct ath_softc *sc,
rix = 0;
rt = sc->sc_currates;
rate = rt->info[rix].rateCode;
if (sc->sc_flags & ATH_PREAMBLE_SHORT)
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
rate |= rt->info[rix].shortPreamble;
ath9k_hw_set11n_txdesc(ah, ds
, skb->len + FCS_LEN /* frame length */
, ATH9K_PKT_TYPE_BEACON /* Atheros packet type */
, avp->av_btxctl.txpower /* txpower XXX */
, ATH9K_TXKEYIX_INVALID /* no encryption */
, ATH9K_KEY_TYPE_CLEAR /* no encryption */
, flags /* no ack, veol for beacons */
ath9k_hw_set11n_txdesc(ah, ds,
skb->len + FCS_LEN, /* frame length */
ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */
avp->av_btxctl.txpower, /* txpower XXX */
ATH9K_TXKEYIX_INVALID, /* no encryption */
ATH9K_KEY_TYPE_CLEAR, /* no encryption */
flags /* no ack, veol for beacons */
);
/* NB: beacon's BufLen must be a multiple of 4 bytes */
ath9k_hw_filltxdesc(ah, ds
, roundup(skb->len, 4) /* buffer length */
, true /* first segment */
, true /* last segment */
, ds /* first descriptor */
ath9k_hw_filltxdesc(ah, ds,
roundup(skb->len, 4), /* buffer length */
true, /* first segment */
true, /* last segment */
ds /* first descriptor */
);
memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
@ -140,55 +140,6 @@ static void ath_beacon_setup(struct ath_softc *sc,
ctsrate, ctsduration, series, 4, 0);
}
/* Move everything from the vap's mcast queue to the hardware cab queue.
* Caller must hold mcasq lock and cabq lock
* XXX MORE_DATA bit?
*/
static void empty_mcastq_into_cabq(struct ath_hal *ah,
struct ath_txq *mcastq, struct ath_txq *cabq)
{
struct ath_buf *bfmcast;
BUG_ON(list_empty(&mcastq->axq_q));
bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list);
/* link the descriptors */
if (!cabq->axq_link)
ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr);
else
*cabq->axq_link = bfmcast->bf_daddr;
/* append the private vap mcast list to the cabq */
cabq->axq_depth += mcastq->axq_depth;
cabq->axq_totalqueued += mcastq->axq_totalqueued;
cabq->axq_linkbuf = mcastq->axq_linkbuf;
cabq->axq_link = mcastq->axq_link;
list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q);
mcastq->axq_depth = 0;
mcastq->axq_totalqueued = 0;
mcastq->axq_linkbuf = NULL;
mcastq->axq_link = NULL;
}
/* This is only run at DTIM. We move everything from the vap's mcast queue
* to the hardware cab queue. Caller must hold the mcastq lock. */
static void trigger_mcastq(struct ath_hal *ah,
struct ath_txq *mcastq, struct ath_txq *cabq)
{
spin_lock_bh(&cabq->axq_lock);
if (!list_empty(&mcastq->axq_q))
empty_mcastq_into_cabq(ah, mcastq, cabq);
/* cabq is gated by beacon so it is safe to start here */
if (!list_empty(&cabq->axq_q))
ath9k_hw_txstart(ah, cabq->axq_qnum);
spin_unlock_bh(&cabq->axq_lock);
}
/*
* Generate beacon frame and queue cab data for a vap.
*
@ -199,19 +150,14 @@ static void trigger_mcastq(struct ath_hal *ah,
*/
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
struct ath_vap *avp;
struct sk_buff *skb;
int cabq_depth;
int mcastq_depth;
int is_beacon_dtim = 0;
unsigned int curlen;
struct ath_txq *cabq;
struct ath_txq *mcastq;
struct ieee80211_tx_info *info;
avp = sc->sc_vaps[if_id];
mcastq = &avp->av_mcastq;
cabq = sc->sc_cabq;
ASSERT(avp);
@ -223,33 +169,34 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
}
bf = avp->av_bcbuf;
skb = (struct sk_buff *) bf->bf_mpdu;
/*
* Update dynamic beacon contents. If this returns
* non-zero then we need to remap the memory because
* the beacon frame changed size (probably because
* of the TIM bitmap).
*/
curlen = skb->len;
/* XXX: spin_lock_bh should not be used here, but sparse bitches
* otherwise. We should fix sparse :) */
spin_lock_bh(&mcastq->axq_lock);
mcastq_depth = avp->av_mcastq.axq_depth;
if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) ==
1) {
ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
} else {
pci_dma_sync_single_for_cpu(sc->pdev,
bf->bf_buf_addr,
skb_tailroom(skb),
PCI_DMA_TODEVICE);
if (skb) {
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
skb_end_pointer(skb) - skb->head,
PCI_DMA_TODEVICE);
}
skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
bf->bf_mpdu = skb;
if (skb == NULL)
return NULL;
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
/*
* TODO: make sure the seq# gets assigned properly (vs. other
* TX frames)
*/
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
sc->seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
}
bf->bf_buf_addr = bf->bf_dmacontext =
pci_map_single(sc->pdev, skb->data,
skb_end_pointer(skb) - skb->head,
PCI_DMA_TODEVICE);
skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
/*
* if the CABQ traffic from previous DTIM is pending and the current
* beacon is also a DTIM.
@ -262,9 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
cabq_depth = cabq->axq_depth;
spin_unlock_bh(&cabq->axq_lock);
is_beacon_dtim = avp->av_boff.bo_tim[4] & 1;
if (mcastq_depth && is_beacon_dtim && cabq_depth) {
if (skb && cabq_depth) {
/*
* Unlock the cabq lock as ath_tx_draintxq acquires
* the lock again which is a common function and that
@ -284,10 +229,11 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
* Enable the CAB queue before the beacon queue to
* insure cab frames are triggered by this beacon.
*/
if (is_beacon_dtim)
trigger_mcastq(ah, mcastq, cabq);
while (skb) {
ath_tx_cabq(sc, skb);
skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
}
spin_unlock_bh(&mcastq->axq_lock);
return bf;
}
@ -375,7 +321,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
struct ath_buf, list);
list_del(&avp->av_bcbuf->list);
if (sc->sc_opmode == ATH9K_M_HOSTAP ||
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
int slot;
/*
@ -408,8 +354,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
skb = (struct sk_buff *)bf->bf_mpdu;
ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
skb_end_pointer(skb) - skb->head,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
@ -418,7 +365,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
* NB: the beacon data buffer must be 32-bit aligned;
* we assume the wbuf routines will return us something
* with this alignment (perhaps should assert).
* FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and
* FIXME: Fill avp->av_btxctl.txpower and
* avp->av_btxctl.shortPreamble
*/
skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
@ -439,9 +386,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
__le64 val;
int intval;
/* FIXME: Use default value for now: Sujith */
intval = ATH_DEFAULT_BINTVAL;
intval = sc->hw->conf.beacon_int ?
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
/*
* The beacon interval is in TU's; the TSF in usecs.
@ -466,8 +412,10 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
memcpy(&wh[1], &val, sizeof(val));
}
bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
bf->bf_buf_addr = bf->bf_dmacontext =
pci_map_single(sc->pdev, skb->data,
skb_end_pointer(skb) - skb->head,
PCI_DMA_TODEVICE);
bf->bf_mpdu = skb;
return 0;
@ -493,8 +441,9 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
skb_end_pointer(skb) - skb->head,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
@ -504,30 +453,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
}
}
/*
* Reclaim beacon resources and return buffer to the pool.
*
* This function will free any wbuf frames that are still attached to the
* beacon buffers in the ATH object. Note that this does not de-allocate
* any wbuf objects that are in the transmit queue and have not yet returned
* to the ATH object.
*/
void ath_beacon_free(struct ath_softc *sc)
{
struct ath_buf *bf;
list_for_each_entry(bf, &sc->sc_bbuf, list) {
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu;
ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
get_dma_mem_context(bf, bf_dmacontext));
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
}
}
/*
* Tasklet for Sending Beacons
*
@ -540,9 +465,6 @@ void ath_beacon_free(struct ath_softc *sc)
void ath9k_beacon_tasklet(unsigned long data)
{
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf = NULL;
@ -555,7 +477,7 @@ void ath9k_beacon_tasklet(unsigned long data)
u32 tsftu;
u16 intval;
if (sc->sc_noreset) {
if (sc->sc_flags & SC_OP_NO_RESET) {
show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
&rx_clear,
&rx_frame,
@ -577,7 +499,7 @@ void ath9k_beacon_tasklet(unsigned long data)
* (in that layer).
*/
if (sc->sc_bmisscount < BSTUCK_THRESH) {
if (sc->sc_noreset) {
if (sc->sc_flags & SC_OP_NO_RESET) {
DPRINTF(sc, ATH_DBG_BEACON,
"%s: missed %u consecutive beacons\n",
__func__, sc->sc_bmisscount);
@ -605,7 +527,7 @@ void ath9k_beacon_tasklet(unsigned long data)
__func__, sc->sc_bmisscount);
}
} else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
if (sc->sc_noreset) {
if (sc->sc_flags & SC_OP_NO_RESET) {
if (sc->sc_bmisscount == BSTUCK_THRESH) {
DPRINTF(sc,
ATH_DBG_BEACON,
@ -624,7 +546,7 @@ void ath9k_beacon_tasklet(unsigned long data)
return;
}
if (sc->sc_bmisscount != 0) {
if (sc->sc_noreset) {
if (sc->sc_flags & SC_OP_NO_RESET) {
DPRINTF(sc,
ATH_DBG_BEACON,
"%s: resume beacon xmit after %u misses\n",
@ -643,8 +565,8 @@ void ath9k_beacon_tasklet(unsigned long data)
* on the tsf to safeguard against missing an swba.
*/
/* FIXME: Use default value for now - Sujith */
intval = ATH_DEFAULT_BINTVAL;
intval = sc->hw->conf.beacon_int ?
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU(tsf>>32, tsf);
@ -704,7 +626,6 @@ void ath9k_beacon_tasklet(unsigned long data)
sc->ast_be_xmit += bc; /* XXX per-vap? */
}
#undef TSF_TO_TU
}
/*
@ -719,7 +640,7 @@ void ath_bstuck_process(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_BEACON,
"%s: stuck beacon; resetting (bmiss count %u)\n",
__func__, sc->sc_bmisscount);
ath_internal_reset(sc);
ath_reset(sc, false);
}
/*
@ -740,8 +661,6 @@ void ath_bstuck_process(struct ath_softc *sc)
void ath_beacon_config(struct ath_softc *sc, int if_id)
{
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
struct ath_hal *ah = sc->sc_ah;
u32 nexttbtt, intval;
struct ath_beacon_config conf;
@ -750,7 +669,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
if (if_id != ATH_IF_ID_ANY)
av_opmode = sc->sc_vaps[if_id]->av_opmode;
else
av_opmode = sc->sc_opmode;
av_opmode = sc->sc_ah->ah_opmode;
memzero(&conf, sizeof(struct ath_beacon_config));
@ -760,7 +679,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
* Protocol stack doesn't support dynamic beacon configuration,
* use default configurations.
*/
conf.beacon_interval = ATH_DEFAULT_BINTVAL;
conf.beacon_interval = sc->hw->conf.beacon_int ?
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
conf.listen_interval = 1;
conf.dtim_period = conf.beacon_interval;
conf.dtim_count = 1;
@ -770,7 +690,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4),
get_unaligned_le32(conf.u.last_tstamp));
/* XXX conditionalize multi-bss support? */
if (sc->sc_opmode == ATH9K_M_HOSTAP) {
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
/*
* For multi-bss ap support beacons are either staggered
* evenly over N slots or burst together. For the former
@ -791,7 +711,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
__func__, nexttbtt, intval, conf.beacon_interval);
/* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
if (sc->sc_opmode == ATH9K_M_STA) {
if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
struct ath9k_beacon_state bs;
u64 tsf;
u32 tsftu;
@ -886,19 +806,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
"cfp:period %u "
"maxdur %u "
"next %u "
"timoffset %u\n"
, __func__
, (unsigned long long)tsf, tsftu
, bs.bs_intval
, bs.bs_nexttbtt
, bs.bs_dtimperiod
, bs.bs_nextdtim
, bs.bs_bmissthreshold
, bs.bs_sleepduration
, bs.bs_cfpperiod
, bs.bs_cfpmaxduration
, bs.bs_cfpnext
, bs.bs_timoffset
"timoffset %u\n",
__func__,
(unsigned long long)tsf, tsftu,
bs.bs_intval,
bs.bs_nexttbtt,
bs.bs_dtimperiod,
bs.bs_nextdtim,
bs.bs_bmissthreshold,
bs.bs_sleepduration,
bs.bs_cfpperiod,
bs.bs_cfpmaxduration,
bs.bs_cfpnext,
bs.bs_timoffset
);
ath9k_hw_set_interrupts(ah, 0);
@ -911,7 +831,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
ath9k_hw_set_interrupts(ah, 0);
if (nexttbtt == intval)
intval |= ATH9K_BEACON_RESET_TSF;
if (sc->sc_opmode == ATH9K_M_IBSS) {
if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
/*
* Pull nexttbtt forward to reflect the current
* TSF .
@ -943,7 +863,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
sc->sc_imask |= ATH9K_INT_SWBA;
ath_beaconq_config(sc);
} else if (sc->sc_opmode == ATH9K_M_HOSTAP) {
} else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
/*
* In AP mode we enable the beacon timers and
* SWBA interrupts to prepare beacon frames.
@ -959,11 +879,10 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
* When using a self-linked beacon descriptor in
* ibss mode load it once here.
*/
if (sc->sc_opmode == ATH9K_M_IBSS &&
if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
ath_beacon_start_adhoc(sc, 0);
}
#undef TSF_TO_TU
}
/* Function to collect beacon rssi data and resync beacon if necessary */
@ -975,5 +894,5 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id)
* beacon frame we just received.
*/
ath_beacon_config(sc, if_id);
sc->sc_beacons = 1;
sc->sc_flags |= SC_OP_BEACONS;
}

View file

@ -21,9 +21,6 @@
static int ath_outdoor; /* enable outdoor use */
static const u8 ath_bcast_mac[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static u32 ath_chainmask_sel_up_rssi_thres =
ATH_CHAINMASK_SEL_UP_RSSI_THRES;
static u32 ath_chainmask_sel_down_rssi_thres =
@ -54,10 +51,8 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
* Set current operating mode
*
* This function initializes and fills the rate table in the ATH object based
* on the operating mode. The blink rates are also set up here, although
* they have been superceeded by the ath_led module.
* on the operating mode.
*/
static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
{
const struct ath9k_rate_table *rt;
@ -235,7 +230,7 @@ static int ath_setup_channels(struct ath_softc *sc)
* Determine mode from channel flags
*
* This routine will provide the enumerated WIRELESSS_MODE value based
* on the settings of the channel flags. If ho valid set of flags
* on the settings of the channel flags. If no valid set of flags
* exist, the lowest mode (11b) is selected.
*/
@ -260,7 +255,8 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
else if (chan->chanmode == CHANNEL_G_HT40MINUS)
return ATH9K_MODE_11NG_HT40MINUS;
/* NB: should not get here */
WARN_ON(1); /* should not get here */
return ATH9K_MODE_11B;
}
@ -275,14 +271,12 @@ static int ath_stop(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n",
__func__, sc->sc_invalid);
DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
__func__, sc->sc_flags & SC_OP_INVALID);
/*
* Shutdown the hardware and driver:
* stop output from above
* reset 802.11 state machine
* (sends station deassoc/deauth frames)
* turn off timers
* disable interrupts
* clear transmit machinery
@ -294,10 +288,10 @@ static int ath_stop(struct ath_softc *sc)
* hardware is gone (invalid).
*/
if (!sc->sc_invalid)
if (!(sc->sc_flags & SC_OP_INVALID))
ath9k_hw_set_interrupts(ah, 0);
ath_draintxq(sc, false);
if (!sc->sc_invalid) {
if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_stoprecv(sc);
ath9k_hw_phy_disable(ah);
} else
@ -306,56 +300,6 @@ static int ath_stop(struct ath_softc *sc)
return 0;
}
/*
* Start Scan
*
* This function is called when starting a channel scan. It will perform
* power save wakeup processing, set the filter for the scan, and get the
* chip ready to send broadcast packets out during the scan.
*/
void ath_scan_start(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
u32 rfilt;
u32 now = (u32) jiffies_to_msecs(get_timestamp());
sc->sc_scanning = 1;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
ath9k_hw_write_associd(ah, ath_bcast_mac, 0);
/* Restore previous power management state. */
DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n",
now / 1000, now % 1000, __func__, rfilt);
}
/*
* Scan End
*
* This routine is called by the upper layer when the scan is completed. This
* will set the filters back to normal operating mode, set the BSSID to the
* correct value, and restore the power save state.
*/
void ath_scan_end(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
u32 rfilt;
u32 now = (u32) jiffies_to_msecs(get_timestamp());
sc->sc_scanning = 0;
/* Request for a full reset due to rx packet filter changes */
sc->sc_full_reset = 1;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n",
now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid);
}
/*
* Set the current channel
*
@ -367,25 +311,23 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_hal *ah = sc->sc_ah;
bool fastcc = true, stopped;
enum ath9k_ht_macmode ht_macmode;
if (sc->sc_invalid) /* if the device is invalid or removed */
if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
return -EIO;
DPRINTF(sc, ATH_DBG_CONFIG,
"%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
__func__,
ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel,
sc->sc_curchan.channelFlags),
sc->sc_curchan.channel,
ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
sc->sc_ah->ah_curchan->channelFlags),
sc->sc_ah->ah_curchan->channel,
ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
hchan->channel, hchan->channelFlags);
ht_macmode = ath_cwm_macmode(sc);
if (hchan->channel != sc->sc_curchan.channel ||
hchan->channelFlags != sc->sc_curchan.channelFlags ||
sc->sc_update_chainmask || sc->sc_full_reset) {
if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
(sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
(sc->sc_flags & SC_OP_FULL_RESET)) {
int status;
/*
* This is only performed if the channel settings have
@ -404,15 +346,16 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
* to flush data frames already in queue because of
* changing channel. */
if (!stopped || sc->sc_full_reset)
if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
fastcc = false;
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan,
ht_macmode, sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
fastcc, &status)) {
if (!ath9k_hw_reset(ah, hchan,
sc->sc_ht_info.tx_chan_width,
sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
fastcc, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to reset channel %u (%uMhz) "
"flags 0x%x hal status %u\n", __func__,
@ -424,9 +367,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
}
spin_unlock_bh(&sc->sc_resetlock);
sc->sc_curchan = *hchan;
sc->sc_update_chainmask = 0;
sc->sc_full_reset = 0;
sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
sc->sc_flags &= ~SC_OP_FULL_RESET;
/* Re-enable rx framework */
if (ath_startrecv(sc) != 0) {
@ -537,7 +479,7 @@ int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
sc->sc_update_chainmask = 1;
sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
if (is_ht) {
sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
@ -554,62 +496,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht)
/* VAP management */
/******************/
/*
* VAP in Listen mode
*
* This routine brings the VAP out of the down state into a "listen" state
* where it waits for association requests. This is used in AP and AdHoc
* modes.
*/
int ath_vap_listen(struct ath_softc *sc, int if_id)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_vap *avp;
u32 rfilt = 0;
DECLARE_MAC_BUF(mac);
avp = sc->sc_vaps[if_id];
if (avp == NULL) {
DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
__func__, if_id);
return -EINVAL;
}
#ifdef CONFIG_SLOW_ANT_DIV
ath_slow_ant_div_stop(&sc->sc_antdiv);
#endif
/* update ratectrl about the new state */
ath_rate_newstate(sc, avp);
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) {
memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN);
ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
} else
sc->sc_curaid = 0;
DPRINTF(sc, ATH_DBG_CONFIG,
"%s: RX filter 0x%x bssid %s aid 0x%x\n",
__func__, rfilt, print_mac(mac,
sc->sc_curbssid), sc->sc_curaid);
/*
* XXXX
* Disable BMISS interrupt when we're not associated
*/
ath9k_hw_set_interrupts(ah,
sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
/* need to reconfigure the beacons when it moves to RUN */
sc->sc_beacons = 0;
return 0;
}
int ath_vap_attach(struct ath_softc *sc,
int if_id,
struct ieee80211_vif *if_data,
@ -647,16 +533,13 @@ int ath_vap_attach(struct ath_softc *sc,
/* Set the VAP opmode */
avp->av_opmode = opmode;
avp->av_bslot = -1;
INIT_LIST_HEAD(&avp->av_mcastq.axq_q);
INIT_LIST_HEAD(&avp->av_mcastq.axq_acq);
spin_lock_init(&avp->av_mcastq.axq_lock);
ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
sc->sc_vaps[if_id] = avp;
sc->sc_nvaps++;
/* Set the device opmode */
sc->sc_opmode = opmode;
sc->sc_ah->ah_opmode = opmode;
/* default VAP configuration */
avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
@ -689,9 +572,6 @@ int ath_vap_detach(struct ath_softc *sc, int if_id)
ath_stoprecv(sc); /* stop recv side */
ath_flushrecv(sc); /* flush recv queue */
/* Reclaim any pending mcast bufs on the vap. */
ath_tx_draintxq(sc, &avp->av_mcastq, false);
kfree(avp);
sc->sc_vaps[if_id] = NULL;
sc->sc_nvaps--;
@ -728,9 +608,9 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
struct ath_hal *ah = sc->sc_ah;
int status;
int error = 0;
enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode);
DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
__func__, sc->sc_ah->ah_opmode);
/*
* Stop anything previously setup. This is safe
@ -752,16 +632,16 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
sc->sc_curchan = *initial_chan;
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, false, &status)) {
if (!ath9k_hw_reset(ah, initial_chan,
sc->sc_ht_info.tx_chan_width,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to reset hardware; hal status %u "
"(freq %u flags 0x%x)\n", __func__, status,
sc->sc_curchan.channel, sc->sc_curchan.channelFlags);
initial_chan->channel, initial_chan->channelFlags);
error = -EIO;
spin_unlock_bh(&sc->sc_resetlock);
goto done;
@ -802,7 +682,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
* Note we only do this (at the moment) for station mode.
*/
if (ath9k_hw_phycounters(ah) &&
((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS)))
((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
(sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
sc->sc_imask |= ATH9K_INT_MIB;
/*
* Some hardware processes the TIM IE and fires an
@ -811,7 +692,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
* enable the TIM interrupt when operating as station.
*/
if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
(sc->sc_opmode == ATH9K_M_STA) &&
(sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
!sc->sc_config.swBeaconProcess)
sc->sc_imask |= ATH9K_INT_TIM;
/*
@ -823,34 +704,34 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
/* XXX: we must make sure h/w is ready and clear invalid flag
* before turning on interrupt. */
sc->sc_invalid = 0;
sc->sc_flags &= ~SC_OP_INVALID;
done:
return error;
}
/*
* Reset the hardware w/o losing operational state. This is
* basically a more efficient way of doing ath_stop, ath_init,
* followed by state transitions to the current 802.11
* operational state. Used to recover from errors rx overrun
* and to reset the hardware when rf gain settings must be reset.
*/
static int ath_reset_start(struct ath_softc *sc, u32 flag)
int ath_reset(struct ath_softc *sc, bool retry_tx)
{
struct ath_hal *ah = sc->sc_ah;
int status;
int error = 0;
ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
ath_draintxq(sc, flag & RESET_RETRY_TXQ); /* stop xmit side */
ath_stoprecv(sc); /* stop recv side */
ath_flushrecv(sc); /* flush recv queue */
ath_draintxq(sc, retry_tx); /* stop xmit */
ath_stoprecv(sc); /* stop recv */
ath_flushrecv(sc); /* flush recv queue */
return 0;
}
static int ath_reset_end(struct ath_softc *sc, u32 flag)
{
struct ath_hal *ah = sc->sc_ah;
/* Reset chip */
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
sc->sc_ht_info.tx_chan_width,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to reset hardware; hal status %u\n",
__func__, status);
error = -EIO;
}
spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0) /* restart recv */
DPRINTF(sc, ATH_DBG_FATAL,
@ -861,16 +742,17 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag)
* that changes the channel so update any state that
* might change as a result.
*/
ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan));
ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
ath_update_txpow(sc); /* update tx power state */
ath_update_txpow(sc);
if (sc->sc_beacons)
if (sc->sc_flags & SC_OP_BEACONS)
ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
ath9k_hw_set_interrupts(ah, sc->sc_imask);
/* Restart the txq */
if (flag & RESET_RETRY_TXQ) {
if (retry_tx) {
int i;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
@ -880,28 +762,6 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag)
}
}
}
return 0;
}
int ath_reset(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
int status;
int error = 0;
enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
/* NB: indicate channel change so we do a full reset */
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan,
ht_macmode,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to reset hardware; hal status %u\n",
__func__, status);
error = -EIO;
}
spin_unlock_bh(&sc->sc_resetlock);
return error;
}
@ -911,7 +771,7 @@ int ath_suspend(struct ath_softc *sc)
struct ath_hal *ah = sc->sc_ah;
/* No I/O if device has been surprise removed */
if (sc->sc_invalid)
if (sc->sc_flags & SC_OP_INVALID)
return -EIO;
/* Shut off the interrupt before setting sc->sc_invalid to '1' */
@ -919,7 +779,7 @@ int ath_suspend(struct ath_softc *sc)
/* XXX: we must make sure h/w will not generate any interrupt
* before setting the invalid flag. */
sc->sc_invalid = 1;
sc->sc_flags |= SC_OP_INVALID;
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
@ -940,7 +800,7 @@ irqreturn_t ath_isr(int irq, void *dev)
bool sched = false;
do {
if (sc->sc_invalid) {
if (sc->sc_flags & SC_OP_INVALID) {
/*
* The hardware is not ready/present, don't
* touch anything. Note this can happen early
@ -1050,7 +910,7 @@ static void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_FATAL) {
/* need a chip reset */
ath_internal_reset(sc);
ath_reset(sc, false);
return;
} else {
@ -1093,10 +953,9 @@ int ath_init(u16 devid, struct ath_softc *sc)
int status;
int error = 0, i;
int csz = 0;
u32 rd;
/* XXX: hardware will not be ready until ath_open() being called */
sc->sc_invalid = 1;
sc->sc_flags |= SC_OP_INVALID;
sc->sc_debug = DBG_DEFAULT;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
@ -1126,9 +985,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
}
sc->sc_ah = ah;
/* Get the chipset-specific aggr limit. */
sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit;
/* Get the hardware key cache size. */
sc->sc_keymax = ah->ah_caps.keycache_size;
if (sc->sc_keymax > ATH_KEYMAX) {
@ -1162,14 +1018,12 @@ int ath_init(u16 devid, struct ath_softc *sc)
* is resposible for filtering this list based on settings
* like the phy mode.
*/
rd = ah->ah_currentRD;
error = ath_setup_channels(sc);
if (error)
goto bad;
/* default to STA mode */
sc->sc_opmode = ATH9K_M_MONITOR;
sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
/* Setup rate tables */
@ -1240,7 +1094,7 @@ int ath_init(u16 devid, struct ath_softc *sc)
sc->sc_rc = ath_rate_attach(ah);
if (sc->sc_rc == NULL) {
error = EIO;
error = -EIO;
goto bad2;
}
@ -1280,20 +1134,13 @@ int ath_init(u16 devid, struct ath_softc *sc)
/* 11n Capabilities */
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
sc->sc_txaggr = 1;
sc->sc_rxaggr = 1;
sc->sc_flags |= SC_OP_TXAGGR;
sc->sc_flags |= SC_OP_RXAGGR;
}
sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
/* Configuration for rx chain detection */
sc->sc_rxchaindetect_ref = 0;
sc->sc_rxchaindetect_thresh5GHz = 35;
sc->sc_rxchaindetect_thresh2GHz = 35;
sc->sc_rxchaindetect_delta5GHz = 30;
sc->sc_rxchaindetect_delta2GHz = 30;
ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
sc->sc_defant = ath9k_hw_getdefantenna(ah);
@ -1337,7 +1184,7 @@ void ath_deinit(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
ath_stop(sc);
if (!sc->sc_invalid)
if (!(sc->sc_flags & SC_OP_INVALID))
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
ath_rate_detach(sc->sc_rc);
/* cleanup tx queues */
@ -1464,9 +1311,9 @@ void ath_newassoc(struct ath_softc *sc,
/* if station reassociates, tear down the aggregation state. */
if (!isnew) {
for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
if (sc->sc_txaggr)
if (sc->sc_flags & SC_OP_TXAGGR)
ath_tx_aggr_teardown(sc, an, tidno);
if (sc->sc_rxaggr)
if (sc->sc_flags & SC_OP_RXAGGR)
ath_rx_aggr_teardown(sc, an, tidno);
}
}
@ -1815,13 +1662,6 @@ void ath_descdma_cleanup(struct ath_softc *sc,
/* Utilities */
/*************/
void ath_internal_reset(struct ath_softc *sc)
{
ath_reset_start(sc, 0);
ath_reset(sc);
ath_reset_end(sc, 0);
}
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
{
int qnum;

View file

@ -39,6 +39,7 @@
#include <linux/scatterlist.h>
#include <asm/page.h>
#include <net/mac80211.h>
#include <linux/leds.h>
#include "ath9k.h"
#include "rc.h"
@ -79,12 +80,12 @@ struct ath_node;
} \
} while (0)
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
/* XXX: remove */
#define memzero(_buf, _len) memset(_buf, 0, _len)
#define get_dma_mem_context(var, field) (&((var)->field))
#define copy_dma_mem_context(dst, src) (*dst = *src)
#define ATH9K_BH_STATUS_INTACT 0
#define ATH9K_BH_STATUS_CHANGE 1
@ -95,6 +96,8 @@ static inline unsigned long get_timestamp(void)
return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
}
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/*************/
/* Debugging */
/*************/
@ -175,11 +178,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht);
/* Descriptor Management */
/*************************/
/* Number of descriptors per buffer. The only case where we see skbuff
chains is due to FF aggregation in the driver. */
#define ATH_TXDESC 1
/* if there's more fragment for this MSDU */
#define ATH_BF_MORE_MPDU 1
#define ATH_TXBUF_RESET(_bf) do { \
(_bf)->bf_status = 0; \
(_bf)->bf_lastbf = NULL; \
@ -189,28 +187,29 @@ chains is due to FF aggregation in the driver. */
sizeof(struct ath_buf_state)); \
} while (0)
enum buffer_type {
BUF_DATA = BIT(0),
BUF_AGGR = BIT(1),
BUF_AMPDU = BIT(2),
BUF_HT = BIT(3),
BUF_RETRY = BIT(4),
BUF_XRETRY = BIT(5),
BUF_SHORT_PREAMBLE = BIT(6),
BUF_BAR = BIT(7),
BUF_PSPOLL = BIT(8),
BUF_AGGR_BURST = BIT(9),
BUF_CALC_AIRTIME = BIT(10),
};
struct ath_buf_state {
int bfs_nframes; /* # frames in aggregate */
u16 bfs_al; /* length of aggregate */
u16 bfs_frmlen; /* length of frame */
int bfs_seqno; /* sequence number */
int bfs_tidno; /* tid of this frame */
int bfs_retries; /* current retries */
int bfs_nframes; /* # frames in aggregate */
u16 bfs_al; /* length of aggregate */
u16 bfs_frmlen; /* length of frame */
int bfs_seqno; /* sequence number */
int bfs_tidno; /* tid of this frame */
int bfs_retries; /* current retries */
struct ath_rc_series bfs_rcs[4]; /* rate series */
u8 bfs_isdata:1; /* is a data frame/aggregate */
u8 bfs_isaggr:1; /* is an aggregate */
u8 bfs_isampdu:1; /* is an a-mpdu, aggregate or not */
u8 bfs_ht:1; /* is an HT frame */
u8 bfs_isretried:1; /* is retried */
u8 bfs_isxretried:1; /* is excessive retried */
u8 bfs_shpreamble:1; /* is short preamble */
u8 bfs_isbar:1; /* is a BAR */
u8 bfs_ispspoll:1; /* is a PS-Poll */
u8 bfs_aggrburst:1; /* is a aggr burst */
u8 bfs_calcairtime:1; /* requests airtime be calculated
when set for tx frame */
int bfs_rifsburst_elem; /* RIFS burst/bar */
int bfs_nrifsubframes; /* # of elements in burst */
u32 bf_type; /* BUF_* (enum buffer_type) */
/* key type use to encrypt this frame */
enum ath9k_key_type bfs_keytype;
};
@ -222,26 +221,22 @@ struct ath_buf_state {
#define bf_seqno bf_state.bfs_seqno
#define bf_tidno bf_state.bfs_tidno
#define bf_rcs bf_state.bfs_rcs
#define bf_isdata bf_state.bfs_isdata
#define bf_isaggr bf_state.bfs_isaggr
#define bf_isampdu bf_state.bfs_isampdu
#define bf_ht bf_state.bfs_ht
#define bf_isretried bf_state.bfs_isretried
#define bf_isxretried bf_state.bfs_isxretried
#define bf_shpreamble bf_state.bfs_shpreamble
#define bf_rifsburst_elem bf_state.bfs_rifsburst_elem
#define bf_nrifsubframes bf_state.bfs_nrifsubframes
#define bf_keytype bf_state.bfs_keytype
#define bf_isbar bf_state.bfs_isbar
#define bf_ispspoll bf_state.bfs_ispspoll
#define bf_aggrburst bf_state.bfs_aggrburst
#define bf_calcairtime bf_state.bfs_calcairtime
#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT)
#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
#define bf_isshpreamble(bf) (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE)
#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR)
#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL)
#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST)
/*
* Abstraction of a contiguous buffer to transmit/receive. There is only
* a single hw descriptor encapsulated here.
*/
struct ath_buf {
struct list_head list;
struct list_head *last;
@ -391,10 +386,10 @@ int ath_rx_input(struct ath_softc *sc,
struct sk_buff *skb,
struct ath_recv_status *rx_status,
enum ATH_RX_TYPE *status);
int ath__rx_indicate(struct ath_softc *sc,
struct sk_buff *skb,
struct ath_recv_status *status,
u16 keyix);
int _ath_rx_indicate(struct ath_softc *sc,
struct sk_buff *skb,
struct ath_recv_status *status,
u16 keyix);
int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
struct ath_recv_status *status);
@ -402,8 +397,7 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
/* TX */
/******/
#define ATH_FRAG_PER_MSDU 1
#define ATH_TXBUF (512/ATH_FRAG_PER_MSDU)
#define ATH_TXBUF 512
/* max number of transmit attempts (tries) */
#define ATH_TXMAXTRY 13
/* max number of 11n transmit attempts (tries) */
@ -522,7 +516,6 @@ struct ath_tx_control {
u32 keyix;
int min_rate;
int mcast_rate;
u16 nextfraglen;
struct ath_softc *dev;
dma_addr_t dmacontext;
};
@ -557,10 +550,10 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_setup(struct ath_softc *sc, int haltype);
void ath_draintxq(struct ath_softc *sc, bool retry_tx);
void ath_tx_draintxq(struct ath_softc *sc,
struct ath_txq *txq, bool retry_tx);
struct ath_txq *txq, bool retry_tx);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_cleanup(struct ath_softc *sc,
struct ath_node *an, bool bh_flag);
struct ath_node *an, bool bh_flag);
void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
@ -575,6 +568,7 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ath_xmit_status *tx_status, struct ath_node *an);
void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
/**********************/
/* Node / Aggregation */
@ -585,7 +579,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
/* indicates the node is 80211 power save */
#define ATH_NODE_PWRSAVE 0x2
#define ADDBA_TIMEOUT 200 /* 200 milliseconds */
#define ADDBA_EXCHANGE_ATTEMPTS 10
#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
@ -705,9 +698,6 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
#define ATH_BCBUF 4 /* number of beacon buffers */
#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */
#define ATH_DEFAULT_BMISS_LIMIT 10
#define ATH_BEACON_AIFS_DEFAULT 0 /* Default aifs for ap beacon q */
#define ATH_BEACON_CWMIN_DEFAULT 0 /* Default cwmin for ap beacon q */
#define ATH_BEACON_CWMAX_DEFAULT 0 /* Default cwmax for ap beacon q */
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
/* beacon configuration */
@ -724,30 +714,16 @@ struct ath_beacon_config {
} u; /* last received beacon/probe response timestamp of this BSS. */
};
/* offsets in a beacon frame for
* quick acess of beacon content by low-level driver */
struct ath_beacon_offset {
u8 *bo_tim; /* start of atim/dtim */
};
void ath9k_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, int if_id);
int ath_beaconq_setup(struct ath_hal *ah);
int ath_beacon_alloc(struct ath_softc *sc, int if_id);
void ath_bstuck_process(struct ath_softc *sc);
void ath_beacon_tasklet(struct ath_softc *sc, int *needmark);
void ath_beacon_free(struct ath_softc *sc);
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
void ath_beacon_sync(struct ath_softc *sc, int if_id);
void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi);
void ath_get_beaconconfig(struct ath_softc *sc,
int if_id,
struct ath_beacon_config *conf);
int ath_update_beacon(struct ath_softc *sc,
int if_id,
struct ath_beacon_offset *bo,
struct sk_buff *skb,
int mcast);
/********/
/* VAPs */
/********/
@ -774,10 +750,8 @@ struct ath_vap {
struct ieee80211_vif *av_if_data;
enum ath9k_opmode av_opmode; /* VAP operational mode */
struct ath_buf *av_bcbuf; /* beacon buffer */
struct ath_beacon_offset av_boff; /* dynamic update state */
struct ath_tx_control av_btxctl; /* txctl information for beacon */
int av_bslot; /* beacon slot index */
struct ath_txq av_mcastq; /* multicast transmit queue */
struct ath_vap_config av_config;/* vap configuration parameters*/
struct ath_rate_node *rc_node;
};
@ -788,8 +762,7 @@ int ath_vap_attach(struct ath_softc *sc,
enum ath9k_opmode opmode);
int ath_vap_detach(struct ath_softc *sc, int if_id);
int ath_vap_config(struct ath_softc *sc,
int if_id, struct ath_vap_config *if_config);
int ath_vap_listen(struct ath_softc *sc, int if_id);
int if_id, struct ath_vap_config *if_config);
/*********************/
/* Antenna diversity */
@ -829,6 +802,27 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv,
struct ath_rx_status *rx_stats);
void ath_setdefantenna(void *sc, u32 antenna);
/********************/
/* LED Control */
/********************/
#define ATH_LED_PIN 1
enum ath_led_type {
ATH_LED_RADIO,
ATH_LED_ASSOC,
ATH_LED_TX,
ATH_LED_RX
};
struct ath_led {
struct ath_softc *sc;
struct led_classdev led_cdev;
enum ath_led_type led_type;
char name[32];
bool registered;
};
/********************/
/* Main driver core */
/********************/
@ -841,11 +835,7 @@ void ath_setdefantenna(void *sc, u32 antenna);
#define ATH_DEFAULT_NOISE_FLOOR -95
#define ATH_REGCLASSIDS_MAX 10
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
#define ATH_PREAMBLE_SHORT (1<<0)
#define ATH_PROTECT_ENABLE (1<<1)
#define ATH_MAX_SW_RETRIES 10
/* Num farmes difference in tx to flip default recv */
#define ATH_ANTENNA_DIFF 2
#define ATH_CHAN_MAX 255
#define IEEE80211_WEP_NKID 4 /* number of key ids */
#define IEEE80211_RATE_VAL 0x7f
@ -859,9 +849,7 @@ void ath_setdefantenna(void *sc, u32 antenna);
*/
#define ATH_KEYMAX 128 /* max key cache size we handle */
#define RESET_RETRY_TXQ 0x00000001
#define ATH_IF_ID_ANY 0xff
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define RSSI_LPF_THRESHOLD -20
@ -907,60 +895,61 @@ struct ath_ht_info {
u8 ext_chan_offset;
};
#define SC_OP_INVALID BIT(0)
#define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2)
#define SC_OP_TXAGGR BIT(3)
#define SC_OP_CHAINMASK_UPDATE BIT(4)
#define SC_OP_FULL_RESET BIT(5)
#define SC_OP_NO_RESET BIT(6)
#define SC_OP_PREAMBLE_SHORT BIT(7)
#define SC_OP_PROTECT_ENABLE BIT(8)
#define SC_OP_RXFLUSH BIT(9)
#define SC_OP_LED_ASSOCIATED BIT(10)
struct ath_softc {
struct ieee80211_hw *hw;
struct pci_dev *pdev;
void __iomem *mem;
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
struct ath_config sc_config; /* load-time parameters */
int sc_debug;
struct ath_config sc_config;
struct ath_hal *sc_ah;
struct ath_rate_softc *sc_rc; /* tx rate control support */
u32 sc_intrstatus;
enum ath9k_opmode sc_opmode; /* current operating mode */
struct ath_rate_softc *sc_rc;
void __iomem *mem;
u8 sc_invalid; /* being detached */
u8 sc_beacons; /* beacons running */
u8 sc_scanning; /* scanning active */
u8 sc_txaggr; /* enable 11n tx aggregation */
u8 sc_rxaggr; /* enable 11n rx aggregation */
u8 sc_update_chainmask; /* change chain mask */
u8 sc_full_reset; /* force full reset */
enum wireless_mode sc_curmode; /* current phy mode */
u16 sc_curtxpow;
u16 sc_curaid;
u8 sc_curbssid[ETH_ALEN];
u8 sc_myaddr[ETH_ALEN];
enum PROT_MODE sc_protmode;
u8 sc_mcastantenna;
u8 sc_txantenna; /* data tx antenna (fixed or auto) */
u8 sc_nbcnvaps; /* # of vaps sending beacons */
u16 sc_nvaps; /* # of active virtual ap's */
struct ath_vap *sc_vaps[ATH_BCBUF];
enum ath9k_int sc_imask;
u8 sc_bssidmask[ETH_ALEN];
u8 sc_defant; /* current default antenna */
u8 sc_rxotherant; /* rx's on non-default antenna */
int sc_debug;
u32 sc_intrstatus;
u32 sc_flags; /* SC_OP_* */
unsigned int rx_filter;
u16 sc_curtxpow;
u16 sc_curaid;
u16 sc_cachelsz;
int sc_slotupdate; /* slot to next advance fsm */
int sc_slottime;
u8 sc_noreset;
int sc_bslot[ATH_BCBUF];
u8 sc_tx_chainmask;
u8 sc_rx_chainmask;
enum ath9k_int sc_imask;
enum wireless_mode sc_curmode; /* current phy mode */
enum PROT_MODE sc_protmode;
u8 sc_nbcnvaps; /* # of vaps sending beacons */
u16 sc_nvaps; /* # of active virtual ap's */
struct ath_vap *sc_vaps[ATH_BCBUF];
u8 sc_mcastantenna;
u8 sc_defant; /* current default antenna */
u8 sc_rxotherant; /* rx's on non-default antenna */
struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
struct list_head node_list;
struct ath_ht_info sc_ht_info;
int16_t sc_noise_floor; /* signal noise floor in dBm */
enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
u8 sc_tx_chainmask;
u8 sc_rx_chainmask;
u8 sc_rxchaindetect_ref;
u8 sc_rxchaindetect_thresh5GHz;
u8 sc_rxchaindetect_thresh2GHz;
u8 sc_rxchaindetect_delta5GHz;
u8 sc_rxchaindetect_delta2GHz;
u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */
u32 sc_flags;
#ifdef CONFIG_SLOW_ANT_DIV
struct ath_antdiv sc_antdiv;
#endif
@ -981,8 +970,6 @@ struct ath_softc {
struct ath_descdma sc_rxdma;
int sc_rxbufsize; /* rx size based on mtu */
u32 *sc_rxlink; /* link ptr in last RX desc */
u32 sc_rxflush; /* rx flush in progress */
u64 sc_lastrx; /* tsf of last rx'd frame */
/* TX */
struct list_head sc_txbuf;
@ -991,7 +978,7 @@ struct ath_softc {
u32 sc_txqsetup;
u32 sc_txintrperiod; /* tx interrupt batching */
int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */
u32 sc_ant_tx[8]; /* recent tx frames/antenna */
u16 seq_no; /* TX sequence number */
/* Beacon */
struct ath9k_tx_queue_info sc_beacon_qi;
@ -1015,7 +1002,6 @@ struct ath_softc {
/* Channel, Band */
struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath9k_channel sc_curchan;
/* Locks */
spinlock_t sc_rxflushlock;
@ -1023,6 +1009,12 @@ struct ath_softc {
spinlock_t sc_txbuflock;
spinlock_t sc_resetlock;
spinlock_t node_lock;
/* LEDs */
struct ath_led radio_led;
struct ath_led assoc_led;
struct ath_led tx_led;
struct ath_led rx_led;
};
int ath_init(u16 devid, struct ath_softc *sc);
@ -1030,14 +1022,8 @@ void ath_deinit(struct ath_softc *sc);
int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
int ath_suspend(struct ath_softc *sc);
irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc);
void ath_scan_start(struct ath_softc *sc);
void ath_scan_end(struct ath_softc *sc);
int ath_reset(struct ath_softc *sc, bool retry_tx);
int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
void ath_setup_rate(struct ath_softc *sc,
enum wireless_mode wMode,
enum RATE_TYPE type,
const struct ath9k_rate_table *rt);
/*********************/
/* Utility Functions */
@ -1056,17 +1042,5 @@ int ath_cabq_update(struct ath_softc *);
void ath_get_currentCountry(struct ath_softc *sc,
struct ath9k_country_entry *ctry);
u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
void ath_internal_reset(struct ath_softc *sc);
u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc);
dma_addr_t ath_skb_map_single(struct ath_softc *sc,
struct sk_buff *skb,
int direction,
dma_addr_t *pa);
void ath_skb_unmap_single(struct ath_softc *sc,
struct sk_buff *skb,
int direction,
dma_addr_t *pa);
void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]);
enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc);
#endif /* CORE_H */

View file

@ -85,29 +85,6 @@ static const struct hal_percal_data adc_init_dc_cal = {
ath9k_hw_adc_dccal_calibrate
};
static const struct ath_hal ar5416hal = {
AR5416_MAGIC,
0,
0,
NULL,
NULL,
CTRY_DEFAULT,
0,
0,
0,
0,
0,
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
};
static struct ath9k_rate_table ar5416_11a_table = {
8,
{0},
@ -371,7 +348,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah)
ah->ah_config.intr_mitigation = 0;
}
static inline void ath9k_hw_override_ini(struct ath_hal *ah,
static void ath9k_hw_override_ini(struct ath_hal *ah,
struct ath9k_channel *chan)
{
if (!AR_SREV_5416_V20_OR_LATER(ah)
@ -381,8 +358,8 @@ static inline void ath9k_hw_override_ini(struct ath_hal *ah,
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
}
static inline void ath9k_hw_init_bb(struct ath_hal *ah,
struct ath9k_channel *chan)
static void ath9k_hw_init_bb(struct ath_hal *ah,
struct ath9k_channel *chan)
{
u32 synthDelay;
@ -397,8 +374,8 @@ static inline void ath9k_hw_init_bb(struct ath_hal *ah,
udelay(synthDelay + BASE_ACTIVATE_DELAY);
}
static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
enum ath9k_opmode opmode)
static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
enum ath9k_opmode opmode)
{
struct ath_hal_5416 *ahp = AH5416(ah);
@ -428,7 +405,7 @@ static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
}
}
static inline void ath9k_hw_init_qos(struct ath_hal *ah)
static void ath9k_hw_init_qos(struct ath_hal *ah)
{
REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
@ -523,7 +500,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hal *ah,
return ath9k_hw_eeprom_read(ah, off, data);
}
static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
{
struct ath_hal_5416 *ahp = AH5416(ah);
struct ar5416_eeprom *eep = &ahp->ah_eeprom;
@ -790,7 +767,7 @@ ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
return true;
}
static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
static int ath9k_hw_check_eeprom(struct ath_hal *ah)
{
u32 sum = 0, el;
u16 *eepdata;
@ -1196,11 +1173,12 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
ah = &ahp->ah;
memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal));
ah->ah_sc = sc;
ah->ah_sh = mem;
ah->ah_magic = AR5416_MAGIC;
ah->ah_countryCode = CTRY_DEFAULT;
ah->ah_devid = devid;
ah->ah_subvendorid = 0;
@ -1294,7 +1272,7 @@ u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
}
}
static inline int ath9k_hw_get_radiorev(struct ath_hal *ah)
static int ath9k_hw_get_radiorev(struct ath_hal *ah)
{
u32 val;
int i;
@ -1307,7 +1285,7 @@ static inline int ath9k_hw_get_radiorev(struct ath_hal *ah)
return ath9k_hw_reverse_bits(val, 8);
}
static inline int ath9k_hw_init_macaddr(struct ath_hal *ah)
static int ath9k_hw_init_macaddr(struct ath_hal *ah)
{
u32 sum;
int i;
@ -1389,7 +1367,7 @@ static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah,
return spur_val;
}
static inline int ath9k_hw_rfattach(struct ath_hal *ah)
static int ath9k_hw_rfattach(struct ath_hal *ah)
{
bool rfStatus = false;
int ecode = 0;
@ -1434,8 +1412,8 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah)
return 0;
}
static inline void ath9k_hw_init_pll(struct ath_hal *ah,
struct ath9k_channel *chan)
static void ath9k_hw_init_pll(struct ath_hal *ah,
struct ath9k_channel *chan)
{
u32 pll;
@ -1553,7 +1531,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
}
}
static inline void
static void
ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
{
u32 rfMode = 0;
@ -1623,7 +1601,7 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
return true;
}
static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
{
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
@ -1664,7 +1642,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah,
}
}
static inline
static
struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
struct ath9k_channel *chan)
{
@ -2098,7 +2076,7 @@ static void ath9k_hw_ani_attach(struct ath_hal *ah)
ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
}
static inline void ath9k_hw_ani_setup(struct ath_hal *ah)
static void ath9k_hw_ani_setup(struct ath_hal *ah)
{
struct ath_hal_5416 *ahp = AH5416(ah);
int i;
@ -2822,32 +2800,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
}
}
static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
enum ath9k_gpio_output_mux_type
halSignalType)
void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
u32 ah_signal_type)
{
u32 ah_signal_type;
u32 gpio_shift;
static u32 MuxSignalConversionTable[] = {
AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
};
if ((halSignalType >= 0)
&& (halSignalType < ARRAY_SIZE(MuxSignalConversionTable)))
ah_signal_type = MuxSignalConversionTable[halSignalType];
else
return false;
ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
gpio_shift = 2 * gpio;
@ -2856,16 +2813,12 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
AR_GPIO_OE_OUT,
(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
(AR_GPIO_OE_OUT_DRV << gpio_shift));
return true;
}
static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio,
u32 val)
void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
{
REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
AR_GPIO_BIT(gpio));
return true;
}
static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
@ -2883,7 +2836,7 @@ static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
}
}
static inline int ath9k_hw_post_attach(struct ath_hal *ah)
static int ath9k_hw_post_attach(struct ath_hal *ah)
{
int ecode;
@ -3595,7 +3548,7 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin,
return true;
}
static inline void
static void
ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
struct ath9k_channel *chan,
struct cal_data_per_freq *pRawDataSet,
@ -3777,7 +3730,7 @@ ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
return;
}
static inline bool
static bool
ath9k_hw_set_power_cal_table(struct ath_hal *ah,
struct ar5416_eeprom *pEepData,
struct ath9k_channel *chan,
@ -3980,7 +3933,7 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
}
}
static inline void
static void
ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
struct ath9k_channel *chan,
struct cal_target_power_leg *powInfo,
@ -4046,7 +3999,7 @@ ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
}
}
static inline void
static void
ath9k_hw_get_target_powers(struct ath_hal *ah,
struct ath9k_channel *chan,
struct cal_target_power_ht *powInfo,
@ -4113,7 +4066,7 @@ ath9k_hw_get_target_powers(struct ath_hal *ah,
}
}
static inline u16
static u16
ath9k_hw_get_max_edge_power(u16 freq,
struct cal_ctl_edges *pRdEdgesPower,
bool is2GHz)
@ -4143,7 +4096,7 @@ ath9k_hw_get_max_edge_power(u16 freq,
return twiceMaxEdgePower;
}
static inline bool
static bool
ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
struct ar5416_eeprom *pEepData,
struct ath9k_channel *chan,
@ -5122,7 +5075,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
}
static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah)
static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
{
struct ath_hal_5416 *ahp = AH5416(ah);
int rx_chainmask, tx_chainmask;
@ -5326,7 +5279,7 @@ bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
}
}
static inline void ath9k_hw_init_user_settings(struct ath_hal *ah)
static void ath9k_hw_init_user_settings(struct ath_hal *ah)
{
struct ath_hal_5416 *ahp = AH5416(ah);
@ -5345,7 +5298,7 @@ static inline void ath9k_hw_init_user_settings(struct ath_hal *ah)
ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
}
static inline int
static int
ath9k_hw_process_ini(struct ath_hal *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode)
@ -5476,7 +5429,7 @@ ath9k_hw_process_ini(struct ath_hal *ah,
return 0;
}
static inline void ath9k_hw_setup_calibration(struct ath_hal *ah,
static void ath9k_hw_setup_calibration(struct ath_hal *ah,
struct hal_cal_list *currCal)
{
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
@ -5512,8 +5465,8 @@ static inline void ath9k_hw_setup_calibration(struct ath_hal *ah,
AR_PHY_TIMING_CTRL4_DO_CAL);
}
static inline void ath9k_hw_reset_calibration(struct ath_hal *ah,
struct hal_cal_list *currCal)
static void ath9k_hw_reset_calibration(struct ath_hal *ah,
struct hal_cal_list *currCal)
{
struct ath_hal_5416 *ahp = AH5416(ah);
int i;
@ -5532,7 +5485,7 @@ static inline void ath9k_hw_reset_calibration(struct ath_hal *ah,
ahp->ah_CalSamples = 0;
}
static inline void
static void
ath9k_hw_per_calibration(struct ath_hal *ah,
struct ath9k_channel *ichan,
u8 rxchainmask,
@ -5622,7 +5575,7 @@ static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah,
return true;
}
static inline bool
static bool
ath9k_hw_channel_change(struct ath_hal *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode)
@ -5799,8 +5752,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
return retval;
}
static inline bool ath9k_hw_init_cal(struct ath_hal *ah,
struct ath9k_channel *chan)
static bool ath9k_hw_init_cal(struct ath_hal *ah,
struct ath9k_channel *chan)
{
struct ath_hal_5416 *ahp = AH5416(ah);
struct ath9k_channel *ichan =
@ -5861,7 +5814,7 @@ static inline bool ath9k_hw_init_cal(struct ath_hal *ah,
}
bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
bool ath9k_hw_reset(struct ath_hal *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode,
u8 txchainmask, u8 rxchainmask,
@ -5945,7 +5898,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
else
ath9k_hw_set_gpio(ah, 9, 1);
}
ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
}
ecode = ath9k_hw_process_ini(ah, chan, macmode);
@ -5975,7 +5928,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
| (ah->ah_config.
ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
| ahp->ah_staId1Defaults);
ath9k_hw_set_operating_mode(ah, opmode);
ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
@ -6005,13 +5958,11 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
for (i = 0; i < ah->ah_caps.total_queues; i++)
ath9k_hw_resettxqueue(ah, i);
ath9k_hw_init_interrupt_masks(ah, opmode);
ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
ath9k_hw_init_qos(ah);
ath9k_hw_init_user_settings(ah);
ah->ah_opmode = opmode;
REG_WRITE(ah, AR_STA_ID1,
REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
@ -7678,8 +7629,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
REG_WRITE(ah, AR_DRETRY_LIMIT(q),
SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
| SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
| SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
);
| SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
REG_WRITE(ah, AR_DMISC(q),
@ -8324,15 +8274,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid,
*error = -ENXIO;
break;
}
if (ah != NULL) {
ah->ah_devid = ah->ah_devid;
ah->ah_subvendorid = ah->ah_subvendorid;
ah->ah_macVersion = ah->ah_macVersion;
ah->ah_macRev = ah->ah_macRev;
ah->ah_phyRev = ah->ah_phyRev;
ah->ah_analog5GhzRev = ah->ah_analog5GhzRev;
ah->ah_analog2GhzRev = ah->ah_analog2GhzRev;
}
return ah;
}

View file

@ -314,14 +314,11 @@ struct ar5416_desc {
#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \
MS(ads->ds_rxstatus0, AR_RxRate) : \
(ads->ds_rxstatus3 >> 2) & 0xFF)
#define RXSTATUS_DUPLICATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \
MS(ads->ds_rxstatus3, AR_Parallel40) : \
(ads->ds_rxstatus3 >> 10) & 0x1)
#define set11nTries(_series, _index) \
#define set11nTries(_series, _index) \
(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
#define set11nRate(_series, _index) \
#define set11nRate(_series, _index) \
(SM((_series)[_index].Rate, AR_XmitRate##_index))
#define set11nPktDurRTSCTS(_series, _index) \
@ -330,11 +327,11 @@ struct ar5416_desc {
AR_RTSCTSQual##_index : 0))
#define set11nRateFlags(_series, _index) \
(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \
AR_2040_##_index : 0) \
|((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \
AR_GI##_index : 0) \
|SM((_series)[_index].ChSel, AR_ChainSel##_index))
(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \
AR_2040_##_index : 0) \
|((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \
AR_GI##_index : 0) \
|SM((_series)[_index].ChSel, AR_ChainSel##_index))
#define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100)
@ -346,9 +343,6 @@ struct ar5416_desc {
#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1)
#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD
#define NUM_CORNER_FIX_BITS_2133 7
#define CCK_OFDM_GAIN_DELTA 15
struct ar5416AniState {
struct ath9k_channel c;
u8 noiseImmunityLevel;
@ -377,11 +371,8 @@ struct ar5416AniState {
};
#define HAL_PROCESS_ANI 0x00000001
#define HAL_RADAR_EN 0x80000000
#define HAL_AR_EN 0x40000000
#define DO_ANI(ah) \
((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
struct ar5416Stats {
u32 ast_ani_niup;
@ -425,7 +416,6 @@ struct ar5416Stats {
#define AR5416_EEP_MINOR_VER_7 0x7
#define AR5416_EEP_MINOR_VER_9 0x9
#define AR5416_EEP_START_LOC 256
#define AR5416_NUM_5G_CAL_PIERS 8
#define AR5416_NUM_2G_CAL_PIERS 4
#define AR5416_NUM_5G_20_TARGET_POWERS 8
@ -441,25 +431,10 @@ struct ar5416Stats {
#define AR5416_EEPROM_MODAL_SPURS 5
#define AR5416_MAX_RATE_POWER 63
#define AR5416_NUM_PDADC_VALUES 128
#define AR5416_NUM_RATES 16
#define AR5416_BCHAN_UNUSED 0xFF
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR5416_EEPMISC_BIG_ENDIAN 0x01
#define AR5416_MAX_CHAINS 3
#define AR5416_ANT_16S 25
#define AR5416_NUM_ANT_CHAIN_FIELDS 7
#define AR5416_NUM_ANT_COMMON_FIELDS 4
#define AR5416_SIZE_ANT_CHAIN_FIELD 3
#define AR5416_SIZE_ANT_COMMON_FIELD 4
#define AR5416_ANT_CHAIN_MASK 0x7
#define AR5416_ANT_COMMON_MASK 0xf
#define AR5416_CHAIN_0_IDX 0
#define AR5416_CHAIN_1_IDX 1
#define AR5416_CHAIN_2_IDX 2
#define AR5416_PWR_TABLE_OFFSET -5
#define AR5416_LEGACY_CHAINMASK 1
enum eeprom_param {
EEP_NFTHRESH_5,
@ -633,7 +608,7 @@ struct ar5416IniArray {
};
#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \
(iniarray)->ia_array = (u32 *)(array); \
(iniarray)->ia_array = (u32 *)(array); \
(iniarray)->ia_rows = (rows); \
(iniarray)->ia_columns = (columns); \
} while (0)
@ -641,16 +616,16 @@ struct ar5416IniArray {
#define INI_RA(iniarray, row, column) \
(((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)])
#define INIT_CAL(_perCal) do { \
(_perCal)->calState = CAL_WAITING; \
(_perCal)->calNext = NULL; \
#define INIT_CAL(_perCal) do { \
(_perCal)->calState = CAL_WAITING; \
(_perCal)->calNext = NULL; \
} while (0)
#define INSERT_CAL(_ahp, _perCal) \
do { \
if ((_ahp)->ah_cal_list_last == NULL) { \
(_ahp)->ah_cal_list = \
(_ahp)->ah_cal_list_last = (_perCal); \
(_ahp)->ah_cal_list = \
(_ahp)->ah_cal_list_last = (_perCal); \
((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
} else { \
((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
@ -696,25 +671,29 @@ struct hal_cal_list {
struct ath_hal_5416 {
struct ath_hal ah;
struct ar5416_eeprom ah_eeprom;
struct ar5416Stats ah_stats;
struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
void __iomem *ah_cal_mem;
u8 ah_macaddr[ETH_ALEN];
u8 ah_bssid[ETH_ALEN];
u8 ah_bssidmask[ETH_ALEN];
u16 ah_assocId;
int16_t ah_curchanRadIndex;
u32 ah_maskReg;
struct ar5416Stats ah_stats;
u32 ah_txDescMask;
u32 ah_txOkInterruptMask;
u32 ah_txErrInterruptMask;
u32 ah_txDescInterruptMask;
u32 ah_txEolInterruptMask;
u32 ah_txUrnInterruptMask;
struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
enum ath9k_power_mode ah_powerMode;
bool ah_chipFullSleep;
u32 ah_atimWindow;
enum ath9k_ant_setting ah_diversityControl;
u16 ah_antennaSwitchSwap;
enum ath9k_power_mode ah_powerMode;
enum ath9k_ant_setting ah_diversityControl;
/* Calibration */
enum hal_cal_types ah_suppCals;
struct hal_cal_list ah_iqCalData;
struct hal_cal_list ah_adcGainCalData;
@ -751,16 +730,16 @@ struct ath_hal_5416 {
int32_t sign[AR5416_MAX_CHAINS];
} ah_Meas3;
u16 ah_CalSamples;
u32 ah_tx6PowerInHalfDbm;
u32 ah_staId1Defaults;
u32 ah_miscMode;
bool ah_tpcEnabled;
u32 ah_beaconInterval;
enum {
AUTO_32KHZ,
USE_32KHZ,
DONT_USE_32KHZ,
} ah_enable32kHzClock;
/* RF */
u32 *ah_analogBank0Data;
u32 *ah_analogBank1Data;
u32 *ah_analogBank2Data;
@ -770,8 +749,9 @@ struct ath_hal_5416 {
u32 *ah_analogBank7Data;
u32 *ah_addac5416_21;
u32 *ah_bank6Temp;
u32 ah_ofdmTxPower;
int16_t ah_txPowerIndexOffset;
u32 ah_beaconInterval;
u32 ah_slottime;
u32 ah_acktimeout;
u32 ah_ctstimeout;
@ -780,7 +760,8 @@ struct ath_hal_5416 {
u32 ah_gpioSelect;
u32 ah_polarity;
u32 ah_gpioBit;
bool ah_eepEnabled;
/* ANI */
u32 ah_procPhyErr;
bool ah_hasHwPhyCounters;
u32 ah_aniPeriod;
@ -790,18 +771,14 @@ struct ath_hal_5416 {
int ah_coarseHigh[5];
int ah_coarseLow[5];
int ah_firpwr[5];
u16 ah_ratesArray[16];
enum ath9k_ani_cmd ah_ani_function;
u32 ah_intrTxqs;
bool ah_intrMitigation;
u32 ah_cycleCount;
u32 ah_ctlBusy;
u32 ah_extBusy;
enum ath9k_ht_extprotspacing ah_extprotspacing;
u8 ah_txchainmask;
u8 ah_rxchainmask;
int ah_hwp;
void __iomem *ah_cal_mem;
enum ath9k_ani_cmd ah_ani_function;
struct ar5416IniArray ah_iniModes;
struct ar5416IniArray ah_iniCommon;
struct ar5416IniArray ah_iniBank0;
@ -820,10 +797,6 @@ struct ath_hal_5416 {
#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
#define IS_5416_EMU(ah) \
((ah->ah_devid == AR5416_DEVID_EMU) || \
(ah->ah_devid == AR5416_DEVID_EMU_PCIE))
#define ar5416RfDetach(ah) do { \
if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \
AH5416(ah)->ah_rfHal.rfDetach(ah); \
@ -841,8 +814,8 @@ struct ath_hal_5416 {
#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \
int r; \
for (r = 0; r < ((iniarray)->ia_rows); r++) { \
REG_WRITE(ah, INI_RA((iniarray), (r), 0), \
INI_RA((iniarray), r, (column))); \
REG_WRITE(ah, INI_RA((iniarray), (r), 0), \
INI_RA((iniarray), r, (column))); \
DO_DELAY(regWr); \
} \
} while (0)
@ -852,30 +825,21 @@ struct ath_hal_5416 {
#define COEF_SCALE_S 24
#define HT40_CHANNEL_CENTER_SHIFT 10
#define ar5416CheckOpMode(_opmode) \
((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) || \
(_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR))
#define AR5416_EEPROM_MAGIC_OFFSET 0x0
#define AR5416_EEPROM_S 2
#define AR5416_EEPROM_OFFSET 0x2000
#define AR5416_EEPROM_START_ADDR \
#define AR5416_EEPROM_START_ADDR \
(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
#define AR5416_EEPROM_MAX 0xae0
#define ar5416_get_eep_ver(_ahp) \
#define ar5416_get_eep_ver(_ahp) \
(((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF)
#define ar5416_get_eep_rev(_ahp) \
#define ar5416_get_eep_rev(_ahp) \
(((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF)
#define ar5416_get_ntxchains(_txchainmask) \
#define ar5416_get_ntxchains(_txchainmask) \
(((_txchainmask >> 2) & 1) + \
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
#define IS_EEP_MINOR_V3(_ahp) \
(ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_3)
#define FIXED_CCA_THRESHOLD 15
#ifdef __BIG_ENDIAN
#define AR5416_EEPROM_MAGIC 0x5aa5
#else
@ -910,8 +874,6 @@ struct ath_hal_5416 {
#define AR_GPIOD_MASK 0x00001FFF
#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
#define MAX_ANALOG_START 319
#define HAL_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
#define BEACON_RSSI(ahp) \
@ -923,8 +885,6 @@ struct ath_hal_5416 {
#define AH_TIMEOUT 100000
#define AH_TIME_QUANTUM 10
#define IS(_c, _f) (((_c)->channelFlags & _f) || 0)
#define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000
@ -964,6 +924,6 @@ struct ath_hal_5416 {
#define OFDM_SYMBOL_TIME_QUARTER 16
u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
enum eeprom_param param);
enum eeprom_param param);
#endif

View file

@ -22,8 +22,6 @@
#define ATH_PCI_VERSION "0.1"
#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
#define IEEE80211_ACTION_CAT_HT 7
#define IEEE80211_ACTION_HT_TXCHWIDTH 0
static char *dev_info = "ath9k";
@ -212,21 +210,16 @@ static int ath_key_config(struct ath_softc *sc,
static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
{
#define ATH_MAX_NUM_KEYS 4
int freeslot;
freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0;
freeslot = (key->keyidx >= 4) ? 1 : 0;
ath_key_reset(sc, key->keyidx, freeslot);
#undef ATH_MAX_NUM_KEYS
}
static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
{
/* Until mac80211 includes these fields */
#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
#define IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define IEEE80211_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
ht_info->ht_supported = 1;
ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
@ -234,8 +227,8 @@ static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
|(u16)IEEE80211_HT_CAP_SGI_40
|(u16)IEEE80211_HT_CAP_DSSSCCK40;
ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536;
ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8;
ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
/* setup supported mcs set */
memset(ht_info->supp_mcs_set, 0, 16);
ht_info->supp_mcs_set[0] = 0xff;
@ -368,6 +361,20 @@ static int ath9k_tx(struct ieee80211_hw *hw,
{
struct ath_softc *sc = hw->priv;
int hdrlen, padsize;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
/*
* As a temporary workaround, assign seq# here; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual
* BSSes.
*/
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
sc->seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
}
/* Add the padding after the header if this is not already done */
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@ -426,10 +433,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
case IEEE80211_IF_TYPE_IBSS:
ic_opmode = ATH9K_M_IBSS;
break;
case IEEE80211_IF_TYPE_AP:
ic_opmode = ATH9K_M_HOSTAP;
break;
default:
DPRINTF(sc, ATH_DBG_FATAL,
"%s: Only STA and IBSS are supported currently\n",
__func__);
"%s: Interface type %d not yet supported\n",
__func__, conf->type);
return -EOPNOTSUPP;
}
@ -472,7 +482,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
ath_rate_newstate(sc, avp);
/* Reclaim beacon resources */
if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) {
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
ath_beacon_return(sc, avp);
}
@ -480,7 +491,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
/* Set interrupt mask */
sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
sc->sc_beacons = 0;
sc->sc_flags &= ~SC_OP_BEACONS;
error = ath_vap_detach(sc, 0);
if (error)
@ -529,6 +540,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
struct ieee80211_if_conf *conf)
{
struct ath_softc *sc = hw->priv;
struct ath_hal *ah = sc->sc_ah;
struct ath_vap *avp;
u32 rfilt = 0;
int error, i;
@ -541,6 +553,17 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
return -EINVAL;
}
/* TODO: Need to decide which hw opmode to use for multi-interface
* cases */
if (vif->type == IEEE80211_IF_TYPE_AP &&
ah->ah_opmode != ATH9K_M_HOSTAP) {
ah->ah_opmode = ATH9K_M_HOSTAP;
ath9k_hw_setopmode(ah);
ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
/* Request full reset to get hw opmode changed properly */
sc->sc_flags |= SC_OP_FULL_RESET;
}
if ((conf->changed & IEEE80211_IFCC_BSSID) &&
!is_zero_ether_addr(conf->bssid)) {
switch (vif->type) {
@ -549,10 +572,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
/* Update ratectrl about the new state */
ath_rate_newstate(sc, avp);
/* Set rx filter */
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
/* Set BSSID */
memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
sc->sc_curaid = 0;
@ -585,7 +604,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
/* need to reconfigure the beacon */
sc->sc_beacons = 0;
sc->sc_flags &= ~SC_OP_BEACONS ;
break;
default:
@ -594,7 +613,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
}
if ((conf->changed & IEEE80211_IFCC_BEACON) &&
(vif->type == IEEE80211_IF_TYPE_IBSS)) {
((vif->type == IEEE80211_IF_TYPE_IBSS) ||
(vif->type == IEEE80211_IF_TYPE_AP))) {
/*
* Allocate and setup the beacon frame.
*
@ -636,8 +656,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | \
FIF_FCSFAIL)
/* Accept unicast, bcast and mcast frames */
/* FIXME: sc->sc_full_reset ? */
static void ath9k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@ -645,16 +664,22 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
struct dev_mc_list *mclist)
{
struct ath_softc *sc = hw->priv;
u32 rfilt;
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
sc->rx_filter = *total_flags;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
ath_scan_start(sc);
else
ath_scan_end(sc);
ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
}
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
__func__, sc->rx_filter);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@ -831,7 +856,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
/* Configure the beacon */
ath_beacon_config(sc, 0);
sc->sc_beacons = 1;
sc->sc_flags |= SC_OP_BEACONS;
/* Reset rssi stats */
sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
@ -894,9 +919,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
__func__,
bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= ATH_PREAMBLE_SHORT;
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
else
sc->sc_flags &= ~ATH_PREAMBLE_SHORT;
sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@ -905,9 +930,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
sc->sc_flags |= ATH_PROTECT_ENABLE;
sc->sc_flags |= SC_OP_PROTECT_ENABLE;
else
sc->sc_flags &= ~ATH_PROTECT_ENABLE;
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
if (changed & BSS_CHANGED_HT) {
@ -1035,15 +1060,6 @@ void ath_get_beaconconfig(struct ath_softc *sc,
conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
}
int ath_update_beacon(struct ath_softc *sc,
int if_id,
struct ath_beacon_offset *bo,
struct sk_buff *skb,
int mcast)
{
return 0;
}
void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ath_xmit_status *tx_status, struct ath_node *an)
{
@ -1065,8 +1081,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
tx_status->flags &= ~ATH_TX_BAR;
}
if (tx_status->flags)
tx_info->status.excessive_retries = 1;
if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* Frame was not ACKed, but an ACK was expected */
tx_info->status.excessive_retries = 1;
}
} else {
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
}
tx_info->status.retry_count = tx_status->retries;
@ -1075,7 +1099,7 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
}
int ath__rx_indicate(struct ath_softc *sc,
int _ath_rx_indicate(struct ath_softc *sc,
struct sk_buff *skb,
struct ath_recv_status *status,
u16 keyix)
@ -1095,9 +1119,6 @@ int ath__rx_indicate(struct ath_softc *sc,
skb_pull(skb, padsize);
}
/* remove FCS before passing up to protocol stack */
skb_trim(skb, (skb->len - FCS_LEN));
/* Prepare rx status */
ath9k_rx_prepare(sc, skb, status, &rx_status);
@ -1146,9 +1167,119 @@ int ath_rx_subframe(struct ath_node *an,
return 0;
}
enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc)
/********************************/
/* LED functions */
/********************************/
static void ath_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
return sc->sc_ht_info.tx_chan_width;
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
struct ath_softc *sc = led->sc;
switch (brightness) {
case LED_OFF:
if (led->led_type == ATH_LED_ASSOC ||
led->led_type == ATH_LED_RADIO)
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
(led->led_type == ATH_LED_RADIO) ? 1 :
!!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
break;
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC)
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
break;
default:
break;
}
}
static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
char *trigger)
{
int ret;
led->sc = sc;
led->led_cdev.name = led->name;
led->led_cdev.default_trigger = trigger;
led->led_cdev.brightness_set = ath_led_brightness;
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
if (ret)
DPRINTF(sc, ATH_DBG_FATAL,
"Failed to register led:%s", led->name);
else
led->registered = 1;
return ret;
}
static void ath_unregister_led(struct ath_led *led)
{
if (led->registered) {
led_classdev_unregister(&led->led_cdev);
led->registered = 0;
}
}
static void ath_deinit_leds(struct ath_softc *sc)
{
ath_unregister_led(&sc->assoc_led);
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
ath_unregister_led(&sc->tx_led);
ath_unregister_led(&sc->rx_led);
ath_unregister_led(&sc->radio_led);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
}
static void ath_init_leds(struct ath_softc *sc)
{
char *trigger;
int ret;
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
trigger = ieee80211_get_radio_led_name(sc->hw);
snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
"ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
ret = ath_register_led(sc, &sc->radio_led, trigger);
sc->radio_led.led_type = ATH_LED_RADIO;
if (ret)
goto fail;
trigger = ieee80211_get_assoc_led_name(sc->hw);
snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
"ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
ret = ath_register_led(sc, &sc->assoc_led, trigger);
sc->assoc_led.led_type = ATH_LED_ASSOC;
if (ret)
goto fail;
trigger = ieee80211_get_tx_led_name(sc->hw);
snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
"ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
ret = ath_register_led(sc, &sc->tx_led, trigger);
sc->tx_led.led_type = ATH_LED_TX;
if (ret)
goto fail;
trigger = ieee80211_get_rx_led_name(sc->hw);
snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
"ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
ret = ath_register_led(sc, &sc->rx_led, trigger);
sc->rx_led.led_type = ATH_LED_RX;
if (ret)
goto fail;
return;
fail:
ath_deinit_leds(sc);
}
static int ath_detach(struct ath_softc *sc)
@ -1157,6 +1288,9 @@ static int ath_detach(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
/* Deinit LED control */
ath_deinit_leds(sc);
/* Unregister hw */
ieee80211_unregister_hw(hw);
@ -1250,18 +1384,21 @@ static int ath_attach(u16 devid,
goto bad;
}
/* Initialize LED control */
ath_init_leds(sc);
/* initialize tx/rx engine */
error = ath_tx_init(sc, ATH_TXBUF);
if (error != 0)
goto bad1;
goto detach;
error = ath_rx_init(sc, ATH_RXBUF);
if (error != 0)
goto bad1;
goto detach;
return 0;
bad1:
detach:
ath_detach(sc);
bad:
return error;
@ -1340,7 +1477,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bad2;
}
hw->flags = IEEE80211_HW_SIGNAL_DBM |
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
SET_IEEE80211_DEV(hw, &pdev->dev);
@ -1404,6 +1543,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, 3);
@ -1413,6 +1556,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int ath_pci_resume(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
u32 val;
int err;
@ -1429,6 +1574,11 @@ static int ath_pci_resume(struct pci_dev *pdev)
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
/* Enable LED */
ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
return 0;
}

View file

@ -18,19 +18,19 @@
#define PHY_H
bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
struct ath9k_channel
*chan);
struct ath9k_channel
*chan);
bool ath9k_hw_set_channel(struct ath_hal *ah,
struct ath9k_channel *chan);
struct ath9k_channel *chan);
void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex,
u32 freqIndex, int regWrites);
bool ath9k_hw_set_rf_regs(struct ath_hal *ah,
struct ath9k_channel *chan,
u16 modesIndex);
struct ath9k_channel *chan,
u16 modesIndex);
void ath9k_hw_decrease_chain_power(struct ath_hal *ah,
struct ath9k_channel *chan);
bool ath9k_hw_init_rf(struct ath_hal *ah,
int *status);
int *status);
#define AR_PHY_BASE 0x9800
#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))

View file

@ -653,8 +653,8 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv,
rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
for (i = 0; i < rate_table->rate_cnt; i++) {
valid = (ath_rc_priv->single_stream ?
rate_table->info[i].valid_single_stream :
rate_table->info[i].valid);
rate_table->info[i].valid_single_stream :
rate_table->info[i].valid);
if (valid == TRUE) {
u32 phy = rate_table->info[i].phy;
u8 valid_rate_count = 0;
@ -740,14 +740,14 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv,
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
u32 valid = (ath_rc_priv->single_stream ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
if (((((struct ath_rateset *)
mcs_set)->rs_rates[i] & 0x7F) !=
(rate_table->info[j].dot11rate & 0x7F)) ||
!WLAN_RC_PHY_HT(phy) ||
!WLAN_RC_PHY_HT_VALID(valid, capflag))
mcs_set)->rs_rates[i] & 0x7F) !=
(rate_table->info[j].dot11rate & 0x7F)) ||
!WLAN_RC_PHY_HT(phy) ||
!WLAN_RC_PHY_HT_VALID(valid, capflag))
continue;
if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
@ -847,9 +847,9 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
/* For half and quarter rate channles use different
* rate tables
*/
if (sc->sc_curchan.channelFlags & CHANNEL_HALF)
if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF)
ar5416_sethalf_ratetable(asc);
else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER)
else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER)
ar5416_setquarter_ratetable(asc);
else /* full rate */
ar5416_setfull_ratetable(asc);
@ -866,10 +866,10 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
}
static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
struct ath_rate_node *ath_rc_priv,
const struct ath_rate_table *rate_table,
int probe_allowed, int *is_probing,
int is_retry)
struct ath_rate_node *ath_rc_priv,
const struct ath_rate_table *rate_table,
int probe_allowed, int *is_probing,
int is_retry)
{
u32 dt, best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
@ -997,8 +997,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
rate = rate_ctrl->rate_table_size - 1;
ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
(rate_table->info[rate].valid_single_stream &&
ath_rc_priv->single_stream));
(rate_table->info[rate].valid_single_stream &&
ath_rc_priv->single_stream));
return rate;
}
@ -1023,10 +1023,10 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table ,
}
static u8 ath_rc_rate_getidx(struct ath_softc *sc,
struct ath_rate_node *ath_rc_priv,
const struct ath_rate_table *rate_table,
u8 rix, u16 stepdown,
u16 min_rate)
struct ath_rate_node *ath_rc_priv,
const struct ath_rate_table *rate_table,
u8 rix, u16 stepdown,
u16 min_rate)
{
u32 j;
u8 nextindex;
@ -1066,8 +1066,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
rate_table =
(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
(rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
is_probe, is_retry);
(rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
is_probe, is_retry);
nrix = rix;
if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) {
@ -1099,13 +1099,13 @@ static void ath_rc_ratefind(struct ath_softc *sc,
try_num = ((i + 1) == num_rates) ?
num_tries - (try_per_rate * i) : try_per_rate ;
min_rate = (((i + 1) == num_rates) &&
(rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
(rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
rate_table, nrix, 1, min_rate);
rate_table, nrix, 1, min_rate);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table,
&series[i], try_num, nrix, TRUE);
&series[i], try_num, nrix, TRUE);
}
/*
@ -1124,13 +1124,13 @@ static void ath_rc_ratefind(struct ath_softc *sc,
* above conditions.
*/
if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) ||
(sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
(sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
(sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
(sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
u8 dot11rate = rate_table->info[rix].dot11rate;
u8 phy = rate_table->info[rix].phy;
if (i == 4 &&
((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
(dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
(dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
series[3].rix = series[2].rix;
series[3].flags = series[2].flags;
series[3].max_4ms_framelen = series[2].max_4ms_framelen;
@ -1141,18 +1141,19 @@ static void ath_rc_ratefind(struct ath_softc *sc,
/*
* Return the Tx rate series.
*/
void ath_rate_findrate(struct ath_softc *sc,
struct ath_rate_node *ath_rc_priv,
int num_tries,
int num_rates,
unsigned int rcflag,
struct ath_rc_series series[],
int *is_probe,
int is_retry)
static void ath_rate_findrate(struct ath_softc *sc,
struct ath_rate_node *ath_rc_priv,
int num_tries,
int num_rates,
unsigned int rcflag,
struct ath_rc_series series[],
int *is_probe,
int is_retry)
{
struct ath_vap *avp = ath_rc_priv->avp;
DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
if (!num_rates || !num_tries)
return;
@ -1174,9 +1175,8 @@ void ath_rate_findrate(struct ath_softc *sc,
unsigned int mcs;
u8 series_rix = 0;
series[idx].tries =
IEEE80211_RATE_IDX_ENTRY(
avp->av_config.av_fixed_retryset, idx);
series[idx].tries = IEEE80211_RATE_IDX_ENTRY(
avp->av_config.av_fixed_retryset, idx);
mcs = IEEE80211_RATE_IDX_ENTRY(
avp->av_config.av_fixed_rateset, idx);
@ -1228,7 +1228,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
u32 now_msec = jiffies_to_msecs(jiffies);
int state_change = FALSE, rate, count;
u8 last_per;
struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_table *rate_table =
(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
@ -1272,14 +1272,14 @@ static void ath_rc_update_ht(struct ath_softc *sc,
} else {
/* xretries == 2 */
count = sizeof(nretry_to_per_lookup) /
sizeof(nretry_to_per_lookup[0]);
sizeof(nretry_to_per_lookup[0]);
if (retries >= count)
retries = count - 1;
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
rate_ctrl->state[tx_rate].per =
(u8)(rate_ctrl->state[tx_rate].per -
(rate_ctrl->state[tx_rate].per >> 3) +
((100) >> 3));
(rate_ctrl->state[tx_rate].per >> 3) +
((100) >> 3));
}
/* xretries == 1 or 2 */
@ -1295,8 +1295,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if (retries >= count)
retries = count - 1;
if (info_priv->n_bad_frames) {
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
/*
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
* Assuming that n_frames is not 0. The current PER
* from the retries is 100 * retries / (retries+1),
* since the first retries attempts failed, and the
@ -1386,7 +1385,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* rssi_ack values.
*/
if (tx_rate == rate_ctrl->rate_max_phy &&
rate_ctrl->hw_maxretry_pktcnt < 255) {
rate_ctrl->hw_maxretry_pktcnt < 255) {
rate_ctrl->hw_maxretry_pktcnt++;
}
@ -1418,7 +1417,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* Now reduce the current
* rssi threshold. */
if ((rssi_ackAvg < rssi_thres + 2) &&
(rssi_thres > rssi_ack_vmin)) {
(rssi_thres > rssi_ack_vmin)) {
rate_ctrl->state[tx_rate].
rssi_thres--;
}
@ -1436,10 +1435,10 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* a while (except if we are probing).
*/
if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
rate_table->info[tx_rate].ratekbps <=
rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
(u8) tx_rate, &rate_ctrl->rate_max_phy);
(u8) tx_rate, &rate_ctrl->rate_max_phy);
/* Don't probe for a little while. */
rate_ctrl->probe_time = now_msec;
@ -1460,43 +1459,43 @@ static void ath_rc_update_ht(struct ath_softc *sc,
break;
if (rate_ctrl->state[rate].rssi_thres +
rate_table->info[rate].rssi_ack_deltamin >
rate_ctrl->state[rate+1].rssi_thres) {
rate_table->info[rate].rssi_ack_deltamin >
rate_ctrl->state[rate+1].rssi_thres) {
rate_ctrl->state[rate+1].rssi_thres =
rate_ctrl->state[rate].
rssi_thres +
rssi_thres +
rate_table->info[rate].
rssi_ack_deltamin;
rssi_ack_deltamin;
}
}
/* Make sure the rates below this have lower rssi thresholds. */
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
rate_table->info[tx_rate].phy)
break;
if (rate_ctrl->state[rate].rssi_thres +
rate_table->info[rate].rssi_ack_deltamin >
rate_ctrl->state[rate+1].rssi_thres) {
rate_table->info[rate].rssi_ack_deltamin >
rate_ctrl->state[rate+1].rssi_thres) {
if (rate_ctrl->state[rate+1].rssi_thres <
rate_table->info[rate].
rssi_ack_deltamin)
rate_table->info[rate].
rssi_ack_deltamin)
rate_ctrl->state[rate].rssi_thres = 0;
else {
rate_ctrl->state[rate].rssi_thres =
rate_ctrl->state[rate+1].
rssi_thres -
rate_table->info[rate].
rssi_ack_deltamin;
rssi_thres -
rate_table->info[rate].
rssi_ack_deltamin;
}
if (rate_ctrl->state[rate].rssi_thres <
rate_table->info[rate].
rssi_ack_validmin) {
rate_table->info[rate].
rssi_ack_validmin) {
rate_ctrl->state[rate].rssi_thres =
rate_table->info[rate].
rssi_ack_validmin;
rssi_ack_validmin;
}
}
}
@ -1507,11 +1506,11 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if (rate_ctrl->state[tx_rate].per < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
rate_table->info[tx_rate].phy)
break;
if (rate_ctrl->state[rate].per >
rate_ctrl->state[rate+1].per) {
rate_ctrl->state[rate+1].per) {
rate_ctrl->state[rate].per =
rate_ctrl->state[rate+1].per;
}
@ -1528,11 +1527,11 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* Every so often, we reduce the thresholds and
* PER (different for CCK and OFDM). */
if (now_msec - rate_ctrl->rssi_down_time >=
rate_table->rssi_reduce_interval) {
rate_table->rssi_reduce_interval) {
for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
if (rate_ctrl->state[rate].rssi_thres >
rate_table->info[rate].rssi_ack_validmin)
rate_table->info[rate].rssi_ack_validmin)
rate_ctrl->state[rate].rssi_thres -= 1;
}
rate_ctrl->rssi_down_time = now_msec;
@ -1541,7 +1540,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
if (now_msec - rate_ctrl->per_down_time >=
rate_table->rssi_reduce_interval) {
rate_table->rssi_reduce_interval) {
for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
rate_ctrl->state[rate].per =
7 * rate_ctrl->state[rate].per / 8;
@ -1560,7 +1559,7 @@ static void ath_rc_update(struct ath_softc *sc,
struct ath_tx_info_priv *info_priv, int final_ts_idx,
int xretries, int long_retry)
{
struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_table *rate_table;
struct ath_tx_ratectrl *rate_ctrl;
struct ath_rc_series rcs[4];
@ -1637,7 +1636,6 @@ static void ath_rc_update(struct ath_softc *sc,
xretries, long_retry);
}
/*
* Process a tx descriptor for a completed transmit (success or failure).
*/
@ -1651,13 +1649,13 @@ static void ath_rate_tx_complete(struct ath_softc *sc,
struct ath_vap *avp;
avp = rc_priv->avp;
if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE)
|| info_priv->tx.ts_status & ATH9K_TXERR_FILT)
if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) ||
(info_priv->tx.ts_status & ATH9K_TXERR_FILT))
return;
if (info_priv->tx.ts_rssi > 0) {
ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
info_priv->tx.ts_rssi);
info_priv->tx.ts_rssi);
}
/*
@ -1682,7 +1680,6 @@ static void ath_rate_tx_complete(struct ath_softc *sc,
info_priv->tx.ts_longretry);
}
/*
* Update the SIB's rate control information
*
@ -1701,8 +1698,8 @@ static void ath_rc_sib_update(struct ath_softc *sc,
struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rateset *rateset = negotiated_rates;
u8 *ht_mcs = (u8 *)negotiated_htrates;
struct ath_tx_ratectrl *rate_ctrl = (struct ath_tx_ratectrl *)
(ath_rc_priv);
struct ath_tx_ratectrl *rate_ctrl =
(struct ath_tx_ratectrl *)ath_rc_priv;
u8 i, j, k, hi = 0, hthi = 0;
rate_table = (struct ath_rate_table *)
@ -1824,7 +1821,8 @@ static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta)
struct ath_rate_node *rc_priv = sta->rate_ctrl_priv;
int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
for (i = 0; i < sband->n_bitrates; i++) {
if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) {
@ -1903,7 +1901,7 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
int state;
DECLARE_MAC_BUF(mac);
if (!sc->sc_txaggr)
if (!(sc->sc_flags & SC_OP_TXAGGR))
return;
txtid = ATH_AN_2_TID(an, tidno);
@ -1944,7 +1942,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
struct ath_rate_node *ath_rc_priv;
struct ath_node *an;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int is_probe, chk, ret;
int is_probe = FALSE, chk, ret;
s8 lowest_idx;
__le16 fc = hdr->frame_control;
u8 *qc, tid;
@ -1962,7 +1960,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
/* lowest rate for management and multicast/broadcast frames */
if (!ieee80211_is_data(fc) ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
is_multicast_ether_addr(hdr->addr1) || !sta) {
sel->rate_idx = lowest_idx;
return;
}
@ -1978,7 +1976,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
false);
if (is_probe)
sel->probe_idx = ((struct ath_tx_ratectrl *)
sta->rate_ctrl_priv)->probe_rate;
sta->rate_ctrl_priv)->probe_rate;
/* Ratecontrol sometimes returns invalid rate index */
if (tx_info_priv->rcs[0].rix != 0xff)
@ -2035,6 +2033,7 @@ static void ath_rate_init(void *priv, void *priv_sta,
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_conf *conf = &local->hw.conf;
struct ath_softc *sc = hw->priv;
struct ath_rate_node *ath_rc_priv = priv_sta;
int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
@ -2046,12 +2045,11 @@ static void ath_rate_init(void *priv, void *priv_sta,
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
for (i = 0; i < MCS_SET_SIZE; i++) {
if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
((struct ath_rate_node *)
priv_sta)->neg_ht_rates.rs_rates[j++] = i;
ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
if (j == ATH_RATE_MAX)
break;
}
((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j;
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
ath_rc_node_update(hw, priv_sta);
}
@ -2066,7 +2064,7 @@ static void *ath_rate_alloc(struct ieee80211_local *local)
struct ieee80211_hw *hw = local_to_hw(local);
struct ath_softc *sc = hw->priv;
DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
return local->hw.priv;
}
@ -2081,14 +2079,17 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
struct ath_vap *avp = sc->sc_vaps[0];
struct ath_rate_node *rate_priv;
DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
if (!rate_priv) {
DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate"
"private rate control structure", __func__);
DPRINTF(sc, ATH_DBG_FATAL,
"%s: Unable to allocate private rc structure\n",
__func__);
return NULL;
}
ath_rc_sib_init(rate_priv);
return rate_priv;
}

View file

@ -71,9 +71,6 @@ enum ieee80211_fixed_rate_mode {
*/
#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
#define SHORT_PRE 1
#define LONG_PRE 0
#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS
#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS
#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI
@ -102,18 +99,18 @@ enum {
WLAN_RC_PHY_MAX
};
#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
@ -135,56 +132,59 @@ enum {
#define WLAN_RC_SGI_FLAG (0x04)
#define WLAN_RC_HT_FLAG (0x08)
/* Index into the rate table */
#define INIT_RATE_MAX_20 23
#define INIT_RATE_MAX_40 40
#define RATE_TABLE_SIZE 64
/* XXX: Convert to kdoc */
/**
* struct ath_rate_table - Rate Control table
* @valid: valid for use in rate control
* @valid_single_stream: valid for use in rate control for
* single stream operation
* @phy: CCK/OFDM
* @ratekbps: rate in Kbits per second
* @user_ratekbps: user rate in Kbits per second
* @ratecode: rate that goes into HW descriptors
* @short_preamble: Mask for enabling short preamble in ratecode for CCK
* @dot11rate: value that goes into supported
* rates info element of MLME
* @ctrl_rate: Index of next lower basic rate, used for duration computation
* @max_4ms_framelen: maximum frame length(bytes) for tx duration
* @probe_interval: interval for rate control to probe for other rates
* @rssi_reduce_interval: interval for rate control to reduce rssi
* @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
*/
struct ath_rate_table {
int rate_cnt;
struct {
int valid; /* Valid for use in rate control */
int valid_single_stream;/* Valid for use in rate control
for single stream operation */
u8 phy; /* CCK/OFDM/TURBO/XR */
u32 ratekbps; /* Rate in Kbits per second */
u32 user_ratekbps; /* User rate in KBits per second */
u8 ratecode; /* rate that goes into
hw descriptors */
u8 short_preamble; /* Mask for enabling short preamble
in rate code for CCK */
u8 dot11rate; /* Value that goes into supported
rates info element of MLME */
u8 ctrl_rate; /* Index of next lower basic rate,
used for duration computation */
int8_t rssi_ack_validmin; /* Rate control related */
int8_t rssi_ack_deltamin; /* Rate control related */
u8 base_index; /* base rate index */
u8 cw40index; /* 40cap rate index */
u8 sgi_index; /* shortgi rate index */
u8 ht_index; /* shortgi rate index */
u32 max_4ms_framelen; /* Maximum frame length(bytes)
for 4ms tx duration */
int valid;
int valid_single_stream;
u8 phy;
u32 ratekbps;
u32 user_ratekbps;
u8 ratecode;
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
int8_t rssi_ack_validmin;
int8_t rssi_ack_deltamin;
u8 base_index;
u8 cw40index;
u8 sgi_index;
u8 ht_index;
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval; /* interval for ratectrl to
probe for other rates */
u32 rssi_reduce_interval; /* interval for ratectrl
to reduce RSSI */
u8 initial_ratemax; /* the initial ratemax value used
in ath_rc_sib_update() */
u32 probe_interval;
u32 rssi_reduce_interval;
u8 initial_ratemax;
};
#define ATH_RC_PROBE_ALLOWED 0x00000001
#define ATH_RC_MINRATE_LASTRATE 0x00000002
#define ATH_RC_SHORT_PREAMBLE 0x00000004
struct ath_rc_series {
u8 rix;
u8 tries;
u8 flags;
u32 max_4ms_framelen;
u8 rix;
u8 tries;
u8 flags;
u32 max_4ms_framelen;
};
/* rcs_flags definition */
@ -201,42 +201,56 @@ struct ath_rc_series {
#define MAX_TX_RATE_PHY 48
struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
};
/**
* struct ath_tx_ratectrl - TX Rate control Information
* @state: RC state
* @rssi_last: last ACK rssi
* @rssi_last_lookup: last ACK rssi used for lookup
* @rssi_last_prev: previous last ACK rssi
* @rssi_last_prev2: 2nd previous last ACK rssi
* @rssi_sum_cnt: count of rssi_sum for averaging
* @rssi_sum_rate: rate that we are averaging
* @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at
* @rssi_time: msec timestamp for last ack rssi
* @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
* @probe_interval: interval for ratectrl to probe for other rates
*/
struct ath_tx_ratectrl {
struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */
int8_t rssi_last; /* last ack rssi */
int8_t rssi_last_lookup; /* last ack rssi used for lookup */
int8_t rssi_last_prev; /* previous last ack rssi */
int8_t rssi_last_prev2; /* 2nd previous last ack rssi */
int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */
int32_t rssi_sum_rate; /* rate that we are averaging */
int32_t rssi_sum; /* running sum of rssi for averaging */
u32 valid_txrate_mask; /* mask of valid rates */
u8 rate_table_size; /* rate table size */
u8 rate_max; /* max rate that has recently worked */
u8 probe_rate; /* rate we are probing at */
u32 rssi_time; /* msec timestamp for last ack rssi */
u32 rssi_down_time; /* msec timestamp for last down step */
u32 probe_time; /* msec timestamp for last probe */
u8 hw_maxretry_pktcnt; /* num packets since we got
HW max retry error */
u8 max_valid_rate; /* maximum number of valid rate */
u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */
u32 per_down_time; /* msec timstamp for last
PER down step */
struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
int8_t rssi_last;
int8_t rssi_last_lookup;
int8_t rssi_last_prev;
int8_t rssi_last_prev2;
int32_t rssi_sum_cnt;
int32_t rssi_sum_rate;
int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
u32 rssi_time;
u32 rssi_down_time;
u32 probe_time;
u8 hw_maxretry_pktcnt;
u8 max_valid_rate;
u8 valid_rate_index[MAX_TX_RATE_TBL];
u32 per_down_time;
/* 11n state */
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
u8 rc_phy_mode;
u8 rate_max_phy; /* Phy index for the max rate */
u32 rate_max_lastused; /* msec timstamp of when we
last used rateMaxPhy */
u32 probe_interval; /* interval for ratectrl to probe
for other rates */
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
u8 rc_phy_mode;
u8 rate_max_phy;
u32 probe_interval;
};
struct ath_rateset {
@ -248,29 +262,32 @@ struct ath_rateset {
struct ath_rate_softc {
/* phy tables that contain rate control data */
const void *hw_rate_table[ATH9K_MODE_MAX];
int fixedrix; /* -1 or index of fixed rate */
/* -1 or index of fixed rate */
int fixedrix;
};
/* per-node state */
struct ath_rate_node {
struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */
u32 prev_data_rix; /* rate idx of last data frame */
struct ath_tx_ratectrl tx_ratectrl;
/* map of rate ix -> negotiated rate set ix */
u8 rixmap[MAX_TX_RATE_TBL];
/* rate idx of last data frame */
u32 prev_data_rix;
/* map of ht rate ix -> negotiated rate set ix */
u8 ht_rixmap[MAX_TX_RATE_TBL];
/* ht capabilities */
u8 ht_cap;
u8 ht_cap; /* ht capabilities */
u8 ant_tx; /* current transmit antenna */
/* When TRUE, only single stream Tx possible */
u8 single_stream;
u8 single_stream; /* When TRUE, only single
stream Tx possible */
struct ath_rateset neg_rates; /* Negotiated rates */
struct ath_rateset neg_ht_rates; /* Negotiated HT rates */
struct ath_rate_softc *asc; /* back pointer to atheros softc */
struct ath_vap *avp; /* back pointer to vap */
/* Negotiated rates */
struct ath_rateset neg_rates;
/* Negotiated HT rates */
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
struct ath_vap *avp;
};
/* Driver data of ieee80211_tx_info */
@ -296,18 +313,11 @@ void ath_rate_detach(struct ath_rate_softc *asc);
void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
/*
* Return the tx rate series.
*/
void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv,
int num_tries, int num_rates,
unsigned int rcflag, struct ath_rc_series[],
int *is_probe, int isretry);
/*
* Return rate index for given Dot11 Rate.
*/
u8 ath_rate_findrateix(struct ath_softc *sc,
u8 dot11_rate);
u8 dot11_rate);
/* Routines to register/unregister rate control algorithm */
int ath_rate_control_register(void);

View file

@ -184,7 +184,7 @@ static int ath_ampdu_input(struct ath_softc *sc,
tid = qc[0] & 0xf;
}
if (sc->sc_opmode == ATH9K_M_STA) {
if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
/* Drop the frame not belonging to me. */
if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
dev_kfree_skb(skb);
@ -448,17 +448,16 @@ static int ath_rx_indicate(struct ath_softc *sc,
int type;
/* indicate frame to the stack, which will free the old skb. */
type = ath__rx_indicate(sc, skb, status, keyix);
type = _ath_rx_indicate(sc, skb, status, keyix);
/* allocate a new skb and queue it to for H/W processing */
nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
if (nskb != NULL) {
bf->bf_mpdu = nskb;
bf->bf_buf_addr = ath_skb_map_single(sc,
nskb,
PCI_DMA_FROMDEVICE,
/* XXX: Remove get_dma_mem_context() */
get_dma_mem_context(bf, bf_dmacontext));
bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
skb_end_pointer(nskb) - nskb->head,
PCI_DMA_FROMDEVICE);
bf->bf_dmacontext = bf->bf_buf_addr;
ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
/* queue the new wbuf to H/W */
@ -504,7 +503,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
do {
spin_lock_init(&sc->sc_rxflushlock);
sc->sc_rxflush = 0;
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->sc_rxbuflock);
/*
@ -541,9 +540,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}
bf->bf_mpdu = skb;
bf->bf_buf_addr =
ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE,
get_dma_mem_context(bf, bf_dmacontext));
bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
skb_end_pointer(skb) - skb->head,
PCI_DMA_FROMDEVICE);
bf->bf_dmacontext = bf->bf_buf_addr;
ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
}
sc->sc_rxlink = NULL;
@ -597,6 +597,7 @@ void ath_rx_cleanup(struct ath_softc *sc)
u32 ath_calcrxfilter(struct ath_softc *sc)
{
#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
u32 rfilt;
rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
@ -604,25 +605,29 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
| ATH9K_RX_FILTER_MCAST;
/* If not a STA, enable processing of Probe Requests */
if (sc->sc_opmode != ATH9K_M_STA)
if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/* Can't set HOSTAP into promiscous mode */
if (sc->sc_opmode == ATH9K_M_MONITOR) {
if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
(sc->rx_filter & FIF_PROMISC_IN_BSS)) ||
(sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
rfilt |= ATH9K_RX_FILTER_PROM;
/* ??? To prevent from sending ACK */
rfilt &= ~ATH9K_RX_FILTER_UCAST;
}
if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS ||
sc->sc_scanning)
if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
(sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) ||
(sc->sc_ah->ah_opmode == ATH9K_M_IBSS))
rfilt |= ATH9K_RX_FILTER_BEACON;
/* If in HOSTAP mode, want to enable reception of PSPOLL frames
& beacon frames */
if (sc->sc_opmode == ATH9K_M_HOSTAP)
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
return rfilt;
#undef RX_FILTER_PRESERVE
}
@ -702,11 +707,11 @@ void ath_flushrecv(struct ath_softc *sc)
* progress (see references to sc_rxflush)
*/
spin_lock_bh(&sc->sc_rxflushlock);
sc->sc_rxflush = 1;
sc->sc_flags |= SC_OP_RXFLUSH;
ath_rx_tasklet(sc, 1);
sc->sc_rxflush = 0;
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_unlock_bh(&sc->sc_rxflushlock);
}
@ -719,7 +724,7 @@ int ath_rx_input(struct ath_softc *sc,
struct ath_recv_status *rx_status,
enum ATH_RX_TYPE *status)
{
if (is_ampdu && sc->sc_rxaggr) {
if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) {
*status = ATH_RX_CONSUMED;
return ath_ampdu_input(sc, an, skb, rx_status);
} else {
@ -750,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
do {
/* If handling rx interrupt and flush is in progress => exit */
if (sc->sc_rxflush && (flush == 0))
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
break;
spin_lock_bh(&sc->sc_rxbuflock);
@ -900,7 +905,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* Enable this if you want to see
* error frames in Monitor mode.
*/
if (sc->sc_opmode != ATH9K_M_MONITOR)
if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
goto rx_next;
#endif
/* fall thru for monitor mode handling... */
@ -945,7 +950,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
if (sc->sc_opmode == ATH9K_M_MONITOR) {
if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
if (ds->ds_rxstat.rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_CRC))
@ -1089,7 +1094,7 @@ rx_next:
"%s: Reset rx chain mask. "
"Do internal reset\n", __func__);
ASSERT(flush == 0);
ath_internal_reset(sc);
ath_reset(sc, false);
}
return 0;
@ -1127,7 +1132,7 @@ int ath_rx_aggr_start(struct ath_softc *sc,
rxtid = &an->an_aggr.rx.tid[tid];
spin_lock_bh(&rxtid->tidlock);
if (sc->sc_rxaggr) {
if (sc->sc_flags & SC_OP_RXAGGR) {
/* Allow aggregation reception
* Adjust rx BA window size. Peer might indicate a
* zero buffer size for a _dont_care_ condition.
@ -1227,7 +1232,7 @@ void ath_rx_aggr_teardown(struct ath_softc *sc,
void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
{
if (sc->sc_rxaggr) {
if (sc->sc_flags & SC_OP_RXAGGR) {
struct ath_arx_tid *rxtid;
int tidno;
@ -1259,7 +1264,7 @@ void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
{
if (sc->sc_rxaggr) {
if (sc->sc_flags & SC_OP_RXAGGR) {
struct ath_arx_tid *rxtid;
int tidno, i;
@ -1292,27 +1297,3 @@ void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
{
ath_rx_node_cleanup(sc, an);
}
dma_addr_t ath_skb_map_single(struct ath_softc *sc,
struct sk_buff *skb,
int direction,
dma_addr_t *pa)
{
/*
* NB: do NOT use skb->len, which is 0 on initialization.
* Use skb's entire data area instead.
*/
*pa = pci_map_single(sc->pdev, skb->data,
skb_end_pointer(skb) - skb->head, direction);
return *pa;
}
void ath_skb_unmap_single(struct ath_softc *sc,
struct sk_buff *skb,
int direction,
dma_addr_t *pa)
{
/* Unmap skb's entire data area */
pci_unmap_single(sc->pdev, *pa,
skb_end_pointer(skb) - skb->head, direction);
}

View file

@ -899,12 +899,6 @@ enum {
#define AR_GPIO_OUTPUT_MUX2 0x4064
#define AR_GPIO_OUTPUT_MUX3 0x4068
#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
#define AR_INPUT_STATE 0x406c
#define AR_EEPROM_STATUS_DATA 0x407c

View file

@ -59,79 +59,6 @@ static u32 bits_per_symbol[][2] = {
#define IS_HT_RATE(_rate) ((_rate) & 0x80)
/*
* Insert a chain of ath_buf (descriptors) on a multicast txq
* but do NOT start tx DMA on this queue.
* NB: must be called with txq lock held
*/
static void ath_tx_mcastqaddbuf(struct ath_softc *sc,
struct ath_txq *txq,
struct list_head *head)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
if (list_empty(head))
return;
/*
* Insert the frame on the outbound list and
* pass it on to the hardware.
*/
bf = list_first_entry(head, struct ath_buf, list);
/*
* The CAB queue is started from the SWBA handler since
* frames only go out on DTIM and to avoid possible races.
*/
ath9k_hw_set_interrupts(ah, 0);
/*
* If there is anything in the mcastq, we want to set
* the "more data" bit in the last item in the queue to
* indicate that there is "more data". It makes sense to add
* it here since you are *always* going to have
* more data when adding to this queue, no matter where
* you call from.
*/
if (txq->axq_depth) {
struct ath_buf *lbf;
struct ieee80211_hdr *hdr;
/*
* Add the "more data flag" to the last frame
*/
lbf = list_entry(txq->axq_q.prev, struct ath_buf, list);
hdr = (struct ieee80211_hdr *)
((struct sk_buff *)(lbf->bf_mpdu))->data;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
/*
* Now, concat the frame onto the queue
*/
list_splice_tail_init(head, &txq->axq_q);
txq->axq_depth++;
txq->axq_totalqueued++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
DPRINTF(sc, ATH_DBG_QUEUE,
"%s: txq depth = %d\n", __func__, txq->axq_depth);
if (txq->axq_link != NULL) {
*txq->axq_link = bf->bf_daddr;
DPRINTF(sc, ATH_DBG_XMIT,
"%s: link[%u](%p)=%llx (%p)\n",
__func__,
txq->axq_qnum, txq->axq_link,
ito64(bf->bf_daddr), bf->bf_desc);
}
txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
ath9k_hw_set_interrupts(ah, sc->sc_imask);
}
/*
* Insert a chain of ath_buf (descriptors) on a txq and
* assume the descriptors are already chained together by caller.
@ -277,8 +204,6 @@ static int ath_tx_prepare(struct ath_softc *sc,
__le16 fc;
u8 *qc;
memset(txctl, 0, sizeof(struct ath_tx_control));
txctl->dev = sc;
hdr = (struct ieee80211_hdr *)skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@ -302,7 +227,6 @@ static int ath_tx_prepare(struct ath_softc *sc,
}
txctl->if_id = 0;
txctl->nextfraglen = 0;
txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
txctl->txpower = MAX_RATE_POWER; /* FIXME */
@ -329,12 +253,18 @@ static int ath_tx_prepare(struct ath_softc *sc,
/* Fill qnum */
txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
txq = &sc->sc_txq[txctl->qnum];
if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) {
txctl->qnum = 0;
txq = sc->sc_cabq;
} else {
txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
txq = &sc->sc_txq[txctl->qnum];
}
spin_lock_bh(&txq->axq_lock);
/* Try to avoid running out of descriptors */
if (txq->axq_depth >= (ATH_TXBUF - 20)) {
if (txq->axq_depth >= (ATH_TXBUF - 20) &&
!(txctl->flags & ATH9K_TXDESC_CAB)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: TX queue: %d is full, depth: %d\n",
__func__,
@ -354,12 +284,12 @@ static int ath_tx_prepare(struct ath_softc *sc,
/* Fill flags */
txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
tx_info->flags |= ATH9K_TXDESC_NOACK;
txctl->flags |= ATH9K_TXDESC_NOACK;
if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
tx_info->flags |= ATH9K_TXDESC_RTSENA;
txctl->flags |= ATH9K_TXDESC_RTSENA;
/*
* Setup for rate calculations.
@ -392,7 +322,7 @@ static int ath_tx_prepare(struct ath_softc *sc,
* incremented by the fragmentation routine.
*/
if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
txctl->ht && sc->sc_txaggr) {
txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
struct ath_atx_tid *tid;
tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
@ -413,50 +343,18 @@ static int ath_tx_prepare(struct ath_softc *sc,
}
rix = rcs[0].rix;
/*
* Calculate duration. This logically belongs in the 802.11
* layer but it lacks sufficient information to calculate it.
*/
if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) {
u16 dur;
if (ieee80211_has_morefrags(fc) ||
(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
/*
* XXX not right with fragmentation.
*/
if (sc->sc_flags & ATH_PREAMBLE_SHORT)
dur = rt->info[rix].spAckDuration;
else
dur = rt->info[rix].lpAckDuration;
if (le16_to_cpu(hdr->frame_control) &
IEEE80211_FCTL_MOREFRAGS) {
dur += dur; /* Add additional 'SIFS + ACK' */
/*
** Compute size of next fragment in order to compute
** durations needed to update NAV.
** The last fragment uses the ACK duration only.
** Add time for next fragment.
*/
dur += ath9k_hw_computetxtime(sc->sc_ah, rt,
txctl->nextfraglen,
rix, sc->sc_flags & ATH_PREAMBLE_SHORT);
}
if (ieee80211_has_morefrags(fc) ||
(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
/*
** Force hardware to use computed duration for next
** fragment by disabling multi-rate retry, which
** updates duration based on the multi-rate
** duration table.
*/
rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
/* reset tries but keep rate index */
rcs[0].tries = ATH_TXMAXTRY;
}
hdr->duration_id = cpu_to_le16(dur);
** Force hardware to use computed duration for next
** fragment by disabling multi-rate retry, which
** updates duration based on the multi-rate
** duration table.
*/
rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
/* reset tries but keep rate index */
rcs[0].tries = ATH_TXMAXTRY;
}
/*
@ -484,12 +382,8 @@ static int ath_tx_prepare(struct ath_softc *sc,
if (is_multicast_ether_addr(hdr->addr1)) {
antenna = sc->sc_mcastantenna + 1;
sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
} else
antenna = sc->sc_txantenna;
}
#ifdef USE_LEGACY_HAL
txctl->antenna = antenna;
#endif
return 0;
}
@ -502,7 +396,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_xmit_status tx_status;
dma_addr_t *pa;
/*
* Set retry information.
@ -518,13 +411,12 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
if (!txok) {
tx_status.flags |= ATH_TX_ERROR;
if (bf->bf_isxretried)
if (bf_isxretried(bf))
tx_status.flags |= ATH_TX_XRETRY;
}
/* Unmap this frame */
pa = get_dma_mem_context(bf, bf_dmacontext);
pci_unmap_single(sc->pdev,
*pa,
bf->bf_dmacontext,
skb->len,
PCI_DMA_TODEVICE);
/* complete this frame */
@ -629,7 +521,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc,
if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
return 0;
isaggr = bf->bf_isaggr;
isaggr = bf_isaggr(bf);
if (isaggr) {
seq_st = ATH_DS_BA_SEQ(ds);
memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3);
@ -651,7 +543,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
bf->bf_isretried = 1;
bf->bf_state.bf_type |= BUF_RETRY;
bf->bf_retries++;
skb = bf->bf_mpdu;
@ -698,7 +590,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc,
u8 rc;
int streams, pktlen;
pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
rc = rt->info[rix].rateCode;
/*
@ -742,7 +634,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
int i, flags, rtsctsena = 0, dynamic_mimops = 0;
u32 ctsduration = 0;
u8 rix = 0, cix, ctsrate = 0;
u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit;
u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit;
struct ath_node *an = (struct ath_node *) bf->bf_node;
/*
@ -781,7 +673,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* let rate series flags determine which rates will actually
* use RTS.
*/
if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) {
if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
BUG_ON(!an);
/*
* 802.11g protection not needed, use our default behavior
@ -793,7 +685,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* and the second aggregate should have any protection at all.
*/
if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
if (!bf->bf_aggrburst) {
if (!bf_isaggrburst(bf)) {
flags = ATH9K_TXDESC_RTSENA;
dynamic_mimops = 1;
} else {
@ -806,7 +698,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* Set protection if aggregate protection on
*/
if (sc->sc_config.ath_aggr_prot &&
(!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) {
(!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
flags = ATH9K_TXDESC_RTSENA;
cix = rt->info[sc->sc_protrix].controlRate;
rtsctsena = 1;
@ -815,7 +707,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
/*
* For AR5416 - RTS cannot be followed by a frame larger than 8K.
*/
if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) {
if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) {
/*
* Ensure that in the case of SM Dynamic power save
* while we are bursting the second aggregate the
@ -832,7 +724,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
/* NB: cix is set above where RTS/CTS is enabled */
BUG_ON(cix == 0xff);
ctsrate = rt->info[cix].rateCode |
(bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0);
(bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
/*
* Setup HAL rate series
@ -846,7 +738,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
rix = bf->bf_rcs[i].rix;
series[i].Rate = rt->info[rix].rateCode |
(bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0);
(bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
series[i].Tries = bf->bf_rcs[i].tries;
@ -862,7 +754,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
sc, rix, bf,
(bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
(bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
bf->bf_shpreamble);
bf_isshpreamble(bf));
if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
(bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
@ -875,7 +767,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
*/
series[i].ChSel = sc->sc_tx_chainmask;
} else {
if (bf->bf_ht)
if (bf_isht(bf))
series[i].ChSel =
ath_chainmask_sel_logic(sc, an);
else
@ -908,7 +800,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* use the precalculated ACK durations.
*/
if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */
ctsduration += bf->bf_shpreamble ?
ctsduration += bf_isshpreamble(bf) ?
rt->info[cix].spAckDuration :
rt->info[cix].lpAckDuration;
}
@ -916,7 +808,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
ctsduration += series[0].PktDuration;
if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
ctsduration += bf->bf_shpreamble ?
ctsduration += bf_isshpreamble(bf) ?
rt->info[rix].spAckDuration :
rt->info[rix].lpAckDuration;
}
@ -932,10 +824,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* set dur_update_en for l-sig computation except for PS-Poll frames
*/
ath9k_hw_set11n_ratescenario(ah, ds, lastds,
!bf->bf_ispspoll,
ctsrate,
ctsduration,
series, 4, flags);
!bf_ispspoll(bf),
ctsrate,
ctsduration,
series, 4, flags);
if (sc->sc_config.ath_aggr_prot && flags)
ath9k_hw_set11n_burstduration(ah, ds, 8192);
}
@ -958,7 +850,7 @@ static int ath_tx_send_normal(struct ath_softc *sc,
BUG_ON(list_empty(bf_head));
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_isampdu = 0; /* regular HT frame */
bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */
skb = (struct sk_buff *)bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
@ -998,7 +890,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while (!list_empty(&tid->buf_q)) {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
ASSERT(!bf->bf_isretried);
ASSERT(!bf_isretried(bf));
list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
ath_tx_send_normal(sc, txq, tid, &bf_head);
}
@ -1025,7 +917,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
isaggr = bf->bf_isaggr;
isaggr = bf_isaggr(bf);
if (isaggr) {
if (txok) {
if (ATH_DS_TX_BA(ds)) {
@ -1047,7 +939,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
* when perform internal reset in this routine.
* Only enable reset in STA mode for now.
*/
if (sc->sc_opmode == ATH9K_M_STA)
if (sc->sc_ah->ah_opmode == ATH9K_M_STA)
needreset = 1;
}
} else {
@ -1075,7 +967,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
ath_tx_set_retry(sc, bf);
txpending = 1;
} else {
bf->bf_isxretried = 1;
bf->bf_state.bf_type |= BUF_XRETRY;
txfail = 1;
sendbar = 1;
}
@ -1175,11 +1067,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
tbf->bf_lastfrm->bf_desc);
/* copy the DMA context */
copy_dma_mem_context(
get_dma_mem_context(tbf,
bf_dmacontext),
get_dma_mem_context(bf_last,
bf_dmacontext));
tbf->bf_dmacontext =
bf_last->bf_dmacontext;
}
list_add_tail(&tbf->list, &bf_head);
} else {
@ -1188,7 +1077,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
* software retry
*/
ath9k_hw_cleartxdesc(sc->sc_ah,
bf->bf_lastfrm->bf_desc);
bf->bf_lastfrm->bf_desc);
}
/*
@ -1242,7 +1131,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
}
if (needreset)
ath_internal_reset(sc);
ath_reset(sc, false);
return;
}
@ -1331,7 +1220,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_depth--;
if (bf->bf_isaggr)
if (bf_isaggr(bf))
txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0);
@ -1345,14 +1234,14 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
spin_unlock_bh(&sc->sc_txbuflock);
}
if (!bf->bf_isampdu) {
if (!bf_isampdu(bf)) {
/*
* This frame is sent out as a single frame.
* Use hardware retry status for this frame.
*/
bf->bf_retries = ds->ds_txstat.ts_longretry;
if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_isxretried = 1;
bf->bf_state.bf_type |= BUF_XRETRY;
nbad = 0;
} else {
nbad = ath_tx_num_badfrms(sc, bf, txok);
@ -1368,7 +1257,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (ds->ds_txstat.ts_status == 0)
nacked++;
if (bf->bf_isdata) {
if (bf_isdata(bf)) {
if (isrifs)
tmp_ds = bf->bf_rifslast->bf_desc;
else
@ -1384,7 +1273,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
/*
* Complete this transmit unit
*/
if (bf->bf_isampdu)
if (bf_isampdu(bf))
ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok);
else
ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
@ -1406,7 +1295,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
/*
* schedule any pending packets if aggregation is enabled
*/
if (sc->sc_txaggr)
if (sc->sc_flags & SC_OP_TXAGGR)
ath_txq_schedule(sc, txq);
spin_unlock_bh(&txq->axq_lock);
}
@ -1430,10 +1319,9 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
struct ath_hal *ah = sc->sc_ah;
int i;
int npend = 0;
enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
/* XXX return value */
if (!sc->sc_invalid) {
if (!(sc->sc_flags & SC_OP_INVALID)) {
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
ath_tx_stopdma(sc, &sc->sc_txq[i]);
@ -1454,10 +1342,11 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
"%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, sc->sc_opmode,
&sc->sc_curchan, ht_macmode,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, true, &status)) {
if (!ath9k_hw_reset(ah,
sc->sc_ah->ah_curchan,
sc->sc_ht_info.tx_chan_width,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, true, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to reset hardware; hal status %u\n",
@ -1481,7 +1370,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc,
{
int index, cindex;
if (bf->bf_isretried)
if (bf_isretried(bf))
return;
index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
@ -1516,7 +1405,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
BUG_ON(list_empty(bf_head));
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_isampdu = 1;
bf->bf_state.bf_type |= BUF_AMPDU;
bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
bf->bf_tidno = txctl->tidno;
@ -1860,7 +1749,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc,
if (bf->bf_nframes == 1) {
ASSERT(bf->bf_lastfrm == bf_last);
bf->bf_isaggr = 0;
bf->bf_state.bf_type &= ~BUF_AGGR;
/*
* clear aggr bits for every descriptor
* XXX TODO: is there a way to optimize it?
@ -1877,7 +1766,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc,
/*
* setup first desc with rate and aggr info
*/
bf->bf_isaggr = 1;
bf->bf_state.bf_type |= BUF_AGGR;
ath_buf_set_rate(sc, bf);
ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
@ -1925,7 +1814,7 @@ static void ath_tid_drain(struct ath_softc *sc,
list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
/* update baw for software retried frame */
if (bf->bf_isretried)
if (bf_isretried(bf))
ath_tx_update_baw(sc, tid, bf->bf_seqno);
/*
@ -1990,13 +1879,18 @@ static int ath_tx_start_dma(struct ath_softc *sc,
struct list_head bf_head;
struct ath_desc *ds;
struct ath_hal *ah = sc->sc_ah;
struct ath_txq *txq = &sc->sc_txq[txctl->qnum];
struct ath_txq *txq;
struct ath_tx_info_priv *tx_info_priv;
struct ath_rc_series *rcs;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
__le16 fc = hdr->frame_control;
if (unlikely(txctl->flags & ATH9K_TXDESC_CAB))
txq = sc->sc_cabq;
else
txq = &sc->sc_txq[txctl->qnum];
/* For each sglist entry, allocate an ath_buf for DMA */
INIT_LIST_HEAD(&bf_head);
spin_lock_bh(&sc->sc_txbuflock);
@ -2014,11 +1908,21 @@ static int ath_tx_start_dma(struct ath_softc *sc,
/* set up this buffer */
ATH_TXBUF_RESET(bf);
bf->bf_frmlen = txctl->frmlen;
bf->bf_isdata = ieee80211_is_data(fc);
bf->bf_isbar = ieee80211_is_back_req(fc);
bf->bf_ispspoll = ieee80211_is_pspoll(fc);
ieee80211_is_data(fc) ?
(bf->bf_state.bf_type |= BUF_DATA) :
(bf->bf_state.bf_type &= ~BUF_DATA);
ieee80211_is_back_req(fc) ?
(bf->bf_state.bf_type |= BUF_BAR) :
(bf->bf_state.bf_type &= ~BUF_BAR);
ieee80211_is_pspoll(fc) ?
(bf->bf_state.bf_type |= BUF_PSPOLL) :
(bf->bf_state.bf_type &= ~BUF_PSPOLL);
(sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
(bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
bf->bf_flags = txctl->flags;
bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT;
bf->bf_keytype = txctl->keytype;
tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
rcs = tx_info_priv->rcs;
@ -2038,8 +1942,7 @@ static int ath_tx_start_dma(struct ath_softc *sc,
/*
* Save the DMA context in the first ath_buf
*/
copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext),
get_dma_mem_context(txctl, dmacontext));
bf->bf_dmacontext = txctl->dmacontext;
/*
* Formulate first tx descriptor with tx controls.
@ -2060,11 +1963,13 @@ static int ath_tx_start_dma(struct ath_softc *sc,
ds); /* first descriptor */
bf->bf_lastfrm = bf;
bf->bf_ht = txctl->ht;
(txctl->ht) ?
(bf->bf_state.bf_type |= BUF_HT) :
(bf->bf_state.bf_type &= ~BUF_HT);
spin_lock_bh(&txq->axq_lock);
if (txctl->ht && sc->sc_txaggr) {
if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
if (ath_aggr_query(sc, an, txctl->tidno)) {
/*
@ -2090,27 +1995,7 @@ static int ath_tx_start_dma(struct ath_softc *sc,
bf->bf_tidno = txctl->tidno;
}
if (is_multicast_ether_addr(hdr->addr1)) {
struct ath_vap *avp = sc->sc_vaps[txctl->if_id];
/*
* When servicing one or more stations in power-save
* mode (or) if there is some mcast data waiting on
* mcast queue (to prevent out of order delivery of
* mcast,bcast packets) multicast frames must be
* buffered until after the beacon. We use the private
* mcast queue for that.
*/
/* XXX? more bit in 802.11 frame header */
spin_lock_bh(&avp->av_mcastq.axq_lock);
if (txctl->ps || avp->av_mcastq.axq_depth)
ath_tx_mcastqaddbuf(sc,
&avp->av_mcastq, &bf_head);
else
ath_tx_txqaddbuf(sc, txq, &bf_head);
spin_unlock_bh(&avp->av_mcastq.axq_lock);
} else
ath_tx_txqaddbuf(sc, txq, &bf_head);
ath_tx_txqaddbuf(sc, txq, &bf_head);
}
spin_unlock_bh(&txq->axq_lock);
return 0;
@ -2118,30 +2003,31 @@ static int ath_tx_start_dma(struct ath_softc *sc,
static void xmit_map_sg(struct ath_softc *sc,
struct sk_buff *skb,
dma_addr_t *pa,
struct ath_tx_control *txctl)
{
struct ath_xmit_status tx_status;
struct ath_atx_tid *tid;
struct scatterlist sg;
*pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
txctl->dmacontext = pci_map_single(sc->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
/* setup S/G list */
memset(&sg, 0, sizeof(struct scatterlist));
sg_dma_address(&sg) = *pa;
sg_dma_address(&sg) = txctl->dmacontext;
sg_dma_len(&sg) = skb->len;
if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
/*
* We have to do drop frame here.
*/
pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE);
pci_unmap_single(sc->pdev, txctl->dmacontext,
skb->len, PCI_DMA_TODEVICE);
tx_status.retries = 0;
tx_status.flags = ATH_TX_ERROR;
if (txctl->ht && sc->sc_txaggr) {
if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
/* Reclaim the seqno. */
tid = ATH_AN_2_TID((struct ath_node *)
txctl->an, txctl->tidno);
@ -2162,7 +2048,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
/* Setup tx descriptors */
error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
"tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC);
"tx", nbufs, 1);
if (error != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: failed to allocate tx descriptors: %d\n",
@ -2403,6 +2289,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
struct ath_tx_control txctl;
int error = 0;
memset(&txctl, 0, sizeof(struct ath_tx_control));
error = ath_tx_prepare(sc, skb, &txctl);
if (error == 0)
/*
@ -2410,9 +2297,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
* ath_tx_start_dma() will be called either synchronously
* or asynchrounsly once DMA is complete.
*/
xmit_map_sg(sc, skb,
get_dma_mem_context(&txctl, dmacontext),
&txctl);
xmit_map_sg(sc, skb, &txctl);
else
ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
@ -2424,8 +2309,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
void ath_tx_tasklet(struct ath_softc *sc)
{
u64 tsf = ath9k_hw_gettsf64(sc->sc_ah);
int i, nacked = 0;
int i;
u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
@ -2435,10 +2319,8 @@ void ath_tx_tasklet(struct ath_softc *sc)
*/
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
nacked += ath_tx_processq(sc, &sc->sc_txq[i]);
ath_tx_processq(sc, &sc->sc_txq[i]);
}
if (nacked)
sc->sc_lastrx = tsf;
}
void ath_tx_draintxq(struct ath_softc *sc,
@ -2486,14 +2368,14 @@ void ath_tx_draintxq(struct ath_softc *sc,
spin_unlock_bh(&txq->axq_lock);
if (bf->bf_isampdu)
if (bf_isampdu(bf))
ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0);
else
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
}
/* flush any pending frames if aggregation is enabled */
if (sc->sc_txaggr) {
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
spin_lock_bh(&txq->axq_lock);
ath_txq_drain_pending_buffers(sc, txq,
@ -2509,7 +2391,7 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx)
{
/* stop beacon queue. The beacon will be freed when
* we go to INIT state */
if (!sc->sc_invalid) {
if (!(sc->sc_flags & SC_OP_INVALID)) {
(void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__,
ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq));
@ -2536,7 +2418,7 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
struct ath_atx_tid *txtid;
DECLARE_MAC_BUF(mac);
if (!sc->sc_txaggr)
if (!(sc->sc_flags & SC_OP_TXAGGR))
return AGGR_NOT_REQUIRED;
/* ADDBA exchange must be completed before sending aggregates */
@ -2583,7 +2465,7 @@ int ath_tx_aggr_start(struct ath_softc *sc,
return -1;
}
if (sc->sc_txaggr) {
if (sc->sc_flags & SC_OP_TXAGGR) {
txtid = ATH_AN_2_TID(an, tid);
txtid->addba_exchangeinprogress = 1;
ath_tx_pause_tid(sc, txtid);
@ -2647,7 +2529,7 @@ void ath_tx_aggr_teardown(struct ath_softc *sc,
spin_lock_bh(&txq->axq_lock);
while (!list_empty(&txtid->buf_q)) {
bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
if (!bf->bf_isretried) {
if (!bf_isretried(bf)) {
/*
* NB: it's based on the assumption that
* software retried frame will always stay
@ -2743,7 +2625,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
{
if (sc->sc_txaggr) {
if (sc->sc_flags & SC_OP_TXAGGR) {
struct ath_atx_tid *tid;
struct ath_atx_ac *ac;
int tidno, acno;
@ -2855,7 +2737,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc,
void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
{
if (sc->sc_txaggr) {
if (sc->sc_flags & SC_OP_TXAGGR) {
struct ath_atx_tid *tid;
int tidno, i;
@ -2869,3 +2751,57 @@ void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
}
}
}
void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
{
int hdrlen, padsize;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_tx_control txctl;
/*
* As a temporary workaround, assign seq# here; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual
* BSSes.
*/
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
sc->seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
}
/* Add the padding after the header if this is not already done */
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
if (hdrlen & 3) {
padsize = hdrlen % 4;
if (skb_headroom(skb) < padsize) {
DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding "
"failed\n", __func__);
dev_kfree_skb_any(skb);
return;
}
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, hdrlen);
}
DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n",
__func__,
skb);
memset(&txctl, 0, sizeof(struct ath_tx_control));
txctl.flags = ATH9K_TXDESC_CAB;
if (ath_tx_prepare(sc, skb, &txctl) == 0) {
/*
* Start DMA mapping.
* ath_tx_start_dma() will be called either synchronously
* or asynchrounsly once DMA is complete.
*/
xmit_map_sg(sc, skb, &txctl);
} else {
ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__);
dev_kfree_skb_any(skb);
}
}

View file

@ -1,7 +1,9 @@
b43-y += main.o
b43-y += tables.o
b43-$(CONFIG_B43_NPHY) += tables_nphy.o
b43-y += phy.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o
b43-$(CONFIG_B43_NPHY) += nphy.o
b43-y += sysfs.o
b43-y += xmit.o

View file

@ -12,7 +12,7 @@
#include "leds.h"
#include "rfkill.h"
#include "lo.h"
#include "phy.h"
#include "phy_common.h"
/* The unique identifier of the firmware that's officially supported by
@ -173,6 +173,11 @@ enum {
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */
#define B43_SHM_SH_TSSI_OFDM_A 0x0068 /* TSSI for last 4 OFDM frames (32bit) */
#define B43_SHM_SH_TSSI_OFDM_G 0x0070 /* TSSI for last 4 OFDM frames (32bit) */
#define B43_TSSI_MAX 0x7F /* Max value for one TSSI value */
/* SHM_SHARED TX FIFO variables */
#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */
#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */
@ -508,122 +513,6 @@ struct b43_iv {
} __attribute__((__packed__));
struct b43_phy {
/* Band support flags. */
bool supports_2ghz;
bool supports_5ghz;
/* GMODE bit enabled? */
bool gmode;
/* Analog Type */
u8 analog;
/* B43_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
bool aci_enable;
bool aci_wlan_automatic;
bool aci_hw_rssi;
/* Radio switched on/off */
bool radio_on;
struct {
/* Values saved when turning the radio off.
* They are needed when turning it on again. */
bool valid;
u16 rfover;
u16 rfoverval;
} radio_off_context;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* TSSI to dBm table in use */
const s8 *tssi2dbm;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* LocalOscillator control values. */
struct b43_txpower_lo_control *lo_control;
/* Values from b43_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in b43_phy_xmitpower(). */
u8 power_level;
/* A-PHY TX Power control value. */
u16 txpwr_offset;
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
struct b43_rfatt rfatt;
u8 tx_control; /* B43_TXCTL_XXX */
/* Hardware Power Control enabled? */
bool hardware_power_control;
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define B43_INTERFSTACK_SIZE 26
u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
/* current channel */
u8 channel;
u16 lofcal;
u16 initval; //FIXME rename?
/* PHY TX errors counter. */
atomic_t txerr_cnt;
/* The device does address auto increment for the OFDM tables.
* We cache the previously used address here and omit the address
* write on the next table access, if possible. */
u16 ofdmtab_addr; /* The address currently set in hardware. */
enum { /* The last data flow direction. */
B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
B43_OFDMTAB_DIRECTION_READ,
B43_OFDMTAB_DIRECTION_WRITE,
} ofdmtab_addr_direction;
#if B43_DEBUG
/* Manual TX-power control enabled? */
bool manual_txpower_control;
/* PHY registers locked by b43_phy_lock()? */
bool phy_locked;
#endif /* B43_DEBUG */
};
/* Data structures for DMA transmission, per 80211 core. */
struct b43_dma {
struct b43_dmaring *tx_ring_AC_BK; /* Background */
@ -764,6 +653,11 @@ struct b43_wl {
struct b43_qos_params qos_params[4];
/* Workqueue for updating QOS parameters in hardware. */
struct work_struct qos_update_work;
/* Work for adjustment of the transmission power.
* This is scheduled when we determine that the actual TX output
* power doesn't match what we want. */
struct work_struct txpower_adjust_work;
};
/* In-memory representation of a cached microcode file. */
@ -908,6 +802,15 @@ static inline int b43_is_mode(struct b43_wl *wl, int type)
return (wl->operating && wl->if_type == type);
}
/**
* b43_current_band - Returns the currently used band.
* Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ.
*/
static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
{
return wl->hw->conf.channel->band;
}
static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
{
return ssb_read16(dev->dev, offset);

View file

@ -443,76 +443,6 @@ out_unlock:
return count;
}
static ssize_t txpower_g_read_file(struct b43_wldev *dev,
char *buf, size_t bufsize)
{
ssize_t count = 0;
if (dev->phy.type != B43_PHYTYPE_G) {
fappend("Device is not a G-PHY\n");
goto out;
}
fappend("Control: %s\n", dev->phy.manual_txpower_control ?
"MANUAL" : "AUTOMATIC");
fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att);
fappend("Radio attenuation: %u\n", dev->phy.rfatt.att);
fappend("TX Mixer Gain: %s\n",
(dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
fappend("PA Gain 2dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
fappend("PA Gain 3dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
fappend("\n\n");
fappend("You can write to this file:\n");
fappend("Writing \"auto\" enables automatic txpower control.\n");
fappend
("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
"enables manual txpower control.\n");
fappend("Example: 5 4 0 0 1\n");
fappend("Enables manual control with Baseband attenuation 5, "
"Radio attenuation 4, No TX Mixer Gain, "
"No PA Gain 2dB, With PA Gain 3dB.\n");
out:
return count;
}
static int txpower_g_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
if (dev->phy.type != B43_PHYTYPE_G)
return -ENODEV;
if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
/* Automatic control */
dev->phy.manual_txpower_control = 0;
b43_phy_xmitpower(dev);
} else {
int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
/* Manual control */
if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
&txmix, &pa2db, &pa3db) != 5)
return -EINVAL;
b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
dev->phy.manual_txpower_control = 1;
dev->phy.bbatt.att = bbatt;
dev->phy.rfatt.att = rfatt;
dev->phy.tx_control = 0;
if (txmix)
dev->phy.tx_control |= B43_TXCTL_TXMIX;
if (pa2db)
dev->phy.tx_control |= B43_TXCTL_PA2DB;
if (pa3db)
dev->phy.tx_control |= B43_TXCTL_PA3DB;
b43_phy_lock(dev);
b43_radio_lock(dev);
b43_set_txpower_g(dev, &dev->phy.bbatt,
&dev->phy.rfatt, dev->phy.tx_control);
b43_radio_unlock(dev);
b43_phy_unlock(dev);
}
return 0;
}
/* wl->irq_lock is locked */
static int restart_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
@ -560,7 +490,7 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,
err = -ENODEV;
goto out;
}
lo = phy->lo_control;
lo = phy->g->lo_control;
fappend("-- Local Oscillator calibration data --\n\n");
fappend("HW-power-control enabled: %d\n",
dev->phy.hardware_power_control);
@ -578,8 +508,8 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,
list_for_each_entry(cal, &lo->calib_list, list) {
bool active;
active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->rfatt));
active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d "
"(expires in %lu sec)%s\n",
cal->bbatt.att,
@ -763,7 +693,6 @@ B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
@ -877,7 +806,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
ADD_FILE(mmio32write, 0200);
ADD_FILE(tsf, 0600);
ADD_FILE(txstat, 0400);
ADD_FILE(txpower_g, 0600);
ADD_FILE(restart, 0200);
ADD_FILE(loctls, 0400);
@ -907,7 +835,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
debugfs_remove(e->file_mmio32write.dentry);
debugfs_remove(e->file_tsf.dentry);
debugfs_remove(e->file_txstat.dentry);
debugfs_remove(e->file_txpower_g.dentry);
debugfs_remove(e->file_restart.dentry);
debugfs_remove(e->file_loctls.dentry);

View file

@ -29,7 +29,7 @@
#include "b43.h"
#include "lo.h"
#include "phy.h"
#include "phy_g.h"
#include "main.h"
#include <linux/delay.h>
@ -174,7 +174,8 @@ static u16 lo_txctl_register_table(struct b43_wldev *dev,
static void lo_measure_txctl_values(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
u16 reg, mask;
u16 trsw_rx, pga;
u16 radio_pctl_reg;
@ -195,7 +196,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
int lb_gain; /* Loopback gain (in dB) */
trsw_rx = 0;
lb_gain = phy->max_lb_gain / 2;
lb_gain = gphy->max_lb_gain / 2;
if (lb_gain > 10) {
radio_pctl_reg = 0;
pga = abs(10 - lb_gain) / 6;
@ -226,7 +227,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
}
b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
& 0xFFF0) | radio_pctl_reg);
b43_phy_set_baseband_attenuation(dev, 2);
b43_gphy_set_baseband_attenuation(dev, 2);
reg = lo_txctl_register_table(dev, &mask, NULL);
mask = ~mask;
@ -277,7 +278,8 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
static void lo_read_power_vector(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
int i;
u64 tmp;
u64 power_vector = 0;
@ -298,6 +300,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
s16 max_rx_gain, int use_trsw_rx)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
u16 tmp;
if (max_rx_gain < 0)
@ -308,7 +311,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
int trsw_rx_gain;
if (use_trsw_rx) {
trsw_rx_gain = phy->trsw_rx_gain / 2;
trsw_rx_gain = gphy->trsw_rx_gain / 2;
if (max_rx_gain >= trsw_rx_gain) {
trsw_rx_gain = max_rx_gain - trsw_rx_gain;
trsw_rx = 0x20;
@ -316,38 +319,38 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
} else
trsw_rx_gain = max_rx_gain;
if (trsw_rx_gain < 9) {
phy->lna_lod_gain = 0;
gphy->lna_lod_gain = 0;
} else {
phy->lna_lod_gain = 1;
gphy->lna_lod_gain = 1;
trsw_rx_gain -= 8;
}
trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
phy->pga_gain = trsw_rx_gain / 3;
if (phy->pga_gain >= 5) {
phy->pga_gain -= 5;
phy->lna_gain = 2;
gphy->pga_gain = trsw_rx_gain / 3;
if (gphy->pga_gain >= 5) {
gphy->pga_gain -= 5;
gphy->lna_gain = 2;
} else
phy->lna_gain = 0;
gphy->lna_gain = 0;
} else {
phy->lna_gain = 0;
phy->trsw_rx_gain = 0x20;
gphy->lna_gain = 0;
gphy->trsw_rx_gain = 0x20;
if (max_rx_gain >= 0x14) {
phy->lna_lod_gain = 1;
phy->pga_gain = 2;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 2;
} else if (max_rx_gain >= 0x12) {
phy->lna_lod_gain = 1;
phy->pga_gain = 1;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 1;
} else if (max_rx_gain >= 0xF) {
phy->lna_lod_gain = 1;
phy->pga_gain = 0;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 0;
} else {
phy->lna_lod_gain = 0;
phy->pga_gain = 0;
gphy->lna_lod_gain = 0;
gphy->pga_gain = 0;
}
}
tmp = b43_radio_read16(dev, 0x7A);
if (phy->lna_lod_gain == 0)
if (gphy->lna_lod_gain == 0)
tmp &= ~0x0008;
else
tmp |= 0x0008;
@ -392,10 +395,11 @@ static void lo_measure_setup(struct b43_wldev *dev,
{
struct ssb_sprom *sprom = &dev->dev->bus->sprom;
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
u16 tmp;
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
@ -496,7 +500,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
if (phy->rev >= 2)
b43_dummy_transmission(dev);
b43_radio_selectchannel(dev, 6, 0);
b43_gphy_channel_switch(dev, 6, 0);
b43_radio_read16(dev, 0x51); /* dummy read */
if (phy->type == B43_PHYTYPE_G)
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
@ -520,18 +524,19 @@ static void lo_measure_restore(struct b43_wldev *dev,
struct lo_g_saved_values *sav)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
u16 tmp;
if (phy->rev >= 2) {
b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
tmp = (phy->pga_gain << 8);
tmp = (gphy->pga_gain << 8);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
udelay(5);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
udelay(2);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
} else {
tmp = (phy->pga_gain | 0xEFA0);
tmp = (gphy->pga_gain | 0xEFA0);
b43_phy_write(dev, B43_PHY_PGACTL, tmp);
}
if (phy->type == B43_PHYTYPE_G) {
@ -572,7 +577,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
}
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
tmp = (sav->phy_lo_mask & 0xBFFF);
b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
@ -580,7 +585,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
}
b43_radio_selectchannel(dev, sav->old_channel, 1);
b43_gphy_channel_switch(dev, sav->old_channel, 1);
}
struct b43_lo_g_statemachine {
@ -597,6 +602,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
struct b43_lo_g_statemachine *d)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_loctl test_loctl;
struct b43_loctl orig_loctl;
struct b43_loctl prev_loctl = {
@ -646,9 +652,9 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
test_loctl.q != prev_loctl.q) &&
(abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
b43_lo_write(dev, &test_loctl);
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
if (feedth < d->lowest_feedth) {
memcpy(probe_loctl, &test_loctl,
sizeof(struct b43_loctl));
@ -677,6 +683,7 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
int *max_rx_gain)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_lo_g_statemachine d;
u16 feedth;
int found_lower;
@ -693,17 +700,17 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
max_repeat = 4;
do {
b43_lo_write(dev, &d.min_loctl);
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
if (feedth < 0x258) {
if (feedth >= 0x12C)
*max_rx_gain += 6;
else
*max_rx_gain += 3;
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
}
d.lowest_feedth = feedth;
@ -752,6 +759,7 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
const struct b43_rfatt *rfatt)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_loctl loctl = {
.i = 0,
.q = 0,
@ -782,11 +790,11 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
if (rfatt->with_padmix)
max_rx_gain -= pad_mix_gain;
if (has_loopback_gain(phy))
max_rx_gain += phy->max_lb_gain;
max_rx_gain += gphy->max_lb_gain;
lo_measure_gain_values(dev, max_rx_gain,
has_loopback_gain(phy));
b43_phy_set_baseband_attenuation(dev, bbatt->att);
b43_gphy_set_baseband_attenuation(dev, bbatt->att);
lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
lo_measure_restore(dev, &saved_regs);
@ -820,7 +828,7 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt)
{
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
struct b43_lo_calib *c;
c = b43_find_lo_calib(lo, bbatt, rfatt);
@ -839,7 +847,8 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
int i;
int rf_offset, bb_offset;
const struct b43_rfatt *rfatt;
@ -917,14 +926,14 @@ static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
void b43_lo_g_adjust(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
struct b43_lo_calib *cal;
struct b43_rfatt rf;
memcpy(&rf, &phy->rfatt, sizeof(rf));
memcpy(&rf, &gphy->rfatt, sizeof(rf));
b43_lo_fixup_rfatt(&rf);
cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf);
if (!cal)
return;
b43_lo_write(dev, &cal->ctl);
@ -952,7 +961,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
void b43_lo_g_maintanance_work(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
unsigned long now;
unsigned long expire;
struct b43_lo_calib *cal, *tmp;
@ -962,7 +972,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
if (!lo)
return;
now = jiffies;
hwpctl = b43_has_hardware_pctl(phy);
hwpctl = b43_has_hardware_pctl(dev);
if (hwpctl) {
/* Read the power vector and update it, if needed. */
@ -983,8 +993,8 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
if (!time_before(cal->calib_time, expire))
continue;
/* This item expired. */
if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) {
B43_WARN_ON(current_item_expired);
current_item_expired = 1;
}
@ -1002,7 +1012,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
/* Recalibrate currently used LO setting. */
if (b43_debug(dev, B43_DBG_LO))
b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt);
if (cal) {
list_add(&cal->list, &lo->calib_list);
b43_lo_write(dev, &cal->ctl);
@ -1013,7 +1023,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
void b43_lo_g_cleanup(struct b43_wldev *dev)
{
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
struct b43_lo_calib *cal, *tmp;
if (!lo)
@ -1027,9 +1037,7 @@ void b43_lo_g_cleanup(struct b43_wldev *dev)
/* LO Initialization */
void b43_lo_g_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
lo_read_power_vector(dev);
b43_gphy_dc_lt_init(dev, 1);
}

View file

@ -1,7 +1,9 @@
#ifndef B43_LO_H_
#define B43_LO_H_
#include "phy.h"
/* G-PHY Local Oscillator */
#include "phy_g.h"
struct b43_wldev;

View file

@ -44,7 +44,8 @@
#include "b43.h"
#include "main.h"
#include "debugfs.h"
#include "phy.h"
#include "phy_common.h"
#include "phy_g.h"
#include "nphy.h"
#include "dma.h"
#include "pio.h"
@ -1174,6 +1175,8 @@ static void b43_calculate_link_quality(struct b43_wldev *dev)
{
/* Top half of Link Quality calculation. */
if (dev->phy.type != B43_PHYTYPE_G)
return;
if (dev->noisecalc.calculation_running)
return;
dev->noisecalc.calculation_running = 1;
@ -1184,7 +1187,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev)
static void handle_irq_noise(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *phy = dev->phy.g;
u16 tmp;
u8 noise[4];
u8 i, j;
@ -1192,6 +1195,9 @@ static void handle_irq_noise(struct b43_wldev *dev)
/* Bottom half of Link Quality calculation. */
if (dev->phy.type != B43_PHYTYPE_G)
return;
/* Possible race condition: It might be possible that the user
* changed to a different channel in the meantime since we
* started the calculation. We ignore that fact, since it's
@ -2688,9 +2694,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
/* This is the opposite of b43_chip_init() */
static void b43_chip_exit(struct b43_wldev *dev)
{
b43_radio_turn_off(dev, 1);
b43_gpio_cleanup(dev);
b43_lo_g_cleanup(dev);
/* firmware is released later */
}
@ -2700,7 +2704,7 @@ static void b43_chip_exit(struct b43_wldev *dev)
static int b43_chip_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
int err, tmp;
int err;
u32 value32, macctl;
u16 value16;
@ -2725,19 +2729,19 @@ static int b43_chip_init(struct b43_wldev *dev)
err = b43_upload_initvals(dev);
if (err)
goto err_gpio_clean;
b43_radio_turn_on(dev);
b43_write16(dev, 0x03E6, 0x0000);
err = b43_phy_init(dev);
if (err)
goto err_radio_off;
goto err_gpio_clean;
/* Select initial Interference Mitigation. */
tmp = phy->interfmode;
phy->interfmode = B43_INTERFMODE_NONE;
b43_radio_set_interference_mitigation(dev, tmp);
/* Disable Interference Mitigation. */
if (phy->ops->interf_mitigation)
phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
/* Select the antennae */
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
if (phy->type == B43_PHYTYPE_B) {
@ -2790,8 +2794,6 @@ static int b43_chip_init(struct b43_wldev *dev)
out:
return err;
err_radio_off:
b43_radio_turn_off(dev, 1);
err_gpio_clean:
b43_gpio_cleanup(dev);
return err;
@ -2799,25 +2801,13 @@ err_gpio_clean:
static void b43_periodic_every60sec(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
const struct b43_phy_operations *ops = dev->phy.ops;
if (phy->type != B43_PHYTYPE_G)
return;
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
b43_mac_suspend(dev);
b43_calc_nrssi_slope(dev);
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
u8 old_chan = phy->channel;
if (ops->pwork_60sec)
ops->pwork_60sec(dev);
/* VCO Calibration */
if (old_chan >= 8)
b43_radio_selectchannel(dev, 1, 0);
else
b43_radio_selectchannel(dev, 13, 0);
b43_radio_selectchannel(dev, old_chan, 0);
}
b43_mac_enable(dev);
}
/* Force check the TX power emission now. */
b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
}
static void b43_periodic_every30sec(struct b43_wldev *dev)
@ -2845,32 +2835,8 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
}
}
if (phy->type == B43_PHYTYPE_G) {
//TODO: update_aci_moving_average
if (phy->aci_enable && phy->aci_wlan_automatic) {
b43_mac_suspend(dev);
if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
if (0 /*TODO: bunch of conditions */ ) {
b43_radio_set_interference_mitigation
(dev, B43_INTERFMODE_MANUALWLAN);
}
} else if (1 /*TODO*/) {
/*
if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
b43_radio_set_interference_mitigation(dev,
B43_INTERFMODE_NONE);
}
*/
}
b43_mac_enable(dev);
} else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
phy->rev == 1) {
//TODO: implement rev1 workaround
}
}
b43_phy_xmitpower(dev); //FIXME: unless scanning?
b43_lo_g_maintanance_work(dev);
//TODO for APHY (temperature?)
if (phy->ops->pwork_15sec)
phy->ops->pwork_15sec(dev);
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
wmb();
@ -3401,7 +3367,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
if (conf->channel->hw_value != phy->channel)
b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
b43_switch_channel(dev, conf->channel->hw_value);
/* Enable/Disable ShortSlot timing. */
if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
@ -3417,17 +3383,21 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
/* Adjust the desired TX power level. */
if (conf->power_level != 0) {
if (conf->power_level != phy->power_level) {
phy->power_level = conf->power_level;
b43_phy_xmitpower(dev);
spin_lock_irqsave(&wl->irq_lock, flags);
if (conf->power_level != phy->desired_txpower) {
phy->desired_txpower = conf->power_level;
b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
B43_TXPWR_IGNORE_TSSI);
}
spin_unlock_irqrestore(&wl->irq_lock, flags);
}
/* Antennas for RX and management frame TX. */
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
b43_mgmtframe_txantenna(dev, antenna);
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
b43_set_rx_antenna(dev, antenna);
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, antenna);
/* Update templates for AP/mesh mode. */
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
@ -3436,7 +3406,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
if (!!conf->radio_enabled != phy->radio_on) {
if (conf->radio_enabled) {
b43_radio_turn_on(dev);
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) {
b43info(dev->wl, "The hardware RF-kill button "
@ -3444,7 +3414,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
"Press the button to turn it on.\n");
}
} else {
b43_radio_turn_off(dev, 0);
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
b43info(dev->wl, "Radio turned off by software\n");
}
}
@ -3818,48 +3788,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
static void setup_struct_phy_for_init(struct b43_wldev *dev,
struct b43_phy *phy)
{
struct b43_txpower_lo_control *lo;
int i;
memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
phy->aci_enable = 0;
phy->aci_wlan_automatic = 0;
phy->aci_hw_rssi = 0;
phy->radio_off_context.valid = 0;
lo = phy->lo_control;
if (lo) {
memset(lo, 0, sizeof(*(phy->lo_control)));
lo->tx_bias = 0xFF;
INIT_LIST_HEAD(&lo->calib_list);
}
phy->max_lb_gain = 0;
phy->trsw_rx_gain = 0;
phy->txpwr_offset = 0;
/* NRSSI */
phy->nrssislope = 0;
for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
phy->nrssi[i] = -1000;
for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
phy->nrssi_lt[i] = i;
phy->lofcal = 0xFFFF;
phy->initval = 0xFFFF;
phy->interfmode = B43_INTERFMODE_NONE;
phy->channel = 0xFF;
phy->hardware_power_control = !!modparam_hwpctl;
phy->next_txpwr_check_time = jiffies;
/* PHY TX errors counter. */
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
/* OFDM-table address caching. */
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
}
static void setup_struct_wldev_for_init(struct b43_wldev *dev)
@ -3995,7 +3927,6 @@ static void b43_set_pretbtt(struct b43_wldev *dev)
/* Locking: wl->mutex */
static void b43_wireless_core_exit(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u32 macctl;
B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
@ -4016,16 +3947,12 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
b43_dma_free(dev);
b43_pio_free(dev);
b43_chip_exit(dev);
b43_radio_turn_off(dev, 1);
b43_switch_analog(dev, 0);
if (phy->dyn_tssi_tbl)
kfree(phy->tssi2dbm);
kfree(phy->lo_control);
phy->lo_control = NULL;
if (dev->wl->current_beacon) {
dev_kfree_skb_any(dev->wl->current_beacon);
dev->wl->current_beacon = NULL;
}
b43_phy_exit(dev);
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(dev->dev->bus);
@ -4052,29 +3979,24 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
b43_wireless_core_reset(dev, tmp);
}
if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
phy->lo_control =
kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
if (!phy->lo_control) {
err = -ENOMEM;
goto err_busdown;
}
}
setup_struct_wldev_for_init(dev);
err = b43_phy_init_tssi2dbm_table(dev);
err = b43_phy_operations_setup(dev);
if (err)
goto err_kfree_lo_control;
goto err_busdown;
/* Enable IRQ routing to this device. */
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
b43_imcfglo_timeouts_workaround(dev);
b43_bluetooth_coext_disable(dev);
b43_phy_early_init(dev);
if (phy->ops->prepare) {
err = phy->ops->prepare(dev);
if (err)
goto err_phy_exit;
}
err = b43_chip_init(dev);
if (err)
goto err_kfree_tssitbl;
goto err_phy_exit;
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
hf = b43_hf_read(dev);
@ -4140,15 +4062,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
out:
return err;
err_chip_exit:
err_chip_exit:
b43_chip_exit(dev);
err_kfree_tssitbl:
if (phy->dyn_tssi_tbl)
kfree(phy->tssi2dbm);
err_kfree_lo_control:
kfree(phy->lo_control);
phy->lo_control = NULL;
err_busdown:
err_phy_exit:
b43_phy_exit(dev);
err_busdown:
ssb_bus_may_powerdown(bus);
B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
return err;
@ -4291,6 +4209,8 @@ static void b43_op_stop(struct ieee80211_hw *hw)
b43_wireless_core_stop(dev);
b43_wireless_core_exit(dev);
mutex_unlock(&wl->mutex);
cancel_work_sync(&(wl->txpower_adjust_work));
}
static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
@ -4511,7 +4431,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
wl->current_dev = dev;
INIT_WORK(&dev->restart_work, b43_chip_reset);
b43_radio_turn_off(dev, 1);
b43_switch_analog(dev, 0);
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(bus);
@ -4669,6 +4588,7 @@ static int b43_wireless_init(struct ssb_device *dev)
INIT_LIST_HEAD(&wl->devlist);
INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
ssb_set_devtypedata(dev, wl);
b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);

View file

@ -34,10 +34,16 @@ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
}
void b43_nphy_xmitpower(struct b43_wldev *dev)
static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
{//TODO
}
static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
bool ignore_tssi)
{//TODO
return B43_TXPWR_RES_DONE;
}
static void b43_chantab_radio_upload(struct b43_wldev *dev,
const struct b43_nphy_channeltab_entry *e)
{
@ -81,9 +87,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
//TODO
}
/* Tune the hardware to a new channel. Don't call this directly.
* Use b43_radio_selectchannel() */
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
/* Tune the hardware to a new channel. */
static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
{
const struct b43_nphy_channeltab_entry *tabent;
@ -162,7 +167,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
msleep(1);
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
msleep(1);
b43_radio_selectchannel(dev, dev->phy.channel, 0);
nphy_channel_switch(dev, dev->phy.channel);
b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
@ -484,3 +489,136 @@ int b43_phy_initn(struct b43_wldev *dev)
b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
return 0;
}
static int b43_nphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_n *nphy;
nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
if (!nphy)
return -ENOMEM;
dev->phy.n = nphy;
//TODO init struct b43_phy_n
return 0;
}
static int b43_nphy_op_init(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
int err;
err = b43_phy_initn(dev);
if (err)
return err;
nphy->initialised = 1;
return 0;
}
static void b43_nphy_op_exit(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
if (nphy->initialised) {
//TODO
nphy->initialised = 0;
}
//TODO
kfree(nphy);
dev->phy.n = NULL;
}
static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
{
#if B43_DEBUG
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
/* OFDM registers are onnly available on A/G-PHYs */
b43err(dev->wl, "Invalid OFDM PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
/* Ext-G registers are only available on G-PHYs */
b43err(dev->wl, "Invalid EXT-G PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
#endif /* B43_DEBUG */
}
static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
/* N-PHY needs 0x100 for read access */
reg |= 0x100;
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state)
{//TODO
}
static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
return -EINVAL;
} else {
if (new_channel > 200)
return -EINVAL;
}
return nphy_channel_switch(dev, new_channel);
}
static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
return 1;
return 36;
}
const struct b43_phy_operations b43_phyops_n = {
.allocate = b43_nphy_op_allocate,
.init = b43_nphy_op_init,
.exit = b43_nphy_op_exit,
.phy_read = b43_nphy_op_read,
.phy_write = b43_nphy_op_write,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
.software_rfkill = b43_nphy_op_software_rfkill,
.switch_channel = b43_nphy_op_switch_channel,
.get_default_chan = b43_nphy_op_get_default_chan,
.recalc_txpower = b43_nphy_op_recalc_txpower,
.adjust_txpower = b43_nphy_op_adjust_txpower,
};

View file

@ -1,7 +1,7 @@
#ifndef B43_NPHY_H_
#define B43_NPHY_H_
#include "phy.h"
#include "phy_common.h"
/* N-PHY registers. */
@ -919,54 +919,14 @@
struct b43_wldev;
struct b43_phy_n {
bool initialised;
#ifdef CONFIG_B43_NPHY
/* N-PHY support enabled */
int b43_phy_initn(struct b43_wldev *dev);
void b43_nphy_radio_turn_on(struct b43_wldev *dev);
void b43_nphy_radio_turn_off(struct b43_wldev *dev);
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
void b43_nphy_xmitpower(struct b43_wldev *dev);
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
//TODO lots of missing stuff
};
#else /* CONFIG_B43_NPHY */
/* N-PHY support disabled */
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_n;
static inline
int b43_phy_initn(struct b43_wldev *dev)
{
return -EOPNOTSUPP;
}
static inline
void b43_nphy_radio_turn_on(struct b43_wldev *dev)
{
}
static inline
void b43_nphy_radio_turn_off(struct b43_wldev *dev)
{
}
static inline
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
{
return -ENOSYS;
}
static inline
void b43_nphy_xmitpower(struct b43_wldev *dev)
{
}
static inline
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{
}
#endif /* CONFIG_B43_NPHY */
#endif /* B43_NPHY_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,340 +0,0 @@
#ifndef B43_PHY_H_
#define B43_PHY_H_
#include <linux/types.h>
struct b43_wldev;
struct b43_phy;
/*** PHY Registers ***/
/* Routing */
#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */
#define B43_PHYROUTE_BASE 0x0000 /* Base registers */
#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */
#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */
#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */
/* CCK (B-PHY) registers. */
#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY registers. */
#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY BMODE registers. */
#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE)
/* OFDM (A-PHY) registers. */
#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers. */
#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
/* OFDM (A) PHY Registers */
#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */
#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
#define B43_PHY_BBANDCFG_RXANT_SHIFT 7
#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */
#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */
#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */
#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */
#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */
#define B43_PHY_CRS0 B43_PHY_OFDM(0x29)
#define B43_PHY_CRS0_EN 0x4000
#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30)
#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */
#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */
#define B43_PHY_LMS B43_PHY_OFDM(0x55)
#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */
#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */
#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */
#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */
#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */
#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
#define B43_PHY_OTABLENR_SHIFT 10
#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */
#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */
#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */
#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */
#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B)
#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */
#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */
#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */
#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */
#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */
#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0)
#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1)
#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2)
#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3)
#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4)
#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */
#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */
#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */
#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9)
#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA)
#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB)
#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */
#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */
#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */
#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */
#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */
#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
/* CCK (B) PHY Registers */
#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */
#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */
#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */
#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */
#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */
#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */
#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */
#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35)
#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */
#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */
#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define B43_PHY_GTABNR_SHIFT 10
#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
#define B43_PHY_RFOVERVAL_LNA 0x7000
#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
#define B43_PHY_RFOVERVAL_PGA 0x0F00
#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
/*** OFDM table numbers ***/
#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename
#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4)
#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0)
#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3)
#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0)
#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0)
#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0)
#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0)
#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0)
#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0)
#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7)
#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12)
#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13)
#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename
#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename
#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12)
#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0)
#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename
#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0)
#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove!
#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0)
#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4)
#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0)
#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0)
#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0)
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value);
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value);
/*** G-PHY table numbers */
#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement
#define B43_DEFAULT_CHANNEL_A 36
#define B43_DEFAULT_CHANNEL_BG 6
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
};
enum {
B43_INTERFMODE_NONE,
B43_INTERFMODE_NONWLAN,
B43_INTERFMODE_MANUALWLAN,
B43_INTERFMODE_AUTOWLAN,
};
/* Masks for the different PHY versioning registers. */
#define B43_PHYVER_ANALOG 0xF000
#define B43_PHYVER_ANALOG_SHIFT 12
#define B43_PHYVER_TYPE 0x0F00
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
void b43_phy_lock(struct b43_wldev *dev);
void b43_phy_unlock(struct b43_wldev *dev);
/* Read a value from a PHY register */
u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
/* Write a value to a PHY register */
void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
/* Mask a PHY register with a mask */
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/* OR a PHY register with a bitmap */
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
/* Mask and OR a PHY register with a mask and bitmap */
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
void b43_phy_early_init(struct b43_wldev *dev);
int b43_phy_init(struct b43_wldev *dev);
void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
void b43_phy_xmitpower(struct b43_wldev *dev);
/* Returns the boolean whether the board has HardwarePowerControl */
bool b43_has_hardware_pctl(struct b43_phy *phy);
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* Radio Attenuation (RF Attenuation) */
struct b43_rfatt {
u8 att; /* Attenuation value */
bool with_padmix; /* Flag, PAD Mixer enabled. */
};
struct b43_rfatt_list {
/* Attenuation values list */
const struct b43_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
const struct b43_rfatt *b)
{
return ((a->att == b->att) &&
(a->with_padmix == b->with_padmix));
}
/* Baseband Attenuation */
struct b43_bbatt {
u8 att; /* Attenuation value */
};
struct b43_bbatt_list {
/* Attenuation values list */
const struct b43_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
const struct b43_bbatt *b)
{
return (a->att == b->att);
}
/* tx_control bits. */
#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
/* Write BasebandAttenuation value to the device. */
void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
u16 baseband_attenuation);
extern const u8 b43_radio_channel_codes_bg[];
void b43_radio_lock(struct b43_wldev *dev);
void b43_radio_unlock(struct b43_wldev *dev);
/* Read a value from a 16bit radio register */
u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
/* Write a value to a 16bit radio register */
void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
/* Mask a 16bit radio register with a mask */
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/* OR a 16bit radio register with a bitmap */
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
/* Mask and OR a PHY register with a mask and bitmap */
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
u16 b43_radio_init2050(struct b43_wldev *dev);
void b43_radio_init2060(struct b43_wldev *dev);
void b43_radio_turn_on(struct b43_wldev *dev);
void b43_radio_turn_off(struct b43_wldev *dev, bool force);
int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
int synthetic_pu_workaround);
u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
u8 b43_radio_aci_scan(struct b43_wldev *dev);
int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
void b43_calc_nrssi_slope(struct b43_wldev *dev);
void b43_calc_nrssi_threshold(struct b43_wldev *dev);
s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
void b43_nrssi_mem_update(struct b43_wldev *dev);
void b43_radio_set_tx_iq(struct b43_wldev *dev);
u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
int *_bbatt, int *_rfatt);
void b43_set_txpower_g(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt, u8 tx_control);
#endif /* B43_PHY_H_ */

View file

@ -0,0 +1,543 @@
/*
Broadcom B43 wireless driver
IEEE 802.11a PHY driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "b43.h"
#include "phy_a.h"
#include "phy_common.h"
#include "wa.h"
#include "tables.h"
#include "main.h"
/* Get the freq, as it has to be written to the device. */
static inline u16 channel2freq_a(u8 channel)
{
B43_WARN_ON(channel > 200);
return (5000 + 5 * channel);
}
static inline u16 freq_r3A_value(u16 frequency)
{
u16 value;
if (frequency < 5091)
value = 0x0040;
else if (frequency < 5321)
value = 0x0000;
else if (frequency < 5806)
value = 0x0080;
else
value = 0x0040;
return value;
}
void b43_radio_set_tx_iq(struct b43_wldev *dev)
{
static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
u16 tmp = b43_radio_read16(dev, 0x001E);
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
if (tmp == (data_high[i] << 4 | data_low[j])) {
b43_phy_write(dev, 0x0069,
(i - j) << 8 | 0x00C0);
return;
}
}
}
}
static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
{
u16 freq, r8, tmp;
freq = channel2freq_a(channel);
r8 = b43_radio_read16(dev, 0x0008);
b43_write16(dev, 0x03F0, freq);
b43_radio_write16(dev, 0x0008, r8);
//TODO: write max channel TX power? to Radio 0x2D
tmp = b43_radio_read16(dev, 0x002E);
tmp &= 0x0080;
//TODO: OR tmp with the Power out estimation for this channel?
b43_radio_write16(dev, 0x002E, tmp);
if (freq >= 4920 && freq <= 5500) {
/*
* r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
* = (freq * 0.025862069
*/
r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
}
b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
& 0x000F) | (r8 << 4));
b43_radio_write16(dev, 0x002A, (r8 << 4));
b43_radio_write16(dev, 0x002B, (r8 << 4));
b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
& 0x00F0) | (r8 << 4));
b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
& 0xFF0F) | 0x00B0);
b43_radio_write16(dev, 0x0035, 0x00AA);
b43_radio_write16(dev, 0x0036, 0x0085);
b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
& 0xFF20) |
freq_r3A_value(freq));
b43_radio_write16(dev, 0x003D,
b43_radio_read16(dev, 0x003D) & 0x00FF);
b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
& 0xFF7F) | 0x0080);
b43_radio_write16(dev, 0x0035,
b43_radio_read16(dev, 0x0035) & 0xFFEF);
b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
& 0xFFEF) | 0x0010);
b43_radio_set_tx_iq(dev);
//TODO: TSSI2dbm workaround
//FIXME b43_phy_xmitpower(dev);
}
void b43_radio_init2060(struct b43_wldev *dev)
{
b43_radio_write16(dev, 0x0004, 0x00C0);
b43_radio_write16(dev, 0x0005, 0x0008);
b43_radio_write16(dev, 0x0009, 0x0040);
b43_radio_write16(dev, 0x0005, 0x00AA);
b43_radio_write16(dev, 0x0032, 0x008F);
b43_radio_write16(dev, 0x0006, 0x008F);
b43_radio_write16(dev, 0x0034, 0x008F);
b43_radio_write16(dev, 0x002C, 0x0007);
b43_radio_write16(dev, 0x0082, 0x0080);
b43_radio_write16(dev, 0x0080, 0x0000);
b43_radio_write16(dev, 0x003F, 0x00DA);
b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
msleep(1); /* delay 400usec */
b43_radio_write16(dev, 0x0081,
(b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
msleep(1); /* delay 400usec */
b43_radio_write16(dev, 0x0005,
(b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
b43_radio_write16(dev, 0x0081,
(b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
b43_radio_write16(dev, 0x0005,
(b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
b43_phy_write(dev, 0x0063, 0xDDC6);
b43_phy_write(dev, 0x0069, 0x07BE);
b43_phy_write(dev, 0x006A, 0x0000);
aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev));
msleep(1);
}
static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
{
int i;
if (dev->phy.rev < 3) {
if (enable)
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
b43_ofdmtab_write16(dev,
B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, 0xFFF8);
}
else
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
b43_ofdmtab_write16(dev,
B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
}
} else {
if (enable)
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, 0x0820);
else
for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
}
}
static void b43_phy_ww(struct b43_wldev *dev)
{
u16 b, curr_s, best_s = 0xFFFF;
int i;
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
b43_phy_write(dev, B43_PHY_OFDM(0x1B),
b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
b43_phy_write(dev, B43_PHY_OFDM(0x82),
(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
b43_radio_write16(dev, 0x0009,
b43_radio_read16(dev, 0x0009) | 0x0080);
b43_radio_write16(dev, 0x0012,
(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
b43_wa_initgains(dev);
b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
b = b43_phy_read(dev, B43_PHY_PWRDOWN);
b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
b43_radio_write16(dev, 0x0004,
b43_radio_read16(dev, 0x0004) | 0x0004);
for (i = 0x10; i <= 0x20; i++) {
b43_radio_write16(dev, 0x0013, i);
curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
if (!curr_s) {
best_s = 0x0000;
break;
} else if (curr_s >= 0x0080)
curr_s = 0x0100 - curr_s;
if (curr_s < best_s)
best_s = curr_s;
}
b43_phy_write(dev, B43_PHY_PWRDOWN, b);
b43_radio_write16(dev, 0x0004,
b43_radio_read16(dev, 0x0004) & 0xFFFB);
b43_radio_write16(dev, 0x0013, best_s);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
b43_phy_write(dev, B43_PHY_OFDM(0xBB),
(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
b43_phy_write(dev, B43_PHY_OFDM61,
(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
b43_phy_write(dev, B43_PHY_OFDM(0x13),
(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
b43_phy_write(dev, B43_PHY_OFDM(0x14),
(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
for (i = 0; i < 6; i++)
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
}
static void hardware_pctl_init_aphy(struct b43_wldev *dev)
{
//TODO
}
void b43_phy_inita(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
struct b43_phy *phy = &dev->phy;
/* This lowlevel A-PHY init is also called from G-PHY init.
* So we must not access phy->a, if called from G-PHY code.
*/
B43_WARN_ON((phy->type != B43_PHYTYPE_A) &&
(phy->type != B43_PHYTYPE_G));
might_sleep();
if (phy->rev >= 6) {
if (phy->type == B43_PHYTYPE_A)
b43_phy_write(dev, B43_PHY_OFDM(0x1B),
b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
b43_phy_write(dev, B43_PHY_ENCORE,
b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
else
b43_phy_write(dev, B43_PHY_ENCORE,
b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
}
b43_wa_all(dev);
if (phy->type == B43_PHYTYPE_A) {
if (phy->gmode && (phy->rev < 3))
b43_phy_write(dev, 0x0034,
b43_phy_read(dev, 0x0034) | 0x0001);
b43_phy_rssiagc(dev, 0);
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
b43_radio_init2060(dev);
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
((bus->boardinfo.type == SSB_BOARD_BU4306) ||
(bus->boardinfo.type == SSB_BOARD_BU4309))) {
; //TODO: A PHY LO
}
if (phy->rev >= 3)
b43_phy_ww(dev);
hardware_pctl_init_aphy(dev);
//TODO: radar detection
}
if ((phy->type == B43_PHYTYPE_G) &&
(dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
b43_phy_write(dev, B43_PHY_OFDM(0x6E),
(b43_phy_read(dev, B43_PHY_OFDM(0x6E))
& 0xE000) | 0x3CF);
}
}
static int b43_aphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_a *aphy;
aphy = kzalloc(sizeof(*aphy), GFP_KERNEL);
if (!aphy)
return -ENOMEM;
dev->phy.a = aphy;
//TODO init struct b43_phy_a
return 0;
}
static int b43_aphy_op_init(struct b43_wldev *dev)
{
struct b43_phy_a *aphy = dev->phy.a;
b43_phy_inita(dev);
aphy->initialised = 1;
return 0;
}
static void b43_aphy_op_exit(struct b43_wldev *dev)
{
struct b43_phy_a *aphy = dev->phy.a;
if (aphy->initialised) {
//TODO
aphy->initialised = 0;
}
//TODO
kfree(aphy);
dev->phy.a = NULL;
}
static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
{
/* OFDM registers are base-registers for the A-PHY. */
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
offset &= ~B43_PHYROUTE;
offset |= B43_PHYROUTE_BASE;
}
#if B43_DEBUG
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
/* Ext-G registers are only available on G-PHYs */
b43err(dev->wl, "Invalid EXT-G PHY access at "
"0x%04X on A-PHY\n", offset);
dump_stack();
}
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
/* N-BMODE registers are only available on N-PHYs */
b43err(dev->wl, "Invalid N-BMODE PHY access at "
"0x%04X on A-PHY\n", offset);
dump_stack();
}
#endif /* B43_DEBUG */
return offset;
}
static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
{
reg = adjust_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
reg = adjust_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
/* A-PHY needs 0x40 for read access */
reg |= 0x40;
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
{
return (dev->phy.rev >= 5);
}
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state)
{//TODO
}
static int b43_aphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
if (new_channel > 200)
return -EINVAL;
aphy_channel_switch(dev, new_channel);
return 0;
}
static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev)
{
return 36; /* Default to channel 36 */
}
static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{//TODO
struct b43_phy *phy = &dev->phy;
u64 hf;
u16 tmp;
int autodiv = 0;
if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
autodiv = 1;
hf = b43_hf_read(dev);
hf &= ~B43_HF_ANTDIVHELP;
b43_hf_write(dev, hf);
tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
tmp &= ~B43_PHY_BBANDCFG_RXANT;
tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
<< B43_PHY_BBANDCFG_RXANT_SHIFT;
b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
if (autodiv) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
if (antenna == B43_ANTENNA_AUTO0)
tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
else
tmp |= B43_PHY_ANTDWELL_AUTODIV1;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
}
if (phy->rev < 3) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
tmp = (tmp & 0xFF00) | 0x24;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
} else {
tmp = b43_phy_read(dev, B43_PHY_OFDM61);
tmp |= 0x10;
b43_phy_write(dev, B43_PHY_OFDM61, tmp);
if (phy->analog == 3) {
b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
0x1D);
b43_phy_write(dev, B43_PHY_ADIVRELATED,
8);
} else {
b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
0x3A);
tmp =
b43_phy_read(dev,
B43_PHY_ADIVRELATED);
tmp = (tmp & 0xFF00) | 8;
b43_phy_write(dev, B43_PHY_ADIVRELATED,
tmp);
}
}
hf |= B43_HF_ANTDIVHELP;
b43_hf_write(dev, hf);
}
static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev)
{//TODO
}
static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev,
bool ignore_tssi)
{//TODO
return B43_TXPWR_RES_DONE;
}
static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev)
{//TODO
}
static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
{//TODO
}
const struct b43_phy_operations b43_phyops_a = {
.allocate = b43_aphy_op_allocate,
.init = b43_aphy_op_init,
.exit = b43_aphy_op_exit,
.phy_read = b43_aphy_op_read,
.phy_write = b43_aphy_op_write,
.radio_read = b43_aphy_op_radio_read,
.radio_write = b43_aphy_op_radio_write,
.supports_hwpctl = b43_aphy_op_supports_hwpctl,
.software_rfkill = b43_aphy_op_software_rfkill,
.switch_channel = b43_aphy_op_switch_channel,
.get_default_chan = b43_aphy_op_get_default_chan,
.set_rx_antenna = b43_aphy_op_set_rx_antenna,
.recalc_txpower = b43_aphy_op_recalc_txpower,
.adjust_txpower = b43_aphy_op_adjust_txpower,
.pwork_15sec = b43_aphy_op_pwork_15sec,
.pwork_60sec = b43_aphy_op_pwork_60sec,
};

View file

@ -0,0 +1,124 @@
#ifndef LINUX_B43_PHY_A_H_
#define LINUX_B43_PHY_A_H_
#include "phy_common.h"
/* OFDM (A) PHY Registers */
#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */
#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
#define B43_PHY_BBANDCFG_RXANT_SHIFT 7
#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */
#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */
#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */
#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */
#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */
#define B43_PHY_CRS0 B43_PHY_OFDM(0x29)
#define B43_PHY_CRS0_EN 0x4000
#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30)
#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */
#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */
#define B43_PHY_LMS B43_PHY_OFDM(0x55)
#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */
#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */
#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */
#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */
#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */
#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
#define B43_PHY_OTABLENR_SHIFT 10
#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */
#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */
#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */
#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */
#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B)
#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */
#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */
#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */
#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */
#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */
#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0)
#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1)
#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2)
#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3)
#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4)
#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */
#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */
#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */
#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9)
#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA)
#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB)
#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */
#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */
#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */
#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */
#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */
#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
/*** OFDM table numbers ***/
#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename
#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4)
#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0)
#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3)
#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0)
#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0)
#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0)
#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0)
#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0)
#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0)
#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7)
#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12)
#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13)
#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename
#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename
#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12)
#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0)
#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename
#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0)
#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove!
#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0)
#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4)
#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0)
#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0)
#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0)
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value);
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value);
struct b43_phy_a {
bool initialised;
/* A-PHY TX Power control value. */
u16 txpwr_offset;
//TODO lots of missing stuff
};
/**
* b43_phy_inita - Lowlevel A-PHY init routine.
* This is _only_ used by the G-PHY code.
*/
void b43_phy_inita(struct b43_wldev *dev);
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_a;
#endif /* LINUX_B43_PHY_A_H_ */

View file

@ -0,0 +1,367 @@
/*
Broadcom B43 wireless driver
Common PHY routines
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "phy_common.h"
#include "phy_g.h"
#include "phy_a.h"
#include "nphy.h"
#include "b43.h"
#include "main.h"
int b43_phy_operations_setup(struct b43_wldev *dev)
{
struct b43_phy *phy = &(dev->phy);
int err;
phy->ops = NULL;
switch (phy->type) {
case B43_PHYTYPE_A:
phy->ops = &b43_phyops_a;
break;
case B43_PHYTYPE_G:
phy->ops = &b43_phyops_g;
break;
case B43_PHYTYPE_N:
#ifdef CONFIG_B43_NPHY
phy->ops = &b43_phyops_n;
#endif
break;
case B43_PHYTYPE_LP:
/* FIXME: Not yet */
break;
}
if (B43_WARN_ON(!phy->ops))
return -ENODEV;
err = phy->ops->allocate(dev);
if (err)
phy->ops = NULL;
return err;
}
int b43_phy_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
const struct b43_phy_operations *ops = phy->ops;
int err;
phy->channel = ops->get_default_chan(dev);
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
err = ops->init(dev);
if (err) {
b43err(dev->wl, "PHY init failed\n");
goto err_block_rf;
}
/* Make sure to switch hardware and firmware (SHM) to
* the default channel. */
err = b43_switch_channel(dev, ops->get_default_chan(dev));
if (err) {
b43err(dev->wl, "PHY init: Channel switch to default failed\n");
goto err_phy_exit;
}
return 0;
err_phy_exit:
if (ops->exit)
ops->exit(dev);
err_block_rf:
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
return err;
}
void b43_phy_exit(struct b43_wldev *dev)
{
const struct b43_phy_operations *ops = dev->phy.ops;
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
if (ops->exit)
ops->exit(dev);
}
bool b43_has_hardware_pctl(struct b43_wldev *dev)
{
if (!dev->phy.hardware_power_control)
return 0;
if (!dev->phy.ops->supports_hwpctl)
return 0;
return dev->phy.ops->supports_hwpctl(dev);
}
void b43_radio_lock(struct b43_wldev *dev)
{
u32 macctl;
macctl = b43_read32(dev, B43_MMIO_MACCTL);
B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
macctl |= B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
/* Commit the write and wait for the device
* to exit any radio register access. */
b43_read32(dev, B43_MMIO_MACCTL);
udelay(10);
}
void b43_radio_unlock(struct b43_wldev *dev)
{
u32 macctl;
/* Commit any write */
b43_read16(dev, B43_MMIO_PHY_VER);
/* unlock */
macctl = b43_read32(dev, B43_MMIO_MACCTL);
B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
macctl &= ~B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
}
void b43_phy_lock(struct b43_wldev *dev)
{
#if B43_DEBUG
B43_WARN_ON(dev->phy.phy_locked);
dev->phy.phy_locked = 1;
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
}
void b43_phy_unlock(struct b43_wldev *dev)
{
#if B43_DEBUG
B43_WARN_ON(!dev->phy.phy_locked);
dev->phy.phy_locked = 0;
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43_power_saving_ctl_bits(dev, 0);
}
u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{
return dev->phy.ops->radio_read(dev, reg);
}
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
dev->phy.ops->radio_write(dev, reg, value);
}
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_radio_write16(dev, offset,
b43_radio_read16(dev, offset) & mask);
}
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
{
b43_radio_write16(dev, offset,
b43_radio_read16(dev, offset) | set);
}
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
b43_radio_write16(dev, offset,
(b43_radio_read16(dev, offset) & mask) | set);
}
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
return dev->phy.ops->phy_read(dev, reg);
}
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
dev->phy.ops->phy_write(dev, reg, value);
}
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) & mask);
}
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) | set);
}
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
b43_phy_write(dev, offset,
(b43_phy_read(dev, offset) & mask) | set);
}
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
{
struct b43_phy *phy = &(dev->phy);
u16 channelcookie, savedcookie;
int err;
if (new_channel == B43_DEFAULT_CHANNEL)
new_channel = phy->ops->get_default_chan(dev);
/* First we set the channel radio code to prevent the
* firmware from sending ghost packets.
*/
channelcookie = new_channel;
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
channelcookie |= 0x100;
//FIXME set 40Mhz flag if required
savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
/* Now try to switch the PHY hardware channel. */
err = phy->ops->switch_channel(dev, new_channel);
if (err)
goto err_restore_cookie;
dev->phy.channel = new_channel;
/* Wait for the radio to tune to the channel and stabilize. */
msleep(8);
return 0;
err_restore_cookie:
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_CHAN, savedcookie);
return err;
}
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
{
struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_HARD_BLOCKED) {
/* We cannot hardware-block the device */
state = RFKILL_STATE_SOFT_BLOCKED;
}
phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
}
/**
* b43_phy_txpower_adjust_work - TX power workqueue.
*
* Workqueue for updating the TX power parameters in hardware.
*/
void b43_phy_txpower_adjust_work(struct work_struct *work)
{
struct b43_wl *wl = container_of(work, struct b43_wl,
txpower_adjust_work);
struct b43_wldev *dev;
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED)))
dev->phy.ops->adjust_txpower(dev);
mutex_unlock(&wl->mutex);
}
/* Called with wl->irq_lock locked */
void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
{
struct b43_phy *phy = &dev->phy;
unsigned long now = jiffies;
enum b43_txpwr_result result;
if (!(flags & B43_TXPWR_IGNORE_TIME)) {
/* Check if it's time for a TXpower check. */
if (time_before(now, phy->next_txpwr_check_time))
return; /* Not yet */
}
/* The next check will be needed in two seconds, or later. */
phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
(dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
return; /* No software txpower adjustment needed */
result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
if (result == B43_TXPWR_RES_DONE)
return; /* We are done. */
B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST);
B43_WARN_ON(phy->ops->adjust_txpower == NULL);
/* We must adjust the transmission power in hardware.
* Schedule b43_phy_txpower_adjust_work(). */
queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
}
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
{
const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK);
unsigned int a, b, c, d;
unsigned int average;
u32 tmp;
tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset);
a = tmp & 0xFF;
b = (tmp >> 8) & 0xFF;
c = (tmp >> 16) & 0xFF;
d = (tmp >> 24) & 0xFF;
if (a == 0 || a == B43_TSSI_MAX ||
b == 0 || b == B43_TSSI_MAX ||
c == 0 || c == B43_TSSI_MAX ||
d == 0 || d == B43_TSSI_MAX)
return -ENOENT;
/* The values are OK. Clear them. */
tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) |
(B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24);
b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp);
if (is_ofdm) {
a = (a + 32) & 0x3F;
b = (b + 32) & 0x3F;
c = (c + 32) & 0x3F;
d = (d + 32) & 0x3F;
}
/* Get the average of the values with 0.5 added to each value. */
average = (a + b + c + d + 2) / 4;
if (is_ofdm) {
/* Adjust for CCK-boost */
if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
& B43_HF_CCKBOOST)
average = (average >= 13) ? (average - 13) : 0;
}
return average;
}

View file

@ -0,0 +1,381 @@
#ifndef LINUX_B43_PHY_COMMON_H_
#define LINUX_B43_PHY_COMMON_H_
#include <linux/rfkill.h>
struct b43_wldev;
/* PHY register routing bits */
#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */
#define B43_PHYROUTE_BASE 0x0000 /* Base registers */
#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */
#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */
#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */
/* CCK (B-PHY) registers. */
#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY registers. */
#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY BMODE registers. */
#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE)
/* OFDM (A-PHY) registers. */
#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers. */
#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
/* Masks for the PHY versioning registers. */
#define B43_PHYVER_ANALOG 0xF000
#define B43_PHYVER_ANALOG_SHIFT 12
#define B43_PHYVER_TYPE 0x0F00
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
/**
* enum b43_interference_mitigation - Interference Mitigation mode
*
* @B43_INTERFMODE_NONE: Disabled
* @B43_INTERFMODE_NONWLAN: Non-WLAN Interference Mitigation
* @B43_INTERFMODE_MANUALWLAN: WLAN Interference Mitigation
* @B43_INTERFMODE_AUTOWLAN: Automatic WLAN Interference Mitigation
*/
enum b43_interference_mitigation {
B43_INTERFMODE_NONE,
B43_INTERFMODE_NONWLAN,
B43_INTERFMODE_MANUALWLAN,
B43_INTERFMODE_AUTOWLAN,
};
/* Antenna identifiers */
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
};
/**
* enum b43_txpwr_result - Return value for the recalc_txpower PHY op.
*
* @B43_TXPWR_RES_NEED_ADJUST: Values changed. Hardware adjustment is needed.
* @B43_TXPWR_RES_DONE: No more work to do. Everything is done.
*/
enum b43_txpwr_result {
B43_TXPWR_RES_NEED_ADJUST,
B43_TXPWR_RES_DONE,
};
/**
* struct b43_phy_operations - Function pointers for PHY ops.
*
* @prepare: Prepare the PHY. This is called before @init.
* Can be NULL, if not required.
* @init: Initialize the PHY.
* Must not be NULL.
* @exit: Shutdown the PHY and free all data structures.
* Can be NULL, if not required.
*
* @phy_read: Read from a PHY register.
* Must not be NULL.
* @phy_write: Write to a PHY register.
* Must not be NULL.
* @radio_read: Read from a Radio register.
* Must not be NULL.
* @radio_write: Write to a Radio register.
* Must not be NULL.
*
* @supports_hwpctl: Returns a boolean whether Hardware Power Control
* is supported or not.
* If NULL, hwpctl is assumed to be never supported.
* @software_rfkill: Turn the radio ON or OFF.
* Possible state values are
* RFKILL_STATE_SOFT_BLOCKED or
* RFKILL_STATE_UNBLOCKED
* Must not be NULL.
* @switch_channel: Switch the radio to another channel.
* Must not be NULL.
* @get_default_chan: Just returns the default channel number.
* Must not be NULL.
* @set_rx_antenna: Set the antenna used for RX.
* Can be NULL, if not supported.
* @interf_mitigation: Switch the Interference Mitigation mode.
* Can be NULL, if not supported.
*
* @recalc_txpower: Recalculate the transmission power parameters.
* This callback has to recalculate the TX power settings,
* but does not need to write them to the hardware, yet.
* Returns enum b43_txpwr_result to indicate whether the hardware
* needs to be adjusted.
* If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower
* will be called later.
* If the parameter "ignore_tssi" is true, the TSSI values should
* be ignored and a recalculation of the power settings should be
* done even if the TSSI values did not change.
* This callback is called with wl->irq_lock held and must not sleep.
* Must not be NULL.
* @adjust_txpower: Write the previously calculated TX power settings
* (from @recalc_txpower) to the hardware.
* This function may sleep.
* Can be NULL, if (and ONLY if) @recalc_txpower _always_
* returns B43_TXPWR_RES_DONE.
*
* @pwork_15sec: Periodic work. Called every 15 seconds.
* Can be NULL, if not required.
* @pwork_60sec: Periodic work. Called every 60 seconds.
* Can be NULL, if not required.
*/
struct b43_phy_operations {
/* Initialisation */
int (*allocate)(struct b43_wldev *dev);
int (*prepare)(struct b43_wldev *dev);
int (*init)(struct b43_wldev *dev);
void (*exit)(struct b43_wldev *dev);
/* Register access */
u16 (*phy_read)(struct b43_wldev *dev, u16 reg);
void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value);
u16 (*radio_read)(struct b43_wldev *dev, u16 reg);
void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value);
/* Radio */
bool (*supports_hwpctl)(struct b43_wldev *dev);
void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
unsigned int (*get_default_chan)(struct b43_wldev *dev);
void (*set_rx_antenna)(struct b43_wldev *dev, int antenna);
int (*interf_mitigation)(struct b43_wldev *dev,
enum b43_interference_mitigation new_mode);
/* Transmission power adjustment */
enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev,
bool ignore_tssi);
void (*adjust_txpower)(struct b43_wldev *dev);
/* Misc */
void (*pwork_15sec)(struct b43_wldev *dev);
void (*pwork_60sec)(struct b43_wldev *dev);
};
struct b43_phy_a;
struct b43_phy_g;
struct b43_phy_n;
struct b43_phy {
/* Hardware operation callbacks. */
const struct b43_phy_operations *ops;
/* Most hardware context information is stored in the standard-
* specific data structures pointed to by the pointers below.
* Only one of them is valid (the currently enabled PHY). */
#ifdef CONFIG_B43_DEBUG
/* No union for debug build to force NULL derefs in buggy code. */
struct {
#else
union {
#endif
/* A-PHY specific information */
struct b43_phy_a *a;
/* G-PHY specific information */
struct b43_phy_g *g;
/* N-PHY specific information */
struct b43_phy_n *n;
};
/* Band support flags. */
bool supports_2ghz;
bool supports_5ghz;
/* GMODE bit enabled? */
bool gmode;
/* Analog Type */
u8 analog;
/* B43_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
/* Software state of the radio */
bool radio_on;
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in b43_phy_xmitpower(). */
int desired_txpower;
/* Hardware Power Control enabled? */
bool hardware_power_control;
/* The time (in absolute jiffies) when the next TX power output
* check is needed. */
unsigned long next_txpwr_check_time;
/* current channel */
unsigned int channel;
/* PHY TX errors counter. */
atomic_t txerr_cnt;
#ifdef CONFIG_B43_DEBUG
/* PHY registers locked by b43_phy_lock()? */
bool phy_locked;
#endif /* B43_DEBUG */
};
/**
* b43_phy_operations_setup - Initialize the PHY operations datastructure
* based on the current PHY type.
*/
int b43_phy_operations_setup(struct b43_wldev *dev);
/**
* b43_phy_init - Initialise the PHY
*/
int b43_phy_init(struct b43_wldev *dev);
/**
* b43_phy_exit - Cleanup PHY
*/
void b43_phy_exit(struct b43_wldev *dev);
/**
* b43_has_hardware_pctl - Hardware Power Control supported?
* Returns a boolean, whether hardware power control is supported.
*/
bool b43_has_hardware_pctl(struct b43_wldev *dev);
/**
* b43_phy_read - 16bit PHY register read access
*/
u16 b43_phy_read(struct b43_wldev *dev, u16 reg);
/**
* b43_phy_write - 16bit PHY register write access
*/
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value);
/**
* b43_phy_mask - Mask a PHY register with a mask
*/
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/**
* b43_phy_set - OR a PHY register with a bitmap
*/
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
/**
* b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap
*/
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
/**
* b43_radio_read - 16bit Radio register read access
*/
u16 b43_radio_read(struct b43_wldev *dev, u16 reg);
#define b43_radio_read16 b43_radio_read /* DEPRECATED */
/**
* b43_radio_write - 16bit Radio register write access
*/
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value);
#define b43_radio_write16 b43_radio_write /* DEPRECATED */
/**
* b43_radio_mask - Mask a 16bit radio register with a mask
*/
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/**
* b43_radio_set - OR a 16bit radio register with a bitmap
*/
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
/**
* b43_radio_maskset - Mask and OR a radio register with a mask and bitmap
*/
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
/**
* b43_radio_lock - Lock firmware radio register access
*/
void b43_radio_lock(struct b43_wldev *dev);
/**
* b43_radio_unlock - Unlock firmware radio register access
*/
void b43_radio_unlock(struct b43_wldev *dev);
/**
* b43_phy_lock - Lock firmware PHY register access
*/
void b43_phy_lock(struct b43_wldev *dev);
/**
* b43_phy_unlock - Unlock firmware PHY register access
*/
void b43_phy_unlock(struct b43_wldev *dev);
/**
* b43_switch_channel - Switch to another channel
*/
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
/**
* B43_DEFAULT_CHANNEL - Switch to the default channel.
*/
#define B43_DEFAULT_CHANNEL UINT_MAX
/**
* b43_software_rfkill - Turn the radio ON or OFF in software.
*/
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state);
/**
* b43_phy_txpower_check - Check TX power output.
*
* Compare the current TX power output to the desired power emission
* and schedule an adjustment in case it mismatches.
* Requires wl->irq_lock locked.
*
* @flags: OR'ed enum b43_phy_txpower_check_flags flags.
* See the docs below.
*/
void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags);
/**
* enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check()
*
* @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo
* the check now.
* @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average
* TSSI did not change.
*/
enum b43_phy_txpower_check_flags {
B43_TXPWR_IGNORE_TIME = (1 << 0),
B43_TXPWR_IGNORE_TSSI = (1 << 1),
};
struct work_struct;
void b43_phy_txpower_adjust_work(struct work_struct *work);
/**
* b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM.
*
* @shm_offset: The SHM address to read the values from.
*
* Returns the average of the 4 TSSI values, or a negative error code.
*/
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
#endif /* LINUX_B43_PHY_COMMON_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,209 @@
#ifndef LINUX_B43_PHY_G_H_
#define LINUX_B43_PHY_G_H_
/* OFDM PHY registers are defined in the A-PHY header. */
#include "phy_a.h"
/* CCK (B) PHY Registers */
#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */
#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */
#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */
#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */
#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */
#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */
#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */
#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35)
#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */
#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */
#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define B43_PHY_GTABNR_SHIFT 10
#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
#define B43_PHY_RFOVERVAL_LNA 0x7000
#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
#define B43_PHY_RFOVERVAL_PGA 0x0F00
#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
/*** G-PHY table numbers */
#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset);
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value);
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* Radio Attenuation (RF Attenuation) */
struct b43_rfatt {
u8 att; /* Attenuation value */
bool with_padmix; /* Flag, PAD Mixer enabled. */
};
struct b43_rfatt_list {
/* Attenuation values list */
const struct b43_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
const struct b43_rfatt *b)
{
return ((a->att == b->att) &&
(a->with_padmix == b->with_padmix));
}
/* Baseband Attenuation */
struct b43_bbatt {
u8 att; /* Attenuation value */
};
struct b43_bbatt_list {
/* Attenuation values list */
const struct b43_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
const struct b43_bbatt *b)
{
return (a->att == b->att);
}
/* tx_control bits. */
#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
struct b43_txpower_lo_control;
struct b43_phy_g {
bool initialised;
/* ACI (adjacent channel interference) flags. */
bool aci_enable;
bool aci_wlan_automatic;
bool aci_hw_rssi;
/* Radio switched on/off */
bool radio_on;
struct {
/* Values saved when turning the radio off.
* They are needed when turning it on again. */
bool valid;
u16 rfover;
u16 rfoverval;
} radio_off_context;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* Pointer to the table used to convert a
* TSSI value to dBm-Q5.2 */
const s8 *tssi2dbm;
/* tssi2dbm is kmalloc()ed. Only used for free()ing. */
bool dyn_tssi_tbl;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* The current average TSSI.
* Needs irq_lock, as it's updated in the IRQ path. */
u8 average_tssi;
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
struct b43_rfatt rfatt;
u8 tx_control; /* B43_TXCTL_XXX */
/* The calculated attenuation deltas that are used later
* when adjusting the actual power output. */
int bbatt_delta;
int rfatt_delta;
/* LocalOscillator control values. */
struct b43_txpower_lo_control *lo_control;
/* Values from b43_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define B43_INTERFSTACK_SIZE 26
u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
u16 lofcal;
u16 initval; //FIXME rename?
/* The device does address auto increment for the OFDM tables.
* We cache the previously used address here and omit the address
* write on the next table access, if possible. */
u16 ofdmtab_addr; /* The address currently set in hardware. */
enum { /* The last data flow direction. */
B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
B43_OFDMTAB_DIRECTION_READ,
B43_OFDMTAB_DIRECTION_WRITE,
} ofdmtab_addr_direction;
};
void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
u16 baseband_attenuation);
void b43_gphy_channel_switch(struct b43_wldev *dev,
unsigned int channel,
bool synthetic_pu_workaround);
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_g;
#endif /* LINUX_B43_PHY_G_H_ */

View file

@ -24,6 +24,7 @@
#include "rfkill.h"
#include "b43.h"
#include "phy_common.h"
#include <linux/kmod.h>
@ -114,11 +115,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
goto out_unlock;
}
if (!dev->phy.radio_on)
b43_radio_turn_on(dev);
b43_software_rfkill(dev, state);
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
b43_radio_turn_off(dev, 0);
b43_software_rfkill(dev, state);
break;
default:
b43warn(wl, "Received unexpected rfkill state %d.\n", state);

View file

@ -29,7 +29,7 @@
#include "b43.h"
#include "sysfs.h"
#include "main.h"
#include "phy.h"
#include "phy_common.h"
#define GENERIC_FILESIZE 64
@ -59,7 +59,12 @@ static ssize_t b43_attr_interfmode_show(struct device *dev,
mutex_lock(&wldev->wl->mutex);
switch (wldev->phy.interfmode) {
if (wldev->phy.type != B43_PHYTYPE_G) {
mutex_unlock(&wldev->wl->mutex);
return -ENOSYS;
}
switch (wldev->phy.g->interfmode) {
case B43_INTERFMODE_NONE:
count =
snprintf(buf, PAGE_SIZE,
@ -117,11 +122,15 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
err = b43_radio_set_interference_mitigation(wldev, mode);
if (err) {
b43err(wldev->wl, "Interference Mitigation not "
"supported by device\n");
}
if (wldev->phy.ops->interf_mitigation) {
err = wldev->phy.ops->interf_mitigation(wldev, mode);
if (err) {
b43err(wldev->wl, "Interference Mitigation not "
"supported by device\n");
}
} else
err = -ENOSYS;
mmiowb();
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);

View file

@ -27,7 +27,8 @@
#include "b43.h"
#include "tables.h"
#include "phy.h"
#include "phy_g.h"
const u32 b43_tab_rotor[] = {
0xFEB93FFD, 0xFEC63FFD, /* 0 */
@ -377,17 +378,17 @@ static inline void assert_sizes(void)
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
return b43_phy_read(dev, B43_PHY_OTABLEI);
@ -398,34 +399,34 @@ u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
}
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u32 ret;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
ret <<= 16;
ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@ -436,17 +437,17 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));

View file

@ -24,7 +24,7 @@
#include "b43.h"
#include "tables_nphy.h"
#include "phy.h"
#include "phy_common.h"
#include "nphy.h"

View file

@ -27,7 +27,7 @@
#include "b43.h"
#include "main.h"
#include "tables.h"
#include "phy.h"
#include "phy_common.h"
#include "wa.h"
static void b43_wa_papd(struct b43_wldev *dev)

View file

@ -28,7 +28,7 @@
*/
#include "xmit.h"
#include "phy.h"
#include "phy_common.h"
#include "dma.h"
#include "pio.h"
@ -431,6 +431,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
int adjust_2053, int adjust_2050)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
s32 tmp;
switch (phy->radio_ver) {
@ -450,7 +451,8 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
boardflags_lo & B43_BFL_RSSI) {
if (in_rssi > 63)
in_rssi = 63;
tmp = phy->nrssi_lt[in_rssi];
B43_WARN_ON(phy->type != B43_PHYTYPE_G);
tmp = gphy->nrssi_lt[in_rssi];
tmp = 31 - tmp;
tmp *= -131;
tmp /= 128;
@ -678,6 +680,8 @@ void b43_handle_txstatus(struct b43_wldev *dev,
b43_pio_handle_txstatus(dev, status);
else
b43_dma_handle_txstatus(dev, status);
b43_phy_txpower_check(dev, 0);
}
/* Fill out the mac80211 TXstatus report based on the b43-specific

View file

@ -34,7 +34,6 @@
#include <linux/moduleparam.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>

View file

@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>

View file

@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>

View file

@ -27,7 +27,6 @@
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <net/mac80211.h>

View file

@ -8,6 +8,7 @@
#include "scan.h"
#include "cmd.h"
static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp);
static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@ -20,12 +21,88 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
#define CAPINFO_MASK (~(0xda00))
/**
* @brief This function finds common rates between rates and card rates.
*
* It will fill common rates in rates as output if found.
*
* NOTE: Setting the MSB of the basic rates need to be taken
* care, either before or after calling this function
*
* @param priv A pointer to struct lbs_private structure
* @param rates the buffer which keeps input and output
* @param rates_size the size of rate1 buffer; new size of buffer on return
*
* @return 0 on success, or -1 on error
*/
static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
u8 tmp[30];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
for (j = 0; rates[j] && (j < *rates_size); j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->enablehwauto) {
for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
goto done;
}
ret = 0;
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
memcpy(rates, tmp, *rates_size);
return ret;
}
/**
* @brief Sets the MSB on basic rates as the firmware requires
*
* Scan through an array and set the MSB for basic data rates.
*
* @param rates buffer of data rates
* @param len size of buffer
*/
static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
{
int i;
for (i = 0; i < len; i++) {
if (rates[i] == 0x02 || rates[i] == 0x04 ||
rates[i] == 0x0b || rates[i] == 0x16)
rates[i] |= 0x80;
}
}
/**
* @brief Associate to a specific BSS discovered in a scan
*
* @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to the BSS descriptor to associate with.
* @param assoc_req The association request describing the BSS to associate with
*
* @return 0-success, otherwise fail
*/
@ -33,29 +110,29 @@ static int lbs_associate(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
int ret;
u8 preamble = RADIO_PREAMBLE_LONG;
lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid);
if (ret)
goto done;
goto out;
/* set preamble to firmware */
/* Use short preamble only when both the BSS and firmware support it */
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
(assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
else
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
preamble = RADIO_PREAMBLE_SHORT;
lbs_set_radio_control(priv);
ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
done:
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
@ -64,17 +141,22 @@ done:
* @brief Join an adhoc network found in a previous scan
*
* @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to a BSS descriptor found in a previous scan
* to attempt to join
* @param assoc_req The association request describing the BSS to join
*
* @return 0--success, -1--fail
* @return 0 on success, error on failure
*/
static int lbs_join_adhoc_network(struct lbs_private *priv,
static int lbs_adhoc_join(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
struct cmd_ds_802_11_ad_hoc_join cmd;
struct bss_descriptor *bss = &assoc_req->bss;
u8 preamble = RADIO_PREAMBLE_LONG;
DECLARE_MAC_BUF(mac);
u16 ratesize = 0;
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
lbs_deb_join("current SSID '%s', ssid length %u\n",
escape_essid(priv->curbssparams.ssid,
priv->curbssparams.ssid_len),
@ -106,29 +188,106 @@ static int lbs_join_adhoc_network(struct lbs_private *priv,
goto out;
}
/* Use shortpreamble only when both creator and card supports
short preamble */
if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ||
!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
} else {
/* Use short preamble only when both the BSS and firmware support it */
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
preamble = RADIO_PREAMBLE_SHORT;
}
lbs_set_radio_control(priv);
ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0;
priv->curbssparams.channel = bss->channel;
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
0, CMD_OPTION_WAITFORRSP,
OID_802_11_SSID, assoc_req);
/* Build the join command */
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.bss.type = CMD_BSS_TYPE_IBSS;
cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
memcpy(&cmd.bss.phyparamset, &bss->phyparamset,
sizeof(union ieeetypes_phyparamset));
memcpy(&cmd.bss.ssparamset, &bss->ssparamset,
sizeof(union IEEEtypes_ssparamset));
cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
print_mac(mac, cmd.bss.bssid), cmd.bss.ssid);
/* Only v8 and below support setting these */
if (priv->fwrelease < 0x09000000) {
/* failtimeout */
cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
/* probedelay */
cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
}
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
ret = -1;
goto out;
}
/* Copy the ad-hoc creation rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow);
if (assoc_req->secinfo.wep_enabled) {
u16 tmp = le16_to_cpu(cmd.bss.capability);
tmp |= WLAN_CAPABILITY_PRIVACY;
cmd.bss.capability = cpu_to_le16(tmp);
}
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
__le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
/* wake up first */
ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
CMD_ACT_SET, 0, 0,
&local_ps_mode);
if (ret) {
ret = -1;
goto out;
}
}
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto out;
}
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
if (ret == 0)
ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
@ -136,39 +295,131 @@ out:
* @brief Start an Adhoc Network
*
* @param priv A pointer to struct lbs_private structure
* @param adhocssid The ssid of the Adhoc Network
* @return 0--success, -1--fail
* @param assoc_req The association request describing the BSS to start
*
* @return 0 on success, error on failure
*/
static int lbs_start_adhoc_network(struct lbs_private *priv,
static int lbs_adhoc_start(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
struct cmd_ds_802_11_ad_hoc_start cmd;
u8 preamble = RADIO_PREAMBLE_LONG;
size_t ratesize = 0;
u16 tmpcap = 0;
int ret = 0;
priv->adhoccreate = 1;
lbs_deb_enter(LBS_DEB_ASSOC);
if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocStart: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
} else {
lbs_deb_join("AdhocStart: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
lbs_deb_join("ADHOC_START: Will use short preamble\n");
preamble = RADIO_PREAMBLE_SHORT;
}
lbs_set_radio_control(priv);
ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
/* Build the start command */
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
cmd.bsstype = CMD_BSS_TYPE_IBSS;
if (priv->beacon_period == 0)
priv->beacon_period = MRVDRV_BEACON_INTERVAL;
cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
WARN_ON(!assoc_req->channel);
/* set Physical parameter set */
cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
cmd.phyparamset.dsparamset.len = 1;
cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
/* set IBSS parameter set */
cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
cmd.ssparamset.ibssparamset.len = 2;
cmd.ssparamset.ibssparamset.atimwindow = 0;
/* set capability info */
tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n");
tmpcap |= WLAN_CAPABILITY_PRIVACY;
} else
lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n");
cmd.capability = cpu_to_le16(tmpcap);
/* Only v8 and below support setting probe delay */
if (priv->fwrelease < 0x09000000)
cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
memcpy(cmd.rates, lbs_bg_rates, ratesize);
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(cmd.rates, ratesize);
lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
if (lbs_create_dnld_countryinfo_11d(priv)) {
lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
ret = -1;
goto out;
}
lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
assoc_req->channel, assoc_req->band);
priv->adhoccreate = 1;
priv->mode = IW_MODE_ADHOC;
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
if (ret == 0)
ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
int lbs_stop_adhoc_network(struct lbs_private *priv)
/**
* @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
*
* @param priv A pointer to struct lbs_private structure
* @return 0 on success, or an error
*/
int lbs_adhoc_stop(struct lbs_private *priv)
{
return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
struct cmd_ds_802_11_ad_hoc_stop cmd;
int ret;
lbs_deb_enter(LBS_DEB_JOIN);
memset(&cmd, 0, sizeof (cmd));
cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
/* Clean up everything even if there was an error */
lbs_mac_event_disconnected(priv);
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
@ -480,14 +731,14 @@ static int assoc_helper_essid(struct lbs_private *priv,
if (bss != NULL) {
lbs_deb_assoc("SSID found, will join\n");
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
lbs_join_adhoc_network(priv, assoc_req);
lbs_adhoc_join(priv, assoc_req);
} else {
/* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
IW_ESSID_MAX_SIZE);
assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_start_adhoc_network(priv, assoc_req);
lbs_adhoc_start(priv, assoc_req);
}
}
@ -520,7 +771,7 @@ static int assoc_helper_bssid(struct lbs_private *priv,
ret = lbs_associate(priv, assoc_req);
lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
} else if (assoc_req->mode == IW_MODE_ADHOC) {
lbs_join_adhoc_network(priv, assoc_req);
lbs_adhoc_join(priv, assoc_req);
}
out:
@ -1029,7 +1280,9 @@ void lbs_association_worker(struct work_struct *work)
*/
if (priv->mode == IW_MODE_INFRA) {
if (should_deauth_infrastructure(priv, assoc_req)) {
ret = lbs_send_deauthentication(priv);
ret = lbs_cmd_80211_deauthenticate(priv,
priv->curbssparams.bssid,
WLAN_REASON_DEAUTH_LEAVING);
if (ret) {
lbs_deb_assoc("Deauthentication due to new "
"configuration request failed: %d\n",
@ -1038,7 +1291,7 @@ void lbs_association_worker(struct work_struct *work)
}
} else if (priv->mode == IW_MODE_ADHOC) {
if (should_stop_adhoc(priv, assoc_req)) {
ret = lbs_stop_adhoc_network(priv);
ret = lbs_adhoc_stop(priv);
if (ret) {
lbs_deb_assoc("Teardown of AdHoc network due to "
"new configuration request failed: %d\n",
@ -1213,94 +1466,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
}
/**
* @brief This function finds common rates between rate1 and card rates.
*
* It will fill common rates in rate1 as output if found.
*
* NOTE: Setting the MSB of the basic rates need to be taken
* care, either before or after calling this function
*
* @param priv A pointer to struct lbs_private structure
* @param rate1 the buffer which keeps input and output
* @param rate1_size the size of rate1 buffer; new size of buffer on return
*
* @return 0 or -1
*/
static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
u8 tmp[30];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
for (j = 0; rates[j] && (j < *rates_size); j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->enablehwauto) {
for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
goto done;
}
ret = 0;
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
memcpy(rates, tmp, *rates_size);
return ret;
}
/**
* @brief Sets the MSB on basic rates as the firmware requires
*
* Scan through an array and set the MSB for basic data rates.
*
* @param rates buffer of data rates
* @param len size of buffer
*/
static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
{
int i;
for (i = 0; i < len; i++) {
if (rates[i] == 0x02 || rates[i] == 0x04 ||
rates[i] == 0x0b || rates[i] == 0x16)
rates[i] |= 0x80;
}
}
/**
* @brief Send Deauthentication Request
*
* @param priv A pointer to struct lbs_private structure
* @return 0--success, -1--fail
*/
int lbs_send_deauthentication(struct lbs_private *priv)
{
return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
* @brief This function prepares command of authenticate.
*
@ -1353,26 +1518,37 @@ out:
return ret;
}
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd)
/**
* @brief Deauthenticate from a specific BSS
*
* @param priv A pointer to struct lbs_private structure
* @param bssid The specific BSS to deauthenticate from
* @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
*
* @return 0 on success, error on failure
*/
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
u16 reason)
{
struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
struct cmd_ds_802_11_deauthenticate cmd;
int ret;
lbs_deb_enter(LBS_DEB_JOIN);
cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
S_DS_GEN);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
cmd.reasoncode = cpu_to_le16(reason);
/* set AP MAC address */
memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
/* Reason code 3 = Station is leaving */
#define REASON_CODE_STA_LEAVING 3
dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
/* Clean up everything even if there was an error; can't assume that
* we're still authenticated to the AP after trying to deauth.
*/
lbs_mac_event_disconnected(priv);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
return ret;
}
int lbs_cmd_80211_associate(struct lbs_private *priv,
@ -1489,231 +1665,6 @@ done:
return ret;
}
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
int ret = 0;
int cmdappendsize = 0;
struct assoc_request *assoc_req = pdata_buf;
u16 tmpcap = 0;
size_t ratesize = 0;
lbs_deb_enter(LBS_DEB_JOIN);
if (!priv) {
ret = -1;
goto done;
}
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
/*
* Fill in the parameters for 2 data structures:
* 1. cmd_ds_802_11_ad_hoc_start command
* 2. priv->scantable[i]
*
* Driver will fill up SSID, bsstype,IBSS param, Physical Param,
* probe delay, and cap info.
*
* Firmware will fill up beacon period, DTIM, Basic rates
* and operational rates.
*/
memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
/* set the BSS type */
adhs->bsstype = CMD_BSS_TYPE_IBSS;
priv->mode = IW_MODE_ADHOC;
if (priv->beacon_period == 0)
priv->beacon_period = MRVDRV_BEACON_INTERVAL;
adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
/* set Physical param set */
#define DS_PARA_IE_ID 3
#define DS_PARA_IE_LEN 1
adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
WARN_ON(!assoc_req->channel);
lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
assoc_req->channel);
adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
/* set IBSS param set */
#define IBSS_PARA_IE_ID 6
#define IBSS_PARA_IE_LEN 2
adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
adhs->ssparamset.ibssparamset.atimwindow = 0;
/* set capability info */
tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_S_CMD: WEP enabled, "
"setting privacy on\n");
tmpcap |= WLAN_CAPABILITY_PRIVACY;
} else {
lbs_deb_join("ADHOC_S_CMD: WEP disabled, "
"setting privacy off\n");
}
adhs->capability = cpu_to_le16(tmpcap);
/* probedelay */
adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
memset(adhs->rates, 0, sizeof(adhs->rates));
ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
memcpy(adhs->rates, lbs_bg_rates, ratesize);
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(adhs->rates, ratesize);
lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
if (lbs_create_dnld_countryinfo_11d(priv)) {
lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
ret = -1;
goto done;
}
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
S_DS_GEN + cmdappendsize);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd)
{
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
cmd->size = cpu_to_le16(S_DS_GEN);
return 0;
}
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
struct assoc_request *assoc_req = pdata_buf;
struct bss_descriptor *bss = &assoc_req->bss;
int cmdappendsize = 0;
int ret = 0;
u16 ratesize = 0;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
sizeof(union ieeetypes_phyparamset));
memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
sizeof(union IEEEtypes_ssparamset));
join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
lbs_deb_join(
"ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
print_mac(mac, join_cmd->bss.bssid),
join_cmd->bss.ssid);
/* failtimeout */
join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
/* probedelay */
join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
priv->curbssparams.channel = bss->channel;
/* Copy Data rates from the rates recorded in scan response */
memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
memcpy(join_cmd->bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
ret = -1;
goto done;
}
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
join_cmd->bss.ssparamset.ibssparamset.atimwindow =
cpu_to_le16(bss->atimwindow);
if (assoc_req->secinfo.wep_enabled) {
u16 tmp = le16_to_cpu(join_cmd->bss.capability);
tmp |= WLAN_CAPABILITY_PRIVACY;
join_cmd->bss.capability = cpu_to_le16(tmp);
}
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
/* wake up first */
__le32 Localpsmode;
Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_PS_MODE,
CMD_ACT_SET,
0, 0, &Localpsmode);
if (ret) {
ret = -1;
goto done;
}
}
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
}
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
S_DS_GEN + cmdappendsize);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_ret_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
@ -1815,34 +1766,19 @@ done:
return ret;
}
int lbs_ret_80211_disassociate(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_JOIN);
lbs_mac_event_disconnected(priv);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
}
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *resp)
static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
{
int ret = 0;
u16 command = le16_to_cpu(resp->command);
u16 result = le16_to_cpu(resp->result);
struct cmd_ds_802_11_ad_hoc_result *padhocresult;
struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
union iwreq_data wrqu;
struct bss_descriptor *bss;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
padhocresult = &resp->params.result;
lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
lbs_deb_join("ADHOC_RESP: command = %x\n", command);
lbs_deb_join("ADHOC_RESP: result = %x\n", result);
adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp;
if (!priv->in_progress_assoc_req) {
lbs_deb_join("ADHOC_RESP: no in-progress association "
@ -1856,26 +1792,19 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
* Join result code 0 --> SUCCESS
*/
if (result) {
lbs_deb_join("ADHOC_RESP: failed\n");
lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
if (priv->connect_status == LBS_CONNECTED)
lbs_mac_event_disconnected(priv);
ret = -1;
goto done;
}
/*
* Now the join cmd should be successful
* If BSSID has changed use SSID to compare instead of BSSID
*/
lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
escape_essid(bss->ssid, bss->ssid_len));
/* Send a Media Connected event, according to the Spec */
priv->connect_status = LBS_CONNECTED;
if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
/* Update the created network descriptor with the new BSSID */
memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN);
}
/* Set the BSSID from the joined/started descriptor */
@ -1894,22 +1823,13 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
print_mac(mac, padhocresult->bssid));
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n",
escape_essid(bss->ssid, bss->ssid_len),
print_mac(mac, priv->curbssparams.bssid),
priv->curbssparams.channel);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_JOIN);
lbs_mac_event_disconnected(priv);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
}

View file

@ -12,28 +12,18 @@ struct cmd_ds_command;
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd);
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_adhoc_stop(struct lbs_private *priv);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd);
u8 bssid[ETH_ALEN], u16 reason);
int lbs_cmd_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv);
int lbs_ret_80211_disassociate(struct lbs_private *priv);
int lbs_ret_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_stop_adhoc_network(struct lbs_private *priv);
int lbs_send_deauthentication(struct lbs_private *priv);
#endif /* _LBS_ASSOC_H */

View file

@ -614,47 +614,67 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
return 0;
}
static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
/**
* @brief Get the min, max, and current TX power
*
* @param priv A pointer to struct lbs_private structure
* @param curlevel Current power level in dBm
* @param minlevel Minimum supported power level in dBm (optional)
* @param maxlevel Maximum supported power level in dBm (optional)
*
* @return 0 on success, error on failure
*/
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel)
{
struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
struct cmd_ds_802_11_rf_tx_power cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
prtp->action = cpu_to_le16(cmd_action);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_GET);
lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
le16_to_cpu(prtp->action));
switch (cmd_action) {
case CMD_ACT_TX_POWER_OPT_GET:
prtp->action = cpu_to_le16(CMD_ACT_GET);
prtp->currentlevel = 0;
break;
case CMD_ACT_TX_POWER_OPT_SET_HIGH:
prtp->action = cpu_to_le16(CMD_ACT_SET);
prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
break;
case CMD_ACT_TX_POWER_OPT_SET_MID:
prtp->action = cpu_to_le16(CMD_ACT_SET);
prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
break;
case CMD_ACT_TX_POWER_OPT_SET_LOW:
prtp->action = cpu_to_le16(CMD_ACT_SET);
prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
break;
ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
if (ret == 0) {
*curlevel = le16_to_cpu(cmd.curlevel);
if (minlevel)
*minlevel = le16_to_cpu(cmd.minlevel);
if (maxlevel)
*maxlevel = le16_to_cpu(cmd.maxlevel);
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
return ret;
}
/**
* @brief Set the TX power
*
* @param priv A pointer to struct lbs_private structure
* @param dbm The desired power level in dBm
*
* @return 0 on success, error on failure
*/
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
{
struct cmd_ds_802_11_rf_tx_power cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
cmd.curlevel = cpu_to_le16(dbm);
lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
@ -1269,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
priv->cur_cmd = NULL;
}
int lbs_set_radio_control(struct lbs_private *priv)
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
{
int ret = 0;
struct cmd_ds_802_11_radio_control cmd;
int ret = -EINVAL;
lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
switch (priv->preamble) {
case CMD_TYPE_SHORT_PREAMBLE:
cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
break;
case CMD_TYPE_LONG_PREAMBLE:
cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
break;
case CMD_TYPE_AUTO_PREAMBLE:
default:
cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
break;
/* Only v8 and below support setting the preamble */
if (priv->fwrelease < 0x09000000) {
switch (preamble) {
case RADIO_PREAMBLE_SHORT:
if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
goto out;
/* Fall through */
case RADIO_PREAMBLE_AUTO:
case RADIO_PREAMBLE_LONG:
cmd.control = cpu_to_le16(preamble);
break;
default:
goto out;
}
}
if (priv->radioon)
cmd.control |= cpu_to_le16(TURN_ON_RF);
else
cmd.control &= cpu_to_le16(~TURN_ON_RF);
if (radio_on)
cmd.control |= cpu_to_le16(0x1);
else {
cmd.control &= cpu_to_le16(~0x1);
priv->txpower_cur = 0;
}
lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
priv->preamble);
lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
radio_on ? "ON" : "OFF", preamble);
priv->radio_on = radio_on;
ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
@ -1393,14 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
break;
case CMD_802_11_DEAUTHENTICATE:
ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
break;
case CMD_802_11_AD_HOC_START:
ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
break;
case CMD_802_11_RESET:
ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
break;
@ -1420,28 +1438,15 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
break;
case CMD_802_11_RF_TX_POWER:
ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
cmd_action, pdata_buf);
break;
case CMD_802_11_MONITOR_MODE:
ret = lbs_cmd_802_11_monitor_mode(cmdptr,
cmd_action, pdata_buf);
break;
case CMD_802_11_AD_HOC_JOIN:
ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
break;
case CMD_802_11_RSSI:
ret = lbs_cmd_802_11_rssi(priv, cmdptr);
break;
case CMD_802_11_AD_HOC_STOP:
ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
break;
case CMD_802_11_SET_AFC:
case CMD_802_11_GET_AFC:

View file

@ -61,4 +61,10 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc);
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel);
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
#endif /* _LBS_CMD_H */

View file

@ -188,21 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
return 0;
}
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
lbs_deb_enter(LBS_DEB_CMD);
priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
@ -273,24 +258,10 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_80211_associate(priv, resp);
break;
case CMD_RET(CMD_802_11_DISASSOCIATE):
case CMD_RET(CMD_802_11_DEAUTHENTICATE):
ret = lbs_ret_80211_disassociate(priv);
break;
case CMD_RET(CMD_802_11_AD_HOC_START):
case CMD_RET(CMD_802_11_AD_HOC_JOIN):
ret = lbs_ret_80211_ad_hoc_start(priv, resp);
break;
case CMD_RET(CMD_802_11_SNMP_MIB):
ret = lbs_ret_802_11_snmp_mib(priv, resp);
break;
case CMD_RET(CMD_802_11_RF_TX_POWER):
ret = lbs_ret_802_11_rf_tx_power(priv, resp);
break;
case CMD_RET(CMD_802_11_SET_AFC):
case CMD_RET(CMD_802_11_GET_AFC):
spin_lock_irqsave(&priv->driver_lock, flags);
@ -309,10 +280,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp);
break;
case CMD_RET(CMD_802_11_AD_HOC_STOP):
ret = lbs_ret_80211_ad_hoc_stop(priv);
break;
case CMD_RET(CMD_802_11D_DOMAIN_INFO):
ret = lbs_ret_802_11d_domain_info(resp);
break;

View file

@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
int lbs_set_radio_control(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);

View file

@ -253,7 +253,9 @@ struct lbs_private {
u32 connect_status;
u32 mesh_connect_status;
u16 regioncode;
u16 txpowerlevel;
s16 txpower_cur;
s16 txpower_min;
s16 txpower_max;
/** POWER MANAGEMENT AND PnP SUPPORT */
u8 surpriseremoved;
@ -291,8 +293,7 @@ struct lbs_private {
u16 nextSNRNF;
u16 numSNRNF;
u8 radioon;
u32 preamble;
u8 radio_on;
/** data rate stuff */
u8 cur_rate;

View file

@ -61,7 +61,6 @@
#define CMD_RF_REG_MAP 0x0023
#define CMD_802_11_DEAUTHENTICATE 0x0024
#define CMD_802_11_REASSOCIATE 0x0025
#define CMD_802_11_DISASSOCIATE 0x0026
#define CMD_MAC_CONTROL 0x0028
#define CMD_802_11_AD_HOC_START 0x002b
#define CMD_802_11_AD_HOC_JOIN 0x002c
@ -153,11 +152,6 @@
#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
/* Define action or option for CMD_802_11_RADIO_CONTROL */
#define CMD_TYPE_AUTO_PREAMBLE 0x0001
#define CMD_TYPE_SHORT_PREAMBLE 0x0002
#define CMD_TYPE_LONG_PREAMBLE 0x0003
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
#define CMD_SUBSCRIBE_SNR_LOW 0x0002
@ -166,28 +160,14 @@
#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
#define TURN_ON_RF 0x01
#define RADIO_ON 0x01
#define RADIO_OFF 0x00
#define SET_AUTO_PREAMBLE 0x05
#define SET_SHORT_PREAMBLE 0x03
#define SET_LONG_PREAMBLE 0x01
#define RADIO_PREAMBLE_LONG 0x00
#define RADIO_PREAMBLE_SHORT 0x02
#define RADIO_PREAMBLE_AUTO 0x04
/* Define action or option for CMD_802_11_RF_CHANNEL */
#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
/* Define action or option for CMD_802_11_RF_TX_POWER */
#define CMD_ACT_TX_POWER_OPT_GET 0x0000
#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
/* Define action or option for CMD_802_11_DATA_RATE */
#define CMD_ACT_SET_TX_AUTO 0x0000
#define CMD_ACT_SET_TX_FIX_RATE 0x0001

View file

@ -232,7 +232,9 @@ struct cmd_ds_802_11_authenticate {
};
struct cmd_ds_802_11_deauthenticate {
u8 macaddr[6];
struct cmd_header hdr;
u8 macaddr[ETH_ALEN];
__le16 reasoncode;
};
@ -251,20 +253,10 @@ struct cmd_ds_802_11_associate {
#endif
} __attribute__ ((packed));
struct cmd_ds_802_11_disassociate {
u8 destmacaddr[6];
__le16 reasoncode;
};
struct cmd_ds_802_11_associate_rsp {
struct ieeetypes_assocrsp assocRsp;
};
struct cmd_ds_802_11_ad_hoc_result {
u8 pad[3];
u8 bssid[ETH_ALEN];
};
struct cmd_ds_802_11_set_wep {
struct cmd_header hdr;
@ -435,8 +427,12 @@ struct cmd_ds_802_11_mac_address {
};
struct cmd_ds_802_11_rf_tx_power {
struct cmd_header hdr;
__le16 action;
__le16 currentlevel;
__le16 curlevel;
s8 maxlevel;
s8 minlevel;
};
struct cmd_ds_802_11_rf_antenna {
@ -507,10 +503,12 @@ struct cmd_ds_802_11_rate_adapt_rateset {
};
struct cmd_ds_802_11_ad_hoc_start {
struct cmd_header hdr;
u8 ssid[IW_ESSID_MAX_SIZE];
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod;
u8 dtimperiod; /* Reserved on v9 and later */
union IEEEtypes_ssparamset ssparamset;
union ieeetypes_phyparamset phyparamset;
__le16 probedelay;
@ -519,9 +517,16 @@ struct cmd_ds_802_11_ad_hoc_start {
u8 tlv_memory_size_pad[100];
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_result {
struct cmd_header hdr;
u8 pad[3];
u8 bssid[ETH_ALEN];
};
struct adhoc_bssdesc {
u8 bssid[6];
u8 ssid[32];
u8 bssid[ETH_ALEN];
u8 ssid[IW_ESSID_MAX_SIZE];
u8 type;
__le16 beaconperiod;
u8 dtimperiod;
@ -539,10 +544,15 @@ struct adhoc_bssdesc {
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_join {
struct adhoc_bssdesc bss;
__le16 failtimeout;
__le16 probedelay;
struct cmd_header hdr;
struct adhoc_bssdesc bss;
__le16 failtimeout; /* Reserved on v9 and later */
__le16 probedelay; /* Reserved on v9 and later */
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_stop {
struct cmd_header hdr;
} __attribute__ ((packed));
struct cmd_ds_802_11_enable_rsn {
@ -693,21 +703,15 @@ struct cmd_ds_command {
union {
struct cmd_ds_802_11_ps_mode psmode;
struct cmd_ds_802_11_associate associate;
struct cmd_ds_802_11_deauthenticate deauth;
struct cmd_ds_802_11_ad_hoc_start ads;
struct cmd_ds_802_11_reset reset;
struct cmd_ds_802_11_ad_hoc_result result;
struct cmd_ds_802_11_authenticate auth;
struct cmd_ds_802_11_get_stat gstat;
struct cmd_ds_802_3_get_stat gstat_8023;
struct cmd_ds_802_11_snmp_mib smib;
struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_ad_hoc_join adj;
struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp;
struct cmd_ds_802_11_disassociate dassociate;
struct cmd_ds_mac_reg_access macreg;
struct cmd_ds_bbp_reg_access bbpreg;
struct cmd_ds_rf_reg_access rfreg;

View file

@ -291,9 +291,11 @@ static ssize_t lbs_rtap_set(struct device *dev,
if (priv->infra_open || priv->mesh_open)
return -EBUSY;
if (priv->mode == IW_MODE_INFRA)
lbs_send_deauthentication(priv);
lbs_cmd_80211_deauthenticate(priv,
priv->curbssparams.bssid,
WLAN_REASON_DEAUTH_LEAVING);
else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv);
lbs_adhoc_stop(priv);
lbs_add_rtap(priv);
}
priv->monitormode = monitor_mode;
@ -956,17 +958,24 @@ EXPORT_SYMBOL_GPL(lbs_resume);
static int lbs_setup_firmware(struct lbs_private *priv)
{
int ret = -1;
s16 curlevel = 0, minlevel = 0, maxlevel = 0;
lbs_deb_enter(LBS_DEB_FW);
/*
* Read MAC address from HW
*/
/* Read MAC address from firmware */
memset(priv->current_addr, 0xff, ETH_ALEN);
ret = lbs_update_hw_spec(priv);
if (ret)
goto done;
/* Read power levels if available */
ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
if (ret == 0) {
priv->txpower_cur = curlevel;
priv->txpower_min = minlevel;
priv->txpower_max = maxlevel;
}
lbs_set_mac_control(priv);
done:
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@ -1042,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mode = IW_MODE_INFRA;
priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radioon = RADIO_ON;
priv->radio_on = 1;
priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;

View file

@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
if (!netif_running(dev)) {
ret = -ENETDOWN;
goto out;

View file

@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
return cfp;
}
/**
* @brief Set Radio On/OFF
*
* @param priv A pointer to struct lbs_private structure
* @option Radio Option
* @return 0 --success, otherwise fail
*/
static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
if (priv->radioon != option) {
lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
priv->radioon = option;
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_RADIO_CONTROL,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, NULL);
}
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
/**
* @brief Copy active data rates based on adapter mode and status
*
@ -420,28 +392,30 @@ static int lbs_get_txpow(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
int ret = 0;
struct lbs_private *priv = dev->priv;
s16 curlevel = 0;
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_RF_TX_POWER,
CMD_ACT_TX_POWER_OPT_GET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (!priv->radio_on) {
lbs_deb_wext("tx power off\n");
vwrq->value = 0;
vwrq->disabled = 1;
goto out;
}
ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
if (ret)
goto out;
lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel);
vwrq->value = priv->txpowerlevel;
lbs_deb_wext("tx power level %d dbm\n", curlevel);
priv->txpower_cur = curlevel;
vwrq->value = curlevel;
vwrq->fixed = 1;
if (priv->radioon) {
vwrq->disabled = 0;
vwrq->flags = IW_TXPOW_DBM;
} else {
vwrq->disabled = 1;
}
vwrq->disabled = 0;
vwrq->flags = IW_TXPOW_DBM;
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@ -693,22 +667,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
range->sensitivity = 0;
/*
* Setup the supported power level ranges
*/
/* Setup the supported power level ranges */
memset(range->txpower, 0, sizeof(range->txpower));
range->txpower[0] = 5;
range->txpower[1] = 7;
range->txpower[2] = 9;
range->txpower[3] = 11;
range->txpower[4] = 13;
range->txpower[5] = 15;
range->txpower[6] = 17;
range->txpower[7] = 19;
range->num_txpower = 8;
range->txpower_capa = IW_TXPOW_DBM;
range->txpower_capa |= IW_TXPOW_RANGE;
range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
range->txpower[0] = priv->txpower_min;
range->txpower[1] = priv->txpower_max;
range->num_txpower = 2;
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
IW_EVENT_CAPA_MASK(SIOCGIWAP) |
@ -998,9 +962,11 @@ static int lbs_mesh_set_freq(struct net_device *dev,
if (fwrq->m != priv->curbssparams.channel) {
lbs_deb_wext("mesh channel change forces eth disconnect\n");
if (priv->mode == IW_MODE_INFRA)
lbs_send_deauthentication(priv);
lbs_cmd_80211_deauthenticate(priv,
priv->curbssparams.bssid,
WLAN_REASON_DEAUTH_LEAVING);
else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv);
lbs_adhoc_stop(priv);
}
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
lbs_update_channel(priv);
@ -1844,39 +1810,50 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
{
int ret = 0;
struct lbs_private *priv = dev->priv;
u16 dbm;
s16 dbm = (s16) vwrq->value;
lbs_deb_enter(LBS_DEB_WEXT);
if (vwrq->disabled) {
lbs_radio_ioctl(priv, RADIO_OFF);
return 0;
lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
goto out;
}
priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
if (vwrq->fixed == 0) {
/* Auto power control */
dbm = priv->txpower_max;
} else {
/* Userspace check in iwrange if it should use dBm or mW,
* therefore this should never happen... Jean II */
if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
ret = -EOPNOTSUPP;
goto out;
}
lbs_radio_ioctl(priv, RADIO_ON);
/* Validate requested power level against firmware allowed levels */
if (priv->txpower_min && (dbm < priv->txpower_min)) {
ret = -EINVAL;
goto out;
}
/* Userspace check in iwrange if it should use dBm or mW,
* therefore this should never happen... Jean II */
if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
return -EOPNOTSUPP;
} else
dbm = (u16) vwrq->value;
if (priv->txpower_max && (dbm > priv->txpower_max)) {
ret = -EINVAL;
goto out;
}
}
/* auto tx power control */
/* If the radio was off, turn it on */
if (!priv->radio_on) {
ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
if (ret)
goto out;
}
if (vwrq->fixed == 0)
dbm = 0xffff;
lbs_deb_wext("txpower set %d dBm\n", dbm);
lbs_deb_wext("txpower set %d dbm\n", dbm);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_RF_TX_POWER,
CMD_ACT_TX_POWER_OPT_SET_LOW,
CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
ret = lbs_set_tx_power(priv, dbm);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
@ -1928,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
/* Check the size of the string */
if (in_ssid_len > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
@ -2005,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
/* Check the size of the string */
if (dwrq->length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
@ -2046,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on)
return -EINVAL;
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;

View file

@ -477,9 +477,9 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
{
struct ieee80211_rx_status stats;
struct rxpd *prxpd;
bool is_qos, is_4addr, is_amsdu, need_padding;
int need_padding;
unsigned int flags;
u16 fc, fc_le;
struct ieee80211_hdr *hdr;
prxpd = (struct rxpd *) skb->data;
@ -497,19 +497,15 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
stats.rate_idx = prxpd->rx_rate;
skb_pull(skb, sizeof(struct rxpd));
fc_le = *((__le16 *) skb->data);
fc = le16_to_cpu(fc_le);
hdr = (struct ieee80211_hdr *)skb->data;
flags = le32_to_cpu(*(__le32 *)(skb->data + 4));
is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
(fc & IEEE80211_STYPE_QOS_DATA);
is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
is_amsdu = ((fc & 0x8C) == 0x88) &&
(*(skb->data + ieee80211_hdrlen(fc_le) - QOS_CONTROL_LEN)
& IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
need_padding = ieee80211_is_data_qos(hdr->frame_control);
need_padding ^= ieee80211_has_a4(hdr->frame_control);
need_padding ^= ieee80211_is_data_qos(hdr->frame_control) &&
(*ieee80211_get_qos_ctl(hdr) &
IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
need_padding = is_qos ^ is_4addr ^ is_amsdu;
if (need_padding) {
memmove(skb->data + 2, skb->data, skb->len);
skb_reserve(skb, 2);

View file

@ -446,7 +446,8 @@ static int __init init_mac80211_hwsim(void)
SET_IEEE80211_PERM_ADDR(hw, addr);
hw->channel_change_time = 1;
hw->queues = 1;
hw->queues = 4;
hw->ampdu_queues = 1;
memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
@ -454,6 +455,19 @@ static int __init init_mac80211_hwsim(void)
data->band.n_channels = ARRAY_SIZE(hwsim_channels);
data->band.bitrates = data->rates;
data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
data->band.ht_info.ht_supported = 1;
data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
data->band.ht_info.ampdu_factor = 0x3;
data->band.ht_info.ampdu_density = 0x6;
memset(data->band.ht_info.supp_mcs_set, 0,
sizeof(data->band.ht_info.supp_mcs_set));
data->band.ht_info.supp_mcs_set[0] = 0xff;
data->band.ht_info.supp_mcs_set[1] = 0xff;
data->band.ht_info.supp_mcs_set[12] =
IEEE80211_HT_CAP_MCS_TX_DEFINED;
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
err = ieee80211_register_hw(hw);

View file

@ -66,7 +66,7 @@ struct p54_common {
unsigned int tx_hdr_len;
void *cached_vdcf;
unsigned int fw_var;
struct ieee80211_tx_queue_stats tx_stats[4];
struct ieee80211_tx_queue_stats tx_stats[8];
};
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);

View file

@ -146,23 +146,23 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
if (priv->fw_var >= 0x300) {
/* Firmware supports QoS, use it! */
priv->tx_stats[0].limit = 3;
priv->tx_stats[1].limit = 4;
priv->tx_stats[2].limit = 3;
priv->tx_stats[3].limit = 1;
priv->tx_stats[4].limit = 3;
priv->tx_stats[5].limit = 4;
priv->tx_stats[6].limit = 3;
priv->tx_stats[7].limit = 1;
dev->queues = 4;
}
}
EXPORT_SYMBOL_GPL(p54_parse_firmware);
static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
static int p54_convert_rev0(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
{
struct p54_common *priv = dev->priv;
struct pda_pa_curve_data_sample_rev1 *rev1;
struct pda_pa_curve_data_sample_rev0 *rev0;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev0 *src;
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*rev1) + 2) *
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
@ -180,27 +180,63 @@ static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
*((__le16 *)target) = *freq;
target += sizeof(__le16);
for (j = 0; j < curve_data->points_per_channel; j++) {
rev1 = target;
rev0 = source;
dst = target;
src = source;
rev1->rf_power = rev0->rf_power;
rev1->pa_detector = rev0->pa_detector;
rev1->data_64qam = rev0->pcv;
dst->rf_power = src->rf_power;
dst->pa_detector = src->pa_detector;
dst->data_64qam = src->pcv;
/* "invent" the points for the other modulations */
#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
rev1->data_16qam = SUB(rev0->pcv, 12);
rev1->data_qpsk = SUB(rev1->data_16qam, 12);
rev1->data_bpsk = SUB(rev1->data_qpsk, 12);
rev1->data_barker= SUB(rev1->data_bpsk, 14);
dst->data_16qam = SUB(src->pcv, 12);
dst->data_qpsk = SUB(dst->data_16qam, 12);
dst->data_bpsk = SUB(dst->data_qpsk, 12);
dst->data_barker = SUB(dst->data_bpsk, 14);
#undef SUB
target += sizeof(*rev1);
source += sizeof(*rev0);
target += sizeof(*dst);
source += sizeof(*src);
}
}
return 0;
}
static int p54_convert_rev1(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
{
struct p54_common *priv = dev->priv;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev1 *src;
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
if (!priv->curve_data)
return -ENOMEM;
memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
source = curve_data->data;
target = priv->curve_data->data;
for (i = 0; i < curve_data->channels; i++) {
__le16 *freq = source;
source += sizeof(__le16);
*((__le16 *)target) = *freq;
target += sizeof(__le16);
for (j = 0; j < curve_data->points_per_channel; j++) {
memcpy(target, source, sizeof(*src));
target += sizeof(*dst);
source += sizeof(*src);
}
source++;
}
return 0;
}
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
{
struct p54_common *priv = dev->priv;
@ -250,27 +286,32 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
entry->data[1]*sizeof(*priv->output_limit));
priv->output_limit_len = entry->data[1];
break;
case PDR_PRISM_PA_CAL_CURVE_DATA:
if (data_len < sizeof(struct pda_pa_curve_data)) {
case PDR_PRISM_PA_CAL_CURVE_DATA: {
struct pda_pa_curve_data *curve_data =
(struct pda_pa_curve_data *)entry->data;
if (data_len < sizeof(*curve_data)) {
err = -EINVAL;
goto err;
}
if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) {
priv->curve_data = kmalloc(data_len, GFP_KERNEL);
if (!priv->curve_data) {
err = -ENOMEM;
goto err;
}
memcpy(priv->curve_data, entry->data, data_len);
} else {
err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data);
if (err)
goto err;
switch (curve_data->cal_method_rev) {
case 0:
err = p54_convert_rev0(dev, curve_data);
break;
case 1:
err = p54_convert_rev1(dev, curve_data);
break;
default:
printk(KERN_ERR "p54: unknown curve data "
"revision %d\n",
curve_data->cal_method_rev);
err = -ENODEV;
break;
}
if (err)
goto err;
break;
}
case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
if (!priv->iq_autocal) {
@ -377,7 +418,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
int i;
for (i = 0; i < dev->queues; i++)
if (priv->tx_stats[i].len < priv->tx_stats[i].limit)
if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
ieee80211_wake_queue(dev, i);
}
@ -391,7 +432,9 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
struct memrecord *range = NULL;
u32 freed = 0;
u32 last_addr = priv->rx_start;
unsigned long flags;
spin_lock_irqsave(&priv->tx_queue.lock, flags);
while (entry != (struct sk_buff *)&priv->tx_queue) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
range = (void *)info->driver_data;
@ -412,13 +455,15 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
last_addr = range->end_addr;
__skb_unlink(entry, &priv->tx_queue);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
memset(&info->status, 0, sizeof(info->status));
entry_hdr = (struct p54_control_hdr *) entry->data;
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
pad = entry_data->align[0];
priv->tx_stats[entry_data->hw_queue - 4].len--;
priv->tx_stats[entry_data->hw_queue].len--;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (!(payload->status & 0x01))
info->flags |= IEEE80211_TX_STAT_ACK;
@ -429,12 +474,14 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
info->status.ack_signal = le16_to_cpu(payload->ack_rssi);
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
ieee80211_tx_status_irqsafe(dev, entry);
break;
goto out;
} else
last_addr = range->end_addr;
entry = entry->next;
}
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
out:
if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
sizeof(struct p54_control_hdr))
p54_wake_free_queues(dev);
@ -559,7 +606,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
u8 rate;
u8 cts_rate = 0x20;
current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
if (unlikely(current_queue->len > current_queue->limit))
return NETDEV_TX_BUSY;
current_queue->len++;
@ -672,12 +719,9 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
struct p54_control_hdr *hdr;
struct p54_tx_control_channel *chan;
unsigned int i;
size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
sizeof(*chan->curve_data) *
priv->curve_data->points_per_channel;
void *entry;
hdr = kzalloc(sizeof(*hdr) + payload_len +
hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
priv->tx_hdr_len, GFP_KERNEL);
if (!hdr)
return -ENOMEM;
@ -689,10 +733,10 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*chan));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan));
chan->magic1 = cpu_to_le16(0x1);
chan->magic2 = cpu_to_le16(0x0);
chan->flags = cpu_to_le16(0x1);
chan->dwell = cpu_to_le16(0x0);
for (i = 0; i < priv->iq_autocal_len; i++) {
if (priv->iq_autocal[i].freq != freq)
@ -710,35 +754,41 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
continue;
chan->val_barker = 0x38;
chan->val_bpsk = priv->output_limit[i].val_bpsk;
chan->val_qpsk = priv->output_limit[i].val_qpsk;
chan->val_16qam = priv->output_limit[i].val_16qam;
chan->val_64qam = priv->output_limit[i].val_64qam;
chan->val_bpsk = chan->dup_bpsk =
priv->output_limit[i].val_bpsk;
chan->val_qpsk = chan->dup_qpsk =
priv->output_limit[i].val_qpsk;
chan->val_16qam = chan->dup_16qam =
priv->output_limit[i].val_16qam;
chan->val_64qam = chan->dup_64qam =
priv->output_limit[i].val_64qam;
break;
}
if (i == priv->output_limit_len)
goto err;
chan->pa_points_per_curve = priv->curve_data->points_per_channel;
entry = priv->curve_data->data;
for (i = 0; i < priv->curve_data->channels; i++) {
if (*((__le16 *)entry) != freq) {
entry += sizeof(__le16);
entry += sizeof(struct pda_pa_curve_data_sample_rev1) *
chan->pa_points_per_curve;
entry += sizeof(struct p54_pa_curve_data_sample) *
priv->curve_data->points_per_channel;
continue;
}
entry += sizeof(__le16);
chan->pa_points_per_curve =
min(priv->curve_data->points_per_channel, (u8) 8);
memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
chan->pa_points_per_curve);
break;
}
memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4);
chan->rssical_mul = cpu_to_le16(130);
chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */
priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1);
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1);
return 0;
err:
@ -987,7 +1037,7 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues);
memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues);
return 0;
}
@ -1025,7 +1075,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
dev->channel_change_time = 1000; /* TODO: find actual value */
dev->max_signal = 127;
priv->tx_stats[0].limit = 5;
priv->tx_stats[0].limit = 1;
priv->tx_stats[1].limit = 1;
priv->tx_stats[2].limit = 1;
priv->tx_stats[3].limit = 1;
priv->tx_stats[4].limit = 5;
dev->queues = 1;
dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +

View file

@ -89,6 +89,16 @@ struct pda_pa_curve_data_sample_rev1 {
u8 data_qpsk;
u8 data_16qam;
u8 data_64qam;
} __attribute__ ((packed));
struct p54_pa_curve_data_sample {
u8 rf_power;
u8 pa_detector;
u8 data_barker;
u8 data_bpsk;
u8 data_qpsk;
u8 data_16qam;
u8 data_64qam;
u8 padding;
} __attribute__ ((packed));
@ -212,8 +222,8 @@ struct p54_tx_control_filter {
} __attribute__ ((packed));
struct p54_tx_control_channel {
__le16 magic1;
__le16 magic2;
__le16 flags;
__le16 dwell;
u8 padding1[20];
struct pda_iq_autocal_entry iq_autocal;
u8 pa_points_per_curve;
@ -222,8 +232,13 @@ struct p54_tx_control_channel {
u8 val_qpsk;
u8 val_16qam;
u8 val_64qam;
struct pda_pa_curve_data_sample_rev1 curve_data[0];
/* additional padding/data after curve_data */
struct pda_pa_curve_data_sample_rev1 curve_data[8];
u8 dup_bpsk;
u8 dup_qpsk;
u8 dup_16qam;
u8 dup_64qam;
__le16 rssical_mul;
__le16 rssical_add;
} __attribute__ ((packed));
struct p54_tx_control_led {

View file

@ -3,6 +3,7 @@
* Linux device driver for PCI based Prism54
*
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2008, Christian Lamparter <chunkeey@web.de>
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
@ -237,20 +238,22 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
return err;
}
static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
int ring_index, struct p54p_desc *ring, u32 ring_limit,
struct sk_buff **rx_buf)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
u32 limit, host_idx, idx;
u32 limit, idx, i;
host_idx = le32_to_cpu(ring_control->host_idx[0]);
limit = host_idx;
limit -= le32_to_cpu(ring_control->device_idx[0]);
limit = ARRAY_SIZE(ring_control->rx_data) - limit;
idx = le32_to_cpu(ring_control->host_idx[ring_index]);
limit = idx;
limit -= le32_to_cpu(ring_control->device_idx[ring_index]);
limit = ring_limit - limit;
idx = host_idx % ARRAY_SIZE(ring_control->rx_data);
i = idx % ring_limit;
while (limit-- > 1) {
struct p54p_desc *desc = &ring_control->rx_data[idx];
struct p54p_desc *desc = &ring[i];
if (!desc->host_addr) {
struct sk_buff *skb;
@ -267,16 +270,106 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
desc->device_addr = 0; // FIXME: necessary?
desc->len = cpu_to_le16(MAX_RX_SIZE);
desc->flags = 0;
priv->rx_buf[idx] = skb;
rx_buf[i] = skb;
}
i++;
idx++;
host_idx++;
idx %= ARRAY_SIZE(ring_control->rx_data);
i %= ring_limit;
}
wmb();
ring_control->host_idx[0] = cpu_to_le32(host_idx);
ring_control->host_idx[ring_index] = cpu_to_le32(idx);
}
static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
int ring_index, struct p54p_desc *ring, u32 ring_limit,
struct sk_buff **rx_buf)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
u32 idx, i;
i = (*index) % ring_limit;
(*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
idx %= ring_limit;
while (i != idx) {
u16 len;
struct sk_buff *skb;
desc = &ring[i];
len = le16_to_cpu(desc->len);
skb = rx_buf[i];
if (!skb)
continue;
skb_put(skb, len);
if (p54_rx(dev, skb)) {
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
rx_buf[i] = NULL;
desc->host_addr = 0;
} else {
skb_trim(skb, 0);
desc->len = cpu_to_le16(MAX_RX_SIZE);
}
i++;
i %= ring_limit;
}
p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
}
/* caller must hold priv->lock */
static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
int ring_index, struct p54p_desc *ring, u32 ring_limit,
void **tx_buf)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
u32 idx, i;
i = (*index) % ring_limit;
(*index) = idx = le32_to_cpu(ring_control->device_idx[1]);
idx %= ring_limit;
while (i != idx) {
desc = &ring[i];
kfree(tx_buf[i]);
tx_buf[i] = NULL;
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
desc->host_addr = 0;
desc->device_addr = 0;
desc->len = 0;
desc->flags = 0;
i++;
i %= ring_limit;
}
}
static void p54p_rx_tasklet(unsigned long dev_id)
{
struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id;
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data,
ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data);
wmb();
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
}
static irqreturn_t p54p_interrupt(int irq, void *dev_id)
@ -298,65 +391,18 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
reg &= P54P_READ(int_enable);
if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
struct p54p_desc *desc;
u32 idx, i;
i = priv->tx_idx;
i %= ARRAY_SIZE(ring_control->tx_data);
priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]);
idx %= ARRAY_SIZE(ring_control->tx_data);
p54p_check_tx_ring(dev, &priv->tx_idx_mgmt,
3, ring_control->tx_mgmt,
ARRAY_SIZE(ring_control->tx_mgmt),
priv->tx_buf_mgmt);
while (i != idx) {
desc = &ring_control->tx_data[i];
if (priv->tx_buf[i]) {
kfree(priv->tx_buf[i]);
priv->tx_buf[i] = NULL;
}
p54p_check_tx_ring(dev, &priv->tx_idx_data,
1, ring_control->tx_data,
ARRAY_SIZE(ring_control->tx_data),
priv->tx_buf_data);
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
tasklet_schedule(&priv->rx_tasklet);
desc->host_addr = 0;
desc->device_addr = 0;
desc->len = 0;
desc->flags = 0;
i++;
i %= ARRAY_SIZE(ring_control->tx_data);
}
i = priv->rx_idx;
i %= ARRAY_SIZE(ring_control->rx_data);
priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]);
idx %= ARRAY_SIZE(ring_control->rx_data);
while (i != idx) {
u16 len;
struct sk_buff *skb;
desc = &ring_control->rx_data[i];
len = le16_to_cpu(desc->len);
skb = priv->rx_buf[i];
skb_put(skb, len);
if (p54_rx(dev, skb)) {
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
priv->rx_buf[i] = NULL;
desc->host_addr = 0;
} else {
skb_trim(skb, 0);
desc->len = cpu_to_le16(MAX_RX_SIZE);
}
i++;
i %= ARRAY_SIZE(ring_control->rx_data);
}
p54p_refill_rx_ring(dev);
wmb();
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
} else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
complete(&priv->boot_comp);
@ -392,7 +438,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
ring_control->host_idx[1] = cpu_to_le32(idx + 1);
if (free_on_tx)
priv->tx_buf[i] = data;
priv->tx_buf_data[i] = data;
spin_unlock_irqrestore(&priv->lock, flags);
@ -420,8 +466,14 @@ static int p54p_open(struct ieee80211_hw *dev)
}
memset(priv->ring_control, 0, sizeof(*priv->ring_control));
priv->rx_idx = priv->tx_idx = 0;
p54p_refill_rx_ring(dev);
priv->rx_idx_data = priv->tx_idx_data = 0;
priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
p54p_upload_firmware(dev);
@ -465,6 +517,8 @@ static void p54p_stop(struct ieee80211_hw *dev)
unsigned int i;
struct p54p_desc *desc;
tasklet_kill(&priv->rx_tasklet);
P54P_WRITE(int_enable, cpu_to_le32(0));
P54P_READ(int_enable);
udelay(10);
@ -473,26 +527,51 @@ static void p54p_stop(struct ieee80211_hw *dev)
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
desc = &ring_control->rx_data[i];
if (desc->host_addr)
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
kfree_skb(priv->rx_buf[i]);
priv->rx_buf[i] = NULL;
kfree_skb(priv->rx_buf_data[i]);
priv->rx_buf_data[i] = NULL;
}
for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) {
desc = &ring_control->rx_mgmt[i];
if (desc->host_addr)
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
kfree_skb(priv->rx_buf_mgmt[i]);
priv->rx_buf_mgmt[i] = NULL;
}
for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) {
desc = &ring_control->tx_data[i];
if (desc->host_addr)
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
kfree(priv->tx_buf[i]);
priv->tx_buf[i] = NULL;
kfree(priv->tx_buf_data[i]);
priv->tx_buf_data[i] = NULL;
}
memset(ring_control, 0, sizeof(ring_control));
for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) {
desc = &ring_control->tx_mgmt[i];
if (desc->host_addr)
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
kfree(priv->tx_buf_mgmt[i]);
priv->tx_buf_mgmt[i] = NULL;
}
memset(ring_control, 0, sizeof(*ring_control));
}
static int __devinit p54p_probe(struct pci_dev *pdev,
@ -585,6 +664,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv->common.tx = p54p_tx;
spin_lock_init(&priv->lock);
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
err = ieee80211_register_hw(dev);
if (err) {

View file

@ -92,13 +92,17 @@ struct p54p_priv {
struct p54_common common;
struct pci_dev *pdev;
struct p54p_csr __iomem *map;
struct tasklet_struct rx_tasklet;
spinlock_t lock;
struct p54p_ring_control *ring_control;
dma_addr_t ring_control_dma;
u32 rx_idx, tx_idx;
struct sk_buff *rx_buf[8];
void *tx_buf[32];
u32 rx_idx_data, tx_idx_data;
u32 rx_idx_mgmt, tx_idx_mgmt;
struct sk_buff *rx_buf_data[8];
struct sk_buff *rx_buf_mgmt[4];
void *tx_buf_data[32];
void *tx_buf_mgmt[4];
struct completion boot_comp;
};

View file

@ -1241,7 +1241,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/*

View file

@ -1316,6 +1316,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
else
rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
}
@ -1377,7 +1379,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/*

View file

@ -1114,8 +1114,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
skb->len - skbdesc->desc_len);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
@ -1280,6 +1279,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
else
rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
@ -1297,7 +1298,7 @@ static void rt2500usb_beacondone(struct urb *urb)
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
return;
/*

View file

@ -44,7 +44,7 @@
/*
* Module information.
*/
#define DRV_VERSION "2.2.0"
#define DRV_VERSION "2.2.1"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
@ -629,14 +629,13 @@ enum rt2x00_flags {
/*
* Device state flags
*/
DEVICE_PRESENT,
DEVICE_REGISTERED_HW,
DEVICE_INITIALIZED,
DEVICE_STARTED,
DEVICE_STARTED_SUSPEND,
DEVICE_ENABLED_RADIO,
DEVICE_DISABLED_RADIO_HW,
DEVICE_DIRTY_CONFIG,
DEVICE_STATE_PRESENT,
DEVICE_STATE_REGISTERED_HW,
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_STARTED_SUSPEND,
DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements

View file

@ -121,7 +121,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* Antenna setup changes require the RX to be disabled,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
/*
@ -136,7 +136,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
rt2x00dev->link.ant.active.rx = libconf.ant.rx;
rt2x00dev->link.ant.active.tx = libconf.ant.tx;
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
}

View file

@ -34,7 +34,7 @@
*/
void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
{
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
@ -94,8 +94,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
return 0;
/*
@ -117,7 +117,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00leds_led_radio(rt2x00dev, true);
rt2x00led_led_activity(rt2x00dev, true);
__set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
/*
* Enable RX.
@ -134,7 +134,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
{
if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
@ -354,7 +354,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
* When the radio is shutting down we should
* immediately cease all link tuning.
*/
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
@ -431,7 +431,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
* note that in the spinlock protected area above the delayed_flags
* have been cleared correctly.
*/
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
if (delayed_flags & DELAYED_UPDATE_BEACON)
@ -484,7 +484,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
{
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
@ -572,7 +572,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
@ -653,7 +653,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->plcp == rxdesc.signal)) ||
(!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) &&
(rate->bitrate == rxdesc.signal))) {
idx = i;
break;
@ -888,7 +888,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
{
if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags))
ieee80211_unregister_hw(rt2x00dev->hw);
if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) {
@ -906,6 +906,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
struct hw_mode_spec *spec = &rt2x00dev->spec;
int status;
if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags))
return 0;
/*
* Initialize HW modes.
*/
@ -927,7 +930,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
return status;
}
__set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags);
return 0;
}
@ -937,7 +940,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
{
if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags))
return;
/*
@ -960,7 +963,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
{
int status;
if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags))
return 0;
/*
@ -979,7 +982,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
return status;
}
__set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
/*
* Register the extra components.
@ -993,7 +996,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
{
int retval;
if (test_bit(DEVICE_STARTED, &rt2x00dev->flags))
if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return 0;
/*
@ -1011,28 +1014,18 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
if (retval)
return retval;
/*
* Enable radio.
*/
retval = rt2x00lib_enable_radio(rt2x00dev);
if (retval) {
rt2x00lib_uninitialize(rt2x00dev);
return retval;
}
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
__set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
return 0;
}
void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
{
if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return;
/*
@ -1044,8 +1037,6 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
}
/*
@ -1100,7 +1091,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
return 0;
@ -1113,7 +1104,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
{
__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
/*
* Disable radio.
@ -1158,14 +1149,15 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
int retval;
NOTICE(rt2x00dev, "Going to sleep.\n");
__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
/*
* Only continue if mac80211 has open interfaces.
*/
if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
goto exit;
__set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags);
set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags);
/*
* Disable radio.
@ -1237,7 +1229,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
/*
* Only continue if mac80211 had open interfaces.
*/
if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags))
return 0;
/*
@ -1264,7 +1256,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
/*
* We are ready again to receive requests from mac80211.
*/
__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
/*
* It is possible that during that mac80211 has attempted
@ -1284,7 +1276,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
return 0;
exit:
rt2x00lib_disable_radio(rt2x00dev);
rt2x00lib_stop(rt2x00dev);
rt2x00lib_uninitialize(rt2x00dev);
rt2x00debug_deregister(rt2x00dev);

View file

@ -117,7 +117,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* Note that we can only stop the TX queues inside the TX path
* due to possible race conditions in mac80211.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
goto exit_fail;
/*
@ -175,7 +175,7 @@ int rt2x00mac_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
return rt2x00lib_start(rt2x00dev);
@ -186,7 +186,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
rt2x00lib_stop(rt2x00dev);
@ -206,8 +206,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* Don't allow interfaces to be added
* the device has disappeared.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return -ENODEV;
switch (conf->type) {
@ -256,7 +256,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
*/
for (i = 0; i < queue->limit; i++) {
entry = &queue->entries[i];
if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
break;
}
@ -310,7 +310,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* either the device has disappeared or when
* no interface is present.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
(conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) ||
(conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count))
return;
@ -324,7 +324,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* Release beacon entry so it is available for
* new interfaces again.
*/
__clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
/*
* Make sure the bssid and mac address registers
@ -338,45 +338,45 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
int force_reconfig;
int radio_on;
int status;
/*
* Mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
/*
* Check if we need to disable the radio,
* if this is not the case, at least the RX must be disabled.
* Only change device state when the radio is enabled. It does not
* matter what parameters we have configured when the radio is disabled
* because we won't be able to send or receive anyway. Also note that
* some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
if (!conf->radio_enabled)
rt2x00lib_disable_radio(rt2x00dev);
else
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
}
radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
if (conf->radio_enabled) {
/* For programming the values, we have to turn RX off */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
/*
* When the DEVICE_DIRTY_CONFIG flag is set, the device has recently
* been started and the configuration must be forced upon the hardware.
* Otherwise registers will not be intialized correctly and could
* result in non-working hardware because essential registers aren't
* initialized.
*/
force_reconfig =
__test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
/* Enable the radio */
status = rt2x00lib_enable_radio(rt2x00dev);
if (unlikely(status))
return status;
rt2x00lib_config(rt2x00dev, conf, force_reconfig);
/*
* When we've just turned on the radio, we want to reprogram
* everything to ensure a consistent state
*/
rt2x00lib_config(rt2x00dev, conf, !radio_on);
/*
* Reenable RX only if the radio should be on.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
/* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
else if (conf->radio_enabled)
return rt2x00lib_enable_radio(rt2x00dev);
} else {
/* Disable the radio */
rt2x00lib_disable_radio(rt2x00dev);
}
return 0;
}
@ -395,7 +395,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
* Mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
spin_lock(&intf->lock);
@ -666,10 +666,11 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
queue->aifs = params->aifs;
queue->txop = params->txop;
INFO(rt2x00dev,
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
queue_idx, queue->cw_min, queue->cw_max, queue->aifs);
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
return 0;
}

View file

@ -100,8 +100,21 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
/*
* If device has requested headroom, we should make sure that
* is also mapped to the DMA so it can be used for transfering
* additional descriptor information to the hardware.
*/
skb_push(skb, rt2x00dev->hw->extra_tx_headroom);
skbdesc->skb_dma =
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
/*
* Restore data pointer to original location again.
*/
skb_pull(skb, rt2x00dev->hw->extra_tx_headroom);
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@ -117,7 +130,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
/*
* Add headroom to the skb length, it has been removed
* by the driver, but it was actually mapped to DMA.
*/
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
skb->len + rt2x00dev->hw->extra_tx_headroom,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
@ -356,7 +374,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
if (unlikely(rt2x00queue_full(queue)))
return -EINVAL;
if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(queue->rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
@ -396,7 +414,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
* the frame to mac80211 because the skb->cb has now been tainted.
*/
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
return 0;
@ -405,7 +423,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
rt2x00queue_map_txskb(queue->rt2x00dev, skb);
__set_bit(ENTRY_DATA_PENDING, &entry->flags);
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(queue, Q_INDEX);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
@ -718,6 +736,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
queue->rt2x00dev = rt2x00dev;
queue->qid = qid;
queue->txop = 0;
queue->aifs = 2;
queue->cw_min = 5;
queue->cw_max = 10;

View file

@ -140,13 +140,14 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
/**
* enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc
*
* @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value,
* or does it contain the bitrate itself.
* @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
* @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
* @RXDONE_MY_BSS: Does this frame originate from device's BSS.
*/
enum rxdone_entry_desc_flags {
RXDONE_SIGNAL_PLCP = 1 << 0,
RXDONE_MY_BSS = 1 << 1,
RXDONE_SIGNAL_BITRATE = 1 << 1,
RXDONE_MY_BSS = 1 << 2,
};
/**
@ -368,6 +369,7 @@ enum queue_index {
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
@ -387,6 +389,7 @@ struct data_queue {
unsigned short length;
unsigned short index[Q_INDEX_MAX];
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;
unsigned short cw_max;

View file

@ -41,16 +41,16 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
/*
* Only continue if there are enabled interfaces.
*/
if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return 0;
if (state == RFKILL_STATE_UNBLOCKED) {
INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
retval = rt2x00lib_enable_radio(rt2x00dev);
} else if (state == RFKILL_STATE_SOFT_BLOCKED) {
INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
rt2x00lib_disable_radio(rt2x00dev);
} else {
WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n",

View file

@ -163,15 +163,10 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct txdone_entry_desc txdesc;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* Remove the descriptor data from the buffer.
*/
skb_pull(entry->skb, entry->queue->desc_size);
/*
* Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
@ -224,6 +219,12 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
/*
* Make sure the skb->data pointer points to the frame, not the
* descriptor.
*/
skb_pull(entry->skb, entry->queue->desc_size);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
@ -232,7 +233,7 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
}
@ -283,7 +284,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u8 rxd[32];
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
@ -293,7 +294,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
* a problem.
*/
if (urb->actual_length < entry->queue->desc_size || urb->status) {
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
return;
}
@ -361,7 +362,7 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);

View file

@ -1478,16 +1478,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
/*
* Clear all beacons
* For the Beacon base registers we only need to clear
@ -2001,6 +1991,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
else
rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
}
@ -2121,7 +2113,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
if (!reg && !reg_mcu)
return IRQ_NONE;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/*
@ -2652,6 +2644,63 @@ static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
return 0;
}
static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
struct rt2x00_field32 field;
int retval;
u32 reg;
/*
* First pass the configuration through rt2x00lib, that will
* update the queue settings and validate the input. After that
* we are free to update the registers based on the value
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
if (retval)
return retval;
queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
/* Update WMM TXOP register */
if (queue_idx < 2) {
field.bit_offset = queue_idx * 16;
field.bit_mask = 0xffff << field.bit_offset;
rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
} else if (queue_idx < 4) {
field.bit_offset = (queue_idx - 2) * 16;
field.bit_mask = 0xffff << field.bit_offset;
rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
}
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->aifs);
rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg);
rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_min);
rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg);
rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_max);
rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0;
}
static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@ -2679,7 +2728,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt61pci_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
};

View file

@ -1277,16 +1277,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
@ -1566,8 +1556,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
skb->len - skbdesc->desc_len);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
rt2x00_set_field32(&word, TXD_W0_BURST2,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
@ -1776,6 +1765,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
else
rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
@ -2246,6 +2237,63 @@ static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
return 0;
}
static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
struct rt2x00_field32 field;
int retval;
u32 reg;
/*
* First pass the configuration through rt2x00lib, that will
* update the queue settings and validate the input. After that
* we are free to update the registers based on the value
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
if (retval)
return retval;
queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
/* Update WMM TXOP register */
if (queue_idx < 2) {
field.bit_offset = queue_idx * 16;
field.bit_mask = 0xffff << field.bit_offset;
rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
} else if (queue_idx < 4) {
field.bit_offset = (queue_idx - 2) * 16;
field.bit_mask = 0xffff << field.bit_offset;
rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
}
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->aifs);
rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_min);
rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_max);
rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0;
}
#if 0
/*
* Mac80211 demands get_tsf must be atomic.
@ -2283,7 +2331,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt73usb_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
};

View file

@ -327,11 +327,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
s8 gain;
u16 loc[3];
if (out->revision == 3) { /* rev 3 moved MAC */
if (out->revision == 3) /* rev 3 moved MAC */
loc[0] = SSB_SPROM3_IL0MAC;
loc[1] = SSB_SPROM3_ET0MAC;
loc[2] = SSB_SPROM3_ET1MAC;
} else {
else {
loc[0] = SSB_SPROM1_IL0MAC;
loc[1] = SSB_SPROM1_ET0MAC;
loc[2] = SSB_SPROM1_ET1MAC;
@ -340,13 +338,15 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
v = in[SPOFF(loc[0]) + i];
*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[1]) + i];
*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[2]) + i];
*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
if (out->revision < 3) { /* only rev 1-2 have et0, et1 */
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[1]) + i];
*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[2]) + i];
*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
}
}
SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
@ -399,30 +399,33 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
out->antenna_gain.ghz5.a3 = gain;
}
static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
{
int i;
u16 v;
u16 il0mac_offset;
/* extract the equivalent of the r1 variables */
if (out->revision == 4)
il0mac_offset = SSB_SPROM4_IL0MAC;
else
il0mac_offset = SSB_SPROM5_IL0MAC;
/* extract the MAC address */
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
v = in[SPOFF(il0mac_offset) + i];
*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
}
SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
SSB_SPROM4_ETHPHY_ET1A_SHIFT);
SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
if (out->revision == 4) {
SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
} else {
SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
}
SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
SSB_SPROM4_ANTAVAIL_A_SHIFT);
SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
@ -433,12 +436,21 @@ static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
SSB_SPROM4_ITSSI_A_SHIFT);
SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
SSB_SPROM4_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
SSB_SPROM4_GPIOB_P3_SHIFT);
if (out->revision == 4) {
SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
SSB_SPROM4_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
SSB_SPROM4_GPIOB_P3_SHIFT);
} else {
SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
SSB_SPROM5_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
SSB_SPROM5_GPIOB_P3_SHIFT);
}
/* Extract the antenna gain values. */
SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
@ -462,6 +474,8 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
out->revision = in[size - 1] & 0x00FF;
ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
memset(out->et1mac, 0xFF, 6);
if ((bus->chip_id & 0xFF00) == 0x4400) {
/* Workaround: The BCM44XX chip has a stupid revision
* number stored in the SPROM.
@ -471,16 +485,16 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
} else if (bus->chip_id == 0x4321) {
/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
out->revision = 4;
sprom_extract_r4(out, in);
sprom_extract_r45(out, in);
} else {
if (out->revision == 0)
goto unsupported;
if (out->revision >= 1 && out->revision <= 3) {
sprom_extract_r123(out, in);
}
if (out->revision == 4)
sprom_extract_r4(out, in);
if (out->revision >= 5)
if (out->revision == 4 || out->revision == 5)
sprom_extract_r45(out, in);
if (out->revision > 5)
goto unsupported;
}

View file

@ -714,6 +714,7 @@ struct ieee80211_ht_addt_info {
#define IEEE80211_HT_CAP_SGI_40 0x0040
#define IEEE80211_HT_CAP_DELAY_BA 0x0400
#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
/* 802.11n HT capability AMPDU settings */
#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03
#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C

View file

@ -89,6 +89,8 @@
* @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all mesh paths, on the interface identified
* by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
* %NL80211_ATTR_IFINDEX.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
@ -127,6 +129,8 @@ enum nl80211_commands {
NL80211_CMD_NEW_MPATH,
NL80211_CMD_DEL_MPATH,
NL80211_CMD_SET_BSS,
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@ -134,6 +138,11 @@ enum nl80211_commands {
NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
};
/*
* Allow user space programs to use #ifdef on new commands by defining them
* here
*/
#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
/**
* enum nl80211_attrs - nl80211 netlink attributes
@ -192,6 +201,15 @@ enum nl80211_commands {
* @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
* &enum nl80211_mntr_flags.
*
* @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
* @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
* (u8, 0 or 1)
* @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
* (u8, 0 or 1)
*
* @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -235,16 +253,29 @@ enum nl80211_attrs {
NL80211_ATTR_MPATH_NEXT_HOP,
NL80211_ATTR_MPATH_INFO,
NL80211_ATTR_BSS_CTS_PROT,
NL80211_ATTR_BSS_SHORT_PREAMBLE,
NL80211_ATTR_BSS_SHORT_SLOT_TIME,
NL80211_ATTR_HT_CAPABILITY,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
/*
* Allow user space programs to use #ifdef on new attributes by defining them
* here
*/
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
/**
* enum nl80211_iftype - (virtual) interface types

View file

@ -245,8 +245,6 @@
/* SPROM Revision 3 (inherits most data from rev 2) */
#define SSB_SPROM3_IL0MAC 0x104A /* 6 bytes MAC address for 802.11b/g */
#define SSB_SPROM3_ET0MAC 0x1050 /* 6 bytes MAC address for Ethernet ?? */
#define SSB_SPROM3_ET1MAC 0x1050 /* 6 bytes MAC address for 802.11a ?? */
#define SSB_SPROM3_OFDMAPO 0x102C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
#define SSB_SPROM3_OFDMALPO 0x1030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
#define SSB_SPROM3_OFDMAHPO 0x1034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
@ -267,8 +265,6 @@
/* SPROM Revision 4 */
#define SSB_SPROM4_IL0MAC 0x104C /* 6 byte MAC address for a/b/g/n */
#define SSB_SPROM4_ET0MAC 0x1018 /* 6 bytes MAC address for Ethernet ?? */
#define SSB_SPROM4_ET1MAC 0x1018 /* 6 bytes MAC address for 802.11a ?? */
#define SSB_SPROM4_ETHPHY 0x105A /* Ethernet PHY settings ?? */
#define SSB_SPROM4_ETHPHY_ET0A 0x001F /* MII Address for enet0 */
#define SSB_SPROM4_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */
@ -316,6 +312,21 @@
#define SSB_SPROM4_PA1B1 0x1090
#define SSB_SPROM4_PA1B2 0x1092
/* SPROM Revision 5 (inherits most data from rev 4) */
#define SSB_SPROM5_BFLLO 0x104A /* Boardflags (low 16 bits) */
#define SSB_SPROM5_BFLHI 0x104C /* Board Flags Hi */
#define SSB_SPROM5_IL0MAC 0x1052 /* 6 byte MAC address for a/b/g/n */
#define SSB_SPROM5_CCODE 0x1044 /* Country Code (2 bytes) */
#define SSB_SPROM5_GPIOA 0x1076 /* Gen. Purpose IO # 0 and 1 */
#define SSB_SPROM5_GPIOA_P0 0x00FF /* Pin 0 */
#define SSB_SPROM5_GPIOA_P1 0xFF00 /* Pin 1 */
#define SSB_SPROM5_GPIOA_P1_SHIFT 8
#define SSB_SPROM5_GPIOB 0x1078 /* Gen. Purpose IO # 2 and 3 */
#define SSB_SPROM5_GPIOB_P2 0x00FF /* Pin 2 */
#define SSB_SPROM5_GPIOB_P3 0xFF00 /* Pin 3 */
#define SSB_SPROM5_GPIOB_P3_SHIFT 8
/* Values for SSB_SPROM1_BINF_CCODE */
enum {
SSB_SPROM1CCODE_WORLD = 0,

View file

@ -152,6 +152,7 @@ struct station_parameters {
u16 aid;
u8 supported_rates_len;
u8 plink_action;
struct ieee80211_ht_cap *ht_capa;
};
/**
@ -268,6 +269,23 @@ struct mpath_info {
u8 flags;
};
/**
* struct bss_parameters - BSS parameters
*
* Used to change BSS parameters (mainly for AP mode).
*
* @use_cts_prot: Whether to use CTS protection
* (0 = no, 1 = yes, -1 = do not change)
* @use_short_preamble: Whether the use of short preambles is allowed
* (0 = no, 1 = yes, -1 = do not change)
* @use_short_slot_time: Whether the use of short slot time is allowed
* (0 = no, 1 = yes, -1 = do not change)
*/
struct bss_parameters {
int use_cts_prot;
int use_short_preamble;
int use_short_slot_time;
};
/* from net/wireless.h */
struct wiphy;
@ -318,6 +336,8 @@ struct wiphy;
* @change_station: Modify a given station.
*
* @set_mesh_cfg: set mesh parameters (by now, just mesh id)
*
* @change_bss: Modify parameters for a given BSS.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@ -370,6 +390,9 @@ struct cfg80211_ops {
int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *dst, u8 *next_hop,
struct mpath_info *pinfo);
int (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params);
};
#endif /* __NET_CFG80211_H */

View file

@ -158,12 +158,14 @@ struct ieee80211_low_level_stats {
* also implies a change in the AID.
* @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed
* @BSS_CHANGED_ERP_PREAMBLE: preamble changed
* @BSS_CHANGED_ERP_SLOT: slot timing changed
* @BSS_CHANGED_HT: 802.11n parameters changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_ERP_CTS_PROT = 1<<1,
BSS_CHANGED_ERP_PREAMBLE = 1<<2,
BSS_CHANGED_ERP_SLOT = 1<<3,
BSS_CHANGED_HT = 1<<4,
};
@ -177,6 +179,7 @@ enum ieee80211_bss_change {
* @aid: association ID number, valid only when @assoc is true
* @use_cts_prot: use CTS protection
* @use_short_preamble: use 802.11b short preamble
* @use_short_slot: use short slot time (only relevant for ERP)
* @dtim_period: num of beacons before the next DTIM, for PSM
* @timestamp: beacon timestamp
* @beacon_int: beacon interval
@ -192,6 +195,7 @@ struct ieee80211_bss_conf {
/* erp related data */
bool use_cts_prot;
bool use_short_preamble;
bool use_short_slot;
u8 dtim_period;
u16 beacon_int;
u16 assoc_capability;
@ -420,6 +424,11 @@ struct ieee80211_rx_status {
* @IEEE80211_CONF_PS: Enable 802.11 power save mode
*/
enum ieee80211_conf_flags {
/*
* TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers
* have been converted to use bss_info_changed() for slot time
* configuration
*/
IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0),
IEEE80211_CONF_RADIOTAP = (1<<1),
IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2),

View file

@ -674,6 +674,11 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sta->supp_rates[local->oper_channel->band] = rates;
}
if (params->ht_capa) {
ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
&sta->ht_info);
}
if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
switch (params->plink_action) {
case PLINK_ACTION_OPEN:
@ -1010,6 +1015,42 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
}
#endif
static int ieee80211_change_bss(struct wiphy *wiphy,
struct net_device *dev,
struct bss_parameters *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata;
u32 changed = 0;
if (dev == local->mdev)
return -EOPNOTSUPP;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
if (params->use_cts_prot >= 0) {
sdata->bss_conf.use_cts_prot = params->use_cts_prot;
changed |= BSS_CHANGED_ERP_CTS_PROT;
}
if (params->use_short_preamble >= 0) {
sdata->bss_conf.use_short_preamble =
params->use_short_preamble;
changed |= BSS_CHANGED_ERP_PREAMBLE;
}
if (params->use_short_slot_time >= 0) {
sdata->bss_conf.use_short_slot =
params->use_short_slot_time;
changed |= BSS_CHANGED_ERP_SLOT;
}
ieee80211_bss_info_change_notify(sdata, changed);
return 0;
}
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -1033,4 +1074,5 @@ struct cfg80211_ops mac80211_config_ops = {
.get_mpath = ieee80211_get_mpath,
.dump_mpath = ieee80211_dump_mpath,
#endif
.change_bss = ieee80211_change_bss,
};

View file

@ -79,16 +79,11 @@ struct ieee80211_sta_bss {
enum ieee80211_band band;
int freq;
int signal, noise, qual;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 *rsn_ie;
size_t rsn_ie_len;
u8 *wmm_ie;
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
u8 *ht_add_ie;
size_t ht_add_ie_len;
u8 *ies; /* all information elements from the last Beacon or Probe
* Response frames; note Beacon frame is not allowed to
* override values from Probe Response */
size_t ies_len;
bool wmm_used;
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
@ -773,6 +768,9 @@ struct ieee80211_ra_tid {
/* Parsed Information Elements */
struct ieee802_11_elems {
u8 *ie_start;
size_t total_len;
/* pointers to IEs */
u8 *ssid;
u8 *supp_rates;

View file

@ -598,7 +598,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
struct ieee80211_local *local = hw_to_local(hw);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
u16 start_seq_num = 0;
u16 start_seq_num;
u8 *state;
int ret;
DECLARE_MAC_BUF(mac);
@ -678,6 +678,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
* call back right away, it must see that the flow has begun */
*state |= HT_ADDBA_REQUESTED_MSK;
/* This is slightly racy because the queue isn't stopped */
start_seq_num = sta->tid_seq[tid];
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
ra, tid, &start_seq_num);

View file

@ -98,6 +98,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
u8 *pos = start;
memset(elems, 0, sizeof(*elems));
elems->ie_start = start;
elems->total_len = len;
while (left >= 2) {
u8 id, elen;
@ -234,6 +236,27 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
}
static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie)
{
u8 *end, *pos;
pos = bss->ies;
if (pos == NULL)
return NULL;
end = pos + bss->ies_len;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == ie)
return pos;
pos += 2 + pos[1];
}
return NULL;
}
static int ecw2cw(int ecw)
{
return (1 << ecw) - 1;
@ -737,7 +760,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *ies;
u8 *pos, *ies, *ht_add_ie;
int i, len, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_sta_bss *bss;
@ -772,7 +795,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
if (bss->wmm_ie)
if (bss->wmm_used)
wmm = 1;
/* get all rates supported by the device and the AP as
@ -894,9 +917,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
/* wmm support is a must to HT */
if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
sband->ht_info.ht_supported && bss->ht_add_ie) {
sband->ht_info.ht_supported &&
(ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
struct ieee80211_ht_addt_info *ht_add_info =
(struct ieee80211_ht_addt_info *)bss->ht_add_ie;
(struct ieee80211_ht_addt_info *)ht_add_ie;
u16 cap = sband->ht_info.cap;
__le16 tmp;
u32 flags = local->hw.conf.channel->flags;
@ -2372,11 +2396,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i
static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
{
kfree(bss->wpa_ie);
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
kfree(bss->ht_add_ie);
kfree(bss->ies);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
kfree(bss);
@ -2662,43 +2682,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
bss->has_erp_value = 1;
}
if (elems->ht_cap_elem &&
(!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
kfree(bss->ht_ie);
bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
if (bss->ht_ie) {
memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
elems->ht_cap_elem_len + 2);
bss->ht_ie_len = elems->ht_cap_elem_len + 2;
} else
bss->ht_ie_len = 0;
} else if (!elems->ht_cap_elem && bss->ht_ie) {
kfree(bss->ht_ie);
bss->ht_ie = NULL;
bss->ht_ie_len = 0;
}
if (elems->ht_info_elem &&
(!bss->ht_add_ie ||
bss->ht_add_ie_len != elems->ht_info_elem_len ||
memcmp(bss->ht_add_ie, elems->ht_info_elem,
elems->ht_info_elem_len))) {
kfree(bss->ht_add_ie);
bss->ht_add_ie =
kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
if (bss->ht_add_ie) {
memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
elems->ht_info_elem_len + 2);
bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
} else
bss->ht_add_ie_len = 0;
} else if (!elems->ht_info_elem && bss->ht_add_ie) {
kfree(bss->ht_add_ie);
bss->ht_add_ie = NULL;
bss->ht_add_ie_len = 0;
}
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
@ -2749,88 +2732,17 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
return;
}
if (elems->wpa &&
(!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
kfree(bss->wpa_ie);
bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
if (bss->wpa_ie) {
memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
bss->wpa_ie_len = elems->wpa_len + 2;
} else
bss->wpa_ie_len = 0;
} else if (!elems->wpa && bss->wpa_ie) {
kfree(bss->wpa_ie);
bss->wpa_ie = NULL;
bss->wpa_ie_len = 0;
if (bss->ies == NULL || bss->ies_len < elems->total_len) {
kfree(bss->ies);
bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
}
if (bss->ies) {
memcpy(bss->ies, elems->ie_start, elems->total_len);
bss->ies_len = elems->total_len;
} else
bss->ies_len = 0;
if (elems->rsn &&
(!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
kfree(bss->rsn_ie);
bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
if (bss->rsn_ie) {
memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
bss->rsn_ie_len = elems->rsn_len + 2;
} else
bss->rsn_ie_len = 0;
} else if (!elems->rsn && bss->rsn_ie) {
kfree(bss->rsn_ie);
bss->rsn_ie = NULL;
bss->rsn_ie_len = 0;
}
/*
* Cf.
* http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC
*
* quoting:
*
* In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia
* Applications with Quality of Service in Wi-Fi Networks," Wi- Fi
* Alliance (September 1, 2004) is incorporated by reference herein.
* The inclusion of the WMM Parameters in probe responses and
* association responses is mandatory for WMM enabled networks. The
* inclusion of the WMM Parameters in beacons, however, is optional.
*/
if (elems->wmm_param &&
(!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
kfree(bss->wmm_ie);
bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
if (bss->wmm_ie) {
memcpy(bss->wmm_ie, elems->wmm_param - 2,
elems->wmm_param_len + 2);
bss->wmm_ie_len = elems->wmm_param_len + 2;
} else
bss->wmm_ie_len = 0;
} else if (elems->wmm_info &&
(!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
memcmp(bss->wmm_ie, elems->wmm_info,
elems->wmm_info_len))) {
/* As for certain AP's Fifth bit is not set in WMM IE in
* beacon frames.So while parsing the beacon frame the
* wmm_info structure is used instead of wmm_param.
* wmm_info structure was never used to set bss->wmm_ie.
* This code fixes this problem by copying the WME
* information from wmm_info to bss->wmm_ie and enabling
* n-band association.
*/
kfree(bss->wmm_ie);
bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
if (bss->wmm_ie) {
memcpy(bss->wmm_ie, elems->wmm_info - 2,
elems->wmm_info_len + 2);
bss->wmm_ie_len = elems->wmm_info_len + 2;
} else
bss->wmm_ie_len = 0;
} else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
kfree(bss->wmm_ie);
bss->wmm_ie = NULL;
bss->wmm_ie_len = 0;
}
bss->wmm_used = elems->wmm_param || elems->wmm_info;
/* check if we need to merge IBSS */
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
@ -4146,6 +4058,48 @@ int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t
return 0;
}
static void ieee80211_sta_add_scan_ies(struct iw_request_info *info,
struct ieee80211_sta_bss *bss,
char **current_ev, char *end_buf)
{
u8 *pos, *end, *next;
struct iw_event iwe;
if (bss == NULL || bss->ies == NULL)
return;
/*
* If needed, fragment the IEs buffer (at IE boundaries) into short
* enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
*/
pos = bss->ies;
end = pos + bss->ies_len;
while (end - pos > IW_GENERIC_IE_MAX) {
next = pos + 2 + pos[1];
while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
next = next + 2 + next[1];
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = next - pos;
*current_ev = iwe_stream_add_point(info, *current_ev,
end_buf, &iwe, pos);
pos = next;
}
if (end > pos) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = end - pos;
*current_ev = iwe_stream_add_point(info, *current_ev,
end_buf, &iwe, pos);
}
}
static char *
ieee80211_sta_scan_result(struct ieee80211_local *local,
struct iw_request_info *info,
@ -4225,29 +4179,7 @@ ieee80211_sta_scan_result(struct ieee80211_local *local,
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, "");
if (bss && bss->wpa_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->wpa_ie_len;
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->wpa_ie);
}
if (bss && bss->rsn_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->rsn_ie_len;
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->rsn_ie);
}
if (bss && bss->ht_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->ht_ie_len;
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->ht_ie);
}
ieee80211_sta_add_scan_ies(info, bss, &current_ev, end_buf);
if (bss && bss->supp_rates_len > 0) {
/* display all supported rates in readable format */

View file

@ -47,8 +47,6 @@ static unsigned int classify_1d(struct sk_buff *skb)
return 0;
}
if (dscp & 0x1c)
return 0;
return dscp >> 5;
}

View file

@ -37,7 +37,7 @@ MODULE_DESCRIPTION("RF switch support");
MODULE_LICENSE("GPL");
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
static DEFINE_MUTEX(rfkill_mutex);
static DEFINE_MUTEX(rfkill_global_mutex);
static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
module_param_named(default_state, rfkill_default_state, uint, 0444);
@ -76,6 +76,7 @@ static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
*/
int register_rfkill_notifier(struct notifier_block *nb)
{
BUG_ON(!nb);
return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(register_rfkill_notifier);
@ -91,6 +92,7 @@ EXPORT_SYMBOL_GPL(register_rfkill_notifier);
*/
int unregister_rfkill_notifier(struct notifier_block *nb)
{
BUG_ON(!nb);
return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
@ -202,6 +204,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
* RFKILL_STATE_HARD_BLOCKED */
break;
default:
WARN(1, KERN_WARNING
"rfkill: illegal state %d passed as parameter "
"to rfkill_toggle_radio\n", state);
return -EINVAL;
}
@ -229,14 +234,18 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
* unless a specific switch is claimed by userspace (in which case,
* that switch is left alone) or suspended.
*
* Caller must have acquired rfkill_mutex.
* Caller must have acquired rfkill_global_mutex.
*/
static void __rfkill_switch_all(const enum rfkill_type type,
const enum rfkill_state state)
{
struct rfkill *rfkill;
if (unlikely(state >= RFKILL_STATE_MAX))
if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX),
KERN_WARNING
"rfkill: illegal state %d or type %d "
"passed as parameter to __rfkill_switch_all\n",
state, type))
return;
rfkill_global_states[type].current_state = state;
@ -254,14 +263,14 @@ static void __rfkill_switch_all(const enum rfkill_type type,
* @type: type of interfaces to be affected
* @state: the new state
*
* Acquires rfkill_mutex and calls __rfkill_switch_all(@type, @state).
* Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
* Please refer to __rfkill_switch_all() for details.
*/
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
{
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
__rfkill_switch_all(type, state);
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
}
EXPORT_SYMBOL(rfkill_switch_all);
@ -269,7 +278,7 @@ EXPORT_SYMBOL(rfkill_switch_all);
* rfkill_epo - emergency power off all transmitters
*
* This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
* ignoring everything in its path but rfkill_mutex and rfkill->mutex.
* ignoring everything in its path but rfkill_global_mutex and rfkill->mutex.
*
* The global state before the EPO is saved and can be restored later
* using rfkill_restore_states().
@ -279,7 +288,8 @@ void rfkill_epo(void)
struct rfkill *rfkill;
int i;
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
list_for_each_entry(rfkill, &rfkill_list, node) {
mutex_lock(&rfkill->mutex);
rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
@ -291,7 +301,7 @@ void rfkill_epo(void)
rfkill_global_states[i].current_state =
RFKILL_STATE_SOFT_BLOCKED;
}
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
}
EXPORT_SYMBOL_GPL(rfkill_epo);
@ -306,10 +316,11 @@ void rfkill_restore_states(void)
{
int i;
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
for (i = 0; i < RFKILL_TYPE_MAX; i++)
__rfkill_switch_all(i, rfkill_global_states[i].default_state);
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
}
EXPORT_SYMBOL_GPL(rfkill_restore_states);
@ -334,7 +345,11 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
{
enum rfkill_state oldstate;
if (unlikely(state >= RFKILL_STATE_MAX))
BUG_ON(!rfkill);
if (WARN((state >= RFKILL_STATE_MAX),
KERN_WARNING
"rfkill: illegal state %d passed as parameter "
"to rfkill_force_state\n", state))
return -EINVAL;
mutex_lock(&rfkill->mutex);
@ -402,12 +417,16 @@ static ssize_t rfkill_state_store(struct device *dev,
const char *buf, size_t count)
{
struct rfkill *rfkill = to_rfkill(dev);
unsigned int state = simple_strtoul(buf, NULL, 0);
unsigned long state;
int error;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
error = strict_strtoul(buf, 0, &state);
if (error)
return error;
/* RFKILL_STATE_HARD_BLOCKED is illegal here... */
if (state != RFKILL_STATE_UNBLOCKED &&
state != RFKILL_STATE_SOFT_BLOCKED)
@ -427,7 +446,7 @@ static ssize_t rfkill_claim_show(struct device *dev,
{
struct rfkill *rfkill = to_rfkill(dev);
return sprintf(buf, "%d", rfkill->user_claim);
return sprintf(buf, "%d\n", rfkill->user_claim);
}
static ssize_t rfkill_claim_store(struct device *dev,
@ -435,7 +454,8 @@ static ssize_t rfkill_claim_store(struct device *dev,
const char *buf, size_t count)
{
struct rfkill *rfkill = to_rfkill(dev);
bool claim = !!simple_strtoul(buf, NULL, 0);
unsigned long claim_tmp;
bool claim;
int error;
if (!capable(CAP_NET_ADMIN))
@ -444,11 +464,16 @@ static ssize_t rfkill_claim_store(struct device *dev,
if (rfkill->user_claim_unsupported)
return -EOPNOTSUPP;
error = strict_strtoul(buf, 0, &claim_tmp);
if (error)
return error;
claim = !!claim_tmp;
/*
* Take the global lock to make sure the kernel is not in
* the middle of rfkill_switch_all
*/
error = mutex_lock_interruptible(&rfkill_mutex);
error = mutex_lock_interruptible(&rfkill_global_mutex);
if (error)
return error;
@ -463,7 +488,7 @@ static ssize_t rfkill_claim_store(struct device *dev,
rfkill->user_claim = claim;
}
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
return error ? error : count;
}
@ -583,10 +608,10 @@ static int rfkill_check_duplicity(const struct rfkill *rfkill)
memset(seen, 0, sizeof(seen));
list_for_each_entry(p, &rfkill_list, node) {
if (p == rfkill) {
WARN_ON(1);
if (WARN((p == rfkill), KERN_WARNING
"rfkill: illegal attempt to register "
"an already registered rfkill struct\n"))
return -EEXIST;
}
set_bit(p->type, seen);
}
@ -598,7 +623,7 @@ static int rfkill_add_switch(struct rfkill *rfkill)
{
int error;
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
error = rfkill_check_duplicity(rfkill);
if (error < 0)
@ -619,16 +644,16 @@ static int rfkill_add_switch(struct rfkill *rfkill)
error = 0;
unlock_out:
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
return error;
}
static void rfkill_remove_switch(struct rfkill *rfkill)
{
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
list_del_init(&rfkill->node);
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
mutex_lock(&rfkill->mutex);
rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
@ -654,6 +679,12 @@ struct rfkill * __must_check rfkill_allocate(struct device *parent,
struct rfkill *rfkill;
struct device *dev;
if (WARN((type >= RFKILL_TYPE_MAX),
KERN_WARNING
"rfkill: illegal type %d passed as parameter "
"to rfkill_allocate\n", type))
return NULL;
rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
if (!rfkill)
return NULL;
@ -726,11 +757,12 @@ int __must_check rfkill_register(struct rfkill *rfkill)
struct device *dev = &rfkill->dev;
int error;
if (!rfkill->toggle_radio)
return -EINVAL;
if (rfkill->type >= RFKILL_TYPE_MAX)
return -EINVAL;
if (rfkill->state >= RFKILL_STATE_MAX)
if (WARN((!rfkill || !rfkill->toggle_radio ||
rfkill->type >= RFKILL_TYPE_MAX ||
rfkill->state >= RFKILL_STATE_MAX),
KERN_WARNING
"rfkill: attempt to register a "
"badly initialized rfkill struct\n"))
return -EINVAL;
snprintf(dev->bus_id, sizeof(dev->bus_id),
@ -765,6 +797,7 @@ EXPORT_SYMBOL(rfkill_register);
*/
void rfkill_unregister(struct rfkill *rfkill)
{
BUG_ON(!rfkill);
device_del(&rfkill->dev);
rfkill_remove_switch(rfkill);
rfkill_led_trigger_unregister(rfkill);
@ -801,12 +834,15 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state)
{
int error;
if (type >= RFKILL_TYPE_MAX ||
(state != RFKILL_STATE_SOFT_BLOCKED &&
state != RFKILL_STATE_UNBLOCKED))
if (WARN((type >= RFKILL_TYPE_MAX ||
(state != RFKILL_STATE_SOFT_BLOCKED &&
state != RFKILL_STATE_UNBLOCKED)),
KERN_WARNING
"rfkill: illegal state %d or type %d passed as "
"parameter to rfkill_set_default\n", state, type))
return -EINVAL;
mutex_lock(&rfkill_mutex);
mutex_lock(&rfkill_global_mutex);
if (!test_and_set_bit(type, rfkill_states_lockdflt)) {
rfkill_global_states[type].default_state = state;
@ -814,7 +850,7 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state)
} else
error = -EPERM;
mutex_unlock(&rfkill_mutex);
mutex_unlock(&rfkill_global_mutex);
return error;
}
EXPORT_SYMBOL_GPL(rfkill_set_default);

View file

@ -87,6 +87,13 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_MESH_ID_LEN },
[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
[NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
[NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
[NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
.len = NL80211_HT_CAPABILITY_LEN },
};
/* message building helper */
@ -1125,6 +1132,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
&params.station_flags))
return -EINVAL;
@ -1188,6 +1199,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
&params.station_flags))
@ -1525,6 +1539,48 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
return err;
}
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct bss_parameters params;
memset(&params, 0, sizeof(params));
/* default to not changing parameters */
params.use_cts_prot = -1;
params.use_short_preamble = -1;
params.use_short_slot_time = -1;
if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
params.use_cts_prot =
nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
params.use_short_preamble =
nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
params.use_short_slot_time =
nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err)
return err;
if (!drv->ops->change_bss) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->change_bss(&drv->wiphy, dev, &params);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@ -1656,6 +1712,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_SET_BSS,
.doit = nl80211_set_bss,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
/* multicast groups */