@@ -309,6 +309,7 @@ int ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
void ath_flushrecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
+void ath_opmode_init(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc);
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
@@ -337,6 +338,12 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
/* VIFs */
/********/
+enum ath_iface_optype {
+ ATH9K_ADD_IFACE,
+ ATH9K_MOD_IFACE,
+ ATH9K_DEL_IFACE,
+};
+
struct ath_vif {
int av_bslot;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
@@ -1341,64 +1341,114 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
}
-static int ath9k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static void ath9k_reclaim_beacon(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ /* Disable SWBA interrupt */
+ sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+ tasklet_kill(&sc->bcon_tasklet);
+ ath9k_ps_restore(sc);
+
+ ath_beacon_return(sc, avp);
+ sc->sc_flags &= ~SC_OP_BEACONS;
+
+ if (sc->nbcnvifs > 0) {
+ /* Re-enable beaconing */
+ sc->sc_ah->imask |= ATH9K_INT_SWBA;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+ ath9k_ps_restore(sc);
+ }
+}
+
+static int ath9k_iface_work(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type,
+ bool p2p,
+ u8 optype)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ enum nl80211_iftype iftype;
int ret = 0;
mutex_lock(&sc->mutex);
- switch (vif->type) {
+ /* Stop ANI timer */
+ del_timer_sync(&common->ani.timer);
+
+ iftype = (optype == ATH9K_MOD_IFACE) ? new_type : vif->type;
+
+ /* Remove interface */
+ if (optype == ATH9K_DEL_IFACE) {
+ if ((iftype == NL80211_IFTYPE_AP) ||
+ (iftype == NL80211_IFTYPE_ADHOC)) {
+ ath9k_reclaim_beacon(sc, vif);
+ if (!sc->nbcnvifs)
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ }
+ ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
+ sc->nvifs--;
+ goto out;
+ }
+
+ switch (iftype) {
case NL80211_IFTYPE_STATION:
- ic_opmode = NL80211_IFTYPE_STATION;
+ if ((optype == ATH9K_MOD_IFACE) &&
+ ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC)))
+ ath9k_reclaim_beacon(sc, vif);
+ if (!sc->nbcnvifs) {
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ ah->opmode = iftype;
+ }
break;
case NL80211_IFTYPE_WDS:
- ic_opmode = NL80211_IFTYPE_WDS;
+ ah->opmode = iftype;
break;
case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
if (sc->nbcnvifs >= ATH_BCBUF) {
ret = -ENOBUFS;
goto out;
}
- ic_opmode = vif->type;
+ sc->sc_flags |= SC_OP_ANI_RUN;
+ ah->opmode = iftype;
break;
default:
ath_err(common, "Interface type %d not yet supported\n",
- vif->type);
+ iftype);
ret = -EOPNOTSUPP;
goto out;
}
-
- ath_dbg(common, ATH_DBG_CONFIG,
- "Attach a VIF of type: %d\n", ic_opmode);
-
- /* Set the VIF opmode */
- avp->av_opmode = ic_opmode;
+ avp->av_opmode = iftype;
avp->av_bslot = -1;
+ vif->type = iftype;
+ vif->p2p = p2p;
- sc->nvifs++;
-
- ath9k_set_bssid_mask(hw, vif);
-
- if (sc->nvifs > 1)
- goto out; /* skip global settings for secondary vif */
+ if (optype == ATH9K_ADD_IFACE) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Attach Interface of type %d\n", vif->type);
+ sc->nvifs++;
+ } else
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Change Interface to type %d\n", vif->type);
- if (ic_opmode == NL80211_IFTYPE_AP) {
+ ath_opmode_init(sc);
+ if (vif->type == NL80211_IFTYPE_AP) {
ath9k_hw_set_tsfadjust(ah, 1);
sc->sc_flags |= SC_OP_TSF_RESET;
}
- /* Set the device opmode */
- ah->opmode = ic_opmode;
-
/*
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
@@ -1410,43 +1460,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ah->imask |= ATH9K_INT_MIB;
ah->imask |= ATH9K_INT_TSFOOR;
}
-
ath9k_hw_set_interrupts(ah, ah->imask);
- if (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC) {
- sc->sc_flags |= SC_OP_ANI_RUN;
- ath_start_ani(common);
- }
-
out:
+ ath_start_ani(common);
mutex_unlock(&sc->mutex);
return ret;
}
-static void ath9k_reclaim_beacon(struct ath_softc *sc,
- struct ieee80211_vif *vif)
+static int ath9k_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
- struct ath_vif *avp = (void *)vif->drv_priv;
-
- /* Disable SWBA interrupt */
- sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
- ath9k_ps_wakeup(sc);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
- ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
- tasklet_kill(&sc->bcon_tasklet);
- ath9k_ps_restore(sc);
-
- ath_beacon_return(sc, avp);
- sc->sc_flags &= ~SC_OP_BEACONS;
-
- if (sc->nbcnvifs > 0) {
- /* Re-enable beaconing */
- sc->sc_ah->imask |= ATH9K_INT_SWBA;
- ath9k_ps_wakeup(sc);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
- ath9k_ps_restore(sc);
- }
+ return ath9k_iface_work(hw, vif, vif->type, vif->p2p, ATH9K_ADD_IFACE);
}
static int ath9k_change_interface(struct ieee80211_hw *hw,
@@ -1454,69 +1479,13 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
enum nl80211_iftype new_type,
bool p2p)
{
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- int ret = 0;
-
- ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
- mutex_lock(&sc->mutex);
-
- switch (new_type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- if (sc->nbcnvifs >= ATH_BCBUF) {
- ath_err(common, "No beacon slot available\n");
- ret = -ENOBUFS;
- goto out;
- }
- break;
- case NL80211_IFTYPE_STATION:
- /* Stop ANI */
- sc->sc_flags &= ~SC_OP_ANI_RUN;
- del_timer_sync(&common->ani.timer);
- if ((vif->type == NL80211_IFTYPE_AP) ||
- (vif->type == NL80211_IFTYPE_ADHOC))
- ath9k_reclaim_beacon(sc, vif);
- break;
- default:
- ath_err(common, "Interface type %d not yet supported\n",
- vif->type);
- ret = -ENOTSUPP;
- goto out;
- }
- vif->type = new_type;
- vif->p2p = p2p;
-
-out:
- mutex_unlock(&sc->mutex);
- return ret;
+ return ath9k_iface_work(hw, vif, new_type, p2p, ATH9K_MOD_IFACE);
}
static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
- ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
-
- mutex_lock(&sc->mutex);
-
- /* Stop ANI */
- sc->sc_flags &= ~SC_OP_ANI_RUN;
- del_timer_sync(&common->ani.timer);
-
- /* Reclaim beacon resources */
- if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT))
- ath9k_reclaim_beacon(sc, vif);
-
- sc->nvifs--;
-
- mutex_unlock(&sc->mutex);
+ ath9k_iface_work(hw, vif, vif->type, vif->p2p, ATH9K_DEL_IFACE);
}
static void ath9k_enable_ps(struct ath_softc *sc)
@@ -107,7 +107,7 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
sc->rx.rxotherant = 0;
}
-static void ath_opmode_init(struct ath_softc *sc)
+void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);