Compare commits

..

1 Commits

Author SHA1 Message Date
test0r f43bcc5dda bes2600: remove userspace /dev/bes2600 character device interface
bes_chardev.c implemented a custom character device at /dev/bes2600 with
its own parser and command-dispatch table, exposing operations such as
'wifi on|off', 'bt on|off', 'change_fw_type <n>', 'bt_wakeup',
'bt_sleep', and 'wakeup_read_flag'. None of these surfaces are used by
the in-tree driver - every kernel call site consumes the internal state
accessors (bes2600_chrdev_is_signal_mode, bes2600_chrdev_get_fw_type,
etc) directly, not through the cdev.

The cdev interface is a standing upstream blocker for two reasons:

  1. Drivers under drivers/staging/ and drivers/net/wireless/ are
     expected to expose tuning via the firmware/nl80211/debugfs
     infrastructure rather than a private /dev node with an ad-hoc
     parser.

  2. The cdev handlers keep a global bes_cdev singleton alive whose
     ->cdev, ->dev_id, ->class and ->device pointers exist only to be
     torn down; they add no functionality that nl80211 or rfkill do
     not already provide (wifi/bt on-off, module_param for fw_type).

Remove the userspace interface:

  - open / read / write / release file_operations handlers and the
    bes2600_chardev_fops instance
  - bes2600_op_* command handlers and bes2600_op_map_tab dispatcher
  - bes2600_get_cmd_and_ifname / bes2600_recyle_cmd_and_ifname_mem
    string helpers
  - bes2600_load_uevent (its only caller was
    bes2600_chrdev_wifi_force_close_work informing userspace of a
    state it already gates via rfkill; that snprintf +
    kobject_uevent_env block is gone too, the kernel-side
    halt_device + switch_wifi(0) + chrdev_check_system_close
    sequence remains)
  - alloc_chrdev_region / cdev_init / cdev_add / class_create /
    device_create in bes2600_chrdev_init plus the fail1/fail2/fail3
    unwind labels
  - cdev_del / unregister_chrdev_region / device_destroy /
    class_destroy in bes2600_chrdev_free
  - cdev/dev_id/major/minor/class/device fields in struct bes_cdev

What remains (unchanged behaviour):

  - fw_type module parameter - the primary user-facing knob for
    signal/no-signal/BT mode switch
  - All in-kernel bes2600_chrdev_* accessor functions called from
    bes2600_sdio.c, bes_pwr.c, sta.c, bh.c, main.c, wsm.c, and
    wifi_testmode_cmd.c (13 call sites)
  - bes2600_chrdev_init / bes2600_chrdev_free as state-init / teardown
    for the remaining bes_cdev state (waitqueues, workqueues, flags)
  - DPD management (bes2600_chrdev_get_dpd_buffer / update / free)
  - wifi_force_close worker, system-close logic, bus-probe state
    machine

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1. Driver continues to associate and pass traffic;
no kernel messages related to the cdev absence. Users that previously
wrote to /dev/bes2600 should switch to the fw_type module parameter
or (future patch c4) nl80211 testmode commands.

Follow-ups:

  - c3.1: thread struct device * through bes2600_chrdev_is_signal_mode
    and friends so the global bes2600_cdev singleton can be dropped
    and the accessors scale to multi-device scenarios.
  - c4:   enable CONFIG_BES2600_TESTMODE and route nl80211 testmode
    commands to the firmware's patch_wifi_testMode entry.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 12:57:57 +02:00
23 changed files with 347 additions and 812 deletions
+15 -3
View File
@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(KERNELRELEASE)/build
# feature option
BES2600 ?= m
CONFIG_BES2600_TESTMODE ?= y
CONFIG_BES2600_TESTMODE ?= n
CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n
@@ -28,6 +28,7 @@ CONFIG_BES2600_WIFI_BOOT_ON ?= y
CONFIG_BES2600_BT_BOOT_ON ?= n
BES2600_GPIO_WAKEUP_AP ?= n
BES2600_WRITE_DPD_TO_FILE ?= n
BES2600_TX_MORE_RETRY ?= n
# bes evb
@@ -64,8 +65,8 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116
ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y)
FACTORY_CRC_CHECK ?= n
STANDARD_FACTORY_EFUSE_FLAG ?= n
FACTORY_PATH ?= bes2600/bes2600_factory.txt
STANDARD_FACTORY_EFUSE_FLAG ?= y
FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt
endif
# basic function
@@ -92,6 +93,12 @@ ccflags-y += -DBES_UNIFIED_PM
ccflags-y += -DBES_SDIO_OPTIMIZED_LEN
ccflags-y += -DBES2600_HOST_TIMESTAMP_DEBUG
ifeq ($(BES2600_WRITE_DPD_TO_FILE),y)
BES2600_DPD_PATH ?= /data/cfg/bes2600_dpd.bin
BES2600_DEFAULT_DPD_PATH ?= /lib/firmware/bes2600_dpd.bin
BES2600_DPD_GOLDEN_PATH ?= /data/cfg/bes2600_dpd_golden.bin
endif
ifeq ($(BES2600_DUMP_FW_DPD_LOG),y)
BES2600_DPD_LOG_PATH ?= /data/applog/bes2600_dpd_log.log
endif
@@ -128,6 +135,9 @@ ccflags-y += $(call boolen_flag,BSS_LOSS_CHECK,y)
ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_PATH)
ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_DEVICE)
ccflags-y += $(call string_flag,BES2600_DRV_VERSION)
ccflags-y += $(call string_flag,BES2600_DPD_PATH)
ccflags-y += $(call string_flag,BES2600_DEFAULT_DPD_PATH)
ccflags-y += $(call string_flag,BES2600_DPD_GOLDEN_PATH)
ccflags-y += $(call boolen_flag,BES2600_INDEPENDENT_EVB,y)
ccflags-y += $(call boolen_flag,BES2600_INTEGRATED_MODULE_V1,y)
@@ -149,6 +159,8 @@ ccflags-y += $(call boolen_flag,FACTORY_SAVE_MULTI_PATH,y)
ccflags-y += $(call boolen_flag,FACTORY_CRC_CHECK,y)
ccflags-y += $(call boolen_flag,BES2600_GPIO_WAKEUP_AP,y)
ccflags-y += $(call boolen_flag,BES2600_WRITE_DPD_TO_FILE,y)
ccflags-y += $(call boolen_flag,BES2600_DUMP_FW_DPD_LOG,y)
ccflags-y += $(call string_flag,BES2600_DPD_LOG_PATH)
-21
View File
@@ -511,9 +511,6 @@ struct bes2600_common {
struct list_head coex_event_list;
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 */
struct bes2600_pwr_t bes_power;
@@ -599,11 +596,6 @@ struct bes2600_vif {
unsigned long rx_timestamp;
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 */
u32 link_id_map;
@@ -630,10 +622,6 @@ struct bes2600_vif {
/* CQM Implementation */
struct delayed_work bss_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;
int delayed_link_loss;
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);
#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 */
+65 -43
View File
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/crc32.h>
@@ -31,18 +30,6 @@
static DEFINE_MUTEX(factory_lock);
/*
* struct device * for request_firmware() context. Set once at SDIO
* probe via bes2600_factory_set_dev(). NULL is tolerated (falls back
* to the udev-less firmware-class path) but loses per-device logging.
*/
static struct device *bes2600_factory_dev;
void bes2600_factory_set_dev(struct device *dev)
{
bes2600_factory_dev = dev;
}
/*
* It is only used for temporary storage.
* Every time get the factory, it will read from the
@@ -150,32 +137,66 @@ static int bes2600_factory_crc_check(struct factory_t *factory_data)
*/
static int factory_section_read_file(char *path, void *buffer)
{
const struct firmware *fw;
int ret;
int ret = 0;
struct file *fp;
if (!path || !buffer) {
bes_err("%s NULL pointer err\n", __func__);
return -1;
}
bes_devel("requesting firmware-class %s\n", path);
bes_devel("reading %s \n", path);
ret = request_firmware(&fw, path, bes2600_factory_dev);
if (ret) {
bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret);
fp = filp_open(path, O_RDONLY, 0); //S_IRUSR
if (IS_ERR(fp)) {
bes_devel("BES2600 : can't open %s\n",path);
return -1;
}
if (fw->size == 0 || fw->size > FACTORY_MAX_SIZE) {
bes_err("bes2600_factory.txt size check failed, read_size: %zu max_size: %d\n",
fw->size, FACTORY_MAX_SIZE);
release_firmware(fw);
if (fp->f_inode->i_size <= 0 || fp->f_inode->i_size > FACTORY_MAX_SIZE) {
bes_err( "bes2600_factory.txt size check failed, read_size: %lld max_size: %d\n",
fp->f_inode->i_size, FACTORY_MAX_SIZE);
filp_close(fp, NULL);
return -1;
}
memcpy(buffer, fw->data, fw->size);
ret = (int)fw->size;
release_firmware(fw);
ret = kernel_read(fp, buffer, fp->f_inode->i_size, &fp->f_pos);
filp_close(fp, NULL);
if (ret != fp->f_inode->i_size) {
bes_err("bes2600_factory.txt read fail\n");
ret = -1;
}
return ret;
}
/**
* factory_section_write_file - Write data of specified length to file
* @path: path of the file
* @buffer: storage of write data
* @size: length of data to write
*
* Return: length on success, negative error code otherwise.
*/
static int factory_section_write_file(char *path, void *buffer, int size)
{
int ret = 0;
struct file *fp;
bes_devel("writing %s \n", path);
fp = filp_open(path, O_TRUNC | O_CREAT | O_RDWR, S_IRUSR);
if (IS_ERR(fp)) {
bes_devel("BES2600 : can't open %s\n",path);
return -1;
}
ret = kernel_write(fp, buffer, size, &fp->f_pos);
filp_close(fp,NULL);
return ret;
}
@@ -870,22 +891,9 @@ static inline int factory_build(uint8_t *dest_buf, struct factory_t *factory)
#endif
}
/*
* Rebuild the serialised calibration blob in file_buffer from the live
* in-memory factory_save_p. Previously this function also persisted the
* blob back to FACTORY_PATH via filp_open(O_CREAT) + kernel_write(); that
* is not acceptable in mainline, so the persistence step has been removed.
*
* The in-memory factory_save_p remains authoritative for the duration of
* the session; on the next probe the firmware-class file is read back
* read-only via request_firmware(). If cross-reboot persistence of runtime
* calibration updates becomes a requirement, the expected route is a
* userspace-facing dump interface (debugfs read-only blob, or nl80211
* vendor command) that lets userspace read the serialised form and store
* it under its own privileges.
*/
static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *factory_save_p)
{
int ret = 0;
int w_size;
u32 crc_len = sizeof(factory_data_t);
#ifndef STANDARD_FACTORY_EFUSE_FLAG
@@ -894,11 +902,13 @@ static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *facto
bes_devel("enter %s\n", __func__);
if (!file_buffer)
if (!file_buffer) {
return -ENOMEM;
}
if (!factory_save_p)
if (!factory_save_p) {
return -ENOENT;
}
/* All initialized to space */
memset(file_buffer, 32, FACTORY_MAX_SIZE);
@@ -910,10 +920,22 @@ static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *facto
w_size = factory_build(file_buffer, factory_save_p);
if (w_size < 0 || w_size > FACTORY_MAX_SIZE) {
bes_err("%s: build failed! w_size = %d.", __func__, w_size);
bes_err("%s: build failed! ret = %d.", __func__, ret);
return -ETXTBSY;
}
#ifdef FACTORY_SAVE_MULTI_PATH
/* avoid trailing characters '\0' */
file_buffer[w_size] = 32;
ret = factory_section_write_file(FACTORY_PATH, file_buffer, FACTORY_MAX_SIZE);
#else
ret = factory_section_write_file(FACTORY_PATH, file_buffer, w_size);
#endif
if(ret < 0) {
bes_err("%s: write failed! ret = %d.", __func__, ret);
return ret;
}
return 0;
}
-3
View File
@@ -199,9 +199,6 @@ enum factory_cali_status {
/* just calibrate 11n, other protocols are automatically mapped */
#define WIFI_RF_11N_MODE 0x15
/* set the struct device * used for request_firmware() context */
void bes2600_factory_set_dev(struct device *dev);
/* read wifi & bt factory cali value*/
u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path);
void factory_little_endian_cvrt(u8 *data);
+3 -106
View File
@@ -16,7 +16,6 @@
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
#include <linux/mmc/sdio.h>
#include <linux/spinlock.h>
#include <net/mac80211.h>
@@ -31,7 +30,6 @@
#include "bes2600.h"
#include "sbus.h"
#include "bes2600_plat.h"
#include "bes2600_factory.h"
#include "hwio.h"
#include "bes_chardev.h"
#include "bes_log.h"
@@ -96,7 +94,6 @@ struct sbus_priv {
struct work_struct tx_work;
struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1];
struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1];
u8 *tx_bounce;
u32 tx_data_cnt;
u32 tx_xfer_cnt;
u32 tx_proc_cnt;
@@ -1138,26 +1135,7 @@ static void sdio_tx_work(struct work_struct *work)
}
}
/*
* The transfer length is rounded up to the SDIO block
* size, but tx_buffer->buf is only tx_buffer->len bytes
* long (it usually aliases into an skb linear head).
* Copy into a driver-owned bounce buffer and zero-pad
* to the aligned size; otherwise DMA reads past the
* skb and leaks adjacent kernel memory on the wire --
* observed as KFENCE OOB reads from
* bes_sdio_memcpy_to_io_helper via dma_map_sg.
*/
if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN))
goto flush_previous;
memcpy(self->tx_bounce + total_len,
tx_buffer->buf, tx_buffer->len);
if (align > tx_buffer->len)
memset(self->tx_bounce + total_len +
tx_buffer->len, 0,
align - tx_buffer->len);
sg_set_buf(&sg[scatters],
self->tx_bounce + total_len, align);
sg_set_buf(&sg[scatters], tx_buffer->buf, align);
total_len += align;
++scatters;
/*del_node:*/
@@ -1389,14 +1367,7 @@ static void bes2600_gpio_wakeup_mcu(struct sbus_priv *self, int flag)
/* error check */
if((self->gpio_wakup_flags & BIT(flag)) != 0) {
/*
* Multiple subsystems holding wake is the steady-state case
* (e.g. WIFI + BT both want MCU awake). Demoted from bes_err
* to bes_devel since it isn't an error - the GPIO is already
* asserted high and the subsystem is now also tracked.
*/
bes_devel("repeat set gpio_wake_flag, sub_sys:%d\n", flag);
self->gpio_wakup_flags |= BIT(flag);
bes_err( "repeat set gpio_wake_flag, sub_sys:%d", flag);
mutex_unlock(&self->io_mutex);
return;
}
@@ -1428,11 +1399,7 @@ static void bes2600_gpio_allow_mcu_sleep(struct sbus_priv *self, int flag)
/* error check */
if((self->gpio_wakup_flags & BIT(flag)) == 0) {
/*
* Mirror of the wake path: a clear when the bit is already
* clear is racy bookkeeping, not a hardware error.
*/
bes_devel("repeat clear gpio_wake_flag, sub_sys:%d\n", flag);
bes_err( "repeat clear gpio_wake_flag, sub_sys:%d", flag);
mutex_unlock(&self->io_mutex);
return;
}
@@ -1789,55 +1756,6 @@ static void bes2600_sdio_halt_device(struct sbus_priv *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)
{
struct bes2600_platform_data_sdio *pdata = bes2600_get_platform_data();
@@ -1876,7 +1794,6 @@ static struct sbus_ops bes2600_sdio_sbus_ops = {
.gpio_sleep = bes2600_gpio_allow_mcu_sleep,
.halt_device = bes2600_sdio_halt_device,
.wakeup_source = bes2600_sdio_wakeup_source,
.bus_reset = bes2600_sdio_bus_reset,
};
static void bes2600_sdio_en_lp_cb(struct bes2600_common *hw_priv)
@@ -1917,9 +1834,6 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (ret)
goto err;
/* wire struct device into factory.c for request_firmware() context */
bes2600_factory_set_dev(dev);
self->pdata = bes2600_get_platform_data();
self->func = func;
self->dev = &func->dev;
@@ -1939,17 +1853,6 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (!self->single_gathered_buffer)
return -ENOMEM;
#endif
#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL,
get_order(MAX_SDIO_TRANSFER_LEN));
if (!self->tx_bounce) {
#ifndef SDIO_HOST_ADMA_SUPPORT
free_pages((unsigned long)self->single_gathered_buffer,
get_order(MAX_SDIO_TRANSFER_LEN));
#endif
return -ENOMEM;
}
#endif
#ifdef BES_SDIO_RXTX_TOGGLE
self->fw_started = false;
#endif
@@ -2078,12 +1981,6 @@ static void bes2600_sdio_remove(struct sdio_func *func)
if (self->single_gathered_buffer) {
free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN));
}
#endif
#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
if (self->tx_bounce) {
free_pages((unsigned long)self->tx_bounce,
get_order(MAX_SDIO_TRANSFER_LEN));
}
#endif
kfree(self);
}
+145 -69
View File
@@ -63,6 +63,9 @@ struct bes_cdev {
struct delayed_work probe_timeout_work;
enum bus_probe_state bus_probe;
struct work_struct wifi_force_close_work;
#ifdef BES2600_WRITE_DPD_TO_FILE
int no_dpd;
#endif
enum pend_read_op read_flag;
enum wakeup_event wakeup_by_event; /* used to filter unwanted event wakeup reason report */
u16 wakeup_state; /* for userspace check wakeup reason */
@@ -82,6 +85,9 @@ struct bes2600_op_map {
static struct bes_cdev bes2600_cdev;
module_param_named(fw_type, bes2600_cdev.fw_type, int, 0644);
#ifdef BES2600_WRITE_DPD_TO_FILE
module_param_named(no_dpd, bes2600_cdev.no_dpd, int, 0644);
#endif
extern int bes2600_register_net_dev(struct sbus_priv *bus_priv);
extern int bes2600_unregister_net_dev(struct sbus_priv *bus_priv);
@@ -263,8 +269,137 @@ static int bes2600_chrdev_check_system_close_internal(void)
#ifdef BES2600_WRITE_DPD_TO_FILE
static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size)
{
int ret = 0;
struct file *fp;
if (buffer == NULL || size == 0)
return 0;
fp = filp_open(path, O_TRUNC | O_CREAT | O_RDWR, S_IRUSR);
if (IS_ERR(fp)) {
bes_err("BES2600 : can't open %s\n",path);
return -1;
}
ret = kernel_write(fp, buffer, size, &fp->f_pos);
if (ret < 0)
bes_err("write dpd to file failed\n");
filp_close(fp,NULL);
bes_devel("write dpd to %s\n", path);
return ret;
}
static bool bes2600_chrdev_dpd_is_vaild(u8 *dpd_data)
{
u32 cal_crc = 0;
u32 dpd_crc = le32_to_cpup((__le32 *)(dpd_data));
u32 dpd_ver = le32_to_cpup((__le32 *)(dpd_data + DPD_VERSION_OFFSET));
/* check version */
if (dpd_ver < DPD_CUR_VERSION)
return false;
cal_crc ^= 0xffffffffL;
cal_crc = crc32_le(cal_crc, dpd_data + 4, DPD_BIN_SIZE - 4);
cal_crc ^= 0xffffffffL;
/* check if the dpd data is valid */
if (cal_crc != dpd_crc) {
bes_err(
"bes2600 dpd data from file check failed, calc_crc:0x%08x dpd_crc: 0x%08x\n",
cal_crc, dpd_crc);
return false;
}
return true;
}
static int bes2600_chrdev_read_and_check_dpd_data(const char *file, u8 **data, u32 *len)
{
int ret = 0;
u8* read_data = NULL;
struct file *fp;
/* open file */
fp = filp_open(file, O_RDONLY, 0);//S_IRUSR
if (IS_ERR(fp)) {
bes_devel("BES2600 : can't open %s\n",file);
return -1;
}
#ifdef BES2600_WRITE_DPD_TO_FILE
if (fp->f_inode->i_size != DPD_BIN_FILE_SIZE) {
bes_err(
"bes2600 dpd data file size check failed, read_size: %lld file_size: %d\n",
fp->f_inode->i_size, DPD_BIN_FILE_SIZE);
filp_close(fp, NULL);
return -1;
}
#endif
/* allocate memory for storing reading data */
read_data = kmalloc(fp->f_inode->i_size, GFP_KERNEL);
if (read_data == NULL) {
bes_devel("%s alloc mem fail\n", __func__);
goto err1;
}
/* read data from file */
ret = kernel_read(fp, read_data, fp->f_inode->i_size, &fp->f_pos);
if (ret < DPD_BIN_SIZE) {
bes_err("%s read fail, ret=%d\n", __func__, ret);
goto err2;
}
/* check dpd version and crc */
if (!bes2600_chrdev_dpd_is_vaild(read_data))
goto err2;
/* close file */
filp_close(fp, NULL);
/* copy data to external */
*data = read_data;
*len = DPD_BIN_SIZE;;
/* output debug information */
bes_devel("read dpd data from %s\n", file);
return 0;
err2:
kfree(read_data);
err1:
filp_close(fp, NULL);
*data = NULL;
*len = 0;
return -1;
}
#endif
const u8* bes2600_chrdev_get_dpd_data(u32 *len)
{
#ifdef BES2600_WRITE_DPD_TO_FILE
if (!bes2600_cdev.dpd_calied && bes2600_cdev.no_dpd) {
/* read dpd data from file that stores factory dpd calibration data */
if ((bes2600_chrdev_read_and_check_dpd_data(BES2600_DPD_GOLDEN_PATH,
&bes2600_cdev.dpd_data, &bes2600_cdev.dpd_len) < 0) &&
(bes2600_chrdev_read_and_check_dpd_data(BES2600_DEFAULT_DPD_PATH,
&bes2600_cdev.dpd_data, &bes2600_cdev.dpd_len) < 0)) {
bes_err("%s read dpd data fail\n", __func__);
return NULL;
} else {
bes2600_cdev.dpd_calied = true;
}
}
#endif
if (!bes2600_cdev.dpd_calied)
return NULL;
if (len)
@@ -325,6 +460,14 @@ int bes2600_chrdev_update_dpd_data(void)
}
spin_unlock(&bes2600_cdev.status_lock);
#ifdef BES2600_WRITE_DPD_TO_FILE
/* write dpd data to file */
memset(bes2600_cdev.dpd_data + DPD_BIN_SIZE, 0, DPD_BIN_FILE_SIZE - DPD_BIN_SIZE);
bes2600_chrdev_write_dpd_data_to_file(BES2600_DPD_PATH,
bes2600_cdev.dpd_data, DPD_BIN_FILE_SIZE);
#endif
return 0;
}
@@ -442,60 +585,6 @@ int bes2600_chrdev_do_system_close(const struct sbus_ops *sbus_ops, struct sbus_
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 wifi_opened = false;
@@ -594,21 +683,8 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
/* unregister wifi */
bes2600_switch_wifi(0);
/*
* Hard exception with a bus_reset implementation: tear the
* 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()) {
/* power down device if wifi is only opened */
if (bes2600_chrdev_check_system_close()) {
bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
bes2600_cdev.sbus_priv);
}
-2
View File
@@ -60,8 +60,6 @@ struct sbus_priv *bes2600_chrdev_get_sbus_priv_data(void);
/* used to control device power down */
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_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_wifi_force_close(struct bes2600_common *hw_priv, bool halt_dev);
void bes2600_chrdev_usb_remove(struct bes2600_common *hw_priv);
+34
View File
@@ -125,6 +125,8 @@ int bes_host_slave_sync(struct bes2600_common *hw_priv)
}
*/
//#define DATA_DUMP_OBSERVE
static int bes_firmware_download_write_reg(struct platform_fw_t *fw_data, u32 addr, u32 val)
{
u8 frame_num = 0;
@@ -466,6 +468,14 @@ static int bes_firmware_download(struct platform_fw_t *fw_data, const char *fw_n
const struct firmware *fw_bin;
#ifdef DATA_DUMP_OBSERVE
char *observe;
size_t observe_len;
loff_t observe_off = 0;
mm_segment_t old_fs;
struct file *observe_file = NULL;
#endif
struct fw_msg_hdr_t header;
struct fw_info_t fw_info;
struct download_fw_t download_addr;
@@ -573,6 +583,14 @@ retry:
}
download_addr.addr = fw_info.addr;
#ifdef DATA_DUMP_OBSERVE
observe_file = filp_open("/lib/firmware/bes2002_fw_write.bin", O_CREAT | O_RDWR, 0);
if (IS_ERR(observe_file)) {
bes_err("create data_dump file err:%ld\n", IS_ERR(observe_file));
observe_file = NULL;
}
#endif
while (code_length) {
#if 1
@@ -622,6 +640,17 @@ retry:
//mdelay(5000);
bes_devel("tx_download_firmware_data:%x %d\n", download_addr.addr, length);
#ifdef DATA_DUMP_OBSERVE
if (observe_file) {
observe = (char *)(long_buf + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
observe_len = length - sizeof(struct fw_msg_hdr_t) - sizeof(struct download_fw_t);
old_fs = get_fs();
set_fs(KERNEL_DS);
vfs_write(observe_file, observe, observe_len, &observe_off);
set_fs(old_fs);
}
#endif
ret = bes2600_data_write(long_buf, length > 512 ? length : 512);
if (ret) {
bes_err("tx download fw data err:%d\n", ret);
@@ -803,6 +832,11 @@ retry:
err2:
kfree(long_buf);
#ifdef DATA_DUMP_OBSERVE
if (observe_file) {
filp_close(observe_file, NULL);
}
#endif
err1:
kfree(short_buf);
release_firmware(fw_bin);
-23
View File
@@ -8,26 +8,3 @@ extern struct device *global_dev;
#define bes_info(fmt, ...) dev_info(global_dev, fmt, ##__VA_ARGS__)
#define bes_warn(fmt, ...) dev_warn(global_dev, fmt, ##__VA_ARGS__)
#define bes_err(fmt, ...) dev_err(global_dev, fmt, ##__VA_ARGS__)
/*
* Legacy debug-subsystem-tagged log macros. The per-subsystem filtering
* was never implemented in-tree; these shims let code paths gated by
* CONFIG_BES2600_TESTMODE / CONFIG_BES2600_ITP / BES2600_DETECTION_LOGIC
* build when their conditions are enabled. The first argument is
* currently unused; pick one of the BES2600_DBG_* constants below for
* documentation.
*/
#define BES2600_DBG_SBUS 0
#define BES2600_DBG_DOWNLOAD 0
#define BES2600_DBG_ITP 0
#define BES2600_DBG_TEST_MODE 0
#define bes2600_info(_dbg, fmt, ...) bes_info(fmt, ##__VA_ARGS__)
#define bes2600_err(_dbg, fmt, ...) bes_err(fmt, ##__VA_ARGS__)
#define bes2600_warn(_dbg, fmt, ...) bes_warn(fmt, ##__VA_ARGS__)
#define bes2600_dbg(_dbg, fmt, ...) bes_devel(fmt, ##__VA_ARGS__)
#define bes2600_err_with_cond(_cond, _dbg, fmt, ...) \
do { \
if (_cond) \
bes_err(fmt, ##__VA_ARGS__); \
} while (0)
+16 -216
View File
@@ -467,65 +467,14 @@ static void bes2600_pwr_device_enter_lp_mode(struct bes2600_common *hw_priv)
bes_devel("device enter sleep\n");
}
/*
* Number of consecutive bes2600_pwr_enter_lp_mode timeouts (with zero
* PM_INDICATIONs received) before we conclude the firmware does not
* honor host-driven PSM and switch to a sticky skip path.
*/
#define BES2600_PM_UNSUPPORTED_THRESHOLD 3
/*
* Latch pm_unsupported = true and force chip_pm_state = ACTIVE so the
* c6.2 wake-side skip branch covers bes2600_pwr_device_exit_lp_mode.
* Called after BES2600_PM_UNSUPPORTED_THRESHOLD consecutive enter_lp_mode
* timeouts with zero PM_INDICATIONs.
*/
static void bes2600_pwr_latch_pm_unsupported(struct bes2600_common *hw_priv)
{
bes_warn("PSM not honored (%u timeouts), switching to skip mode\n",
hw_priv->bes_power.pm_consecutive_timeouts);
hw_priv->bes_power.pm_unsupported = true;
atomic_set(&hw_priv->bes_power.chip_pm_state,
BES2600_CHIP_PM_ACTIVE);
/*
* Hold the MCU wake-flag bit permanently. Without this, every
* sdio_rx_work invocation hits bes2600_gpio_wakeup_mcu(SDIO_RX)
* when gpio_wakup_flags == 0, drives the GPIO high and msleeps
* 10 ms per RX. With ~50 RX/s of beacons + multicast that's
* ~50%% of the bes_sdio workqueue thread blocked in msleep,
* which directly caps RX throughput. Holding the MCU bit makes
* those calls bit-only bookkeeping (gpio_wakeup = (flags == 0)
* stays false, no GPIO toggle, no msleep). The bit is never
* cleared once pm_unsupported is set because
* bes2600_pwr_device_enter_lp_mode is unreachable under the
* early-return.
*/
if (hw_priv->sbus_ops->gpio_wake)
hw_priv->sbus_ops->gpio_wake(hw_priv->sbus_priv,
GPIO_WAKE_FLAG_MCU);
}
static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
{
int i = 0;
struct bes2600_vif *priv;
int ret = 0;
int timeouts = 0;
char ip_str[20];
unsigned long status = 0;
/*
* Sticky early-return when we've previously concluded the firmware
* doesn't honor PSM. Each attempt would otherwise burn 5s on a
* doomed wait_for_completion_timeout and produce a noisy three-line
* cascade in dmesg every time power_down_work retries (every
* ~10s). The chip stays in active mode, which on this firmware is
* the de-facto state anyway.
*/
if (hw_priv->bes_power.pm_unsupported)
return -EOPNOTSUPP;
/* set interface low power configuration */
bes2600_for_each_vif(hw_priv, priv, i) {
#ifdef P2P_MULTIVIF
@@ -574,100 +523,27 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
bes_devel("%s, psMode:%s, fastPsmIdlePeriod:%d apPsmChangePeriod:%d minAutoPsPollPeriod:%d\n",
__func__, bes2600_get_ps_mode_str(priv->powersave_mode.pmMode), priv->powersave_mode.fastPsmIdlePeriod,
priv->powersave_mode.apPsmChangePeriod, priv->powersave_mode.minAutoPsPollPeriod);
/*
* Reinit BEFORE the WSM goes out, so a stale
* indication from a previous cycle cannot have
* primed pm_enter_cmpl. From here until the
* indication callback's cmpxchg(1->0) on
* pm_set_in_process, only the indication for
* THIS request can complete the wait.
*/
reinit_completion(&hw_priv->bes_power.pm_enter_cmpl);
atomic_set(&hw_priv->bes_power.pm_set_in_process, 1);
ret = bes2600_set_pm(priv, &priv->powersave_mode);
if (ret) {
atomic_set(&hw_priv->bes_power.pm_set_in_process, 0);
bes_err("%s, set operation mode fail\n", __func__);
timeouts++;
continue;
}
/* wait power save mode changed indication */
status = wait_for_completion_timeout(&hw_priv->bes_power.pm_enter_cmpl, 5 * HZ);
if (!status) {
/*
* The indication callback only fires
* complete() when it observes
* pm_set_in_process == 1; cmpxchg it
* to 0 here so a late indication
* cannot prime the next wait.
*
* If we win the cmpxchg, this is a
* real timeout: the firmware's PS
* state is unknown to us. Mark it as
* such so the next wake path can
* probe before assuming the chip is
* still active.
*
* If we lose the cmpxchg, the
* indication arrived between the
* wait timing out and us getting
* here; treat as success.
*/
if (atomic_cmpxchg(&hw_priv->bes_power.pm_set_in_process,
1, 0) == 1) {
bes_devel("%s, wait pm ind timeout\n", __func__);
atomic_set(&hw_priv->bes_power.chip_pm_state,
BES2600_CHIP_PM_UNKNOWN);
timeouts++;
if (++hw_priv->bes_power.pm_consecutive_timeouts
>= BES2600_PM_UNSUPPORTED_THRESHOLD)
bes2600_pwr_latch_pm_unsupported(hw_priv);
}
}
atomic_set(&hw_priv->bes_power.pm_set_in_process, 0);
reinit_completion(&hw_priv->bes_power.pm_enter_cmpl);
if (!status)
bes_err("%s, wait pm ind timeout\n", __func__);
} else {
bes_devel("skip enter lp mode\n");
}
}
}
/*
* Enter the device-end of the LP transition only if every per-VIF
* mac80211 handshake reached firmware-ACKed completion. Doing the
* device-LP setup while any VIF is still pending leaves the driver
* in an inconsistent state that cascades into SDIO TX errors on
* the BES2600.
*/
if (timeouts == 0) {
bes2600_pwr_device_enter_lp_mode(hw_priv);
} else {
/*
* device_enter_lp_mode() was skipped (one or more VIFs
* timed out waiting for the firmware indication) so its
* gpio_sleep(MCU) - which drops the wake-flag bit and, if
* no other subsystem holds the wake, drives the GPIO low -
* never ran. Without it the bit stays asserted, and the
* next bes2600_pwr_device_exit_lp_mode() calls
* gpio_wake(MCU) into a "bit already set" no-op: the GPIO
* never re-edges, sbus_active() exhausts its 200x2ms
* MCU_WAKEUP_READY budget against an unwoken chip, and
* the first TX after idle stalls for several seconds.
*
* Drop the MCU wake-flag bit explicitly here so the next
* wake injects a real GPIO edge. gpio_allow_mcu_sleep
* preserves multi-subsystem semantics: it only drives the
* GPIO low when no other subsystem still holds wake; if
* BT or another holder is keeping the chip awake, the
* GPIO stays high and the bit clear here is purely
* bookkeeping (so the next gpio_wake doesn't no-op).
*/
if (!hw_priv->bes_power.pm_unsupported &&
hw_priv->sbus_ops->gpio_sleep)
hw_priv->sbus_ops->gpio_sleep(hw_priv->sbus_priv,
GPIO_WAKE_FLAG_MCU);
ret = -ETIMEDOUT;
}
/* set device low power configuration */
bes2600_pwr_device_enter_lp_mode(hw_priv);
return ret;
}
@@ -675,61 +551,19 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
static void bes2600_pwr_device_exit_lp_mode(struct bes2600_common *hw_priv)
{
int ret = 0;
enum bes2600_chip_pm_state state;
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_active,
.disableMoreFlagUsage = true,
};
/*
* Consult chip_pm_state set by bes2600_pwr_notify_ps_changed().
* If we last saw the firmware confirm ACTIVE, skip ONLY the
* gpio_wake + sbus_active wake handshake - the GPIO is already
* asserted high and the SDIO MCU subsystem is already running,
* so another sbus_active() round-trip just hits its 200x2ms
* timeout because the firmware has nothing to do.
*
* wsm_set_operational_mode() below is NOT part of the wake
* handshake; it is the operational-mode setter the firmware
* tracks per call. Skipping it leaves the chip's SDIO state
* machine without a fresh operational-mode update, which on
* PineTab2 wedges the bus (-EBUSY on next sdio_rx_work read)
* within a few seconds of probe completion. So it must run
* unconditionally.
*/
state = atomic_read(&hw_priv->bes_power.chip_pm_state);
if (state == BES2600_CHIP_PM_ACTIVE) {
bes_devel("device_exit_lp_mode: chip already ACTIVE, skipping wake handshake\n");
} else {
bes_devel("host lock lmac\n");
if (hw_priv->sbus_ops->gpio_wake)
hw_priv->sbus_ops->gpio_wake(hw_priv->sbus_priv,
GPIO_WAKE_FLAG_MCU);
bes_devel("host lock lmac\n");
if(hw_priv->sbus_ops->gpio_wake)
hw_priv->sbus_ops->gpio_wake(hw_priv->sbus_priv, GPIO_WAKE_FLAG_MCU);
if (hw_priv->sbus_ops->sbus_active) {
ret = hw_priv->sbus_ops->sbus_active(hw_priv->sbus_priv,
SUBSYSTEM_MCU);
if (ret) {
/*
* MCU_WAKEUP_READY did not arrive within
* the SDIO handshake window. Record state
* as UNKNOWN so the next exit_lp_mode call
* also runs the full wake sequence (no
* skip), but still send operational_mode
* below to match pre-c6 behaviour - the
* WSM may succeed even if the SDIO active
* confirm was lost, and if it fails too,
* we just emit a second devel-level error.
* Repeated UNKNOWN is the signal for the
* LMAC active-monitor to eventually
* escalate to bus_reset (c5.2's
* mmc_hw_reset path).
*/
bes_err("%s, active mcu fail\n", __func__);
atomic_set(&hw_priv->bes_power.chip_pm_state,
BES2600_CHIP_PM_UNKNOWN);
}
}
if(hw_priv->sbus_ops->sbus_active) {
ret = hw_priv->sbus_ops->sbus_active(hw_priv->sbus_priv, SUBSYSTEM_MCU);
if (ret)
bes_err("%s, active mcu fail\n", __func__);
}
ret = wsm_set_operational_mode(hw_priv, &mode, 0);
@@ -985,9 +819,6 @@ void bes2600_pwr_init(struct bes2600_common *hw_priv)
hw_priv->bes_power.power_up_task = NULL;
mutex_init(&hw_priv->bes_power.pwr_mutex);
atomic_set(&hw_priv->bes_power.dev_state, 0);
atomic_set(&hw_priv->bes_power.chip_pm_state, BES2600_CHIP_PM_UNKNOWN);
hw_priv->bes_power.pm_unsupported = false;
hw_priv->bes_power.pm_consecutive_timeouts = 0;
init_completion(&hw_priv->bes_power.pm_enter_cmpl);
sema_init(&hw_priv->bes_power.sync_lock, 1);
device_set_wakeup_capable(hw_priv->pdev, true);
@@ -1368,40 +1199,9 @@ int bes2600_pwr_clear_busy_event(struct bes2600_common *hw_priv, u32 event)
void bes2600_pwr_notify_ps_changed(struct bes2600_common *hw_priv, u8 psmode)
{
/*
* The firmware sends a PM-changed indication for every transition,
* including ones we didn't ask for (firmware-internal coex moves,
* idle-driven aging). Update chip_pm_state unconditionally so the
* wake path can use it, but only fire pm_enter_cmpl when a host-
* initiated set_pm is actually in flight - otherwise a stale
* indication can prime a future wait against a freshly
* reinit_completion()'ed state.
*/
/*
* Any PM indication, whatever its psmode, proves the firmware is
* actually emitting them. Reset the consecutive-timeout counter
* so a transient stall doesn't permanently disable PSM, and clear
* pm_unsupported if a previous run had latched it.
*/
hw_priv->bes_power.pm_consecutive_timeouts = 0;
if (hw_priv->bes_power.pm_unsupported) {
bes_warn("PM indication arrived after pm_unsupported was set; re-enabling PSM transitions\n");
hw_priv->bes_power.pm_unsupported = false;
}
if ((psmode & 0x01) != WSM_PSM_ACTIVE) {
atomic_set(&hw_priv->bes_power.chip_pm_state,
BES2600_CHIP_PM_LP);
if (atomic_cmpxchg(&hw_priv->bes_power.pm_set_in_process,
1, 0) == 1) {
bes_devel("complete pm_enter_cmpl\n");
complete(&hw_priv->bes_power.pm_enter_cmpl);
} else {
bes_devel("PM ind (LP) without pending wait; state recorded\n");
}
} else {
atomic_set(&hw_priv->bes_power.chip_pm_state,
BES2600_CHIP_PM_ACTIVE);
if((psmode & 0x01) != WSM_PSM_ACTIVE) {
bes_devel("complete pm_enter_cmpl\n");
complete(&hw_priv->bes_power.pm_enter_cmpl);
}
}
-24
View File
@@ -64,20 +64,6 @@ enum power_down_state
POWER_DOWN_STATE_UNLOCKED,
};
/*
* Confirmed PM state of the firmware-side chip. Tracks what the host
* has *seen* the firmware acknowledge, not what the host has
* requested. UNKNOWN means a host-initiated transition timed out
* before the firmware indication arrived; the next wake path should
* treat it as "we don't know" and probe before issuing GPIO/SDIO
* wakeup ops.
*/
enum bes2600_chip_pm_state {
BES2600_CHIP_PM_ACTIVE = 0,
BES2600_CHIP_PM_LP,
BES2600_CHIP_PM_UNKNOWN,
};
typedef void (*bes_pwr_enter_lp_cb)(struct bes2600_common *hw_priv);
typedef void (*bes_pwr_exit_lp_cb)(struct bes2600_common *hw_priv);
@@ -120,16 +106,6 @@ struct bes2600_pwr_t
bool ap_lp_bad;
struct bes2600_pwr_event_t pwr_events[BES2600_DELAY_EVENT_NUM];
atomic_t pm_set_in_process;
atomic_t chip_pm_state;
/*
* Sticky flag set after BES2600_PM_UNSUPPORTED_THRESHOLD
* consecutive enter_lp_mode timeouts with zero PM_INDICATIONs
* received from firmware. Indicates this chip's firmware does
* not honor host-driven PSM transitions; further attempts are
* skipped to avoid the 5s timeout cascade.
*/
bool pm_unsupported;
unsigned int pm_consecutive_timeouts;
};
#ifdef CONFIG_BES2600_WOWLAN
+6 -6
View File
@@ -101,7 +101,7 @@ void bes2600_unregister_bh(struct bes2600_common *hw_priv)
coex_deinit_mode(hw_priv);
#endif
atomic_inc(&hw_priv->bh_term);
atomic_add(1, &hw_priv->bh_term);
wake_up(&hw_priv->bh_wq);
flush_workqueue(hw_priv->bh_workqueue);
@@ -590,7 +590,7 @@ static int bes2600_bh(void *arg)
bes_devel("[BH] Device resume.\n");
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
wake_up(&hw_priv->bh_evt_wq);
atomic_inc(&hw_priv->bh_rx);
atomic_add(1, &hw_priv->bh_rx);
continue;
}
@@ -758,9 +758,9 @@ tx:
#if 0 /* count is not implemented */
if (ret > 1)
atomic_inc(&hw_priv->bh_tx);
atomic_add(1, &hw_priv->bh_tx);
#else
atomic_inc(&hw_priv->bh_tx);
atomic_add(1, &hw_priv->bh_tx);
#endif
#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;
#endif
atomic_inc(&hw_priv->bh_tx);
atomic_add(1, &hw_priv->bh_tx);
tx_len = hw_priv->sbus_ops->align_size(
hw_priv->sbus_priv, tx_len);
@@ -1435,7 +1435,7 @@ static int bes2600_bh(void *arg)
bes_devel("[BH] Device resume.\n");
atomic_set(&hw_priv->bh_suspend, BES2600_BH_RESUMED);
wake_up(&hw_priv->bh_evt_wq);
atomic_inc(&hw_priv->bh_rx);
atomic_add(1, &hw_priv->bh_rx);
goto done;
}
-4
View File
@@ -542,10 +542,6 @@ static int bes2600_status_show_priv(struct seq_file *seq, void *v)
priv->listening ? " (listening)" : "");
seq_printf(seq, "Assoc: %s\n",
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)
seq_puts(seq, "Filter: promisc\n");
else if (priv->rx_filter.fcs)
+1 -1
View File
@@ -570,7 +570,7 @@ int bes2600_itp_get_tx(struct bes2600_common *priv, u8 **data,
*burst = 2;
atomic_set(&priv->bh_tx, 1);
ktime_get_ts(&itp->last_sent);
atomic_inc(&itp->awaiting_confirm);
atomic_add(1, &itp->awaiting_confirm);
spin_unlock_bh(&itp->tx_lock);
return 1;
+35 -4
View File
@@ -484,8 +484,6 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
spin_lock_init(&hw_priv->rtsvalue_lock);
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->connection_loss_storm_recover_work,
bes2600_connection_loss_storm_recover);
spin_lock_init(&hw_priv->event_queue_lock);
INIT_LIST_HEAD(&hw_priv->event_queue);
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,
bes2600_skb_dtor,
hw_priv))) {
destroy_workqueue(hw_priv->workqueue);
ieee80211_free_hw(hw);
return NULL;
}
@@ -509,7 +506,6 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
for (; i > 0; i--)
bes2600_queue_deinit(&hw_priv->tx_queue[i - 1]);
bes2600_queue_stats_deinit(&hw_priv->tx_queue_stats);
destroy_workqueue(hw_priv->workqueue);
ieee80211_free_hw(hw);
return NULL;
}
@@ -794,6 +790,41 @@ void bes2600_core_release(struct bes2600_common *self)
return;
}
#if (GET_MAC_ADDR_METHOD == 2) || (GET_MAC_ADDR_METHOD == 3) /* To use macaddr and ps mode of customers */
int access_file(char *path, char *buffer, int size, int isRead)
{
int ret=0;
struct file *fp;
mm_segment_t old_fs = get_fs();
if(isRead)
fp = filp_open(path,O_RDONLY,S_IRUSR);
else
fp = filp_open(path,O_CREAT|O_WRONLY,S_IRUSR);
if (IS_ERR(fp)) {
bes_err("BES2600 : can't open %s\n", path);
return -1;
}
if (isRead) {
fp->f_pos = 0;
set_fs(KERNEL_DS);
ret = vfs_read(fp,buffer,size,&fp->f_pos);
set_fs(old_fs);
} else {
fp->f_pos = 0;
set_fs(KERNEL_DS);
ret = vfs_write(fp,buffer,size,&fp->f_pos);
set_fs(old_fs);
}
filp_close(fp,NULL);
bes_info("BES2600 : access_file return code(%d)\n", ret);
return ret;
}
#endif
int bes2600_wifi_start(struct bes2600_common *hw_priv)
{
int ret = 0, if_id;
-8
View File
@@ -75,14 +75,6 @@ struct sbus_ops {
void (*halt_device)(struct sbus_priv *self);
bool (*wakeup_source)(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);
+17 -95
View File
@@ -14,63 +14,11 @@
#include "scan.h"
#include "sta.h"
#include "pm.h"
#include "epta_coex.h"
#include "epta_request.h"
#include "bes_pwr.h"
/*
* After this many consecutive WSM scan rejections from firmware, stop
* issuing new scans for BES2600_SCAN_BACKOFF_JIFFIES and let the state
* that's rejecting them (coex window, firmware-internal busy) clear.
*
* The backoff has to be at least as long as the natural mac80211 scan-
* retry cadence, otherwise the next attempt lands outside the window
* and bypasses the defer guard. Observed in the wild on PineTab2:
* roam-evaluation bursts at ~12 s cadence, idle background scans at
* ~5 min cadence. 30 s catches the burst and leaves the slow case
* alone (the firmware-policy state has had minutes to clear by then
* anyway).
*/
#define BES2600_SCAN_REJECT_THRESHOLD 3
#define BES2600_SCAN_BACKOFF_JIFFIES (30 * HZ)
static void bes2600_scan_restart_delayed(struct bes2600_vif *priv);
/*
* Decide whether to skip sending the next WSM scan command without
* bothering the firmware. Two triggers:
*
* 1. BT A2DP is streaming in non-FDD coex mode. The firmware is
* known to reject scan requests during that window; short-
* circuiting here saves a WSM round-trip and avoids the
* wsm_generic_confirm / scan_work warning cascade that follows.
*
* 2. We already saw >= BES2600_SCAN_REJECT_THRESHOLD consecutive
* rejections on recent scan attempts and the backoff window has
* not yet elapsed. Whatever was rejecting them is likely still
* rejecting them; give it time. If the backoff has elapsed without
* a fresh reject refreshing it, the burst is over and we reset the
* count so an isolated reject doesn't immediately re-trip.
*
* Returns true if the caller should abandon the scan iteration.
*/
static bool bes2600_scan_should_defer(struct bes2600_common *hw_priv)
{
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
if (!coex_is_fdd_mode() && coex_is_bt_a2dp())
return true;
#endif
if (time_after(jiffies, hw_priv->scan.backoff_until))
hw_priv->scan.reject_count = 0;
if (hw_priv->scan.reject_count >= BES2600_SCAN_REJECT_THRESHOLD &&
time_before(jiffies, hw_priv->scan.backoff_until))
return true;
return false;
}
#ifdef CONFIG_BES2600_TESTMODE
static int bes2600_advance_scan_start(struct bes2600_common *hw_priv)
{
@@ -257,21 +205,18 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
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,
req->ie_len);
if (!frame.skb) {
up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock);
if (!frame.skb)
return -ENOMEM;
}
if (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) {
int ret;
//if (priv->if_id == 0)
@@ -289,9 +234,9 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
}
#endif
if (ret) {
dev_kfree_skb(frame.skb);
up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock);
dev_kfree_skb(frame.skb);
return ret;
}
}
@@ -321,10 +266,10 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
++hw_priv->scan.n_ssids;
}
up(&hw_priv->conf_lock);
if (frame.skb)
dev_kfree_skb(frame.skb);
up(&hw_priv->conf_lock);
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING);
#endif
@@ -365,18 +310,14 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
if (req->n_ssids > hw->wiphy->max_scan_ssids)
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() */
down(&hw_priv->scan.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) {
int ret;
if (priv->if_id == 0)
@@ -387,9 +328,9 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
ret = wsm_set_probe_responder(priv, true);
}
if (ret) {
dev_kfree_skb(frame.skb);
up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock);
dev_kfree_skb(frame.skb);
return ret;
}
}
@@ -421,10 +362,10 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw,
}
}
up(&hw_priv->conf_lock);
if (frame.skb)
dev_kfree_skb(frame.skb);
up(&hw_priv->conf_lock);
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
wiphy_warn(hw->wiphy, "<--[SCAN] Scheduled scan request.\n");
return 0;
@@ -761,29 +702,10 @@ void bes2600_scan_work(struct work_struct *work)
wsm_unlock_tx(hw_priv);
} else
#endif
{
if (bes2600_scan_should_defer(hw_priv)) {
hw_priv->scan.status = -EBUSY;
hw_priv->scan.reject_count++;
hw_priv->scan.backoff_until =
jiffies + BES2600_SCAN_BACKOFF_JIFFIES;
wiphy_dbg(priv->hw->wiphy,
"[SCAN] deferred (coex/backoff, reject_count=%u)\n",
hw_priv->scan.reject_count);
kfree(scan.ch);
goto fail;
}
hw_priv->scan.status = bes2600_scan_start(priv, &scan);
}
kfree(scan.ch);
if (hw_priv->scan.status) {
hw_priv->scan.reject_count++;
hw_priv->scan.backoff_until =
jiffies + BES2600_SCAN_BACKOFF_JIFFIES;
/* Lower callers already logged the reason at wiphy_warn. */
if (WARN_ON(hw_priv->scan.status))
goto fail;
}
hw_priv->scan.reject_count = 0;
hw_priv->scan.curr = it;
}
up(&hw_priv->conf_lock);
-11
View File
@@ -42,17 +42,6 @@ struct bes2600_scan {
struct delayed_work probe_work;
int direct_probe;
u8 if_id;
/*
* Track consecutive firmware-side WSM scan rejections so we can
* back off briefly instead of re-issuing the same scan on every
* mac80211 background-scan tick. Firmware returns WSM status != 0
* for a handful of transient conditions (BT A2DP active in non-
* FDD coex, firmware-internal busy windows) and keeps rejecting
* until the state clears; retrying at full cadence just floods
* dmesg.
*/
unsigned int reject_count;
unsigned long backoff_until;
};
int bes2600_hw_scan(struct ieee80211_hw *hw,
+5 -85
View File
@@ -266,7 +266,6 @@ void bes2600_stop(struct ieee80211_hw *dev, bool suspend)
cancel_work_sync(&hw_priv->coex_work);
coex_stop(hw_priv);
#endif
cancel_work_sync(&hw_priv->connection_loss_storm_recover_work);
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->set_cts_work);
cancel_delayed_work_sync(&priv->pending_offchanneltx_work);
cancel_work_sync(&priv->decrypt_storm_recover_work);
del_timer_sync(&priv->mcast_timeout);
/* TODO:COMBO: May be reset of these variables "delayed_link_loss and
@@ -1660,70 +1658,6 @@ report:
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)
{
struct bes2600_vif *priv =
@@ -1733,21 +1667,9 @@ void bes2600_connection_loss_work(struct work_struct *work)
bes_devel("[CQM] Reporting connection loss.\n");
bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_BSS_LOST);
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))
if(bes2600_suspend_status_get(hw_priv)) {
bes2600_pending_unjoin_set(hw_priv, priv->if_id);
else
} else
ieee80211_connection_loss(priv->vif);
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
// set disconnected in BSS_CHANGED_ASSOC
@@ -2697,8 +2619,6 @@ int bes2600_vif_setup(struct bes2600_vif *priv)
/* Setup per vif workitems and locks */
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_DELAYED_WORK(&priv->join_timeout, bes2600_join_timeout);
INIT_WORK(&priv->unjoin_work, bes2600_unjoin_work);
@@ -3713,7 +3633,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw,
*
* Returns: 0 on success or non zero value on failure
*/
static int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
{
struct bes_msg_start_stop_tsm *start_stop_tsm =
(struct bes_msg_start_stop_tsm *) data;
@@ -3743,7 +3663,7 @@ static int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
*
* Returns: TSM parameters collected
*/
static int bes2600_get_tsm_params(struct ieee80211_hw *hw)
int bes2600_get_tsm_params(struct ieee80211_hw *hw)
{
struct bes2600_common *hw_priv = hw->priv;
struct bes_tsm_stats tsm_stats;
@@ -3783,7 +3703,7 @@ static int bes2600_get_tsm_params(struct ieee80211_hw *hw)
*
* Returns: Returns the last measured roam delay
*/
static int bes2600_get_roam_delay(struct ieee80211_hw *hw)
int bes2600_get_roam_delay(struct ieee80211_hw *hw)
{
struct bes2600_common *hw_priv = hw->priv;
u16 roam_delay = hw_priv->tsm_info.roam_delay / 1000;
-74
View File
@@ -25,78 +25,6 @@
#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
#include "bes_nl80211_testmode_msg.h"
#endif /* CONFIG_BES2600_TESTMODE */
@@ -1744,8 +1672,6 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
goto drop;
} else {
bes_warn("[RX] Receive failure: %d.\n", arg->status);
if (arg->status == WSM_STATUS_DECRYPTFAILURE)
bes2600_decrypt_storm_account(priv);
goto drop;
}
}
+1 -13
View File
@@ -134,20 +134,8 @@ static int wsm_generic_confirm(struct bes2600_common *hw_priv,
struct wsm_buf *buf)
{
u32 status = WSM_GET32(buf);
/*
* A non-SUCCESS status here is a firmware-side policy decision for
* the command whose confirm this is -- commonly WSM status 2 for
* scan (0x0407) rejected because of a coex window or transient
* firmware-busy state. It is not a driver/kernel bug, so avoid the
* WARN()/stack-trace treatment; the caller already emits a
* wiphy_warn identifying the request id and will propagate the
* error to mac80211.
*/
if (status != WSM_STATUS_SUCCESS) {
bes_devel("%s ret %u\n", __func__, status);
if (WARN(status != WSM_STATUS_SUCCESS, "wsm_generic_confirm ret %u", status))
return -EINVAL;
}
return 0;
underflow:
+2
View File
@@ -2236,5 +2236,7 @@ int wsm_cpu_usage_cmd(struct bes2600_common *hw_priv);
int wsm_wifi_status_cmd(struct bes2600_common *hw_priv, uint32_t status);
#if defined(STANDARD_FACTORY_EFUSE_FLAG)
int wsm_save_factory_txt_to_mcu(struct bes2600_common *hw_priv, const u8 *data, int if_id, enum bes2600_rf_cmd_type cmd_type);
#endif
#endif /* BES2600_HWIO_H_INCLUDED */
+2 -1
View File
@@ -18,7 +18,8 @@ License: LGPL-2.1
License for more details.
.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, see <https://www.gnu.org/licenses/>.
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the full text of the GNU Lesser General Public License
version 2.1 can be found in the file "/usr/share/common-licenses/LGPL-2.1".