ath9k: Cleanup multiple VIF processing
Replace the internal sc_vaps array and index values by using vif pointer from mac80211. Allow multiple VIPs to be registered. Though, number of beaconing VIFs is still limited by ATH_BCBUF (currently 1). Multiple virtual STAs support is not yet complete, but at least the data structures should now be able to handle this. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
860559fe68
commit
2c3db3d51e
@@ -439,7 +439,7 @@ struct ath_beacon {
|
|||||||
u32 bmisscnt;
|
u32 bmisscnt;
|
||||||
u32 ast_be_xmit;
|
u32 ast_be_xmit;
|
||||||
u64 bc_tstamp;
|
u64 bc_tstamp;
|
||||||
int bslot[ATH_BCBUF];
|
struct ieee80211_vif *bslot[ATH_BCBUF];
|
||||||
int slottime;
|
int slottime;
|
||||||
int slotupdate;
|
int slotupdate;
|
||||||
struct ath9k_tx_queue_info beacon_qi;
|
struct ath9k_tx_queue_info beacon_qi;
|
||||||
@@ -449,9 +449,9 @@ struct ath_beacon {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ath_beacon_tasklet(unsigned long data);
|
void ath_beacon_tasklet(unsigned long data);
|
||||||
void ath_beacon_config(struct ath_softc *sc, int if_id);
|
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||||
int ath_beaconq_setup(struct ath_hw *ah);
|
int ath_beaconq_setup(struct ath_hw *ah);
|
||||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id);
|
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 ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
||||||
|
|
||||||
/*******/
|
/*******/
|
||||||
@@ -532,7 +532,6 @@ struct ath_rfkill {
|
|||||||
*/
|
*/
|
||||||
#define ATH_KEYMAX 128 /* max key cache size we handle */
|
#define ATH_KEYMAX 128 /* max key cache size we handle */
|
||||||
|
|
||||||
#define ATH_IF_ID_ANY 0xff
|
|
||||||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||||
#define ATH_RSSI_DUMMY_MARKER 0x127
|
#define ATH_RSSI_DUMMY_MARKER 0x127
|
||||||
#define ATH_RATE_DUMMY_MARKER 0
|
#define ATH_RATE_DUMMY_MARKER 0
|
||||||
@@ -595,7 +594,6 @@ struct ath_softc {
|
|||||||
struct ath_rx rx;
|
struct ath_rx rx;
|
||||||
struct ath_tx tx;
|
struct ath_tx tx;
|
||||||
struct ath_beacon beacon;
|
struct ath_beacon beacon;
|
||||||
struct ieee80211_vif *vifs[ATH_BCBUF];
|
|
||||||
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
|
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
|
||||||
struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
|
struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
|
||||||
struct ath_rate_table *cur_rate_table;
|
struct ath_rate_table *cur_rate_table;
|
||||||
|
@@ -113,17 +113,16 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
|
|||||||
series, 4, 0);
|
series, 4, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
struct ath_vif *avp;
|
struct ath_vif *avp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ath_txq *cabq;
|
struct ath_txq *cabq;
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
int cabq_depth;
|
int cabq_depth;
|
||||||
|
|
||||||
vif = sc->vifs[if_id];
|
|
||||||
avp = (void *)vif->drv_priv;
|
avp = (void *)vif->drv_priv;
|
||||||
cabq = sc->beacon.cabq;
|
cabq = sc->beacon.cabq;
|
||||||
|
|
||||||
@@ -208,15 +207,14 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
|||||||
* Startup beacon transmission for adhoc mode when they are sent entirely
|
* Startup beacon transmission for adhoc mode when they are sent entirely
|
||||||
* by the hardware using the self-linked descriptor + veol trick.
|
* by the hardware using the self-linked descriptor + veol trick.
|
||||||
*/
|
*/
|
||||||
static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
|
static void ath_beacon_start_adhoc(struct ath_softc *sc,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
struct ath_vif *avp;
|
struct ath_vif *avp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
vif = sc->vifs[if_id];
|
|
||||||
avp = (void *)vif->drv_priv;
|
avp = (void *)vif->drv_priv;
|
||||||
|
|
||||||
if (avp->av_bcbuf == NULL)
|
if (avp->av_bcbuf == NULL)
|
||||||
@@ -246,16 +244,14 @@ int ath_beaconq_setup(struct ath_hw *ah)
|
|||||||
return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
|
return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
struct ath_vif *avp;
|
struct ath_vif *avp;
|
||||||
struct ieee80211_hdr *hdr;
|
struct ieee80211_hdr *hdr;
|
||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
__le64 tstamp;
|
__le64 tstamp;
|
||||||
|
|
||||||
vif = sc->vifs[if_id];
|
|
||||||
avp = (void *)vif->drv_priv;
|
avp = (void *)vif->drv_priv;
|
||||||
|
|
||||||
/* Allocate a beacon descriptor if we haven't done so. */
|
/* Allocate a beacon descriptor if we haven't done so. */
|
||||||
@@ -275,22 +271,21 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
|||||||
*/
|
*/
|
||||||
avp->av_bslot = 0;
|
avp->av_bslot = 0;
|
||||||
for (slot = 0; slot < ATH_BCBUF; slot++)
|
for (slot = 0; slot < ATH_BCBUF; slot++)
|
||||||
if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) {
|
if (sc->beacon.bslot[slot] == NULL) {
|
||||||
/*
|
/*
|
||||||
* XXX hack, space out slots to better
|
* XXX hack, space out slots to better
|
||||||
* deal with misses
|
* deal with misses
|
||||||
*/
|
*/
|
||||||
if (slot+1 < ATH_BCBUF &&
|
if (slot+1 < ATH_BCBUF &&
|
||||||
sc->beacon.bslot[slot+1] ==
|
sc->beacon.bslot[slot+1] == NULL) {
|
||||||
ATH_IF_ID_ANY) {
|
|
||||||
avp->av_bslot = slot+1;
|
avp->av_bslot = slot+1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
avp->av_bslot = slot;
|
avp->av_bslot = slot;
|
||||||
/* NB: keep looking for a double slot */
|
/* NB: keep looking for a double slot */
|
||||||
}
|
}
|
||||||
BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
|
BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
|
||||||
sc->beacon.bslot[avp->av_bslot] = if_id;
|
sc->beacon.bslot[avp->av_bslot] = vif;
|
||||||
sc->nbcnvifs++;
|
sc->nbcnvifs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,7 +367,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
|
|||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
|
|
||||||
if (avp->av_bslot != -1) {
|
if (avp->av_bslot != -1) {
|
||||||
sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
|
sc->beacon.bslot[avp->av_bslot] = NULL;
|
||||||
sc->nbcnvifs--;
|
sc->nbcnvifs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +390,8 @@ void ath_beacon_tasklet(unsigned long data)
|
|||||||
struct ath_softc *sc = (struct ath_softc *)data;
|
struct ath_softc *sc = (struct ath_softc *)data;
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
struct ath_buf *bf = NULL;
|
struct ath_buf *bf = NULL;
|
||||||
int slot, if_id;
|
struct ieee80211_vif *vif;
|
||||||
|
int slot;
|
||||||
u32 bfaddr, bc = 0, tsftu;
|
u32 bfaddr, bc = 0, tsftu;
|
||||||
u64 tsf;
|
u64 tsf;
|
||||||
u16 intval;
|
u16 intval;
|
||||||
@@ -442,15 +438,15 @@ void ath_beacon_tasklet(unsigned long data)
|
|||||||
tsf = ath9k_hw_gettsf64(ah);
|
tsf = ath9k_hw_gettsf64(ah);
|
||||||
tsftu = TSF_TO_TU(tsf>>32, tsf);
|
tsftu = TSF_TO_TU(tsf>>32, tsf);
|
||||||
slot = ((tsftu % intval) * ATH_BCBUF) / intval;
|
slot = ((tsftu % intval) * ATH_BCBUF) / intval;
|
||||||
if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
|
vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
|
||||||
|
|
||||||
DPRINTF(sc, ATH_DBG_BEACON,
|
DPRINTF(sc, ATH_DBG_BEACON,
|
||||||
"slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
|
"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
|
||||||
slot, tsf, tsftu, intval, if_id);
|
slot, tsf, tsftu, intval, vif);
|
||||||
|
|
||||||
bfaddr = 0;
|
bfaddr = 0;
|
||||||
if (if_id != ATH_IF_ID_ANY) {
|
if (vif) {
|
||||||
bf = ath_beacon_generate(sc, if_id);
|
bf = ath_beacon_generate(sc, vif);
|
||||||
if (bf != NULL) {
|
if (bf != NULL) {
|
||||||
bfaddr = bf->bf_daddr;
|
bfaddr = bf->bf_daddr;
|
||||||
bc = 1;
|
bc = 1;
|
||||||
@@ -652,7 +648,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
|
|||||||
|
|
||||||
static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
||||||
struct ath_beacon_config *conf,
|
struct ath_beacon_config *conf,
|
||||||
struct ath_vif *avp)
|
struct ath_vif *avp,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
u64 tsf;
|
u64 tsf;
|
||||||
u32 tsftu, intval, nexttbtt;
|
u32 tsftu, intval, nexttbtt;
|
||||||
@@ -696,14 +693,12 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
|||||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||||
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
|
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
|
||||||
ath_beacon_start_adhoc(sc, 0);
|
ath_beacon_start_adhoc(sc, vif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath_beacon_config(struct ath_softc *sc, int if_id)
|
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct ath_beacon_config conf;
|
struct ath_beacon_config conf;
|
||||||
struct ath_vif *avp;
|
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
|
|
||||||
/* Setup the beacon configuration parameters */
|
/* Setup the beacon configuration parameters */
|
||||||
|
|
||||||
@@ -715,16 +710,15 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
|||||||
conf.dtim_count = 1;
|
conf.dtim_count = 1;
|
||||||
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
|
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
|
||||||
|
|
||||||
if (if_id != ATH_IF_ID_ANY) {
|
if (vif) {
|
||||||
vif = sc->vifs[if_id];
|
struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
|
||||||
avp = (struct ath_vif *)vif->drv_priv;
|
|
||||||
|
|
||||||
switch(avp->av_opmode) {
|
switch(avp->av_opmode) {
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
ath_beacon_config_ap(sc, &conf, avp);
|
ath_beacon_config_ap(sc, &conf, avp);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
ath_beacon_config_adhoc(sc, &conf, avp);
|
ath_beacon_config_adhoc(sc, &conf, avp, vif);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
ath_beacon_config_sta(sc, &conf, avp);
|
ath_beacon_config_sta(sc, &conf, avp);
|
||||||
|
@@ -800,13 +800,10 @@ static int ath_key_config(struct ath_softc *sc,
|
|||||||
* need to change with virtual interfaces. */
|
* need to change with virtual interfaces. */
|
||||||
idx = key->keyidx;
|
idx = key->keyidx;
|
||||||
} else if (key->keyidx) {
|
} else if (key->keyidx) {
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
|
|
||||||
if (WARN_ON(!sta))
|
if (WARN_ON(!sta))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
mac = sta->addr;
|
mac = sta->addr;
|
||||||
|
|
||||||
vif = sc->vifs[0];
|
|
||||||
if (vif->type != NL80211_IFTYPE_AP) {
|
if (vif->type != NL80211_IFTYPE_AP) {
|
||||||
/* Only keyidx 0 should be used with unicast key, but
|
/* Only keyidx 0 should be used with unicast key, but
|
||||||
* allow this for client mode for now. */
|
* allow this for client mode for now. */
|
||||||
@@ -915,7 +912,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the beacon */
|
/* Configure the beacon */
|
||||||
ath_beacon_config(sc, 0);
|
ath_beacon_config(sc, vif);
|
||||||
|
|
||||||
/* Reset rssi stats */
|
/* Reset rssi stats */
|
||||||
sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||||
@@ -1120,7 +1117,7 @@ static void ath_radio_enable(struct ath_softc *sc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_BEACONS)
|
if (sc->sc_flags & SC_OP_BEACONS)
|
||||||
ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
|
ath_beacon_config(sc, NULL); /* restart beacons */
|
||||||
|
|
||||||
/* Re-Enable interrupts */
|
/* Re-Enable interrupts */
|
||||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||||
@@ -1527,7 +1524,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
|
|||||||
|
|
||||||
/* initialize beacon slots */
|
/* initialize beacon slots */
|
||||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
|
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
|
||||||
sc->beacon.bslot[i] = ATH_IF_ID_ANY;
|
sc->beacon.bslot[i] = NULL;
|
||||||
|
|
||||||
/* save MISC configurations */
|
/* save MISC configurations */
|
||||||
sc->config.swBeaconProcess = 1;
|
sc->config.swBeaconProcess = 1;
|
||||||
@@ -1715,7 +1712,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
|||||||
ath_update_txpow(sc);
|
ath_update_txpow(sc);
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_BEACONS)
|
if (sc->sc_flags & SC_OP_BEACONS)
|
||||||
ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
|
ath_beacon_config(sc, NULL); /* restart beacons */
|
||||||
|
|
||||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||||
|
|
||||||
@@ -2127,11 +2124,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||||||
struct ath_softc *sc = hw->priv;
|
struct ath_softc *sc = hw->priv;
|
||||||
struct ath_vif *avp = (void *)conf->vif->drv_priv;
|
struct ath_vif *avp = (void *)conf->vif->drv_priv;
|
||||||
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
|
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
|
||||||
|
int ret = 0;
|
||||||
/* Support only vif for now */
|
|
||||||
|
|
||||||
if (sc->nvifs)
|
|
||||||
return -ENOBUFS;
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
mutex_lock(&sc->mutex);
|
||||||
|
|
||||||
@@ -2140,16 +2133,24 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||||||
ic_opmode = NL80211_IFTYPE_STATION;
|
ic_opmode = NL80211_IFTYPE_STATION;
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
|
if (sc->nbcnvifs >= ATH_BCBUF) {
|
||||||
|
ret = -ENOBUFS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ic_opmode = NL80211_IFTYPE_ADHOC;
|
ic_opmode = NL80211_IFTYPE_ADHOC;
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
|
if (sc->nbcnvifs >= ATH_BCBUF) {
|
||||||
|
ret = -ENOBUFS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ic_opmode = NL80211_IFTYPE_AP;
|
ic_opmode = NL80211_IFTYPE_AP;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF(sc, ATH_DBG_FATAL,
|
DPRINTF(sc, ATH_DBG_FATAL,
|
||||||
"Interface type %d not yet supported\n", conf->type);
|
"Interface type %d not yet supported\n", conf->type);
|
||||||
mutex_unlock(&sc->mutex);
|
ret = -EOPNOTSUPP;
|
||||||
return -EOPNOTSUPP;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
|
DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
|
||||||
@@ -2158,14 +2159,15 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||||||
avp->av_opmode = ic_opmode;
|
avp->av_opmode = ic_opmode;
|
||||||
avp->av_bslot = -1;
|
avp->av_bslot = -1;
|
||||||
|
|
||||||
|
sc->nvifs++;
|
||||||
|
if (sc->nvifs > 1)
|
||||||
|
goto out; /* skip global settings for secondary vif */
|
||||||
|
|
||||||
if (ic_opmode == NL80211_IFTYPE_AP) {
|
if (ic_opmode == NL80211_IFTYPE_AP) {
|
||||||
ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
|
ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
|
||||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc->vifs[0] = conf->vif;
|
|
||||||
sc->nvifs++;
|
|
||||||
|
|
||||||
/* Set the device opmode */
|
/* Set the device opmode */
|
||||||
sc->sc_ah->opmode = ic_opmode;
|
sc->sc_ah->opmode = ic_opmode;
|
||||||
|
|
||||||
@@ -2200,9 +2202,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||||||
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
mutex_unlock(&sc->mutex);
|
mutex_unlock(&sc->mutex);
|
||||||
|
return ret;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
||||||
@@ -2210,6 +2212,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
|||||||
{
|
{
|
||||||
struct ath_softc *sc = hw->priv;
|
struct ath_softc *sc = hw->priv;
|
||||||
struct ath_vif *avp = (void *)conf->vif->drv_priv;
|
struct ath_vif *avp = (void *)conf->vif->drv_priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
|
DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
|
||||||
|
|
||||||
@@ -2227,7 +2230,14 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
sc->sc_flags &= ~SC_OP_BEACONS;
|
sc->sc_flags &= ~SC_OP_BEACONS;
|
||||||
|
|
||||||
sc->vifs[0] = NULL;
|
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
|
||||||
|
if (sc->beacon.bslot[i] == conf->vif) {
|
||||||
|
printk(KERN_DEBUG "%s: vif had allocated beacon "
|
||||||
|
"slot\n", __func__);
|
||||||
|
sc->beacon.bslot[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sc->nvifs--;
|
sc->nvifs--;
|
||||||
|
|
||||||
mutex_unlock(&sc->mutex);
|
mutex_unlock(&sc->mutex);
|
||||||
@@ -2364,13 +2374,13 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
|
|||||||
*/
|
*/
|
||||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||||
|
|
||||||
error = ath_beacon_alloc(sc, 0);
|
error = ath_beacon_alloc(sc, vif);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
mutex_unlock(&sc->mutex);
|
mutex_unlock(&sc->mutex);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ath_beacon_config(sc, 0);
|
ath_beacon_config(sc, vif);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user