Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f12e870025 | |||
| 822a5f1bab | |||
| c57c77e446 | |||
| db4ea70fb5 |
@@ -511,9 +511,6 @@ struct bes2600_common {
|
|||||||
struct list_head coex_event_list;
|
struct list_head coex_event_list;
|
||||||
spinlock_t coex_event_lock;
|
spinlock_t coex_event_lock;
|
||||||
|
|
||||||
/* Connection-loss-storm fast-recover (Trigger A). See sta.c. */
|
|
||||||
struct work_struct connection_loss_storm_recover_work;
|
|
||||||
|
|
||||||
/* member for low power */
|
/* member for low power */
|
||||||
struct bes2600_pwr_t bes_power;
|
struct bes2600_pwr_t bes_power;
|
||||||
|
|
||||||
@@ -599,11 +596,6 @@ struct bes2600_vif {
|
|||||||
unsigned long rx_timestamp;
|
unsigned long rx_timestamp;
|
||||||
u32 cipherType;
|
u32 cipherType;
|
||||||
|
|
||||||
/* Decrypt-storm fast-recover (Trigger B). See txrx.c. */
|
|
||||||
unsigned long decrypt_storm_window_start;
|
|
||||||
unsigned int decrypt_storm_count;
|
|
||||||
unsigned int decrypt_storm_recoveries;
|
|
||||||
struct work_struct decrypt_storm_recover_work;
|
|
||||||
|
|
||||||
/* AP powersave */
|
/* AP powersave */
|
||||||
u32 link_id_map;
|
u32 link_id_map;
|
||||||
@@ -630,10 +622,6 @@ struct bes2600_vif {
|
|||||||
/* CQM Implementation */
|
/* CQM Implementation */
|
||||||
struct delayed_work bss_loss_work;
|
struct delayed_work bss_loss_work;
|
||||||
struct delayed_work connection_loss_work;
|
struct delayed_work connection_loss_work;
|
||||||
/* Connection-loss-storm fast-recover (Trigger A). See sta.c. */
|
|
||||||
unsigned long connection_loss_storm_window_start;
|
|
||||||
unsigned int connection_loss_storm_count;
|
|
||||||
unsigned int connection_loss_storm_recoveries;
|
|
||||||
struct work_struct tx_failure_work;
|
struct work_struct tx_failure_work;
|
||||||
int delayed_link_loss;
|
int delayed_link_loss;
|
||||||
spinlock_t bss_loss_lock;
|
spinlock_t bss_loss_lock;
|
||||||
@@ -868,13 +856,4 @@ int bes2600_btusb_setup_pipes(struct sbus_priv *sbus_priv);
|
|||||||
void bes2600_btusb_uninit(struct usb_interface *interface);
|
void bes2600_btusb_uninit(struct usb_interface *interface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Decrypt-storm fast-recover helpers — see txrx.c. */
|
|
||||||
void bes2600_decrypt_storm_init(struct bes2600_vif *priv);
|
|
||||||
void bes2600_decrypt_storm_account(struct bes2600_vif *priv);
|
|
||||||
|
|
||||||
/* Connection-loss-storm fast-recover helpers — see sta.c. */
|
|
||||||
void bes2600_connection_loss_storm_init(struct bes2600_vif *priv);
|
|
||||||
bool bes2600_connection_loss_storm_account(struct bes2600_vif *priv);
|
|
||||||
void bes2600_connection_loss_storm_recover(struct work_struct *work);
|
|
||||||
|
|
||||||
#endif /* BES2600_H */
|
#endif /* BES2600_H */
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
||||||
#include <linux/mmc/sdio_func.h>
|
#include <linux/mmc/sdio_func.h>
|
||||||
#include <linux/mmc/card.h>
|
#include <linux/mmc/card.h>
|
||||||
#include <linux/mmc/core.h>
|
|
||||||
#include <linux/mmc/sdio.h>
|
#include <linux/mmc/sdio.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
@@ -1789,55 +1788,6 @@ static void bes2600_sdio_halt_device(struct sbus_priv *self)
|
|||||||
sdio_work_debug(self);
|
sdio_work_debug(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Trigger an SDIO bus reset via mmc_hw_reset().
|
|
||||||
*
|
|
||||||
* With multiple SDIO functions probed (PineTab2 binds func 1 for WLAN and
|
|
||||||
* func 2 for the BT-companion path) mmc_sdio_hw_reset() takes the
|
|
||||||
* remove-and-rescan path: it marks the card removed and schedules
|
|
||||||
* mmc_rescan, which tears down the bound function drivers and re-detects
|
|
||||||
* the card on the next sweep, in turn reinvoking bes2600_sdio_probe().
|
|
||||||
*
|
|
||||||
* With a single function probed it instead invokes mmc_power_cycle()
|
|
||||||
* directly, which on PineTab2 toggles the wifi-reset GPIO via sdio_pwrseq.
|
|
||||||
*
|
|
||||||
* In both cases the chip ends up in a freshly reset state, which is the
|
|
||||||
* goal of the recovery path.
|
|
||||||
*
|
|
||||||
* mmc_hw_reset() must be called without holding the SDIO host claim --
|
|
||||||
* the multi-func remove-and-rescan path acquires the host claim via the
|
|
||||||
* mmc workqueue.
|
|
||||||
*/
|
|
||||||
static int bes2600_sdio_bus_reset(struct sbus_priv *self)
|
|
||||||
{
|
|
||||||
struct mmc_host *host;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!self || !self->func || !self->func->card)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
host = self->func->card->host;
|
|
||||||
ret = mmc_hw_reset(self->func->card);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On multi-function SDIO cards (BES2600 has WLAN func 1 + BT
|
|
||||||
* companion func 2), mmc_sdio_hw_reset() removes the card and
|
|
||||||
* returns 1 to signal "remove happened, caller must trigger
|
|
||||||
* rescan". The kernel does NOT auto-rescan in this case;
|
|
||||||
* single-function cards take the rescan path inline and return 0.
|
|
||||||
* Treat any non-negative return as success and force a rescan if
|
|
||||||
* mmc_hw_reset signalled the multi-function path - otherwise the
|
|
||||||
* card stays removed indefinitely after a wedge recovery,
|
|
||||||
* leaving wifi (and the BT companion) silent until reboot.
|
|
||||||
*/
|
|
||||||
if (ret > 0) {
|
|
||||||
bes_info("multi-func mmc_hw_reset removed card; scheduling rescan\n");
|
|
||||||
mmc_detect_change(host, 0);
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool bes2600_sdio_wakeup_source(struct sbus_priv *self)
|
static bool bes2600_sdio_wakeup_source(struct sbus_priv *self)
|
||||||
{
|
{
|
||||||
struct bes2600_platform_data_sdio *pdata = bes2600_get_platform_data();
|
struct bes2600_platform_data_sdio *pdata = bes2600_get_platform_data();
|
||||||
@@ -1876,7 +1826,6 @@ static struct sbus_ops bes2600_sdio_sbus_ops = {
|
|||||||
.gpio_sleep = bes2600_gpio_allow_mcu_sleep,
|
.gpio_sleep = bes2600_gpio_allow_mcu_sleep,
|
||||||
.halt_device = bes2600_sdio_halt_device,
|
.halt_device = bes2600_sdio_halt_device,
|
||||||
.wakeup_source = bes2600_sdio_wakeup_source,
|
.wakeup_source = bes2600_sdio_wakeup_source,
|
||||||
.bus_reset = bes2600_sdio_bus_reset,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bes2600_sdio_en_lp_cb(struct bes2600_common *hw_priv)
|
static void bes2600_sdio_en_lp_cb(struct bes2600_common *hw_priv)
|
||||||
|
|||||||
+2
-69
@@ -442,60 +442,6 @@ int bes2600_chrdev_do_system_close(const struct sbus_ops *sbus_ops, struct sbus_
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Hard-reset the bus and wait for the bus core to remove the chip.
|
|
||||||
*
|
|
||||||
* Used by the firmware-wedge recovery path on platforms where the normal
|
|
||||||
* power_switch(0) sequence has no effective chip-reset signal. The bus
|
|
||||||
* implementation triggers an asynchronous re-detect; this helper waits for
|
|
||||||
* the resulting remove() callback to clear bes2600_cdev.sbus_priv so that a
|
|
||||||
* subsequent bes2600_switch_wifi(true) sees a clean state and can wait on
|
|
||||||
* the fresh probe.
|
|
||||||
*/
|
|
||||||
int bes2600_chrdev_do_bus_reset(const struct sbus_ops *sbus_ops, struct sbus_priv *priv)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
long status;
|
|
||||||
|
|
||||||
if (!sbus_ops || !priv)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!sbus_ops->bus_reset)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
bes_info("trigger bus reset to recover wedged firmware.\n");
|
|
||||||
|
|
||||||
ret = sbus_ops->bus_reset(priv);
|
|
||||||
if (ret) {
|
|
||||||
bes_err("bus_reset failed: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The bus reset is asynchronous: the bus core schedules a rescan
|
|
||||||
* which removes the bound function drivers and then re-detects the
|
|
||||||
* chip. Wait for the remove callback to clear sbus_priv. Do not
|
|
||||||
* dereference 'priv' after this point -- it may already be freed.
|
|
||||||
*/
|
|
||||||
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
|
|
||||||
!bes2600_cdev.sbus_priv, HZ * 3);
|
|
||||||
WARN_ON(status <= 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Trigger bes2600_chrdev_do_bus_reset() against the file-global
|
|
||||||
* bes2600_cdev. Used by host-side recovery paths outside this
|
|
||||||
* compilation unit (e.g. sta.c connection-loss-storm fast-recover) so
|
|
||||||
* those callers do not need to reach the static bes2600_cdev directly.
|
|
||||||
*/
|
|
||||||
int bes2600_chrdev_trigger_bus_reset(void)
|
|
||||||
{
|
|
||||||
return bes2600_chrdev_do_bus_reset(bes2600_cdev.sbus_ops,
|
|
||||||
bes2600_cdev.sbus_priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bes2600_chrdev_is_wifi_opened(void)
|
bool bes2600_chrdev_is_wifi_opened(void)
|
||||||
{
|
{
|
||||||
bool wifi_opened = false;
|
bool wifi_opened = false;
|
||||||
@@ -594,21 +540,8 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
|
|||||||
/* unregister wifi */
|
/* unregister wifi */
|
||||||
bes2600_switch_wifi(0);
|
bes2600_switch_wifi(0);
|
||||||
|
|
||||||
/*
|
/* power down device if wifi is only opened */
|
||||||
* Hard exception with a bus_reset implementation: tear the
|
if (bes2600_chrdev_check_system_close()) {
|
||||||
* bus down via mmc_hw_reset() (or equivalent) so the next
|
|
||||||
* bringup probes a freshly reset chip. On PineTab2 this is
|
|
||||||
* the only effective recovery path -- the existing
|
|
||||||
* power_switch(0)/(1) sequence has no chip-reset signal of
|
|
||||||
* its own (sdio_pwrseq owns wifi_reset).
|
|
||||||
*
|
|
||||||
* Soft close, or hard close on a board without bus_reset:
|
|
||||||
* fall back to the legacy power_switch(0) sequence.
|
|
||||||
*/
|
|
||||||
if (bes2600_cdev.halt_dev && bes2600_cdev.sbus_ops->bus_reset) {
|
|
||||||
bes2600_chrdev_do_bus_reset(bes2600_cdev.sbus_ops,
|
|
||||||
bes2600_cdev.sbus_priv);
|
|
||||||
} else if (bes2600_chrdev_check_system_close()) {
|
|
||||||
bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
|
bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
|
||||||
bes2600_cdev.sbus_priv);
|
bes2600_cdev.sbus_priv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,6 @@ struct sbus_priv *bes2600_chrdev_get_sbus_priv_data(void);
|
|||||||
/* used to control device power down */
|
/* used to control device power down */
|
||||||
int bes2600_chrdev_check_system_close(void);
|
int bes2600_chrdev_check_system_close(void);
|
||||||
int bes2600_chrdev_do_system_close(const struct sbus_ops *sbus_ops, struct sbus_priv *priv);
|
int bes2600_chrdev_do_system_close(const struct sbus_ops *sbus_ops, struct sbus_priv *priv);
|
||||||
int bes2600_chrdev_do_bus_reset(const struct sbus_ops *sbus_ops, struct sbus_priv *priv);
|
|
||||||
int bes2600_chrdev_trigger_bus_reset(void);
|
|
||||||
void bes2600_chrdev_wakeup_bt(void);
|
void bes2600_chrdev_wakeup_bt(void);
|
||||||
void bes2600_chrdev_wifi_force_close(struct bes2600_common *hw_priv, bool halt_dev);
|
void bes2600_chrdev_wifi_force_close(struct bes2600_common *hw_priv, bool halt_dev);
|
||||||
void bes2600_chrdev_usb_remove(struct bes2600_common *hw_priv);
|
void bes2600_chrdev_usb_remove(struct bes2600_common *hw_priv);
|
||||||
|
|||||||
+6
-6
@@ -101,7 +101,7 @@ void bes2600_unregister_bh(struct bes2600_common *hw_priv)
|
|||||||
coex_deinit_mode(hw_priv);
|
coex_deinit_mode(hw_priv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
atomic_inc(&hw_priv->bh_term);
|
atomic_add(1, &hw_priv->bh_term);
|
||||||
wake_up(&hw_priv->bh_wq);
|
wake_up(&hw_priv->bh_wq);
|
||||||
|
|
||||||
flush_workqueue(hw_priv->bh_workqueue);
|
flush_workqueue(hw_priv->bh_workqueue);
|
||||||
@@ -590,7 +590,7 @@ static int bes2600_bh(void *arg)
|
|||||||
bes_devel("[BH] Device resume.\n");
|
bes_devel("[BH] Device resume.\n");
|
||||||
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
|
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
|
||||||
wake_up(&hw_priv->bh_evt_wq);
|
wake_up(&hw_priv->bh_evt_wq);
|
||||||
atomic_inc(&hw_priv->bh_rx);
|
atomic_add(1, &hw_priv->bh_rx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,9 +758,9 @@ tx:
|
|||||||
|
|
||||||
#if 0 /* count is not implemented */
|
#if 0 /* count is not implemented */
|
||||||
if (ret > 1)
|
if (ret > 1)
|
||||||
atomic_inc(&hw_priv->bh_tx);
|
atomic_add(1, &hw_priv->bh_tx);
|
||||||
#else
|
#else
|
||||||
atomic_inc(&hw_priv->bh_tx);
|
atomic_add(1, &hw_priv->bh_tx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BES2600_NON_POWER_OF_TWO_BLOCKSIZES)
|
#if defined(CONFIG_BES2600_NON_POWER_OF_TWO_BLOCKSIZES)
|
||||||
@@ -1134,7 +1134,7 @@ static int bes2600_bh_tx_helper(struct bes2600_common *hw_priv,
|
|||||||
tx_len += 4;
|
tx_len += 4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
atomic_inc(&hw_priv->bh_tx);
|
atomic_add(1, &hw_priv->bh_tx);
|
||||||
|
|
||||||
tx_len = hw_priv->sbus_ops->align_size(
|
tx_len = hw_priv->sbus_ops->align_size(
|
||||||
hw_priv->sbus_priv, tx_len);
|
hw_priv->sbus_priv, tx_len);
|
||||||
@@ -1435,7 +1435,7 @@ static int bes2600_bh(void *arg)
|
|||||||
bes_devel("[BH] Device resume.\n");
|
bes_devel("[BH] Device resume.\n");
|
||||||
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
|
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
|
||||||
wake_up(&hw_priv->bh_evt_wq);
|
wake_up(&hw_priv->bh_evt_wq);
|
||||||
atomic_inc(&hw_priv->bh_rx);
|
atomic_add(1, &hw_priv->bh_rx);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -542,10 +542,6 @@ static int bes2600_status_show_priv(struct seq_file *seq, void *v)
|
|||||||
priv->listening ? " (listening)" : "");
|
priv->listening ? " (listening)" : "");
|
||||||
seq_printf(seq, "Assoc: %s\n",
|
seq_printf(seq, "Assoc: %s\n",
|
||||||
bes2600_debug_join_status[priv->join_status]);
|
bes2600_debug_join_status[priv->join_status]);
|
||||||
seq_printf(seq, "DecryptStormRecoveries: %u\n",
|
|
||||||
priv->decrypt_storm_recoveries);
|
|
||||||
seq_printf(seq, "ConnectionLossStormRecoveries: %u\n",
|
|
||||||
priv->connection_loss_storm_recoveries);
|
|
||||||
if (priv->rx_filter.promiscuous)
|
if (priv->rx_filter.promiscuous)
|
||||||
seq_puts(seq, "Filter: promisc\n");
|
seq_puts(seq, "Filter: promisc\n");
|
||||||
else if (priv->rx_filter.fcs)
|
else if (priv->rx_filter.fcs)
|
||||||
|
|||||||
+1
-1
@@ -570,7 +570,7 @@ int bes2600_itp_get_tx(struct bes2600_common *priv, u8 **data,
|
|||||||
*burst = 2;
|
*burst = 2;
|
||||||
atomic_set(&priv->bh_tx, 1);
|
atomic_set(&priv->bh_tx, 1);
|
||||||
ktime_get_ts(&itp->last_sent);
|
ktime_get_ts(&itp->last_sent);
|
||||||
atomic_inc(&itp->awaiting_confirm);
|
atomic_add(1, &itp->awaiting_confirm);
|
||||||
spin_unlock_bh(&itp->tx_lock);
|
spin_unlock_bh(&itp->tx_lock);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|||||||
@@ -484,8 +484,6 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
|
|||||||
spin_lock_init(&hw_priv->rtsvalue_lock);
|
spin_lock_init(&hw_priv->rtsvalue_lock);
|
||||||
INIT_WORK(&hw_priv->dynamic_opt_txrx_work, bes2600_dynamic_opt_txrx_work);
|
INIT_WORK(&hw_priv->dynamic_opt_txrx_work, bes2600_dynamic_opt_txrx_work);
|
||||||
INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work);
|
INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work);
|
||||||
INIT_WORK(&hw_priv->connection_loss_storm_recover_work,
|
|
||||||
bes2600_connection_loss_storm_recover);
|
|
||||||
spin_lock_init(&hw_priv->event_queue_lock);
|
spin_lock_init(&hw_priv->event_queue_lock);
|
||||||
INIT_LIST_HEAD(&hw_priv->event_queue);
|
INIT_LIST_HEAD(&hw_priv->event_queue);
|
||||||
INIT_WORK(&hw_priv->event_handler, bes2600_event_handler);
|
INIT_WORK(&hw_priv->event_handler, bes2600_event_handler);
|
||||||
@@ -497,7 +495,6 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
|
|||||||
WLAN_LINK_ID_MAX,
|
WLAN_LINK_ID_MAX,
|
||||||
bes2600_skb_dtor,
|
bes2600_skb_dtor,
|
||||||
hw_priv))) {
|
hw_priv))) {
|
||||||
destroy_workqueue(hw_priv->workqueue);
|
|
||||||
ieee80211_free_hw(hw);
|
ieee80211_free_hw(hw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -509,7 +506,6 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
|
|||||||
for (; i > 0; i--)
|
for (; i > 0; i--)
|
||||||
bes2600_queue_deinit(&hw_priv->tx_queue[i - 1]);
|
bes2600_queue_deinit(&hw_priv->tx_queue[i - 1]);
|
||||||
bes2600_queue_stats_deinit(&hw_priv->tx_queue_stats);
|
bes2600_queue_stats_deinit(&hw_priv->tx_queue_stats);
|
||||||
destroy_workqueue(hw_priv->workqueue);
|
|
||||||
ieee80211_free_hw(hw);
|
ieee80211_free_hw(hw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,14 +75,6 @@ struct sbus_ops {
|
|||||||
void (*halt_device)(struct sbus_priv *self);
|
void (*halt_device)(struct sbus_priv *self);
|
||||||
bool (*wakeup_source)(struct sbus_priv *self);
|
bool (*wakeup_source)(struct sbus_priv *self);
|
||||||
int (*reboot)(struct sbus_priv *self);
|
int (*reboot)(struct sbus_priv *self);
|
||||||
/*
|
|
||||||
* Force the host bus to re-detect and re-probe the chip. Called
|
|
||||||
* from the firmware-wedge recovery path when power_switch() has no
|
|
||||||
* effective chip-reset signal of its own (e.g. PineTab2, where the
|
|
||||||
* wifi-reset GPIO is owned by sdio_pwrseq, not the bes2600 node).
|
|
||||||
* Returns 0 on success or a negative errno.
|
|
||||||
*/
|
|
||||||
int (*bus_reset)(struct sbus_priv *self);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void bes2600_irq_handler(struct bes2600_common *priv);
|
void bes2600_irq_handler(struct bes2600_common *priv);
|
||||||
|
|||||||
+16
-23
@@ -257,21 +257,18 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_SCAN);
|
bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_SCAN);
|
||||||
|
|
||||||
/* will be unlocked in bes2600_scan_work() */
|
|
||||||
down(&hw_priv->scan.lock);
|
|
||||||
down(&hw_priv->conf_lock);
|
|
||||||
|
|
||||||
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
||||||
req->ie_len);
|
req->ie_len);
|
||||||
if (!frame.skb) {
|
if (!frame.skb)
|
||||||
up(&hw_priv->conf_lock);
|
|
||||||
up(&hw_priv->scan.lock);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
if (req->ie_len)
|
if (req->ie_len)
|
||||||
skb_put_data(frame.skb, req->ie, req->ie_len);
|
skb_put_data(frame.skb, req->ie, req->ie_len);
|
||||||
|
|
||||||
|
/* will be unlocked in bes2600_scan_work() */
|
||||||
|
down(&hw_priv->scan.lock);
|
||||||
|
down(&hw_priv->conf_lock);
|
||||||
|
|
||||||
if (frame.skb) {
|
if (frame.skb) {
|
||||||
int ret;
|
int ret;
|
||||||
//if (priv->if_id == 0)
|
//if (priv->if_id == 0)
|
||||||
@@ -289,9 +286,9 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_kfree_skb(frame.skb);
|
|
||||||
up(&hw_priv->conf_lock);
|
up(&hw_priv->conf_lock);
|
||||||
up(&hw_priv->scan.lock);
|
up(&hw_priv->scan.lock);
|
||||||
|
dev_kfree_skb(frame.skb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,10 +318,10 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
|
|||||||
++hw_priv->scan.n_ssids;
|
++hw_priv->scan.n_ssids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up(&hw_priv->conf_lock);
|
||||||
|
|
||||||
if (frame.skb)
|
if (frame.skb)
|
||||||
dev_kfree_skb(frame.skb);
|
dev_kfree_skb(frame.skb);
|
||||||
|
|
||||||
up(&hw_priv->conf_lock);
|
|
||||||
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
||||||
bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING);
|
bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING);
|
||||||
#endif
|
#endif
|
||||||
@@ -365,18 +362,14 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
|
|||||||
if (req->n_ssids > hw->wiphy->max_scan_ssids)
|
if (req->n_ssids > hw->wiphy->max_scan_ssids)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
||||||
|
req->ie_len);
|
||||||
|
if (!frame.skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* will be unlocked in bes2600_scan_work() */
|
/* will be unlocked in bes2600_scan_work() */
|
||||||
down(&hw_priv->scan.lock);
|
down(&hw_priv->scan.lock);
|
||||||
down(&hw_priv->conf_lock);
|
down(&hw_priv->conf_lock);
|
||||||
|
|
||||||
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
|
||||||
req->ie_len);
|
|
||||||
if (!frame.skb) {
|
|
||||||
up(&hw_priv->conf_lock);
|
|
||||||
up(&hw_priv->scan.lock);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame.skb) {
|
if (frame.skb) {
|
||||||
int ret;
|
int ret;
|
||||||
if (priv->if_id == 0)
|
if (priv->if_id == 0)
|
||||||
@@ -387,9 +380,9 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
|
|||||||
ret = wsm_set_probe_responder(priv, true);
|
ret = wsm_set_probe_responder(priv, true);
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_kfree_skb(frame.skb);
|
|
||||||
up(&hw_priv->conf_lock);
|
up(&hw_priv->conf_lock);
|
||||||
up(&hw_priv->scan.lock);
|
up(&hw_priv->scan.lock);
|
||||||
|
dev_kfree_skb(frame.skb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,10 +414,10 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up(&hw_priv->conf_lock);
|
||||||
|
|
||||||
if (frame.skb)
|
if (frame.skb)
|
||||||
dev_kfree_skb(frame.skb);
|
dev_kfree_skb(frame.skb);
|
||||||
|
|
||||||
up(&hw_priv->conf_lock);
|
|
||||||
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
|
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
|
||||||
wiphy_warn(hw->wiphy, "<--[SCAN] Scheduled scan request.\n");
|
wiphy_warn(hw->wiphy, "<--[SCAN] Scheduled scan request.\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+2
-82
@@ -266,7 +266,6 @@ void bes2600_stop(struct ieee80211_hw *dev, bool suspend)
|
|||||||
cancel_work_sync(&hw_priv->coex_work);
|
cancel_work_sync(&hw_priv->coex_work);
|
||||||
coex_stop(hw_priv);
|
coex_stop(hw_priv);
|
||||||
#endif
|
#endif
|
||||||
cancel_work_sync(&hw_priv->connection_loss_storm_recover_work);
|
|
||||||
|
|
||||||
bes2600_wifi_stop(hw_priv);
|
bes2600_wifi_stop(hw_priv);
|
||||||
|
|
||||||
@@ -449,7 +448,6 @@ void bes2600_remove_interface(struct ieee80211_hw *dev,
|
|||||||
cancel_delayed_work_sync(&priv->join_timeout);
|
cancel_delayed_work_sync(&priv->join_timeout);
|
||||||
cancel_delayed_work_sync(&priv->set_cts_work);
|
cancel_delayed_work_sync(&priv->set_cts_work);
|
||||||
cancel_delayed_work_sync(&priv->pending_offchanneltx_work);
|
cancel_delayed_work_sync(&priv->pending_offchanneltx_work);
|
||||||
cancel_work_sync(&priv->decrypt_storm_recover_work);
|
|
||||||
|
|
||||||
del_timer_sync(&priv->mcast_timeout);
|
del_timer_sync(&priv->mcast_timeout);
|
||||||
/* TODO:COMBO: May be reset of these variables "delayed_link_loss and
|
/* TODO:COMBO: May be reset of these variables "delayed_link_loss and
|
||||||
@@ -1660,70 +1658,6 @@ report:
|
|||||||
spin_unlock(&priv->bss_loss_lock);
|
spin_unlock(&priv->bss_loss_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Connection-loss-storm fast-recover (Trigger A).
|
|
||||||
*
|
|
||||||
* bes2600_connection_loss_work below is the driver's own decision-point
|
|
||||||
* to give up on a BSS (after bss-loss detection accumulates beyond
|
|
||||||
* tolerance) and tell mac80211 via ieee80211_connection_loss(). On the
|
|
||||||
* deployed pinetab2 stack a single ieee80211_connection_loss() event
|
|
||||||
* sometimes triggers a userspace reauth blackhole (assoc-comeback
|
|
||||||
* timeouts followed by AP unprotected-deauth-reason-6) that ends only
|
|
||||||
* via cross-channel/cross-SSID fallback and can take 80+ s. Receipts at
|
|
||||||
* https://git.reauktion.de/marfrit/besser, notes/phase4-2026-05-07.md.
|
|
||||||
*
|
|
||||||
* When N connection-loss decisions land within WINDOW on the same vif,
|
|
||||||
* skip the ieee80211_connection_loss() path and trigger a chip-level
|
|
||||||
* bus_reset (the c5.2-introduced bes2600_chrdev_do_bus_reset). The chip
|
|
||||||
* is removed and re-probed; userspace re-associates from a fresh state,
|
|
||||||
* dodging the assoc-comeback loop.
|
|
||||||
*
|
|
||||||
* Threshold (3 / 60 s) is chosen well above the steady-state per-vif
|
|
||||||
* connection-loss rate observed in the patch-A Phase-7 rep
|
|
||||||
* (0.86/h under sustained load), so a true storm is required.
|
|
||||||
*
|
|
||||||
* The recover work_struct lives on bes2600_common (hw_priv) so that
|
|
||||||
* scheduling it does not race with vif teardown after bus_reset frees
|
|
||||||
* the per-vif state.
|
|
||||||
*/
|
|
||||||
#define BES2600_CONNECTION_LOSS_STORM_THRESHOLD 3
|
|
||||||
#define BES2600_CONNECTION_LOSS_STORM_WINDOW_MS 60000
|
|
||||||
|
|
||||||
void bes2600_connection_loss_storm_recover(struct work_struct *work)
|
|
||||||
{
|
|
||||||
bes_warn("[bes2600] connection-loss-storm fast-recover: bus_reset\n");
|
|
||||||
bes2600_chrdev_trigger_bus_reset();
|
|
||||||
/*
|
|
||||||
* After bes2600_chrdev_do_bus_reset() returns, the SDIO core has
|
|
||||||
* scheduled a remove + rescan; per-vif state may already be gone.
|
|
||||||
* Do not dereference any per-vif pointer here.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void bes2600_connection_loss_storm_init(struct bes2600_vif *priv)
|
|
||||||
{
|
|
||||||
priv->connection_loss_storm_window_start = 0;
|
|
||||||
priv->connection_loss_storm_count = 0;
|
|
||||||
priv->connection_loss_storm_recoveries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bes2600_connection_loss_storm_account(struct bes2600_vif *priv)
|
|
||||||
{
|
|
||||||
unsigned long now = jiffies;
|
|
||||||
unsigned long window =
|
|
||||||
msecs_to_jiffies(BES2600_CONNECTION_LOSS_STORM_WINDOW_MS);
|
|
||||||
|
|
||||||
if (priv->connection_loss_storm_window_start == 0 ||
|
|
||||||
time_after(now, priv->connection_loss_storm_window_start + window)) {
|
|
||||||
priv->connection_loss_storm_window_start = now;
|
|
||||||
priv->connection_loss_storm_count = 1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ++priv->connection_loss_storm_count >=
|
|
||||||
BES2600_CONNECTION_LOSS_STORM_THRESHOLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bes2600_connection_loss_work(struct work_struct *work)
|
void bes2600_connection_loss_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct bes2600_vif *priv =
|
struct bes2600_vif *priv =
|
||||||
@@ -1733,21 +1667,9 @@ void bes2600_connection_loss_work(struct work_struct *work)
|
|||||||
|
|
||||||
bes_devel("[CQM] Reporting connection loss.\n");
|
bes_devel("[CQM] Reporting connection loss.\n");
|
||||||
bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_BSS_LOST);
|
bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_BSS_LOST);
|
||||||
|
if(bes2600_suspend_status_get(hw_priv)) {
|
||||||
if (bes2600_connection_loss_storm_account(priv)) {
|
|
||||||
bes_warn("[bes2600] connection-loss storm: %u in %u s, scheduling bus reset\n",
|
|
||||||
priv->connection_loss_storm_count,
|
|
||||||
BES2600_CONNECTION_LOSS_STORM_WINDOW_MS / 1000);
|
|
||||||
priv->connection_loss_storm_count = 0;
|
|
||||||
priv->connection_loss_storm_recoveries++;
|
|
||||||
schedule_work(&hw_priv->connection_loss_storm_recover_work);
|
|
||||||
/* bus_reset will tear the chip down; skip the mac80211 path. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bes2600_suspend_status_get(hw_priv))
|
|
||||||
bes2600_pending_unjoin_set(hw_priv, priv->if_id);
|
bes2600_pending_unjoin_set(hw_priv, priv->if_id);
|
||||||
else
|
} else
|
||||||
ieee80211_connection_loss(priv->vif);
|
ieee80211_connection_loss(priv->vif);
|
||||||
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
||||||
// set disconnected in BSS_CHANGED_ASSOC
|
// set disconnected in BSS_CHANGED_ASSOC
|
||||||
@@ -2697,8 +2619,6 @@ int bes2600_vif_setup(struct bes2600_vif *priv)
|
|||||||
|
|
||||||
/* Setup per vif workitems and locks */
|
/* Setup per vif workitems and locks */
|
||||||
spin_lock_init(&priv->vif_lock);
|
spin_lock_init(&priv->vif_lock);
|
||||||
bes2600_decrypt_storm_init(priv);
|
|
||||||
bes2600_connection_loss_storm_init(priv);
|
|
||||||
INIT_WORK(&priv->join_work, bes2600_join_work);
|
INIT_WORK(&priv->join_work, bes2600_join_work);
|
||||||
INIT_DELAYED_WORK(&priv->join_timeout, bes2600_join_timeout);
|
INIT_DELAYED_WORK(&priv->join_timeout, bes2600_join_timeout);
|
||||||
INIT_WORK(&priv->unjoin_work, bes2600_unjoin_work);
|
INIT_WORK(&priv->unjoin_work, bes2600_unjoin_work);
|
||||||
|
|||||||
@@ -25,78 +25,6 @@
|
|||||||
|
|
||||||
#define BES2600_INVALID_RATE_ID (0xFF)
|
#define BES2600_INVALID_RATE_ID (0xFF)
|
||||||
|
|
||||||
/*
|
|
||||||
* Decrypt-storm fast-recover (Trigger B).
|
|
||||||
*
|
|
||||||
* When the BES2600 firmware reports WSM_STATUS_DECRYPTFAILURE for a
|
|
||||||
* burst of received frames (typically because the host's PTK or GTK
|
|
||||||
* has fallen out of sync with the AP), the AP eventually concludes that
|
|
||||||
* the STA is not authenticated and emits an unprotected deauth-reason-6
|
|
||||||
* ("Class 2 frame received from non-authenticated station"). On the
|
|
||||||
* deployed pinetab2 + bes2600 stack this AP-initiated deauth has been
|
|
||||||
* observed to leave the link blackholed for up to 109 s before
|
|
||||||
* userspace finds a different SSID/channel to recover on. (Receipts at
|
|
||||||
* https://git.reauktion.de/marfrit/besser, notes/phase5-2026-05-06.md.)
|
|
||||||
*
|
|
||||||
* Recovery here pre-empts the AP: when we see THRESHOLD decrypt
|
|
||||||
* failures within WINDOW, we ask mac80211 for a clean reassoc via
|
|
||||||
* ieee80211_connection_loss(), which causes immediate disassociation
|
|
||||||
* and lets userspace auto-reconnect with fresh keys.
|
|
||||||
*
|
|
||||||
* mac80211 contract: ieee80211_connection_loss() may be called
|
|
||||||
* regardless of IEEE80211_HW_CONNECTION_MONITOR; it causes immediate
|
|
||||||
* disassociation without driver-side recovery attempts. See
|
|
||||||
* include/net/mac80211.h for the canonical doc-comment.
|
|
||||||
*
|
|
||||||
* The threshold is set well above the steady-state per-vif
|
|
||||||
* decrypt-fail rate observed in measurement (~1/min even under
|
|
||||||
* sustained 1 MB/s load), so a true storm is required to trip it.
|
|
||||||
*/
|
|
||||||
#define BES2600_DECRYPT_STORM_THRESHOLD 5
|
|
||||||
#define BES2600_DECRYPT_STORM_WINDOW_MS 5000
|
|
||||||
|
|
||||||
static void bes2600_decrypt_storm_recover_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct bes2600_vif *priv = container_of(work, struct bes2600_vif,
|
|
||||||
decrypt_storm_recover_work);
|
|
||||||
|
|
||||||
if (!priv->vif)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bes_warn("[bes2600] decrypt-storm fast-recover: forcing reassoc\n");
|
|
||||||
ieee80211_connection_loss(priv->vif);
|
|
||||||
priv->decrypt_storm_recoveries++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bes2600_decrypt_storm_init(struct bes2600_vif *priv)
|
|
||||||
{
|
|
||||||
INIT_WORK(&priv->decrypt_storm_recover_work,
|
|
||||||
bes2600_decrypt_storm_recover_work);
|
|
||||||
priv->decrypt_storm_window_start = 0;
|
|
||||||
priv->decrypt_storm_count = 0;
|
|
||||||
priv->decrypt_storm_recoveries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bes2600_decrypt_storm_account(struct bes2600_vif *priv)
|
|
||||||
{
|
|
||||||
unsigned long now = jiffies;
|
|
||||||
unsigned long window = msecs_to_jiffies(BES2600_DECRYPT_STORM_WINDOW_MS);
|
|
||||||
|
|
||||||
if (priv->decrypt_storm_window_start == 0 ||
|
|
||||||
time_after(now, priv->decrypt_storm_window_start + window)) {
|
|
||||||
priv->decrypt_storm_window_start = now;
|
|
||||||
priv->decrypt_storm_count = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++priv->decrypt_storm_count >= BES2600_DECRYPT_STORM_THRESHOLD) {
|
|
||||||
priv->decrypt_storm_count = 0;
|
|
||||||
/* Skew the window so we don't re-fire on the same storm. */
|
|
||||||
priv->decrypt_storm_window_start = now + window;
|
|
||||||
schedule_work(&priv->decrypt_storm_recover_work);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_BES2600_TESTMODE
|
#ifdef CONFIG_BES2600_TESTMODE
|
||||||
#include "bes_nl80211_testmode_msg.h"
|
#include "bes_nl80211_testmode_msg.h"
|
||||||
#endif /* CONFIG_BES2600_TESTMODE */
|
#endif /* CONFIG_BES2600_TESTMODE */
|
||||||
@@ -1744,8 +1672,6 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
|
|||||||
goto drop;
|
goto drop;
|
||||||
} else {
|
} else {
|
||||||
bes_warn("[RX] Receive failure: %d.\n", arg->status);
|
bes_warn("[RX] Receive failure: %d.\n", arg->status);
|
||||||
if (arg->status == WSM_STATUS_DECRYPTFAILURE)
|
|
||||||
bes2600_decrypt_storm_account(priv);
|
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user