diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:26 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:44 -0500 |
commit | 2c3db3d51ee1fcf84f5828788905a4c091b9ae27 (patch) | |
tree | 44df855975d0848f15821cc285cbd5d7c8bf3feb /drivers/net/wireless/ath9k | |
parent | 860559fe686b44a533c83c79fe5d1ad41bf9e090 (diff) |
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>
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/beacon.c | 54 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 54 |
3 files changed, 59 insertions, 57 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index ec1bf174c706..09b2b008feba 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -439,7 +439,7 @@ struct ath_beacon { | |||
439 | u32 bmisscnt; | 439 | u32 bmisscnt; |
440 | u32 ast_be_xmit; | 440 | u32 ast_be_xmit; |
441 | u64 bc_tstamp; | 441 | u64 bc_tstamp; |
442 | int bslot[ATH_BCBUF]; | 442 | struct ieee80211_vif *bslot[ATH_BCBUF]; |
443 | int slottime; | 443 | int slottime; |
444 | int slotupdate; | 444 | int slotupdate; |
445 | struct ath9k_tx_queue_info beacon_qi; | 445 | struct ath9k_tx_queue_info beacon_qi; |
@@ -449,9 +449,9 @@ struct ath_beacon { | |||
449 | }; | 449 | }; |
450 | 450 | ||
451 | void ath_beacon_tasklet(unsigned long data); | 451 | void ath_beacon_tasklet(unsigned long data); |
452 | void ath_beacon_config(struct ath_softc *sc, int if_id); | 452 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); |
453 | int ath_beaconq_setup(struct ath_hw *ah); | 453 | int ath_beaconq_setup(struct ath_hw *ah); |
454 | int ath_beacon_alloc(struct ath_softc *sc, int if_id); | 454 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); |
455 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); | 455 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); |
456 | 456 | ||
457 | /*******/ | 457 | /*******/ |
@@ -532,7 +532,6 @@ struct ath_rfkill { | |||
532 | */ | 532 | */ |
533 | #define ATH_KEYMAX 128 /* max key cache size we handle */ | 533 | #define ATH_KEYMAX 128 /* max key cache size we handle */ |
534 | 534 | ||
535 | #define ATH_IF_ID_ANY 0xff | ||
536 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ | 535 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ |
537 | #define ATH_RSSI_DUMMY_MARKER 0x127 | 536 | #define ATH_RSSI_DUMMY_MARKER 0x127 |
538 | #define ATH_RATE_DUMMY_MARKER 0 | 537 | #define ATH_RATE_DUMMY_MARKER 0 |
@@ -595,7 +594,6 @@ struct ath_softc { | |||
595 | struct ath_rx rx; | 594 | struct ath_rx rx; |
596 | struct ath_tx tx; | 595 | struct ath_tx tx; |
597 | struct ath_beacon beacon; | 596 | struct ath_beacon beacon; |
598 | struct ieee80211_vif *vifs[ATH_BCBUF]; | ||
599 | struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; | 597 | struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; |
600 | struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; | 598 | struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; |
601 | struct ath_rate_table *cur_rate_table; | 599 | struct ath_rate_table *cur_rate_table; |
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index d1365726d2f3..357d797e79c1 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c | |||
@@ -113,17 +113,16 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
113 | series, 4, 0); | 113 | series, 4, 0); |
114 | } | 114 | } |
115 | 115 | ||
116 | static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) | 116 | static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, |
117 | struct ieee80211_vif *vif) | ||
117 | { | 118 | { |
118 | struct ath_buf *bf; | 119 | struct ath_buf *bf; |
119 | struct ath_vif *avp; | 120 | struct ath_vif *avp; |
120 | struct sk_buff *skb; | 121 | struct sk_buff *skb; |
121 | struct ath_txq *cabq; | 122 | struct ath_txq *cabq; |
122 | struct ieee80211_vif *vif; | ||
123 | struct ieee80211_tx_info *info; | 123 | struct ieee80211_tx_info *info; |
124 | int cabq_depth; | 124 | int cabq_depth; |
125 | 125 | ||
126 | vif = sc->vifs[if_id]; | ||
127 | avp = (void *)vif->drv_priv; | 126 | avp = (void *)vif->drv_priv; |
128 | cabq = sc->beacon.cabq; | 127 | cabq = sc->beacon.cabq; |
129 | 128 | ||
@@ -208,15 +207,14 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) | |||
208 | * Startup beacon transmission for adhoc mode when they are sent entirely | 207 | * Startup beacon transmission for adhoc mode when they are sent entirely |
209 | * by the hardware using the self-linked descriptor + veol trick. | 208 | * by the hardware using the self-linked descriptor + veol trick. |
210 | */ | 209 | */ |
211 | static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) | 210 | static void ath_beacon_start_adhoc(struct ath_softc *sc, |
211 | struct ieee80211_vif *vif) | ||
212 | { | 212 | { |
213 | struct ieee80211_vif *vif; | ||
214 | struct ath_hw *ah = sc->sc_ah; | 213 | struct ath_hw *ah = sc->sc_ah; |
215 | struct ath_buf *bf; | 214 | struct ath_buf *bf; |
216 | struct ath_vif *avp; | 215 | struct ath_vif *avp; |
217 | struct sk_buff *skb; | 216 | struct sk_buff *skb; |
218 | 217 | ||
219 | vif = sc->vifs[if_id]; | ||
220 | avp = (void *)vif->drv_priv; | 218 | avp = (void *)vif->drv_priv; |
221 | 219 | ||
222 | if (avp->av_bcbuf == NULL) | 220 | if (avp->av_bcbuf == NULL) |
@@ -246,16 +244,14 @@ int ath_beaconq_setup(struct ath_hw *ah) | |||
246 | return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); | 244 | return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); |
247 | } | 245 | } |
248 | 246 | ||
249 | int ath_beacon_alloc(struct ath_softc *sc, int if_id) | 247 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) |
250 | { | 248 | { |
251 | struct ieee80211_vif *vif; | ||
252 | struct ath_vif *avp; | 249 | struct ath_vif *avp; |
253 | struct ieee80211_hdr *hdr; | 250 | struct ieee80211_hdr *hdr; |
254 | struct ath_buf *bf; | 251 | struct ath_buf *bf; |
255 | struct sk_buff *skb; | 252 | struct sk_buff *skb; |
256 | __le64 tstamp; | 253 | __le64 tstamp; |
257 | 254 | ||
258 | vif = sc->vifs[if_id]; | ||
259 | avp = (void *)vif->drv_priv; | 255 | avp = (void *)vif->drv_priv; |
260 | 256 | ||
261 | /* Allocate a beacon descriptor if we haven't done so. */ | 257 | /* 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) | |||
275 | */ | 271 | */ |
276 | avp->av_bslot = 0; | 272 | avp->av_bslot = 0; |
277 | for (slot = 0; slot < ATH_BCBUF; slot++) | 273 | for (slot = 0; slot < ATH_BCBUF; slot++) |
278 | if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) { | 274 | if (sc->beacon.bslot[slot] == NULL) { |
279 | /* | 275 | /* |
280 | * XXX hack, space out slots to better | 276 | * XXX hack, space out slots to better |
281 | * deal with misses | 277 | * deal with misses |
282 | */ | 278 | */ |
283 | if (slot+1 < ATH_BCBUF && | 279 | if (slot+1 < ATH_BCBUF && |
284 | sc->beacon.bslot[slot+1] == | 280 | sc->beacon.bslot[slot+1] == NULL) { |
285 | ATH_IF_ID_ANY) { | ||
286 | avp->av_bslot = slot+1; | 281 | avp->av_bslot = slot+1; |
287 | break; | 282 | break; |
288 | } | 283 | } |
289 | avp->av_bslot = slot; | 284 | avp->av_bslot = slot; |
290 | /* NB: keep looking for a double slot */ | 285 | /* NB: keep looking for a double slot */ |
291 | } | 286 | } |
292 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY); | 287 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); |
293 | sc->beacon.bslot[avp->av_bslot] = if_id; | 288 | sc->beacon.bslot[avp->av_bslot] = vif; |
294 | sc->nbcnvifs++; | 289 | sc->nbcnvifs++; |
295 | } | 290 | } |
296 | } | 291 | } |
@@ -372,7 +367,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) | |||
372 | struct ath_buf *bf; | 367 | struct ath_buf *bf; |
373 | 368 | ||
374 | if (avp->av_bslot != -1) { | 369 | if (avp->av_bslot != -1) { |
375 | sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY; | 370 | sc->beacon.bslot[avp->av_bslot] = NULL; |
376 | sc->nbcnvifs--; | 371 | sc->nbcnvifs--; |
377 | } | 372 | } |
378 | 373 | ||
@@ -395,7 +390,8 @@ void ath_beacon_tasklet(unsigned long data) | |||
395 | struct ath_softc *sc = (struct ath_softc *)data; | 390 | struct ath_softc *sc = (struct ath_softc *)data; |
396 | struct ath_hw *ah = sc->sc_ah; | 391 | struct ath_hw *ah = sc->sc_ah; |
397 | struct ath_buf *bf = NULL; | 392 | struct ath_buf *bf = NULL; |
398 | int slot, if_id; | 393 | struct ieee80211_vif *vif; |
394 | int slot; | ||
399 | u32 bfaddr, bc = 0, tsftu; | 395 | u32 bfaddr, bc = 0, tsftu; |
400 | u64 tsf; | 396 | u64 tsf; |
401 | u16 intval; | 397 | u16 intval; |
@@ -442,15 +438,15 @@ void ath_beacon_tasklet(unsigned long data) | |||
442 | tsf = ath9k_hw_gettsf64(ah); | 438 | tsf = ath9k_hw_gettsf64(ah); |
443 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 439 | tsftu = TSF_TO_TU(tsf>>32, tsf); |
444 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 440 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; |
445 | if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; | 441 | vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; |
446 | 442 | ||
447 | DPRINTF(sc, ATH_DBG_BEACON, | 443 | DPRINTF(sc, ATH_DBG_BEACON, |
448 | "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", | 444 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", |
449 | slot, tsf, tsftu, intval, if_id); | 445 | slot, tsf, tsftu, intval, vif); |
450 | 446 | ||
451 | bfaddr = 0; | 447 | bfaddr = 0; |
452 | if (if_id != ATH_IF_ID_ANY) { | 448 | if (vif) { |
453 | bf = ath_beacon_generate(sc, if_id); | 449 | bf = ath_beacon_generate(sc, vif); |
454 | if (bf != NULL) { | 450 | if (bf != NULL) { |
455 | bfaddr = bf->bf_daddr; | 451 | bfaddr = bf->bf_daddr; |
456 | bc = 1; | 452 | bc = 1; |
@@ -652,7 +648,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
652 | 648 | ||
653 | static void ath_beacon_config_adhoc(struct ath_softc *sc, | 649 | static void ath_beacon_config_adhoc(struct ath_softc *sc, |
654 | struct ath_beacon_config *conf, | 650 | struct ath_beacon_config *conf, |
655 | struct ath_vif *avp) | 651 | struct ath_vif *avp, |
652 | struct ieee80211_vif *vif) | ||
656 | { | 653 | { |
657 | u64 tsf; | 654 | u64 tsf; |
658 | u32 tsftu, intval, nexttbtt; | 655 | u32 tsftu, intval, nexttbtt; |
@@ -696,14 +693,12 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
696 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); | 693 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); |
697 | 694 | ||
698 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) | 695 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) |
699 | ath_beacon_start_adhoc(sc, 0); | 696 | ath_beacon_start_adhoc(sc, vif); |
700 | } | 697 | } |
701 | 698 | ||
702 | void ath_beacon_config(struct ath_softc *sc, int if_id) | 699 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) |
703 | { | 700 | { |
704 | struct ath_beacon_config conf; | 701 | struct ath_beacon_config conf; |
705 | struct ath_vif *avp; | ||
706 | struct ieee80211_vif *vif; | ||
707 | 702 | ||
708 | /* Setup the beacon configuration parameters */ | 703 | /* Setup the beacon configuration parameters */ |
709 | 704 | ||
@@ -715,16 +710,15 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) | |||
715 | conf.dtim_count = 1; | 710 | conf.dtim_count = 1; |
716 | conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; | 711 | conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; |
717 | 712 | ||
718 | if (if_id != ATH_IF_ID_ANY) { | 713 | if (vif) { |
719 | vif = sc->vifs[if_id]; | 714 | struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; |
720 | avp = (struct ath_vif *)vif->drv_priv; | ||
721 | 715 | ||
722 | switch(avp->av_opmode) { | 716 | switch(avp->av_opmode) { |
723 | case NL80211_IFTYPE_AP: | 717 | case NL80211_IFTYPE_AP: |
724 | ath_beacon_config_ap(sc, &conf, avp); | 718 | ath_beacon_config_ap(sc, &conf, avp); |
725 | break; | 719 | break; |
726 | case NL80211_IFTYPE_ADHOC: | 720 | case NL80211_IFTYPE_ADHOC: |
727 | ath_beacon_config_adhoc(sc, &conf, avp); | 721 | ath_beacon_config_adhoc(sc, &conf, avp, vif); |
728 | break; | 722 | break; |
729 | case NL80211_IFTYPE_STATION: | 723 | case NL80211_IFTYPE_STATION: |
730 | ath_beacon_config_sta(sc, &conf, avp); | 724 | ath_beacon_config_sta(sc, &conf, avp); |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index b7a3523e6ed8..e43cee7907b2 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -800,13 +800,10 @@ static int ath_key_config(struct ath_softc *sc, | |||
800 | * need to change with virtual interfaces. */ | 800 | * need to change with virtual interfaces. */ |
801 | idx = key->keyidx; | 801 | idx = key->keyidx; |
802 | } else if (key->keyidx) { | 802 | } else if (key->keyidx) { |
803 | struct ieee80211_vif *vif; | ||
804 | |||
805 | if (WARN_ON(!sta)) | 803 | if (WARN_ON(!sta)) |
806 | return -EOPNOTSUPP; | 804 | return -EOPNOTSUPP; |
807 | mac = sta->addr; | 805 | mac = sta->addr; |
808 | 806 | ||
809 | vif = sc->vifs[0]; | ||
810 | if (vif->type != NL80211_IFTYPE_AP) { | 807 | if (vif->type != NL80211_IFTYPE_AP) { |
811 | /* Only keyidx 0 should be used with unicast key, but | 808 | /* Only keyidx 0 should be used with unicast key, but |
812 | * allow this for client mode for now. */ | 809 | * allow this for client mode for now. */ |
@@ -915,7 +912,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
915 | } | 912 | } |
916 | 913 | ||
917 | /* Configure the beacon */ | 914 | /* Configure the beacon */ |
918 | ath_beacon_config(sc, 0); | 915 | ath_beacon_config(sc, vif); |
919 | 916 | ||
920 | /* Reset rssi stats */ | 917 | /* Reset rssi stats */ |
921 | sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; | 918 | sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; |
@@ -1120,7 +1117,7 @@ static void ath_radio_enable(struct ath_softc *sc) | |||
1120 | } | 1117 | } |
1121 | 1118 | ||
1122 | if (sc->sc_flags & SC_OP_BEACONS) | 1119 | if (sc->sc_flags & SC_OP_BEACONS) |
1123 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ | 1120 | ath_beacon_config(sc, NULL); /* restart beacons */ |
1124 | 1121 | ||
1125 | /* Re-Enable interrupts */ | 1122 | /* Re-Enable interrupts */ |
1126 | ath9k_hw_set_interrupts(ah, sc->imask); | 1123 | ath9k_hw_set_interrupts(ah, sc->imask); |
@@ -1527,7 +1524,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) | |||
1527 | 1524 | ||
1528 | /* initialize beacon slots */ | 1525 | /* initialize beacon slots */ |
1529 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) | 1526 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) |
1530 | sc->beacon.bslot[i] = ATH_IF_ID_ANY; | 1527 | sc->beacon.bslot[i] = NULL; |
1531 | 1528 | ||
1532 | /* save MISC configurations */ | 1529 | /* save MISC configurations */ |
1533 | sc->config.swBeaconProcess = 1; | 1530 | sc->config.swBeaconProcess = 1; |
@@ -1715,7 +1712,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
1715 | ath_update_txpow(sc); | 1712 | ath_update_txpow(sc); |
1716 | 1713 | ||
1717 | if (sc->sc_flags & SC_OP_BEACONS) | 1714 | if (sc->sc_flags & SC_OP_BEACONS) |
1718 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ | 1715 | ath_beacon_config(sc, NULL); /* restart beacons */ |
1719 | 1716 | ||
1720 | ath9k_hw_set_interrupts(ah, sc->imask); | 1717 | ath9k_hw_set_interrupts(ah, sc->imask); |
1721 | 1718 | ||
@@ -2127,11 +2124,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2127 | struct ath_softc *sc = hw->priv; | 2124 | struct ath_softc *sc = hw->priv; |
2128 | struct ath_vif *avp = (void *)conf->vif->drv_priv; | 2125 | struct ath_vif *avp = (void *)conf->vif->drv_priv; |
2129 | enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; | 2126 | enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; |
2130 | 2127 | int ret = 0; | |
2131 | /* Support only vif for now */ | ||
2132 | |||
2133 | if (sc->nvifs) | ||
2134 | return -ENOBUFS; | ||
2135 | 2128 | ||
2136 | mutex_lock(&sc->mutex); | 2129 | mutex_lock(&sc->mutex); |
2137 | 2130 | ||
@@ -2140,16 +2133,24 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2140 | ic_opmode = NL80211_IFTYPE_STATION; | 2133 | ic_opmode = NL80211_IFTYPE_STATION; |
2141 | break; | 2134 | break; |
2142 | case NL80211_IFTYPE_ADHOC: | 2135 | case NL80211_IFTYPE_ADHOC: |
2136 | if (sc->nbcnvifs >= ATH_BCBUF) { | ||
2137 | ret = -ENOBUFS; | ||
2138 | goto out; | ||
2139 | } | ||
2143 | ic_opmode = NL80211_IFTYPE_ADHOC; | 2140 | ic_opmode = NL80211_IFTYPE_ADHOC; |
2144 | break; | 2141 | break; |
2145 | case NL80211_IFTYPE_AP: | 2142 | case NL80211_IFTYPE_AP: |
2143 | if (sc->nbcnvifs >= ATH_BCBUF) { | ||
2144 | ret = -ENOBUFS; | ||
2145 | goto out; | ||
2146 | } | ||
2146 | ic_opmode = NL80211_IFTYPE_AP; | 2147 | ic_opmode = NL80211_IFTYPE_AP; |
2147 | break; | 2148 | break; |
2148 | default: | 2149 | default: |
2149 | DPRINTF(sc, ATH_DBG_FATAL, | 2150 | DPRINTF(sc, ATH_DBG_FATAL, |
2150 | "Interface type %d not yet supported\n", conf->type); | 2151 | "Interface type %d not yet supported\n", conf->type); |
2151 | mutex_unlock(&sc->mutex); | 2152 | ret = -EOPNOTSUPP; |
2152 | return -EOPNOTSUPP; | 2153 | goto out; |
2153 | } | 2154 | } |
2154 | 2155 | ||
2155 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); | 2156 | 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, | |||
2158 | avp->av_opmode = ic_opmode; | 2159 | avp->av_opmode = ic_opmode; |
2159 | avp->av_bslot = -1; | 2160 | avp->av_bslot = -1; |
2160 | 2161 | ||
2162 | sc->nvifs++; | ||
2163 | if (sc->nvifs > 1) | ||
2164 | goto out; /* skip global settings for secondary vif */ | ||
2165 | |||
2161 | if (ic_opmode == NL80211_IFTYPE_AP) { | 2166 | if (ic_opmode == NL80211_IFTYPE_AP) { |
2162 | ath9k_hw_set_tsfadjust(sc->sc_ah, 1); | 2167 | ath9k_hw_set_tsfadjust(sc->sc_ah, 1); |
2163 | sc->sc_flags |= SC_OP_TSF_RESET; | 2168 | sc->sc_flags |= SC_OP_TSF_RESET; |
2164 | } | 2169 | } |
2165 | 2170 | ||
2166 | sc->vifs[0] = conf->vif; | ||
2167 | sc->nvifs++; | ||
2168 | |||
2169 | /* Set the device opmode */ | 2171 | /* Set the device opmode */ |
2170 | sc->sc_ah->opmode = ic_opmode; | 2172 | sc->sc_ah->opmode = ic_opmode; |
2171 | 2173 | ||
@@ -2200,9 +2202,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2200 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 2202 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
2201 | } | 2203 | } |
2202 | 2204 | ||
2205 | out: | ||
2203 | mutex_unlock(&sc->mutex); | 2206 | mutex_unlock(&sc->mutex); |
2204 | 2207 | return ret; | |
2205 | return 0; | ||
2206 | } | 2208 | } |
2207 | 2209 | ||
2208 | static void ath9k_remove_interface(struct ieee80211_hw *hw, | 2210 | static void ath9k_remove_interface(struct ieee80211_hw *hw, |
@@ -2210,6 +2212,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
2210 | { | 2212 | { |
2211 | struct ath_softc *sc = hw->priv; | 2213 | struct ath_softc *sc = hw->priv; |
2212 | struct ath_vif *avp = (void *)conf->vif->drv_priv; | 2214 | struct ath_vif *avp = (void *)conf->vif->drv_priv; |
2215 | int i; | ||
2213 | 2216 | ||
2214 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); | 2217 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); |
2215 | 2218 | ||
@@ -2227,7 +2230,14 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
2227 | 2230 | ||
2228 | sc->sc_flags &= ~SC_OP_BEACONS; | 2231 | sc->sc_flags &= ~SC_OP_BEACONS; |
2229 | 2232 | ||
2230 | sc->vifs[0] = NULL; | 2233 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { |
2234 | if (sc->beacon.bslot[i] == conf->vif) { | ||
2235 | printk(KERN_DEBUG "%s: vif had allocated beacon " | ||
2236 | "slot\n", __func__); | ||
2237 | sc->beacon.bslot[i] = NULL; | ||
2238 | } | ||
2239 | } | ||
2240 | |||
2231 | sc->nvifs--; | 2241 | sc->nvifs--; |
2232 | 2242 | ||
2233 | mutex_unlock(&sc->mutex); | 2243 | mutex_unlock(&sc->mutex); |
@@ -2364,13 +2374,13 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
2364 | */ | 2374 | */ |
2365 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 2375 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
2366 | 2376 | ||
2367 | error = ath_beacon_alloc(sc, 0); | 2377 | error = ath_beacon_alloc(sc, vif); |
2368 | if (error != 0) { | 2378 | if (error != 0) { |
2369 | mutex_unlock(&sc->mutex); | 2379 | mutex_unlock(&sc->mutex); |
2370 | return error; | 2380 | return error; |
2371 | } | 2381 | } |
2372 | 2382 | ||
2373 | ath_beacon_config(sc, 0); | 2383 | ath_beacon_config(sc, vif); |
2374 | } | 2384 | } |
2375 | } | 2385 | } |
2376 | 2386 | ||