diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:29 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:45 -0500 |
commit | c52f33d05e5f8d59f02722fbc308f5f391575ca5 (patch) | |
tree | 19c6d56f3594e8b43d725b5d919bb775921fde38 /drivers | |
parent | bce048d77dff3dcfd75d54dc38580c81baa95853 (diff) |
ath9k: Add support for multiple secondary virtual wiphys
The new struct ath_softc::sec_wiphy array is used to store information
about virtual wiphys and select which wiphy is used in calls to
mac80211. Each virtual wiphy will be assigned a different MAC address
based on the virtual wiphy index.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/beacon.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 65 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/rc.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/recv.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/virtual.c | 90 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/xmit.c | 20 |
7 files changed, 212 insertions, 41 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 41eeac42a80c..386b93622e58 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -373,10 +373,10 @@ int ath_tx_cleanup(struct ath_softc *sc); | |||
373 | struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); | 373 | struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); |
374 | int ath_txq_update(struct ath_softc *sc, int qnum, | 374 | int ath_txq_update(struct ath_softc *sc, int qnum, |
375 | struct ath9k_tx_queue_info *q); | 375 | struct ath9k_tx_queue_info *q); |
376 | int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, | 376 | int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, |
377 | struct ath_tx_control *txctl); | 377 | struct ath_tx_control *txctl); |
378 | void ath_tx_tasklet(struct ath_softc *sc); | 378 | void ath_tx_tasklet(struct ath_softc *sc); |
379 | void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); | 379 | void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); |
380 | bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); | 380 | bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); |
381 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | 381 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, |
382 | u16 tid, u16 *ssn); | 382 | u16 tid, u16 *ssn); |
@@ -429,6 +429,7 @@ struct ath_beacon { | |||
429 | u32 ast_be_xmit; | 429 | u32 ast_be_xmit; |
430 | u64 bc_tstamp; | 430 | u64 bc_tstamp; |
431 | struct ieee80211_vif *bslot[ATH_BCBUF]; | 431 | struct ieee80211_vif *bslot[ATH_BCBUF]; |
432 | struct ath_wiphy *bslot_aphy[ATH_BCBUF]; | ||
432 | int slottime; | 433 | int slottime; |
433 | int slotupdate; | 434 | int slotupdate; |
434 | struct ath9k_tx_queue_info beacon_qi; | 435 | struct ath9k_tx_queue_info beacon_qi; |
@@ -440,7 +441,7 @@ struct ath_beacon { | |||
440 | void ath_beacon_tasklet(unsigned long data); | 441 | void ath_beacon_tasklet(unsigned long data); |
441 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); | 442 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); |
442 | int ath_beaconq_setup(struct ath_hw *ah); | 443 | int ath_beaconq_setup(struct ath_hw *ah); |
443 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); | 444 | int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); |
444 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); | 445 | void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); |
445 | 446 | ||
446 | /*******/ | 447 | /*******/ |
@@ -554,7 +555,12 @@ struct ath_wiphy; | |||
554 | struct ath_softc { | 555 | struct ath_softc { |
555 | struct ieee80211_hw *hw; | 556 | struct ieee80211_hw *hw; |
556 | struct device *dev; | 557 | struct device *dev; |
558 | |||
559 | spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ | ||
557 | struct ath_wiphy *pri_wiphy; | 560 | struct ath_wiphy *pri_wiphy; |
561 | struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may | ||
562 | * have NULL entries */ | ||
563 | int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ | ||
558 | struct tasklet_struct intr_tq; | 564 | struct tasklet_struct intr_tq; |
559 | struct tasklet_struct bcon_tasklet; | 565 | struct tasklet_struct bcon_tasklet; |
560 | struct ath_hw *sc_ah; | 566 | struct ath_hw *sc_ah; |
@@ -638,6 +644,7 @@ int ath_attach(u16 devid, struct ath_softc *sc); | |||
638 | void ath_detach(struct ath_softc *sc); | 644 | void ath_detach(struct ath_softc *sc); |
639 | const char *ath_mac_bb_name(u32 mac_bb_version); | 645 | const char *ath_mac_bb_name(u32 mac_bb_version); |
640 | const char *ath_rf_name(u16 rf_version); | 646 | const char *ath_rf_name(u16 rf_version); |
647 | void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); | ||
641 | 648 | ||
642 | #ifdef CONFIG_PCI | 649 | #ifdef CONFIG_PCI |
643 | int ath_pci_init(void); | 650 | int ath_pci_init(void); |
@@ -675,5 +682,7 @@ static inline void ath9k_ps_restore(struct ath_softc *sc) | |||
675 | 682 | ||
676 | 683 | ||
677 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw); | 684 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw); |
685 | int ath9k_wiphy_add(struct ath_softc *sc); | ||
686 | int ath9k_wiphy_del(struct ath_wiphy *aphy); | ||
678 | 687 | ||
679 | #endif /* ATH9K_H */ | 688 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 357d797e79c1..760f5b80f79e 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c | |||
@@ -113,9 +113,11 @@ 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, | 116 | static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, |
117 | struct ieee80211_vif *vif) | 117 | struct ieee80211_vif *vif) |
118 | { | 118 | { |
119 | struct ath_wiphy *aphy = hw->priv; | ||
120 | struct ath_softc *sc = aphy->sc; | ||
119 | struct ath_buf *bf; | 121 | struct ath_buf *bf; |
120 | struct ath_vif *avp; | 122 | struct ath_vif *avp; |
121 | struct sk_buff *skb; | 123 | struct sk_buff *skb; |
@@ -144,7 +146,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, | |||
144 | 146 | ||
145 | /* Get a new beacon from mac80211 */ | 147 | /* Get a new beacon from mac80211 */ |
146 | 148 | ||
147 | skb = ieee80211_beacon_get(sc->hw, vif); | 149 | skb = ieee80211_beacon_get(hw, vif); |
148 | bf->bf_mpdu = skb; | 150 | bf->bf_mpdu = skb; |
149 | if (skb == NULL) | 151 | if (skb == NULL) |
150 | return NULL; | 152 | return NULL; |
@@ -171,7 +173,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, | |||
171 | return NULL; | 173 | return NULL; |
172 | } | 174 | } |
173 | 175 | ||
174 | skb = ieee80211_get_buffered_bc(sc->hw, vif); | 176 | skb = ieee80211_get_buffered_bc(hw, vif); |
175 | 177 | ||
176 | /* | 178 | /* |
177 | * if the CABQ traffic from previous DTIM is pending and the current | 179 | * if the CABQ traffic from previous DTIM is pending and the current |
@@ -196,8 +198,8 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, | |||
196 | ath_beacon_setup(sc, avp, bf); | 198 | ath_beacon_setup(sc, avp, bf); |
197 | 199 | ||
198 | while (skb) { | 200 | while (skb) { |
199 | ath_tx_cabq(sc, skb); | 201 | ath_tx_cabq(hw, skb); |
200 | skb = ieee80211_get_buffered_bc(sc->hw, vif); | 202 | skb = ieee80211_get_buffered_bc(hw, vif); |
201 | } | 203 | } |
202 | 204 | ||
203 | return bf; | 205 | return bf; |
@@ -244,8 +246,9 @@ int ath_beaconq_setup(struct ath_hw *ah) | |||
244 | return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); | 246 | return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); |
245 | } | 247 | } |
246 | 248 | ||
247 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | 249 | int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) |
248 | { | 250 | { |
251 | struct ath_softc *sc = aphy->sc; | ||
249 | struct ath_vif *avp; | 252 | struct ath_vif *avp; |
250 | struct ieee80211_hdr *hdr; | 253 | struct ieee80211_hdr *hdr; |
251 | struct ath_buf *bf; | 254 | struct ath_buf *bf; |
@@ -286,6 +289,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
286 | } | 289 | } |
287 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); | 290 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); |
288 | sc->beacon.bslot[avp->av_bslot] = vif; | 291 | sc->beacon.bslot[avp->av_bslot] = vif; |
292 | sc->beacon.bslot_aphy[avp->av_bslot] = aphy; | ||
289 | sc->nbcnvifs++; | 293 | sc->nbcnvifs++; |
290 | } | 294 | } |
291 | } | 295 | } |
@@ -368,6 +372,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) | |||
368 | 372 | ||
369 | if (avp->av_bslot != -1) { | 373 | if (avp->av_bslot != -1) { |
370 | sc->beacon.bslot[avp->av_bslot] = NULL; | 374 | sc->beacon.bslot[avp->av_bslot] = NULL; |
375 | sc->beacon.bslot_aphy[avp->av_bslot] = NULL; | ||
371 | sc->nbcnvifs--; | 376 | sc->nbcnvifs--; |
372 | } | 377 | } |
373 | 378 | ||
@@ -391,6 +396,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
391 | struct ath_hw *ah = sc->sc_ah; | 396 | struct ath_hw *ah = sc->sc_ah; |
392 | struct ath_buf *bf = NULL; | 397 | struct ath_buf *bf = NULL; |
393 | struct ieee80211_vif *vif; | 398 | struct ieee80211_vif *vif; |
399 | struct ath_wiphy *aphy; | ||
394 | int slot; | 400 | int slot; |
395 | u32 bfaddr, bc = 0, tsftu; | 401 | u32 bfaddr, bc = 0, tsftu; |
396 | u64 tsf; | 402 | u64 tsf; |
@@ -439,6 +445,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
439 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 445 | tsftu = TSF_TO_TU(tsf>>32, tsf); |
440 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 446 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; |
441 | vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; | 447 | vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; |
448 | aphy = sc->beacon.bslot_aphy[(slot + 1) % ATH_BCBUF]; | ||
442 | 449 | ||
443 | DPRINTF(sc, ATH_DBG_BEACON, | 450 | DPRINTF(sc, ATH_DBG_BEACON, |
444 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | 451 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", |
@@ -446,7 +453,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
446 | 453 | ||
447 | bfaddr = 0; | 454 | bfaddr = 0; |
448 | if (vif) { | 455 | if (vif) { |
449 | bf = ath_beacon_generate(sc, vif); | 456 | bf = ath_beacon_generate(aphy->hw, vif); |
450 | if (bf != NULL) { | 457 | if (bf != NULL) { |
451 | bfaddr = bf->bf_daddr; | 458 | bfaddr = bf->bf_daddr; |
452 | bc = 1; | 459 | bc = 1; |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0c0e587d7942..433a11c41838 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -1307,6 +1307,7 @@ void ath_cleanup(struct ath_softc *sc) | |||
1307 | ath_detach(sc); | 1307 | ath_detach(sc); |
1308 | free_irq(sc->irq, sc); | 1308 | free_irq(sc->irq, sc); |
1309 | ath_bus_cleanup(sc); | 1309 | ath_bus_cleanup(sc); |
1310 | kfree(sc->sec_wiphy); | ||
1310 | ieee80211_free_hw(sc->hw); | 1311 | ieee80211_free_hw(sc->hw); |
1311 | } | 1312 | } |
1312 | 1313 | ||
@@ -1324,6 +1325,14 @@ void ath_detach(struct ath_softc *sc) | |||
1324 | #endif | 1325 | #endif |
1325 | ath_deinit_leds(sc); | 1326 | ath_deinit_leds(sc); |
1326 | 1327 | ||
1328 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
1329 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
1330 | if (aphy == NULL) | ||
1331 | continue; | ||
1332 | sc->sec_wiphy[i] = NULL; | ||
1333 | ieee80211_unregister_hw(aphy->hw); | ||
1334 | ieee80211_free_hw(aphy->hw); | ||
1335 | } | ||
1327 | ieee80211_unregister_hw(hw); | 1336 | ieee80211_unregister_hw(hw); |
1328 | ath_rx_cleanup(sc); | 1337 | ath_rx_cleanup(sc); |
1329 | ath_tx_cleanup(sc); | 1338 | ath_tx_cleanup(sc); |
@@ -1357,6 +1366,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) | |||
1357 | if (ath9k_init_debug(sc) < 0) | 1366 | if (ath9k_init_debug(sc) < 0) |
1358 | printk(KERN_ERR "Unable to create debugfs files\n"); | 1367 | printk(KERN_ERR "Unable to create debugfs files\n"); |
1359 | 1368 | ||
1369 | spin_lock_init(&sc->wiphy_lock); | ||
1360 | spin_lock_init(&sc->sc_resetlock); | 1370 | spin_lock_init(&sc->sc_resetlock); |
1361 | mutex_init(&sc->mutex); | 1371 | mutex_init(&sc->mutex); |
1362 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 1372 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
@@ -1520,8 +1530,10 @@ static int ath_init(u16 devid, struct ath_softc *sc) | |||
1520 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ | 1530 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ |
1521 | 1531 | ||
1522 | /* initialize beacon slots */ | 1532 | /* initialize beacon slots */ |
1523 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) | 1533 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { |
1524 | sc->beacon.bslot[i] = NULL; | 1534 | sc->beacon.bslot[i] = NULL; |
1535 | sc->beacon.bslot_aphy[i] = NULL; | ||
1536 | } | ||
1525 | 1537 | ||
1526 | /* save MISC configurations */ | 1538 | /* save MISC configurations */ |
1527 | sc->config.swBeaconProcess = 1; | 1539 | sc->config.swBeaconProcess = 1; |
@@ -1561,22 +1573,8 @@ bad: | |||
1561 | return error; | 1573 | return error; |
1562 | } | 1574 | } |
1563 | 1575 | ||
1564 | int ath_attach(u16 devid, struct ath_softc *sc) | 1576 | void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) |
1565 | { | 1577 | { |
1566 | struct ieee80211_hw *hw = sc->hw; | ||
1567 | const struct ieee80211_regdomain *regd; | ||
1568 | int error = 0, i; | ||
1569 | |||
1570 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); | ||
1571 | |||
1572 | error = ath_init(devid, sc); | ||
1573 | if (error != 0) | ||
1574 | return error; | ||
1575 | |||
1576 | /* get mac address from hardware and set in mac80211 */ | ||
1577 | |||
1578 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); | ||
1579 | |||
1580 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 1578 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
1581 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1579 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1582 | IEEE80211_HW_SIGNAL_DBM | | 1580 | IEEE80211_HW_SIGNAL_DBM | |
@@ -1604,17 +1602,37 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1604 | 1602 | ||
1605 | hw->rate_control_algorithm = "ath9k_rate_control"; | 1603 | hw->rate_control_algorithm = "ath9k_rate_control"; |
1606 | 1604 | ||
1605 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
1606 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
1607 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | ||
1608 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
1609 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
1610 | } | ||
1611 | |||
1612 | int ath_attach(u16 devid, struct ath_softc *sc) | ||
1613 | { | ||
1614 | struct ieee80211_hw *hw = sc->hw; | ||
1615 | const struct ieee80211_regdomain *regd; | ||
1616 | int error = 0, i; | ||
1617 | |||
1618 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); | ||
1619 | |||
1620 | error = ath_init(devid, sc); | ||
1621 | if (error != 0) | ||
1622 | return error; | ||
1623 | |||
1624 | /* get mac address from hardware and set in mac80211 */ | ||
1625 | |||
1626 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); | ||
1627 | |||
1628 | ath_set_hw_capab(sc, hw); | ||
1629 | |||
1607 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 1630 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { |
1608 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | 1631 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); |
1609 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | 1632 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) |
1610 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | 1633 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); |
1611 | } | 1634 | } |
1612 | 1635 | ||
1613 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
1614 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | ||
1615 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
1616 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
1617 | |||
1618 | /* initialize tx/rx engine */ | 1636 | /* initialize tx/rx engine */ |
1619 | error = ath_tx_init(sc, ATH_TXBUF); | 1637 | error = ath_tx_init(sc, ATH_TXBUF); |
1620 | if (error != 0) | 1638 | if (error != 0) |
@@ -2067,7 +2085,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, | |||
2067 | 2085 | ||
2068 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); | 2086 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); |
2069 | 2087 | ||
2070 | if (ath_tx_start(sc, skb, &txctl) != 0) { | 2088 | if (ath_tx_start(hw, skb, &txctl) != 0) { |
2071 | DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); | 2089 | DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); |
2072 | goto exit; | 2090 | goto exit; |
2073 | } | 2091 | } |
@@ -2247,6 +2265,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
2247 | printk(KERN_DEBUG "%s: vif had allocated beacon " | 2265 | printk(KERN_DEBUG "%s: vif had allocated beacon " |
2248 | "slot\n", __func__); | 2266 | "slot\n", __func__); |
2249 | sc->beacon.bslot[i] = NULL; | 2267 | sc->beacon.bslot[i] = NULL; |
2268 | sc->beacon.bslot_aphy[i] = NULL; | ||
2250 | } | 2269 | } |
2251 | } | 2270 | } |
2252 | 2271 | ||
@@ -2388,7 +2407,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
2388 | */ | 2407 | */ |
2389 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 2408 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
2390 | 2409 | ||
2391 | error = ath_beacon_alloc(sc, vif); | 2410 | error = ath_beacon_alloc(aphy, vif); |
2392 | if (error != 0) { | 2411 | if (error != 0) { |
2393 | mutex_unlock(&sc->mutex); | 2412 | mutex_unlock(&sc->mutex); |
2394 | return error; | 2413 | return error; |
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index a6dc82d92612..0584122341ad 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h | |||
@@ -195,6 +195,7 @@ struct ath_rate_priv { | |||
195 | }; | 195 | }; |
196 | 196 | ||
197 | struct ath_tx_info_priv { | 197 | struct ath_tx_info_priv { |
198 | struct ath_wiphy *aphy; | ||
198 | struct ath_tx_status tx; | 199 | struct ath_tx_status tx; |
199 | int n_frames; | 200 | int n_frames; |
200 | int n_bad_frames; | 201 | int n_bad_frames; |
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index ec535834f961..a9a55df500a4 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c | |||
@@ -19,7 +19,22 @@ | |||
19 | static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, | 19 | static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, |
20 | struct ieee80211_hdr *hdr) | 20 | struct ieee80211_hdr *hdr) |
21 | { | 21 | { |
22 | return sc->pri_wiphy->hw; | 22 | struct ieee80211_hw *hw = sc->pri_wiphy->hw; |
23 | int i; | ||
24 | |||
25 | spin_lock_bh(&sc->wiphy_lock); | ||
26 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
27 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
28 | if (aphy == NULL) | ||
29 | continue; | ||
30 | if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) | ||
31 | == 0) { | ||
32 | hw = aphy->hw; | ||
33 | break; | ||
34 | } | ||
35 | } | ||
36 | spin_unlock_bh(&sc->wiphy_lock); | ||
37 | return hw; | ||
23 | } | 38 | } |
24 | 39 | ||
25 | /* | 40 | /* |
@@ -611,7 +626,29 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
611 | } | 626 | } |
612 | 627 | ||
613 | /* Send the frame to mac80211 */ | 628 | /* Send the frame to mac80211 */ |
614 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, &rx_status); | 629 | if (hdr->addr1[5] & 0x01) { |
630 | int i; | ||
631 | /* | ||
632 | * Deliver broadcast/multicast frames to all suitable | ||
633 | * virtual wiphys. | ||
634 | */ | ||
635 | /* TODO: filter based on channel configuration */ | ||
636 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
637 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
638 | struct sk_buff *nskb; | ||
639 | if (aphy == NULL) | ||
640 | continue; | ||
641 | nskb = skb_copy(skb, GFP_ATOMIC); | ||
642 | if (nskb) | ||
643 | __ieee80211_rx(aphy->hw, nskb, | ||
644 | &rx_status); | ||
645 | } | ||
646 | __ieee80211_rx(sc->hw, skb, &rx_status); | ||
647 | } else { | ||
648 | /* Deliver unicast frames based on receiver address */ | ||
649 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, | ||
650 | &rx_status); | ||
651 | } | ||
615 | 652 | ||
616 | /* We will now give hardware our shiny new allocated skb */ | 653 | /* We will now give hardware our shiny new allocated skb */ |
617 | bf->bf_mpdu = requeue_skb; | 654 | bf->bf_mpdu = requeue_skb; |
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c index a91f2f1c911b..67bcb9343ca6 100644 --- a/drivers/net/wireless/ath9k/virtual.c +++ b/drivers/net/wireless/ath9k/virtual.c | |||
@@ -57,8 +57,16 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
57 | iter_data.count = 0; | 57 | iter_data.count = 0; |
58 | 58 | ||
59 | /* Get list of all active MAC addresses */ | 59 | /* Get list of all active MAC addresses */ |
60 | ieee80211_iterate_active_interfaces_atomic(hw, ath9k_vif_iter, | 60 | spin_lock_bh(&sc->wiphy_lock); |
61 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, | ||
61 | &iter_data); | 62 | &iter_data); |
63 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
64 | if (sc->sec_wiphy[i] == NULL) | ||
65 | continue; | ||
66 | ieee80211_iterate_active_interfaces_atomic( | ||
67 | sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); | ||
68 | } | ||
69 | spin_unlock_bh(&sc->wiphy_lock); | ||
62 | 70 | ||
63 | /* Generate an address mask to cover all active addresses */ | 71 | /* Generate an address mask to cover all active addresses */ |
64 | memset(mask, 0, ETH_ALEN); | 72 | memset(mask, 0, ETH_ALEN); |
@@ -87,3 +95,83 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
87 | 95 | ||
88 | ath9k_hw_setbssidmask(sc); | 96 | ath9k_hw_setbssidmask(sc); |
89 | } | 97 | } |
98 | |||
99 | int ath9k_wiphy_add(struct ath_softc *sc) | ||
100 | { | ||
101 | int i, error; | ||
102 | struct ath_wiphy *aphy; | ||
103 | struct ieee80211_hw *hw; | ||
104 | u8 addr[ETH_ALEN]; | ||
105 | |||
106 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); | ||
107 | if (hw == NULL) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | spin_lock_bh(&sc->wiphy_lock); | ||
111 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
112 | if (sc->sec_wiphy[i] == NULL) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (i == sc->num_sec_wiphy) { | ||
117 | /* No empty slot available; increase array length */ | ||
118 | struct ath_wiphy **n; | ||
119 | n = krealloc(sc->sec_wiphy, | ||
120 | (sc->num_sec_wiphy + 1) * | ||
121 | sizeof(struct ath_wiphy *), | ||
122 | GFP_ATOMIC); | ||
123 | if (n == NULL) { | ||
124 | spin_unlock_bh(&sc->wiphy_lock); | ||
125 | ieee80211_free_hw(hw); | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | n[i] = NULL; | ||
129 | sc->sec_wiphy = n; | ||
130 | sc->num_sec_wiphy++; | ||
131 | } | ||
132 | |||
133 | SET_IEEE80211_DEV(hw, sc->dev); | ||
134 | |||
135 | aphy = hw->priv; | ||
136 | aphy->sc = sc; | ||
137 | aphy->hw = hw; | ||
138 | sc->sec_wiphy[i] = aphy; | ||
139 | spin_unlock_bh(&sc->wiphy_lock); | ||
140 | |||
141 | memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); | ||
142 | addr[0] |= 0x02; /* Locally managed address */ | ||
143 | /* | ||
144 | * XOR virtual wiphy index into the least significant bits to generate | ||
145 | * a different MAC address for each virtual wiphy. | ||
146 | */ | ||
147 | addr[5] ^= i & 0xff; | ||
148 | addr[4] ^= (i & 0xff00) >> 8; | ||
149 | addr[3] ^= (i & 0xff0000) >> 16; | ||
150 | |||
151 | SET_IEEE80211_PERM_ADDR(hw, addr); | ||
152 | |||
153 | ath_set_hw_capab(sc, hw); | ||
154 | |||
155 | error = ieee80211_register_hw(hw); | ||
156 | |||
157 | return error; | ||
158 | } | ||
159 | |||
160 | int ath9k_wiphy_del(struct ath_wiphy *aphy) | ||
161 | { | ||
162 | struct ath_softc *sc = aphy->sc; | ||
163 | int i; | ||
164 | |||
165 | spin_lock_bh(&sc->wiphy_lock); | ||
166 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
167 | if (aphy == sc->sec_wiphy[i]) { | ||
168 | sc->sec_wiphy[i] = NULL; | ||
169 | spin_unlock_bh(&sc->wiphy_lock); | ||
170 | ieee80211_unregister_hw(aphy->hw); | ||
171 | ieee80211_free_hw(aphy->hw); | ||
172 | return 0; | ||
173 | } | ||
174 | } | ||
175 | spin_unlock_bh(&sc->wiphy_lock); | ||
176 | return -ENOENT; | ||
177 | } | ||
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 363bb2a94d99..3c48fa5646f5 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c | |||
@@ -1497,10 +1497,12 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) | |||
1497 | ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); | 1497 | ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); |
1498 | } | 1498 | } |
1499 | 1499 | ||
1500 | static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, | 1500 | static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, |
1501 | struct sk_buff *skb, | 1501 | struct sk_buff *skb, |
1502 | struct ath_tx_control *txctl) | 1502 | struct ath_tx_control *txctl) |
1503 | { | 1503 | { |
1504 | struct ath_wiphy *aphy = hw->priv; | ||
1505 | struct ath_softc *sc = aphy->sc; | ||
1504 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1506 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
1505 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1507 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1506 | struct ath_tx_info_priv *tx_info_priv; | 1508 | struct ath_tx_info_priv *tx_info_priv; |
@@ -1511,6 +1513,7 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, | |||
1511 | if (unlikely(!tx_info_priv)) | 1513 | if (unlikely(!tx_info_priv)) |
1512 | return -ENOMEM; | 1514 | return -ENOMEM; |
1513 | tx_info->rate_driver_data[0] = tx_info_priv; | 1515 | tx_info->rate_driver_data[0] = tx_info_priv; |
1516 | tx_info_priv->aphy = aphy; | ||
1514 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 1517 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
1515 | fc = hdr->frame_control; | 1518 | fc = hdr->frame_control; |
1516 | 1519 | ||
@@ -1614,9 +1617,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1614 | } | 1617 | } |
1615 | 1618 | ||
1616 | /* Upon failure caller should free skb */ | 1619 | /* Upon failure caller should free skb */ |
1617 | int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, | 1620 | int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, |
1618 | struct ath_tx_control *txctl) | 1621 | struct ath_tx_control *txctl) |
1619 | { | 1622 | { |
1623 | struct ath_wiphy *aphy = hw->priv; | ||
1624 | struct ath_softc *sc = aphy->sc; | ||
1620 | struct ath_buf *bf; | 1625 | struct ath_buf *bf; |
1621 | int r; | 1626 | int r; |
1622 | 1627 | ||
@@ -1626,7 +1631,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, | |||
1626 | return -1; | 1631 | return -1; |
1627 | } | 1632 | } |
1628 | 1633 | ||
1629 | r = ath_tx_setup_buffer(sc, bf, skb, txctl); | 1634 | r = ath_tx_setup_buffer(hw, bf, skb, txctl); |
1630 | if (unlikely(r)) { | 1635 | if (unlikely(r)) { |
1631 | struct ath_txq *txq = txctl->txq; | 1636 | struct ath_txq *txq = txctl->txq; |
1632 | 1637 | ||
@@ -1656,8 +1661,10 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, | |||
1656 | return 0; | 1661 | return 0; |
1657 | } | 1662 | } |
1658 | 1663 | ||
1659 | void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) | 1664 | void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) |
1660 | { | 1665 | { |
1666 | struct ath_wiphy *aphy = hw->priv; | ||
1667 | struct ath_softc *sc = aphy->sc; | ||
1661 | int hdrlen, padsize; | 1668 | int hdrlen, padsize; |
1662 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1669 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1663 | struct ath_tx_control txctl; | 1670 | struct ath_tx_control txctl; |
@@ -1694,7 +1701,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) | |||
1694 | 1701 | ||
1695 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); | 1702 | DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); |
1696 | 1703 | ||
1697 | if (ath_tx_start(sc, skb, &txctl) != 0) { | 1704 | if (ath_tx_start(hw, skb, &txctl) != 0) { |
1698 | DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); | 1705 | DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); |
1699 | goto exit; | 1706 | goto exit; |
1700 | } | 1707 | } |
@@ -1718,6 +1725,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
1718 | 1725 | ||
1719 | DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); | 1726 | DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); |
1720 | 1727 | ||
1728 | if (tx_info_priv) | ||
1729 | hw = tx_info_priv->aphy->hw; | ||
1730 | |||
1721 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || | 1731 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || |
1722 | tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { | 1732 | tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { |
1723 | kfree(tx_info_priv); | 1733 | kfree(tx_info_priv); |