Skip to content

Commit

Permalink
ath9k: Fix beacon setup
Browse files Browse the repository at this point in the history
This patch revamps interface addition and deletion and simplifies
slot allocation. There is no need to setup the beacon buffer
in add/remove interface, remove this and use simple APIs for
assigning/deleting slots.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sujith Manoharan authored and John W. Linville committed Jul 17, 2012
1 parent 0f245ed commit 130ef6e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 146 deletions.
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,8 @@ struct ath_beacon {

void ath_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beaconq_config(struct ath_softc *sc);
void ath_set_beacon(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
Expand Down
141 changes: 33 additions & 108 deletions drivers/net/wireless/ath/ath9k/beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,132 +222,57 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
return bf;
}

int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp;
struct ath_buf *bf;
struct sk_buff *skb;
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
__le64 tstamp;
struct ath_vif *avp = (void *)vif->drv_priv;
int slot;

avp = (void *)vif->drv_priv;
avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
list_del(&avp->av_bcbuf->list);

/* Allocate a beacon descriptor if we haven't done so. */
if (!avp->av_bcbuf) {
/* Allocate beacon state for hostap/ibss. We know
* a buffer is available. */
avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
struct ath_buf, list);
list_del(&avp->av_bcbuf->list);

if (ath9k_uses_beacons(vif->type)) {
int slot;
/*
* Assign the vif to a beacon xmit slot. As
* above, this cannot fail to find one.
*/
avp->av_bslot = 0;
for (slot = 0; slot < ATH_BCBUF; slot++)
if (sc->beacon.bslot[slot] == NULL) {
avp->av_bslot = slot;
avp->is_bslot_active = false;

/* NB: keep looking for a double slot */
if (slot == 0 || !sc->beacon.bslot[slot-1])
break;
}
BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
sc->beacon.bslot[avp->av_bslot] = vif;
sc->nbcnvifs++;
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (sc->beacon.bslot[slot] == NULL) {
avp->av_bslot = slot;
avp->is_bslot_active = false;
break;
}
}

/* release the previous beacon frame, if it already exists. */
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
}

/* NB: the beacon data buffer must be 32-bit aligned. */
skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL)
return -ENOMEM;

tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
/* Calculate a TSF adjustment factor required for staggered beacons. */
if (avp->av_bslot > 0) {
u64 tsfadjust;
int intval;
sc->beacon.bslot[avp->av_bslot] = vif;
sc->nbcnvifs++;

intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
avp->av_bslot);
}

/*
* Calculate the TSF offset for this beacon slot, i.e., the
* number of usecs that need to be added to the timestamp field
* in Beacon and Probe Response frames. Beacon slot 0 is
* processed at the correct offset, so it does not require TSF
* adjustment. Other slots are adjusted to get the timestamp
* close to the TBTT for the BSS.
*/
tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_buf *bf = avp->av_bcbuf;

ath_dbg(common, BEACON,
"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
avp->av_bslot, intval, (unsigned long long)tsfadjust);
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
avp->av_bslot);

((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
avp->tsf_adjust;
} else
avp->tsf_adjust = cpu_to_le64(0);
tasklet_disable(&sc->bcon_tasklet);

bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
if (bf && bf->bf_mpdu) {
struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
ath_err(common, "dma_mapping_error on beacon alloc\n");
return -ENOMEM;
}
avp->is_bslot_active = true;

return 0;
}

void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
{
if (avp->av_bcbuf != NULL) {
struct ath_buf *bf;

avp->is_bslot_active = false;
if (avp->av_bslot != -1) {
sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
avp->av_bslot = -1;
}

bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
}
list_add_tail(&bf->list, &sc->beacon.bbuf);
avp->av_bcbuf = NULL;
avp->is_bslot_active = false;
sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
list_add_tail(&bf->list, &sc->beacon.bbuf);

avp->av_bcbuf = NULL;
}
tasklet_enable(&sc->bcon_tasklet);
}

void ath_beacon_tasklet(unsigned long data)
Expand Down
48 changes: 12 additions & 36 deletions drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,16 +852,6 @@ bool ath9k_uses_beacons(int type)
}
}

static void ath9k_reclaim_beacon(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_vif *avp = (void *)vif->drv_priv;

ath9k_set_beaconing_status(sc, false);
ath_beacon_return(sc, avp);
ath9k_set_beaconing_status(sc, true);
}

static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath9k_vif_iter_data *iter_data = data;
Expand Down Expand Up @@ -977,22 +967,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
}
}

/* Called with sc->mutex held, vif counts set up properly. */
static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;

ath9k_calculate_summary_state(hw, vif);

if (ath9k_uses_beacons(vif->type)) {
/* Reserve a beacon slot for the vif */
ath9k_set_beaconing_status(sc, false);
ath_beacon_alloc(sc, vif);
ath9k_set_beaconing_status(sc, true);
}
}

static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
Expand Down Expand Up @@ -1032,7 +1006,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,

sc->nvifs++;

ath9k_do_vif_add_setup(hw, vif);
ath9k_calculate_summary_state(hw, vif);
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);

out:
mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc);
Expand All @@ -1049,6 +1026,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
int ret = 0;

ath_dbg(common, CONFIG, "Change Interface\n");

mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);

Expand All @@ -1061,15 +1039,16 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
}
}

/* Clean up old vif stuff */
if (ath9k_uses_beacons(vif->type))
ath9k_reclaim_beacon(sc, vif);
ath9k_beacon_remove_slot(sc, vif);

/* Add new settings */
vif->type = new_type;
vif->p2p = p2p;

ath9k_do_vif_add_setup(hw, vif);
ath9k_calculate_summary_state(hw, vif);
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);

out:
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
Expand All @@ -1089,9 +1068,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,

sc->nvifs--;

/* Reclaim beacon resources */
if (ath9k_uses_beacons(vif->type))
ath9k_reclaim_beacon(sc, vif);
ath9k_beacon_remove_slot(sc, vif);

ath9k_calculate_summary_state(hw, NULL);

Expand Down Expand Up @@ -1610,9 +1588,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
(changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT))) {
ath9k_set_beaconing_status(sc, false);
if (bss_conf->enable_beacon)
ath_beacon_alloc(sc, vif);
else
if (!bss_conf->enable_beacon)
avp->is_bslot_active = false;
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
Expand Down

0 comments on commit 130ef6e

Please sign in to comment.