Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b3b991d authored by Rajkumar Manoharan's avatar Rajkumar Manoharan Committed by John W. Linville
Browse files

ath9k: Add change_interface callback



Add support to change interface type
without bringing down the interface.

Signed-off-by: default avatarRajkumar Manoharan <rmanoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a7ffac95
Loading
Loading
Loading
Loading
+69 −21
Original line number Diff line number Diff line
@@ -1428,45 +1428,92 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
	return ret;
}

static void ath9k_remove_interface(struct ieee80211_hw *hw,
static void ath9k_reclaim_beacon(struct ath_softc *sc,
				 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);
	struct ath_vif *avp = (void *)vif->drv_priv;

	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)) {
	/* 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);
		ath9k_ps_restore(sc);
	tasklet_kill(&sc->bcon_tasklet);
	}
	ath9k_ps_restore(sc);

	ath_beacon_return(sc, avp);
	sc->sc_flags &= ~SC_OP_BEACONS;

	if (sc->nbcnvifs) {
		/* Re-enable SWBA interrupt */
	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_change_interface(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
				  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);

	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");
			return -ENOBUFS;
		}
		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);
		mutex_unlock(&sc->mutex);
		return -ENOTSUPP;
	}
	vif->type = new_type;
	vif->p2p = p2p;

	mutex_unlock(&sc->mutex);
	return 0;
}

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--;

@@ -2111,6 +2158,7 @@ struct ieee80211_ops ath9k_ops = {
	.start 		    = ath9k_start,
	.stop 		    = ath9k_stop,
	.add_interface 	    = ath9k_add_interface,
	.change_interface   = ath9k_change_interface,
	.remove_interface   = ath9k_remove_interface,
	.config 	    = ath9k_config,
	.configure_filter   = ath9k_configure_filter,