|
@@ -779,7 +779,9 @@ static int wl1271_plt_init(struct wl1271 *wl)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
|
|
|
+static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
|
|
+ struct wl12xx_vif *wlvif,
|
|
|
+ u8 hlid, u8 tx_pkts)
|
|
|
{
|
|
|
bool fw_ps, single_sta;
|
|
|
|
|
@@ -791,7 +793,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
|
|
|
* packets in FW or if the STA is awake.
|
|
|
*/
|
|
|
if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
|
|
|
- wl1271_ps_link_end(wl, hlid);
|
|
|
+ wl12xx_ps_link_end(wl, wlvif, hlid);
|
|
|
|
|
|
/*
|
|
|
* Start high-level PS if the STA is asleep with enough blocks in FW.
|
|
@@ -799,7 +801,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
|
|
|
* case FW-memory congestion is not a problem.
|
|
|
*/
|
|
|
else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
|
|
- wl1271_ps_link_start(wl, hlid, true);
|
|
|
+ wl12xx_ps_link_start(wl, wlvif, hlid, true);
|
|
|
}
|
|
|
|
|
|
static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
|
@@ -829,15 +831,15 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
|
|
lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
|
|
|
lnk->allocated_pkts -= cnt;
|
|
|
|
|
|
- wl12xx_irq_ps_regulate_link(wl, hlid, lnk->allocated_pkts);
|
|
|
+ wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
|
|
|
+ lnk->allocated_pkts);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void wl12xx_fw_status(struct wl1271 *wl,
|
|
|
struct wl12xx_fw_status *status)
|
|
|
{
|
|
|
- struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
|
|
|
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
struct timespec ts;
|
|
|
u32 old_tx_blk_count = wl->tx_blocks_available;
|
|
|
int avail, freed_blocks;
|
|
@@ -892,8 +894,9 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
|
|
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
|
|
|
|
|
|
/* for AP update num of allocated TX blocks per link and ps status */
|
|
|
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
|
|
+ wl12xx_for_each_wlvif_ap(wl, wlvif) {
|
|
|
wl12xx_irq_update_links_status(wl, wlvif, status);
|
|
|
+ }
|
|
|
|
|
|
/* update the host-chipset time offset */
|
|
|
getnstimeofday(&ts);
|
|
@@ -1212,6 +1215,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|
|
struct wl1271 *wl =
|
|
|
container_of(work, struct wl1271, recovery_work);
|
|
|
struct wl12xx_vif *wlvif;
|
|
|
+ struct ieee80211_vif *vif;
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
@@ -1249,7 +1253,12 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|
|
}
|
|
|
|
|
|
/* reboot the chipset */
|
|
|
- __wl1271_op_remove_interface(wl, wl->vif, false);
|
|
|
+ while (!list_empty(&wl->wlvif_list)) {
|
|
|
+ wlvif = list_first_entry(&wl->wlvif_list,
|
|
|
+ struct wl12xx_vif, list);
|
|
|
+ vif = wl12xx_wlvif_to_vif(wlvif);
|
|
|
+ __wl1271_op_remove_interface(wl, vif, false);
|
|
|
+ }
|
|
|
|
|
|
clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
|
|
|
|
|
@@ -1721,18 +1730,19 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
struct cfg80211_wowlan *wow)
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
- struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
|
|
|
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
int ret;
|
|
|
|
|
|
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
|
|
|
WARN_ON(!wow || !wow->any);
|
|
|
|
|
|
wl->wow_enabled = true;
|
|
|
- ret = wl1271_configure_suspend(wl, wlvif);
|
|
|
- if (ret < 0) {
|
|
|
- wl1271_warning("couldn't prepare device to suspend");
|
|
|
- return ret;
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ ret = wl1271_configure_suspend(wl, wlvif);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_warning("couldn't prepare device to suspend");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
}
|
|
|
/* flush any remaining work */
|
|
|
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
|
|
@@ -1751,7 +1761,9 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
|
|
|
wl1271_enable_interrupts(wl);
|
|
|
flush_work(&wl->tx_work);
|
|
|
- flush_delayed_work(&wlvif->pspoll_work);
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ flush_delayed_work(&wlvif->pspoll_work);
|
|
|
+ }
|
|
|
flush_delayed_work(&wl->elp_work);
|
|
|
|
|
|
return 0;
|
|
@@ -1760,8 +1772,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
static int wl1271_op_resume(struct ieee80211_hw *hw)
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
- struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
|
|
|
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
unsigned long flags;
|
|
|
bool run_irq_work = false;
|
|
|
|
|
@@ -1785,7 +1796,9 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
|
|
|
wl1271_irq(0, wl);
|
|
|
wl1271_enable_interrupts(wl);
|
|
|
}
|
|
|
- wl1271_configure_resume(wl, wlvif);
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ wl1271_configure_resume(wl, wlvif);
|
|
|
+ }
|
|
|
wl->wow_enabled = false;
|
|
|
|
|
|
return 0;
|
|
@@ -2242,6 +2255,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *iter;
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
@@ -2253,10 +2267,14 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
|
|
* wl->vif can be null here if someone shuts down the interface
|
|
|
* just when hardware recovery has been started.
|
|
|
*/
|
|
|
- if (wl->vif) {
|
|
|
- WARN_ON(wl->vif != vif);
|
|
|
+ wl12xx_for_each_wlvif(wl, iter) {
|
|
|
+ if (iter != wlvif)
|
|
|
+ continue;
|
|
|
+
|
|
|
__wl1271_op_remove_interface(wl, vif, true);
|
|
|
+ break;
|
|
|
}
|
|
|
+ WARN_ON(iter != wlvif);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
cancel_work_sync(&wl->recovery_work);
|
|
@@ -2326,8 +2344,10 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|
|
int ret;
|
|
|
|
|
|
if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
|
|
|
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
|
|
+
|
|
|
wl12xx_cmd_stop_channel_switch(wl);
|
|
|
- ieee80211_chswitch_done(wl->vif, false);
|
|
|
+ ieee80211_chswitch_done(vif, false);
|
|
|
}
|
|
|
|
|
|
/* to stop listening to a channel, we disconnect */
|
|
@@ -2642,8 +2662,7 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
|
|
{
|
|
|
struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
- struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
|
|
|
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
|
|
|
int ret;
|
|
|
|
|
@@ -2662,17 +2681,20 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
|
- if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
|
|
- if (*total & FIF_ALLMULTI)
|
|
|
- ret = wl1271_acx_group_address_tbl(wl, wlvif, false,
|
|
|
- NULL, 0);
|
|
|
- else if (fp)
|
|
|
- ret = wl1271_acx_group_address_tbl(wl, wlvif,
|
|
|
- fp->enabled,
|
|
|
- fp->mc_list,
|
|
|
- fp->mc_list_length);
|
|
|
- if (ret < 0)
|
|
|
- goto out_sleep;
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
|
|
+ if (*total & FIF_ALLMULTI)
|
|
|
+ ret = wl1271_acx_group_address_tbl(wl, wlvif,
|
|
|
+ false,
|
|
|
+ NULL, 0);
|
|
|
+ else if (fp)
|
|
|
+ ret = wl1271_acx_group_address_tbl(wl, wlvif,
|
|
|
+ fp->enabled,
|
|
|
+ fp->mc_list,
|
|
|
+ fp->mc_list_length);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out_sleep;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -3162,8 +3184,7 @@ out:
|
|
|
static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
- struct ieee80211_vif *vif = wl->vif;
|
|
|
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
int ret = 0;
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
@@ -3177,10 +3198,11 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_acx_rts_threshold(wl, wlvif, value);
|
|
|
- if (ret < 0)
|
|
|
- wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
|
|
|
-
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ ret = wl1271_acx_rts_threshold(wl, wlvif, value);
|
|
|
+ if (ret < 0)
|
|
|
+ wl1271_warning("set rts threshold failed: %d", ret);
|
|
|
+ }
|
|
|
wl1271_ps_elp_sleep(wl);
|
|
|
|
|
|
out:
|
|
@@ -3669,7 +3691,7 @@ sta_not_found:
|
|
|
wlvif->probereq = NULL;
|
|
|
|
|
|
/* re-enable dynamic ps - just in case */
|
|
|
- ieee80211_enable_dyn_ps(wl->vif);
|
|
|
+ ieee80211_enable_dyn_ps(vif);
|
|
|
|
|
|
/* revert back to minimum rates for the current band */
|
|
|
wl1271_set_band_rate(wl, wlvif);
|
|
@@ -4305,9 +4327,11 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
|
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
|
|
- mutex_unlock(&wl->mutex);
|
|
|
- ieee80211_chswitch_done(wl->vif, false);
|
|
|
- return;
|
|
|
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
|
|
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
|
|
+ ieee80211_chswitch_done(vif, false);
|
|
|
+ }
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
ret = wl1271_ps_elp_wakeup(wl);
|