diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 90 |
1 files changed, 69 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ef87637e4245..ca35aaa7aec6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1428,13 +1428,78 @@ out: | |||
1428 | return ret; | 1428 | return ret; |
1429 | } | 1429 | } |
1430 | 1430 | ||
1431 | static void ath9k_reclaim_beacon(struct ath_softc *sc, | ||
1432 | struct ieee80211_vif *vif) | ||
1433 | { | ||
1434 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1435 | |||
1436 | /* Disable SWBA interrupt */ | ||
1437 | sc->sc_ah->imask &= ~ATH9K_INT_SWBA; | ||
1438 | ath9k_ps_wakeup(sc); | ||
1439 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | ||
1440 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | ||
1441 | tasklet_kill(&sc->bcon_tasklet); | ||
1442 | ath9k_ps_restore(sc); | ||
1443 | |||
1444 | ath_beacon_return(sc, avp); | ||
1445 | sc->sc_flags &= ~SC_OP_BEACONS; | ||
1446 | |||
1447 | if (sc->nbcnvifs > 0) { | ||
1448 | /* Re-enable beaconing */ | ||
1449 | sc->sc_ah->imask |= ATH9K_INT_SWBA; | ||
1450 | ath9k_ps_wakeup(sc); | ||
1451 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | ||
1452 | ath9k_ps_restore(sc); | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | static int ath9k_change_interface(struct ieee80211_hw *hw, | ||
1457 | struct ieee80211_vif *vif, | ||
1458 | enum nl80211_iftype new_type, | ||
1459 | bool p2p) | ||
1460 | { | ||
1461 | struct ath_wiphy *aphy = hw->priv; | ||
1462 | struct ath_softc *sc = aphy->sc; | ||
1463 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
1464 | |||
1465 | ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); | ||
1466 | mutex_lock(&sc->mutex); | ||
1467 | |||
1468 | switch (new_type) { | ||
1469 | case NL80211_IFTYPE_AP: | ||
1470 | case NL80211_IFTYPE_ADHOC: | ||
1471 | if (sc->nbcnvifs >= ATH_BCBUF) { | ||
1472 | ath_err(common, "No beacon slot available\n"); | ||
1473 | return -ENOBUFS; | ||
1474 | } | ||
1475 | break; | ||
1476 | case NL80211_IFTYPE_STATION: | ||
1477 | /* Stop ANI */ | ||
1478 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
1479 | del_timer_sync(&common->ani.timer); | ||
1480 | if ((vif->type == NL80211_IFTYPE_AP) || | ||
1481 | (vif->type == NL80211_IFTYPE_ADHOC)) | ||
1482 | ath9k_reclaim_beacon(sc, vif); | ||
1483 | break; | ||
1484 | default: | ||
1485 | ath_err(common, "Interface type %d not yet supported\n", | ||
1486 | vif->type); | ||
1487 | mutex_unlock(&sc->mutex); | ||
1488 | return -ENOTSUPP; | ||
1489 | } | ||
1490 | vif->type = new_type; | ||
1491 | vif->p2p = p2p; | ||
1492 | |||
1493 | mutex_unlock(&sc->mutex); | ||
1494 | return 0; | ||
1495 | } | ||
1496 | |||
1431 | static void ath9k_remove_interface(struct ieee80211_hw *hw, | 1497 | static void ath9k_remove_interface(struct ieee80211_hw *hw, |
1432 | struct ieee80211_vif *vif) | 1498 | struct ieee80211_vif *vif) |
1433 | { | 1499 | { |
1434 | struct ath_wiphy *aphy = hw->priv; | 1500 | struct ath_wiphy *aphy = hw->priv; |
1435 | struct ath_softc *sc = aphy->sc; | 1501 | struct ath_softc *sc = aphy->sc; |
1436 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1502 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1437 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1438 | 1503 | ||
1439 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); | 1504 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); |
1440 | 1505 | ||
@@ -1447,26 +1512,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1447 | /* Reclaim beacon resources */ | 1512 | /* Reclaim beacon resources */ |
1448 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || | 1513 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || |
1449 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || | 1514 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || |
1450 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { | 1515 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) |
1451 | /* Disable SWBA interrupt */ | 1516 | ath9k_reclaim_beacon(sc, vif); |
1452 | sc->sc_ah->imask &= ~ATH9K_INT_SWBA; | ||
1453 | ath9k_ps_wakeup(sc); | ||
1454 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | ||
1455 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | ||
1456 | ath9k_ps_restore(sc); | ||
1457 | tasklet_kill(&sc->bcon_tasklet); | ||
1458 | } | ||
1459 | |||
1460 | ath_beacon_return(sc, avp); | ||
1461 | sc->sc_flags &= ~SC_OP_BEACONS; | ||
1462 | |||
1463 | if (sc->nbcnvifs) { | ||
1464 | /* Re-enable SWBA interrupt */ | ||
1465 | sc->sc_ah->imask |= ATH9K_INT_SWBA; | ||
1466 | ath9k_ps_wakeup(sc); | ||
1467 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); | ||
1468 | ath9k_ps_restore(sc); | ||
1469 | } | ||
1470 | 1517 | ||
1471 | sc->nvifs--; | 1518 | sc->nvifs--; |
1472 | 1519 | ||
@@ -2111,6 +2158,7 @@ struct ieee80211_ops ath9k_ops = { | |||
2111 | .start = ath9k_start, | 2158 | .start = ath9k_start, |
2112 | .stop = ath9k_stop, | 2159 | .stop = ath9k_stop, |
2113 | .add_interface = ath9k_add_interface, | 2160 | .add_interface = ath9k_add_interface, |
2161 | .change_interface = ath9k_change_interface, | ||
2114 | .remove_interface = ath9k_remove_interface, | 2162 | .remove_interface = ath9k_remove_interface, |
2115 | .config = ath9k_config, | 2163 | .config = ath9k_config, |
2116 | .configure_filter = ath9k_configure_filter, | 2164 | .configure_filter = ath9k_configure_filter, |