Compare commits

..

3 Commits

Author SHA1 Message Date
test0r 8732881c59 bes2600: thread struct device * through factory request_firmware() call
Follow-up to \"bes2600: use request_firmware() for factory.txt read\".
That patch switched the factory calibration read path from filp_open()
+ kernel_read() to request_firmware(), but passed dev=NULL to
request_firmware() because factory_section_read_file() did not have a
struct device * in scope. The resulting logs carry the
'(NULL device *):' prefix and do not propagate a udev association.

Add a module-local static struct device * used as the firmware-class
load context, plus a small exported setter:

    static struct device *bes2600_factory_dev;
    void bes2600_factory_set_dev(struct device *dev);

Wire bes2600_factory_set_dev(&func->dev) from bes2600_sdio_probe(),
right after bes2600_platform_data_init() so the platform layer has
already had a chance to use the same struct device for its own
initialization.

factory_section_read_file() now passes bes2600_factory_dev (instead
of NULL) to request_firmware(). When the factory read happens before
probe (not currently the case on PineTab2) the pointer is still NULL
and request_firmware() accepts that; no regression.

No API changes to bes2600_get_factory_cali_data() callers. The
char *path parameter remains (it is the firmware-class name fed
straight to request_firmware()).

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1. Driver probes, factory data is read, and any
post-c5 factory diagnostics now carry the SDIO device identity
instead of '(NULL device *)'.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 13:21:19 +02:00
test0r 82ba594a44 bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format
The shipped factory calibration file bes2600_factory.txt on PineTab2
(danctnix linux-firmware 0.3.5_2023.0209) contains 30 calibration
fields: head (3), iq/xtal (3), 2.4G power 11n (5), 5G power 11n (15),
bt (4). The file terminates with '%%\n' directly after edr_power.

When STANDARD_FACTORY_EFUSE_FLAG is defined at compile time the driver
assembles STANDARD_FACTORY with an extra select_efuse_flag section
appended and expects 31 sscanf matches (FACTORY_MEMBER_NUM=31):

    __STANDARD_FACTORY + \"##select_efuse_flag\\nselect_efuse:%hx\\n\"
                      + \"%%%%\\n\"

The PineTab2 factory.txt has no select_efuse_flag section, so sscanf
stops after field 30 and factory_parse() returns -1 with:

    bes2600_factory.txt parse fail
    read and check bes2600/bes2600_factory.txt error
    factory cali data get failed.

This was latent until the preceding patch (use request_firmware() for
factory.txt read) fixed the path bug that masked the parse failure.

Default STANDARD_FACTORY_EFUSE_FLAG to n. The flag remains overridable
at build time (make STANDARD_FACTORY_EFUSE_FLAG=y ...) for chips /
firmware packages that do ship the select_efuse_flag section.

Also: the wsm_save_factory_txt_to_mcu() prototype in wsm.h was
inconsistently wrapped in a conditional that keyed on
STANDARD_FACTORY_EFUSE_FLAG, but the function definition in wsm.c and
the call site in sta.c are ungated. With the flag now defaulting to
n, the gcc -Werror=missing-prototypes flag breaks the build. Drop the
conditional wrapper around the prototype — the function exists and is
used regardless of the factory-parse flag.

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1. With the flag defaulted off, factory_parse()
succeeds on the shipped factory.txt, factory_cali_data is populated,
and dmesg no longer shows the parse-fail / read-and-check-error /
factory-cali-data-get-failed sequence.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 12:26:22 +02:00
test0r 1a5d54a321 bes2600: use request_firmware() for factory.txt read
The BES2600 factory calibration file (bes2600_factory.txt) was being read
via filp_open() + kernel_read() from a hard-coded absolute path baked in
at compile time via the FACTORY_PATH Makefile macro
(default: /lib/firmware/bes2600_factory.txt).

This had several problems:

1. Path mismatch - linux-firmware-style packaging (and danctnix 0.2-5
   device-pine64-pinetab2) ships the file at
   /lib/firmware/bes2600/bes2600_factory.txt, not /lib/firmware/. The
   driver logged '(NULL device *): read and check
   /lib/firmware/bes2600_factory.txt error' on every boot on PineTab2
   running linux-pinetab2 6.19.10-danctnix1-1.

2. Direct filesystem access via filp_open() / kernel_read() from a driver
   is an anti-pattern that upstream rejects: drivers should use
   request_firmware() to get binary data from userspace-managed firmware
   directories. request_firmware() natively searches the firmware_class
   path list (typically /lib/firmware + derivatives), associates the load
   with a uevent, and respects the firmware-loading infrastructure.

3. The (NULL device *) prefix in error messages indicated the absence of
   proper device-context logging. While this patch does not yet thread
   struct device through, the upstream path uses request_firmware() which
   works with dev=NULL and is the building block for a follow-up patch
   that adds per-chip device context.

Repoint the FACTORY_PATH default to the firmware-class name
(bes2600/bes2600_factory.txt) - request_firmware() prepends
/lib/firmware/ from the configured search paths. The macro remains
overridable at build time for non-standard deployments.

Rewrite factory_section_read_file() to:
  * Call request_firmware(&fw, path, NULL).
  * Size-check fw->size against FACTORY_MAX_SIZE.
  * memcpy the data into the caller's buffer.
  * Always call release_firmware() on exit.

The file write path (factory_section_write_file + kernel_write) is left
unchanged in this patch; it is the subject of a follow-up patch that
removes kernel_write and moves any remaining userspace-visible factory
configuration to a standard kernel-userspace boundary (debugfs or
nl80211 testmode).

No caller signature changes. No Makefile flag drops. Bisectable.

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1, deployed via /lib/modules/<ver>/extra/. Verified
post-reboot: original 'read and check /lib/firmware/bes2600_factory.txt
error' is gone; request_firmware reads the file successfully (a separate
factory_parse() bug, previously masked by the read failure, is now
exposed and tracked separately).

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 10:09:44 +02:00
19 changed files with 78 additions and 1433 deletions
+2 -2
View File
@@ -65,8 +65,8 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116
ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y) ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y)
FACTORY_CRC_CHECK ?= n FACTORY_CRC_CHECK ?= n
STANDARD_FACTORY_EFUSE_FLAG ?= y STANDARD_FACTORY_EFUSE_FLAG ?= n
FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt FACTORY_PATH ?= bes2600/bes2600_factory.txt
endif endif
# basic function # basic function
+3 -4
View File
@@ -17,7 +17,6 @@
#include <linux/umh.h> #include <linux/umh.h>
#include "epta_request.h" #include "epta_request.h"
#include "epta_coex.h" #include "epta_coex.h"
#include "txrx_opt.h"
#ifdef AP_HT_CAP_UPDATE #ifdef AP_HT_CAP_UPDATE
#define HT_INFO_OFFSET 4 #define HT_INFO_OFFSET 4
@@ -1155,7 +1154,7 @@ void bes2600_multicast_stop_work(struct work_struct *work)
container_of(work, struct bes2600_vif, multicast_stop_work); container_of(work, struct bes2600_vif, multicast_stop_work);
if (priv->aid0_bit_set) { if (priv->aid0_bit_set) {
timer_delete_sync(&priv->mcast_timeout); del_timer_sync(&priv->mcast_timeout);
wsm_lock_tx(priv->hw_priv); wsm_lock_tx(priv->hw_priv);
priv->aid0_bit_set = false; priv->aid0_bit_set = false;
bes2600_set_tim_impl(priv, false); bes2600_set_tim_impl(priv, false);
@@ -1165,7 +1164,7 @@ void bes2600_multicast_stop_work(struct work_struct *work)
void bes2600_mcast_timeout(struct timer_list *t) void bes2600_mcast_timeout(struct timer_list *t)
{ {
struct bes2600_vif *priv = timer_container_of(priv, t, mcast_timeout); struct bes2600_vif *priv = from_timer(priv, t, mcast_timeout);
wiphy_warn(priv->hw->wiphy, wiphy_warn(priv->hw->wiphy,
"Multicast delivery timeout.\n"); "Multicast delivery timeout.\n");
@@ -1239,7 +1238,7 @@ void bes2600_suspend_resume(struct bes2600_vif *priv,
} }
spin_unlock_bh(&priv->ps_state_lock); spin_unlock_bh(&priv->ps_state_lock);
if (cancel_tmo) if (cancel_tmo)
timer_delete_sync(&priv->mcast_timeout); del_timer_sync(&priv->mcast_timeout);
} else { } else {
spin_lock_bh(&priv->ps_state_lock); spin_lock_bh(&priv->ps_state_lock);
bes2600_ps_notify(priv, arg->link_id, arg->stop); bes2600_ps_notify(priv, arg->link_id, arg->stop);
-509
View File
@@ -1,509 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestechnic BES2600 BT UART driver
*
* Copyright (c) 2025 Dang Huynh <dang.huynh@mainlining.org>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/device.h>
#include <linux/pm.h>
#include <linux/pm_wakeirq.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "bes2600.h"
#include "bes_chardev.h"
#include "h4_recv.h"
struct bes2600_btuart_data {
struct serdev_device *serdev;
struct hci_dev *hdev;
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_default;
/* Device tree properties */
struct gpio_desc *power;
struct gpio_desc *wakeup;
int speed;
unsigned long state;
int wake_irq;
bool opened;
int err_count; /* workaround for broken firmware */
struct sk_buff_head txq;
struct work_struct tx_work;
rwlock_t lock;
struct sk_buff *rx_skb;
};
static const struct h4_recv_pkt bes2600_btuart_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
};
static int bes2600_btuart_power(struct bes2600_btuart_data *data, bool enable)
{
int ret, val;
if (enable)
val = 1;
else
val = 0;
ret = gpiod_set_value_cansleep(data->power, val);
if (ret)
return ret;
ret = bes2600_chrdev_switch_subsys_glb(-1, val);
if (ret)
return ret;
return 0;
}
/*
* HACK: Potential DOS issue, not sure if the firmware can filter it but
* there needs to be a better way to detect this. Even better, fix the firmware.
*/
static int bes2600_btuart_bug_recovery(struct bes2600_btuart_data *data)
{
struct hci_dev *hdev = data->hdev;
struct serdev_device *serdev = data->serdev;
bt_dev_info(hdev, "Attempting to recover from Firmware bug (might not work)");
serdev_device_set_flow_control(serdev, false);
bes2600_btuart_power(data, false);
msleep(20);
bes2600_btuart_power(data, true);
serdev_device_set_flow_control(serdev, true);
msleep(100);
hci_reset_dev(hdev);
return 0;
}
static int bes2600_btuart_recv(struct bes2600_btuart_data *data, const void *buffer, int count)
{
struct hci_dev *hdev = data->hdev;
int err = 0;
data->rx_skb = h4_recv_buf(hdev, data->rx_skb, buffer, count,
bes2600_btuart_recv_pkts, ARRAY_SIZE(bes2600_btuart_recv_pkts));
if (IS_ERR(data->rx_skb))
err = PTR_ERR(data->rx_skb);
return err;
}
static size_t bes2600_btuart_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t count)
{
struct bes2600_btuart_data *data = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = data->hdev;
int ret;
read_lock(&data->lock);
ret = bes2600_btuart_recv(data, buf, count);
if (ret) {
bt_dev_err(hdev, "Failed to receive packet (%d)", ret);
data->err_count++;
ret = 0;
} else {
hdev->stat.byte_rx += count;
ret = count;
}
read_unlock(&data->lock);
/* Attempting to recovery from a bugged firmware */
if (data->err_count > 10) {
bes2600_btuart_bug_recovery(data);
data->err_count = 0;
}
return ret;
}
static const struct serdev_device_ops bes2600_btuart_serdev_client_ops = {
.receive_buf = bes2600_btuart_receive_buf,
.write_wakeup = serdev_device_write_wakeup,
};
static void bes2600_btuart_wake(struct hci_dev *hdev, bool enable)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
if (enable)
gpiod_set_value_cansleep(data->wakeup, 1);
else
gpiod_set_value_cansleep(data->wakeup, 0);
}
static int bes2600_btuart_open(struct hci_dev *hdev)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
struct serdev_device *serdev = data->serdev;
int ret;
ret = serdev_device_open(serdev);
if (ret < 0) {
bt_dev_err(hdev, "Failed to open serial device");
return ret;
}
serdev_device_set_flow_control(serdev, false);
ret = serdev_device_set_baudrate(serdev, data->speed);
if (ret < 0) {
bt_dev_err(hdev, "Failed to set baud rate");
return ret;
}
serdev_device_set_flow_control(serdev, true);
data->opened = true;
bes2600_btuart_wake(hdev, true);
return 0;
}
static int bes2600_btuart_flush(struct hci_dev *hdev)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
struct serdev_device *serdev = data->serdev;
serdev_device_write_flush(serdev);
read_lock(&data->lock);
skb_queue_purge(&data->txq);
cancel_work_sync(&data->tx_work);
read_unlock(&data->lock);
return 0;
}
static int bes2600_btuart_close(struct hci_dev *hdev)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
struct serdev_device *serdev = data->serdev;
bes2600_btuart_wake(hdev, false);
serdev_device_set_flow_control(serdev, false);
serdev_device_close(serdev);
data->opened = false;
return 0;
}
static int bes2600_btuart_setup(struct hci_dev *hdev)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
int ret;
if (bes2600_chrdev_is_bus_error())
return -EFAULT;
/* Set pinctrl state to default */
ret = pinctrl_select_state(data->pinctrl, data->pinctrl_default);
if (ret < 0) {
bt_dev_err(hdev, "Failed to setup pinctrl state");
return ret;
}
/* Set power GPIO to high and tell chardev to switch to BT */
bes2600_btuart_power(data, true);
return 0;
}
static int bes2600_btuart_shutdown(struct hci_dev *hdev)
{
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
if (bes2600_chrdev_is_bus_error())
return -EFAULT;
bes2600_btuart_power(data, false);
return 0;
}
static int bes2600_btuart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
char *pkt_type = NULL;
struct bes2600_btuart_data *data = hci_get_drvdata(hdev);
switch (hci_skb_pkt_type(skb)) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
case HCI_ACLDATA_PKT:
hdev->stat.acl_tx++;
break;
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
break;
default:
return -EILSEQ;
}
pkt_type = skb_push(skb, 1);
pkt_type[0] = hci_skb_pkt_type(skb);
read_lock(&data->lock);
skb_queue_tail(&data->txq, skb);
read_unlock(&data->lock);
schedule_work(&data->tx_work);
return 0;
}
static ssize_t bes2600_btuart_send(struct bes2600_btuart_data *data, struct sk_buff *skb)
{
struct hci_dev *hdev = data->hdev;
int len;
len = serdev_device_write_buf(data->serdev, skb->data, skb->len);
if (len < 0) {
bt_dev_err(data->hdev, "Failed to write buffer to TTY");
return -EIO;
}
serdev_device_wait_until_sent(data->serdev, 0);
hdev->stat.byte_tx += len;
skb_pull(skb, len);
return skb->len;
}
static void bes2600_btuart_work(struct work_struct *work)
{
struct bes2600_btuart_data *data = container_of(work, struct bes2600_btuart_data, tx_work);
struct sk_buff *skb;
while ((skb = skb_dequeue(&data->txq))) {
if (bes2600_btuart_send(data, skb) > 0) {
skb_queue_head(&data->txq, skb);
break;
}
kfree_skb(skb);
}
}
static void bes2600_btuart_parse_dt(struct serdev_device *serdev)
{
struct bes2600_btuart_data *data = serdev_device_get_drvdata(serdev);
struct device_node *node = serdev->dev.of_node;
int speed = 1500000;
of_property_read_u32(node, "current-speed", &speed);
data->speed = speed;
}
static irqreturn_t bes2600_btuart_wakeup_handler(int irq, void *priv)
{
struct bes2600_btuart_data *data = (struct bes2600_btuart_data *)priv;
dev_info(&data->serdev->dev, "IRQ wake\n");
return IRQ_HANDLED;
}
#ifdef CONFIG_PM_SLEEP
static int bes2600_btuart_suspend(struct device *dev)
{
struct serdev_device *serdev = to_serdev_device(dev);
struct bes2600_btuart_data *data = serdev_device_get_drvdata(serdev);
if (data->opened) {
bes2600_btuart_wake(data->hdev, false);
if (device_may_wakeup(dev) && data->wake_irq)
enable_irq_wake(data->wake_irq);
}
return 0;
}
static int bes2600_btuart_resume(struct device *dev)
{
struct serdev_device *serdev = to_serdev_device(dev);
struct bes2600_btuart_data *data = serdev_device_get_drvdata(serdev);
if (data->opened) {
bes2600_btuart_wake(data->hdev, true);
if (device_may_wakeup(dev) && data->wake_irq)
disable_irq_wake(data->wake_irq);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(bes2600_btuart_pm_ops,
bes2600_btuart_suspend, bes2600_btuart_resume);
static int bes2600_btuart_probe(struct serdev_device *serdev)
{
struct device *dev = &serdev->dev;
struct bes2600_btuart_data *data;
struct hci_dev *hdev;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
skb_queue_head_init(&data->txq);
data->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(data->pinctrl))
return dev_err_probe(dev, PTR_ERR(data->pinctrl), "Cannot get pinctrl\n");
data->pinctrl_default = pinctrl_lookup_state(data->pinctrl, PINCTRL_STATE_DEFAULT);
if (IS_ERR(data->pinctrl_default))
return dev_err_probe(dev, PTR_ERR(data->pinctrl_default),
"Cannot get default pinctrl state\n");
data->power = devm_gpiod_get_index(dev, "power", 0, GPIOD_OUT_HIGH);
if (IS_ERR(data->power))
return dev_err_probe(dev, PTR_ERR(data->power), "Failed to get power gpio\n");
data->wakeup = devm_gpiod_get_index_optional(dev, "wakeup", 0, GPIOD_OUT_HIGH);
if (!data->wakeup)
dev_err(dev, "Failed to get wakeup gpio\n");
data->wake_irq = of_irq_get_byname(dev->of_node, "wakeup");
if (data->wake_irq <= 0) {
ret = data->wake_irq;
dev_err(dev, "Failed to get IRQ number, host will not wake up (ret=%d)\n", ret);
}
if (data->wake_irq > 0) {
ret = devm_device_init_wakeup(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to initialize device wakeup\n");
ret = devm_request_threaded_irq(dev, data->wake_irq, NULL,
bes2600_btuart_wakeup_handler,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
"bes2600_btwakeup_irq", data);
if (ret < 0)
return dev_err_probe(dev, ret, "Cannot request IRQ\n");
ret = devm_pm_set_wake_irq(dev, data->wake_irq);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to set wake irq\n");
}
data->err_count = 0;
hdev = hci_alloc_dev();
if (!hdev)
return -ENOMEM;
rwlock_init(&data->lock);
data->serdev = serdev;
data->hdev = hdev;
serdev_device_set_drvdata(serdev, data);
serdev_device_set_client_ops(serdev, &bes2600_btuart_serdev_client_ops);
bes2600_btuart_parse_dt(serdev);
INIT_WORK(&data->tx_work, bes2600_btuart_work);
hdev->bus = HCI_UART;
hci_set_drvdata(hdev, data);
hdev->open = bes2600_btuart_open;
hdev->close = bes2600_btuart_close;
hdev->flush = bes2600_btuart_flush;
hdev->setup = bes2600_btuart_setup;
hdev->shutdown = bes2600_btuart_shutdown;
hdev->send = bes2600_btuart_send_frame;
hdev->manufacturer = 0x02B0;
SET_HCIDEV_DEV(hdev, &serdev->dev);
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_STORED_LINK_KEY);
/* Firmware claims to support HCI_OP_LE_READ_BUFFER_SIZE_V2 but broken */
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_BUFFER_SIZE_V2);
/*
* Once shutdown() is ran, it turns off the Bluetooth regulator and
* would not power back on unless setup() is run again.
*/
hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP);
ret = hci_register_dev(hdev);
if (ret < 0) {
hci_free_dev(hdev);
return dev_err_probe(dev, ret, "Failed to register HCI device\n");
}
return 0;
}
static void bes2600_btuart_remove(struct serdev_device *serdev)
{
struct bes2600_btuart_data *data = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = data->hdev;
cancel_work_sync(&data->tx_work);
if (hdev) {
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
}
static const struct of_device_id bes2600_btuart_of_match[] = {
{ .compatible = "bestechnic,bes2600-btuart", },
{},
};
MODULE_DEVICE_TABLE(of, bes2600_btuart_of_match);
static struct serdev_device_driver bes2600_btuart_driver = {
.probe = bes2600_btuart_probe,
.remove = bes2600_btuart_remove,
.driver = {
.name = "bes2600_btuart",
.pm = &bes2600_btuart_pm_ops,
.of_match_table = of_match_ptr(bes2600_btuart_of_match),
},
};
module_serdev_device_driver(bes2600_btuart_driver);
MODULE_AUTHOR("Dang Huynh <dang.huynh@mainlining.org>");
MODULE_DESCRIPTION("BES2600 BT UART driver");
MODULE_LICENSE("GPL");
+26 -19
View File
@@ -12,6 +12,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/firmware.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/crc32.h> #include <linux/crc32.h>
@@ -30,6 +31,18 @@
static DEFINE_MUTEX(factory_lock); 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. * It is only used for temporary storage.
* Every time get the factory, it will read from the * Every time get the factory, it will read from the
@@ -137,38 +150,32 @@ static int bes2600_factory_crc_check(struct factory_t *factory_data)
*/ */
static int factory_section_read_file(char *path, void *buffer) static int factory_section_read_file(char *path, void *buffer)
{ {
int ret = 0; const struct firmware *fw;
struct file *fp; int ret;
if (!path || !buffer) { if (!path || !buffer) {
bes_err("%s NULL pointer err\n", __func__); bes_err("%s NULL pointer err\n", __func__);
return -1; return -1;
} }
bes_devel("reading %s \n", path); bes_devel("requesting firmware-class %s\n", path);
fp = filp_open(path, O_RDONLY, 0); //S_IRUSR ret = request_firmware(&fw, path, bes2600_factory_dev);
if (IS_ERR(fp)) { if (ret) {
bes_devel("BES2600 : can't open %s\n",path); bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret);
return -1; return -1;
} }
if (fp->f_inode->i_size <= 0 || fp->f_inode->i_size > FACTORY_MAX_SIZE) { if (fw->size == 0 || fw->size > FACTORY_MAX_SIZE) {
bes_err( "bes2600_factory.txt size check failed, read_size: %lld max_size: %d\n", bes_err("bes2600_factory.txt size check failed, read_size: %zu max_size: %d\n",
fp->f_inode->i_size, FACTORY_MAX_SIZE); fw->size, FACTORY_MAX_SIZE);
filp_close(fp, NULL); release_firmware(fw);
return -1; return -1;
} }
ret = kernel_read(fp, buffer, fp->f_inode->i_size, &fp->f_pos); memcpy(buffer, fw->data, fw->size);
ret = (int)fw->size;
filp_close(fp, NULL); release_firmware(fw);
if (ret != fp->f_inode->i_size) {
bes_err("bes2600_factory.txt read fail\n");
ret = -1;
}
return ret; return ret;
} }
+3
View File
@@ -199,6 +199,9 @@ enum factory_cali_status {
/* just calibrate 11n, other protocols are automatically mapped */ /* just calibrate 11n, other protocols are automatically mapped */
#define WIFI_RF_11N_MODE 0x15 #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*/ /* read wifi & bt factory cali value*/
u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path); u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path);
void factory_little_endian_cvrt(u8 *data); void factory_little_endian_cvrt(u8 *data);
+6 -1
View File
@@ -30,6 +30,7 @@
#include "bes2600.h" #include "bes2600.h"
#include "sbus.h" #include "sbus.h"
#include "bes2600_plat.h" #include "bes2600_plat.h"
#include "bes2600_factory.h"
#include "hwio.h" #include "hwio.h"
#include "bes_chardev.h" #include "bes_chardev.h"
#include "bes_log.h" #include "bes_log.h"
@@ -1834,6 +1835,9 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (ret) if (ret)
goto err; goto err;
/* wire struct device into factory.c for request_firmware() context */
bes2600_factory_set_dev(dev);
self->pdata = bes2600_get_platform_data(); self->pdata = bes2600_get_platform_data();
self->func = func; self->func = func;
self->dev = &func->dev; self->dev = &func->dev;
@@ -1879,6 +1883,7 @@ static int bes2600_sdio_probe(struct sdio_func *func,
out: out:
bes2600_chrdev_set_sbus_priv_data(self, false); bes2600_chrdev_set_sbus_priv_data(self, false);
bes2600_switch_bt(true);
bes2600_gpio_allow_mcu_sleep(self, GPIO_WAKE_FLAG_SDIO_PROBE); bes2600_gpio_allow_mcu_sleep(self, GPIO_WAKE_FLAG_SDIO_PROBE);
return 0; return 0;
@@ -1913,8 +1918,8 @@ int bes2600_unregister_net_dev(struct sbus_priv *bus_priv)
BUG_ON(!bus_priv); BUG_ON(!bus_priv);
if (bus_priv->core && !bus_priv->unregister_in_process) { if (bus_priv->core && !bus_priv->unregister_in_process) {
bus_priv->unregister_in_process = true; bus_priv->unregister_in_process = true;
bes2600_pwr_unregister_en_lp_cb(bus_priv->core, bes2600_sdio_en_lp_cb);
bes2600_core_release(bus_priv->core); bes2600_core_release(bus_priv->core);
bes2600_pwr_unregister_en_lp_cb(bus_priv->core, bes2600_sdio_en_lp_cb);
bus_priv->core = NULL; bus_priv->core = NULL;
if (bus_priv->sdio_wq) { if (bus_priv->sdio_wq) {
+3 -46
View File
@@ -196,7 +196,7 @@ static int bes2600_switch_wifi(bool on)
return ret; return ret;
} }
static int bes2600_switch_bt(bool on) int bes2600_switch_bt(bool on)
{ {
int ret = 0; int ret = 0;
long status = 0; long status = 0;
@@ -229,11 +229,11 @@ static int bes2600_switch_bt(bool on)
/* check if there is a error when bootup */ /* check if there is a error when bootup */
ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0; ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0;
} else { } else {
bes_devel("bes2600 activate bt.\n"); bes_info("enable BT\n");
ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_ON, SUBSYSTEM_BT, true); ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_ON, SUBSYSTEM_BT, true);
} }
} else { } else {
bes_devel("bes2600 deactivate bt.\n"); bes_info("disable BT\n");
bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_OFF, SUBSYSTEM_BT, false); bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_OFF, SUBSYSTEM_BT, false);
} }
@@ -249,47 +249,6 @@ static int bes2600_switch_bt(bool on)
return ret; return ret;
} }
/*
* This is a global function so we don't have to make many changes to
* the driver.
*
* @wifi: 1 to turn on, 0 to turn off. Otherwise, leave unchanged
* @bt: 1 to turn on, 0 to turn off. Otherwise, leave unchanged
*/
int bes2600_chrdev_switch_subsys_glb(int wifi, int bt)
{
int ret = 0;
switch (wifi) {
case 0:
ret = bes2600_switch_wifi(false);
break;
case 1:
ret = bes2600_switch_wifi(true);
break;
default:
break;
}
if (ret)
goto result;
switch (bt) {
case 0:
ret = bes2600_switch_bt(false);
break;
case 1:
ret = bes2600_switch_bt(true);
break;
default:
break;
}
result:
return ret;
}
EXPORT_SYMBOL_GPL(bes2600_chrdev_switch_subsys_glb);
static int bes2600_get_cmd_and_ifname(const char *str, char **result) static int bes2600_get_cmd_and_ifname(const char *str, char **result)
{ {
int cmd_len = 0; int cmd_len = 0;
@@ -1126,7 +1085,6 @@ void bes2600_chrdev_wakeup_bt(void)
bes_err("Wakeup BT fail in resume\n"); bes_err("Wakeup BT fail in resume\n");
} }
} }
EXPORT_SYMBOL_GPL(bes2600_chrdev_wakeup_bt);
int bes2600_chrdev_get_fw_type(void) int bes2600_chrdev_get_fw_type(void)
{ {
@@ -1148,7 +1106,6 @@ bool bes2600_chrdev_is_bus_error(void)
return error; return error;
} }
EXPORT_SYMBOL_GPL(bes2600_chrdev_is_bus_error);
void bes2600_chrdev_update_signal_mode(void) void bes2600_chrdev_update_signal_mode(void)
{ {
+2 -1
View File
@@ -63,7 +63,6 @@ int bes2600_chrdev_do_system_close(const struct sbus_ops *sbus_ops, struct sbus_
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);
int bes2600_chrdev_switch_subsys_glb(int wifi, int bt);
/* get and set internal state */ /* get and set internal state */
bool bes2600_chrdev_is_wifi_opened(void); bool bes2600_chrdev_is_wifi_opened(void);
@@ -92,4 +91,6 @@ u8* bes2600_alloc_dpd_log_buffer(u16 len);
void bes2600_get_dpd_log(char **data, size_t *len); void bes2600_get_dpd_log(char **data, size_t *len);
#endif #endif
int bes2600_switch_bt(bool);
#endif /* __BES_CHARDEV_H__ */ #endif /* __BES_CHARDEV_H__ */
+3 -10
View File
@@ -22,7 +22,6 @@
#include "debug.h" #include "debug.h"
#include "epta_coex.h" #include "epta_coex.h"
#include "bes_chardev.h" #include "bes_chardev.h"
#include "txrx_opt.h"
#include "sta.h" #include "sta.h"
#include "bes_log.h" #include "bes_log.h"
@@ -1260,8 +1259,6 @@ int bes2600_bh_sw_process(struct bes2600_common *hw_priv,
delta_time = jiffies + ((unsigned long)0xffffffff - timestamp); delta_time = jiffies + ((unsigned long)0xffffffff - timestamp);
else else
delta_time = jiffies - timestamp; delta_time = jiffies - timestamp;
bes2600_add_tx_delta_time(delta_time);
bes2600_add_tx_ac_delta_time(queue_id, delta_time);
if (bes2600_need_retry_type(skb, tx_confirm->status) == 0) if (bes2600_need_retry_type(skb, tx_confirm->status) == 0)
return -1; return -1;
@@ -1270,12 +1267,8 @@ int bes2600_bh_sw_process(struct bes2600_common *hw_priv,
return -1; return -1;
if (txpriv->retry_count < CW1200_MAX_SW_RETRY_CNT ) { if (txpriv->retry_count < CW1200_MAX_SW_RETRY_CNT ) {
struct bes2600_vif *priv =
__cw12xx_hwpriv_to_vifpriv(hw_priv, txpriv->if_id);
txpriv->retry_count++; txpriv->retry_count++;
bes2600_tx_status(priv,skb);
bes2600_pwr_set_busy_event_with_timeout_async( bes2600_pwr_set_busy_event_with_timeout_async(
hw_priv, BES_PWR_LOCK_ON_TX, BES_PWR_EVENT_TX_TIMEOUT); hw_priv, BES_PWR_LOCK_ON_TX, BES_PWR_EVENT_TX_TIMEOUT);
@@ -1311,14 +1304,14 @@ void bes2600_bh_dec_pending_count(struct bes2600_common *hw_priv, int idx)
} }
if (--hw_priv->wsm_tx_pending[idx] == 0) if (--hw_priv->wsm_tx_pending[idx] == 0)
timer_delete_sync(timer); del_timer_sync(timer);
else else
mod_timer(timer, jiffies + 3 * HZ); mod_timer(timer, jiffies + 3 * HZ);
} }
void bes2600_bh_mcu_active_monitor(struct timer_list* t) void bes2600_bh_mcu_active_monitor(struct timer_list* t)
{ {
struct bes2600_common *hw_priv = timer_container_of(hw_priv, t, mcu_mon_timer); struct bes2600_common *hw_priv = from_timer(hw_priv, t, mcu_mon_timer);
bes_err("link break between mcu and host, hw_buf_used:%d pending:%d\n", bes_err("link break between mcu and host, hw_buf_used:%d pending:%d\n",
hw_priv->hw_bufs_used, hw_priv->wsm_tx_pending[1]); hw_priv->hw_bufs_used, hw_priv->wsm_tx_pending[1]);
@@ -1327,7 +1320,7 @@ void bes2600_bh_mcu_active_monitor(struct timer_list* t)
void bes2600_bh_lmac_active_monitor(struct timer_list* t) void bes2600_bh_lmac_active_monitor(struct timer_list* t)
{ {
struct bes2600_common *hw_priv = timer_container_of(hw_priv, t, lmac_mon_timer); struct bes2600_common *hw_priv = from_timer(hw_priv, t, lmac_mon_timer);
bes_err("link break between lmac and host, hw_buf_used:%d pending:%d\n", bes_err("link break between lmac and host, hw_buf_used:%d pending:%d\n",
hw_priv->hw_bufs_used, hw_priv->wsm_tx_pending[0]); hw_priv->hw_bufs_used, hw_priv->wsm_tx_pending[0]);
-154
View File
@@ -1,154 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copy of drivers/bluetooth/h4_recv.h
*
* Generic Bluetooth HCI UART driver
*
* Copyright (C) 2015-2018 Intel Corporation
*/
#include <linux/unaligned.h>
struct h4_recv_pkt {
u8 type; /* Packet type */
u8 hlen; /* Header length */
u8 loff; /* Data length offset in header */
u8 lsize; /* Data length field size */
u16 maxlen; /* Max overall packet length */
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
};
#define H4_RECV_ACL \
.type = HCI_ACLDATA_PKT, \
.hlen = HCI_ACL_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE \
#define H4_RECV_SCO \
.type = HCI_SCODATA_PKT, \
.hlen = HCI_SCO_HDR_SIZE, \
.loff = 2, \
.lsize = 1, \
.maxlen = HCI_MAX_SCO_SIZE
#define H4_RECV_EVENT \
.type = HCI_EVENT_PKT, \
.hlen = HCI_EVENT_HDR_SIZE, \
.loff = 1, \
.lsize = 1, \
.maxlen = HCI_MAX_EVENT_SIZE
#define H4_RECV_ISO \
.type = HCI_ISODATA_PKT, \
.hlen = HCI_ISO_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE
static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
struct sk_buff *skb,
const unsigned char *buffer,
int count,
const struct h4_recv_pkt *pkts,
int pkts_count)
{
/* Check for error from previous call */
if (IS_ERR(skb))
skb = NULL;
while (count) {
int i, len;
if (!skb) {
for (i = 0; i < pkts_count; i++) {
if (buffer[0] != (&pkts[i])->type)
continue;
skb = bt_skb_alloc((&pkts[i])->maxlen,
GFP_ATOMIC);
if (!skb)
return ERR_PTR(-ENOMEM);
hci_skb_pkt_type(skb) = (&pkts[i])->type;
hci_skb_expect(skb) = (&pkts[i])->hlen;
break;
}
/* Check for invalid packet type */
if (!skb)
return ERR_PTR(-EILSEQ);
count -= 1;
buffer += 1;
}
len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
skb_put_data(skb, buffer, len);
count -= len;
buffer += len;
/* Check for partial packet */
if (skb->len < hci_skb_expect(skb))
continue;
for (i = 0; i < pkts_count; i++) {
if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
break;
}
if (i >= pkts_count) {
kfree_skb(skb);
return ERR_PTR(-EILSEQ);
}
if (skb->len == (&pkts[i])->hlen) {
u16 dlen;
switch ((&pkts[i])->lsize) {
case 0:
/* No variable data length */
dlen = 0;
break;
case 1:
/* Single octet variable length */
dlen = skb->data[(&pkts[i])->loff];
hci_skb_expect(skb) += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
return ERR_PTR(-EMSGSIZE);
}
break;
case 2:
/* Double octet variable length */
dlen = get_unaligned_le16(skb->data +
(&pkts[i])->loff);
hci_skb_expect(skb) += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
return ERR_PTR(-EMSGSIZE);
}
break;
default:
/* Unsupported variable length */
kfree_skb(skb);
return ERR_PTR(-EILSEQ);
}
if (!dlen) {
/* No more data, complete frame */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
}
} else {
/* Complete frame */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
}
}
return skb;
}
+4 -9
View File
@@ -32,7 +32,6 @@
#include "pm.h" #include "pm.h"
#include "bes2600_factory.h" #include "bes2600_factory.h"
#include "bes_chardev.h" #include "bes_chardev.h"
#include "txrx_opt.h"
MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>"); MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>");
MODULE_DESCRIPTION("Softmac BES2600 common code"); MODULE_DESCRIPTION("Softmac BES2600 common code");
@@ -199,11 +198,7 @@ static const struct ieee80211_iface_limit bes2600_if_limits[] = {
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) }, BIT(NL80211_IFTYPE_P2P_GO) },
#ifdef P2P_MULTIVIF #ifdef P2P_MULTIVIF
/* { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
* HACK: Disable P2P_DEVICE implementation for BES2600
* as the code is a little buggy.
*/
//{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
#endif #endif
}; };
@@ -598,7 +593,7 @@ static void bes2600_unregister_common(struct ieee80211_hw *dev)
ieee80211_unregister_hw(dev); ieee80211_unregister_hw(dev);
timer_delete_sync(&hw_priv->ba_timer); del_timer_sync(&hw_priv->ba_timer);
hw_priv->sbus_ops->irq_unsubscribe(hw_priv->sbus_priv); hw_priv->sbus_ops->irq_unsubscribe(hw_priv->sbus_priv);
bes2600_unregister_bh(hw_priv); bes2600_unregister_bh(hw_priv);
@@ -901,8 +896,8 @@ int bes2600_wifi_stop(struct bes2600_common *hw_priv)
hw_priv->wsm_tx_seq[1] = 0; hw_priv->wsm_tx_seq[1] = 0;
hw_priv->wsm_tx_pending[0] = 0; hw_priv->wsm_tx_pending[0] = 0;
hw_priv->wsm_tx_pending[1] = 0; hw_priv->wsm_tx_pending[1] = 0;
timer_delete_sync(&hw_priv->mcu_mon_timer); del_timer_sync(&hw_priv->mcu_mon_timer);
timer_delete_sync(&hw_priv->lmac_mon_timer); del_timer_sync(&hw_priv->lmac_mon_timer);
#ifdef CONFIG_BES2600_STATIC_SDD #ifdef CONFIG_BES2600_STATIC_SDD
hw_priv->sdd = NULL; hw_priv->sdd = NULL;
#else #else
+10 -8
View File
@@ -119,9 +119,10 @@ static void bes2600_queue_register_post_gc(struct list_head *gc_list,
struct bes2600_queue_item *item) struct bes2600_queue_item *item)
{ {
struct bes2600_queue_item *gc_item; struct bes2600_queue_item *gc_item;
gc_item = kmemdup(item, sizeof(struct bes2600_queue_item), gc_item = kmalloc(sizeof(struct bes2600_queue_item),
GFP_ATOMIC); GFP_ATOMIC);
BUG_ON(!gc_item); BUG_ON(!gc_item);
memcpy(gc_item, item, sizeof(struct bes2600_queue_item));
list_add_tail(&gc_item->head, gc_list); list_add_tail(&gc_item->head, gc_list);
} }
@@ -130,9 +131,9 @@ static void bes2600_queue_pending_record(struct list_head *pending_record_list,
{ {
struct bes2600_queue_item *record_item; struct bes2600_queue_item *record_item;
record_item = kmemdup(pending_item, sizeof(struct bes2600_queue_item), record_item = kmalloc(sizeof(struct bes2600_queue_item),GFP_ATOMIC);
GFP_ATOMIC);
BUG_ON(!record_item); BUG_ON(!record_item);
memcpy(record_item, pending_item, sizeof(struct bes2600_queue_item));
record_item->skb = skb_clone(pending_item->skb, GFP_ATOMIC); record_item->skb = skb_clone(pending_item->skb, GFP_ATOMIC);
list_add_tail(&record_item->head, pending_record_list); list_add_tail(&record_item->head, pending_record_list);
} }
@@ -195,7 +196,7 @@ static void __bes2600_queue_gc(struct bes2600_queue *queue,
static void bes2600_queue_gc(struct timer_list *t) static void bes2600_queue_gc(struct timer_list *t)
{ {
LIST_HEAD(list); LIST_HEAD(list);
struct bes2600_queue *queue = timer_container_of(queue, t, gc); struct bes2600_queue *queue = from_timer(queue, t, gc);
spin_lock_bh(&queue->lock); spin_lock_bh(&queue->lock);
__bes2600_queue_gc(queue, &list, true); __bes2600_queue_gc(queue, &list, true);
@@ -217,7 +218,7 @@ int bes2600_queue_stats_init(struct bes2600_queue_stats *stats,
spin_lock_init(&stats->lock); spin_lock_init(&stats->lock);
init_waitqueue_head(&stats->wait_link_id_empty); init_waitqueue_head(&stats->wait_link_id_empty);
for (i = 0; i < CW12XX_MAX_VIFS; i++) { for (i = 0; i < CW12XX_MAX_VIFS; i++) {
stats->link_map_cache[i] = kcalloc(map_capacity, sizeof(int), stats->link_map_cache[i] = kzalloc(map_capacity * sizeof(int),
GFP_KERNEL); GFP_KERNEL);
if (!stats->link_map_cache[i]) { if (!stats->link_map_cache[i]) {
for (; i >= 0; i--) for (; i >= 0; i--)
@@ -248,14 +249,14 @@ int bes2600_queue_init(struct bes2600_queue *queue,
queue->queue_all_lock = false; queue->queue_all_lock = false;
spin_lock_init(&queue->lock); spin_lock_init(&queue->lock);
timer_setup(&queue->gc, bes2600_queue_gc, 0); timer_setup(&queue->gc, bes2600_queue_gc, 0);
queue->pool = kcalloc(capacity, sizeof(struct bes2600_queue_item), queue->pool = kzalloc(sizeof(struct bes2600_queue_item) * capacity,
GFP_KERNEL); GFP_KERNEL);
if (!queue->pool) if (!queue->pool)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < CW12XX_MAX_VIFS; i++) { for (i = 0; i < CW12XX_MAX_VIFS; i++) {
queue->link_map_cache[i] = queue->link_map_cache[i] =
kcalloc(stats->map_capacity, sizeof(int), kzalloc(stats->map_capacity * sizeof(int),
GFP_KERNEL); GFP_KERNEL);
if (!queue->link_map_cache[i]) { if (!queue->link_map_cache[i]) {
for (; i >= 0; i--) for (; i >= 0; i--)
@@ -362,7 +363,7 @@ void bes2600_queue_deinit(struct bes2600_queue *queue)
int i; int i;
bes2600_queue_clear(queue, CW12XX_ALL_IFS); bes2600_queue_clear(queue, CW12XX_ALL_IFS);
timer_delete_sync(&queue->gc); del_timer_sync(&queue->gc);
INIT_LIST_HEAD(&queue->free_pool); INIT_LIST_HEAD(&queue->free_pool);
kfree(queue->pool); kfree(queue->pool);
for (i = 0; i < CW12XX_MAX_VIFS; i++) { for (i = 0; i < CW12XX_MAX_VIFS; i++) {
@@ -409,6 +410,7 @@ int bes2600_queue_put(struct bes2600_queue *queue,
struct timespec64 tmval; struct timespec64 tmval;
#endif /*CONFIG_BES2600_TESTMODE*/ #endif /*CONFIG_BES2600_TESTMODE*/
LIST_HEAD(gc_list);
struct bes2600_queue_stats *stats = queue->stats; struct bes2600_queue_stats *stats = queue->stats;
/* TODO:COMBO: Add interface ID info to queue item */ /* TODO:COMBO: Add interface ID info to queue item */
+5 -6
View File
@@ -533,10 +533,10 @@ void bes2600_scan_work(struct work_struct *work)
"[SCAN] Scan failed (%d).\n", "[SCAN] Scan failed (%d).\n",
hw_priv->scan.status); hw_priv->scan.status);
else if (hw_priv->scan.req) else if (hw_priv->scan.req)
wiphy_dbg(priv->hw->wiphy, wiphy_info(priv->hw->wiphy,
"[SCAN] Scan completed.\n"); "[SCAN] Scan completed.\n");
else else
wiphy_dbg(priv->hw->wiphy, wiphy_info(priv->hw->wiphy,
"[SCAN] Scan canceled.\n"); "[SCAN] Scan canceled.\n");
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE #ifdef WIFI_BT_COEXIST_EPTA_ENABLE
@@ -621,9 +621,8 @@ void bes2600_scan_work(struct work_struct *work)
scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.scanType = WSM_SCAN_TYPE_BACKGROUND;
scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND;
} }
scan.ch = kcalloc((it - hw_priv->scan.curr), scan.ch = kzalloc((it - hw_priv->scan.curr) *
sizeof(struct wsm_scan_ch), sizeof(struct wsm_scan_ch), GFP_KERNEL);
GFP_KERNEL);
if (!scan.ch) { if (!scan.ch) {
hw_priv->scan.status = -ENOMEM; hw_priv->scan.status = -ENOMEM;
goto fail; goto fail;
@@ -906,7 +905,7 @@ void bes2600_scan_complete_cb(struct bes2600_common *hw_priv,
// recover EPTA timer after scan wsm msg complete, in case of epta state error // recover EPTA timer after scan wsm msg complete, in case of epta state error
// bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING_COMP); // bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING_COMP);
#endif #endif
wiphy_dbg(hw_priv->hw->wiphy, "bes2600_scan_complete_cb status: %u", arg->status); wiphy_info(hw_priv->hw->wiphy, "bes2600_scan_complete_cb status: %u", arg->status);
if(hw_priv->scan.status == -ETIMEDOUT) if(hw_priv->scan.status == -ETIMEDOUT)
wiphy_warn(hw_priv->hw->wiphy, wiphy_warn(hw_priv->hw->wiphy,
+8 -29
View File
@@ -42,8 +42,6 @@
#include "bes2600_factory.h" #include "bes2600_factory.h"
#endif #endif
#include "txrx_opt.h"
#define WEP_ENCRYPT_HDR_SIZE 4 #define WEP_ENCRYPT_HDR_SIZE 4
#define WEP_ENCRYPT_TAIL_SIZE 4 #define WEP_ENCRYPT_TAIL_SIZE 4
#define WPA_ENCRYPT_HDR_SIZE 8 #define WPA_ENCRYPT_HDR_SIZE 8
@@ -221,7 +219,7 @@ void bes2600_stop(struct ieee80211_hw *dev, bool suspend)
cancel_delayed_work_sync(&hw_priv->advance_scan_timeout); cancel_delayed_work_sync(&hw_priv->advance_scan_timeout);
#endif #endif
flush_workqueue(hw_priv->workqueue); flush_workqueue(hw_priv->workqueue);
timer_delete_sync(&hw_priv->ba_timer); del_timer_sync(&hw_priv->ba_timer);
down(&hw_priv->conf_lock); down(&hw_priv->conf_lock);
@@ -261,7 +259,7 @@ void bes2600_stop(struct ieee80211_hw *dev, bool suspend)
cancel_delayed_work_sync(&priv->bss_loss_work); cancel_delayed_work_sync(&priv->bss_loss_work);
cancel_delayed_work_sync(&priv->connection_loss_work); cancel_delayed_work_sync(&priv->connection_loss_work);
cancel_delayed_work_sync(&priv->link_id_gc_work); cancel_delayed_work_sync(&priv->link_id_gc_work);
timer_delete_sync(&priv->mcast_timeout); del_timer_sync(&priv->mcast_timeout);
} }
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE #ifdef WIFI_BT_COEXIST_EPTA_ENABLE
@@ -377,23 +375,9 @@ void bes2600_remove_interface(struct ieee80211_hw *dev,
atomic_set(&priv->enabled, 0); atomic_set(&priv->enabled, 0);
down(&hw_priv->scan.lock); down(&hw_priv->scan.lock);
down(&hw_priv->conf_lock); down(&hw_priv->conf_lock);
if (!__cw12xx_hwpriv_to_vifpriv(hw_priv, priv->if_id)) {
/*
* There's a chance remove_interface will run again on the same
* (already removed) interface.
*
* Currently this only happens when NetworkManager creates a P2P_DEVICE
* alongside a STA.
*
* But there can be other cases where this may run as well. So if that
* happens, let's throw a warning and decrease the vifs count by one.
*/
if (WARN_ON(!__cw12xx_hwpriv_to_vifpriv(hw_priv, priv->if_id))) {
bes_devel(" !!! %s: interface addr %pM already removed\n", bes_devel(" !!! %s: interface addr %pM already removed\n",
__func__, vif->addr); __func__, vif->addr);
atomic_dec(&hw_priv->num_vifs);
up(&hw_priv->conf_lock); up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock); up(&hw_priv->scan.lock);
return; return;
@@ -465,7 +449,7 @@ void bes2600_remove_interface(struct ieee80211_hw *dev,
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);
timer_delete_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
* join_status to default can be removed as dev_priv will be freed by * join_status to default can be removed as dev_priv will be freed by
* mac80211 */ * mac80211 */
@@ -518,7 +502,7 @@ int bes2600_change_interface(struct ieee80211_hw *dev,
return ret; return ret;
} }
int bes2600_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) int bes2600_config(struct ieee80211_hw *dev, u32 changed)
{ {
int ret = 0; int ret = 0;
struct bes2600_common *hw_priv = dev->priv; struct bes2600_common *hw_priv = dev->priv;
@@ -1153,7 +1137,7 @@ void bes2600_wep_key_work(struct work_struct *work)
wsm_unlock_tx(hw_priv); wsm_unlock_tx(hw_priv);
} }
int bes2600_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value) int bes2600_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{ {
struct bes2600_common *hw_priv = hw->priv; struct bes2600_common *hw_priv = hw->priv;
int ret; int ret;
@@ -2185,8 +2169,6 @@ void bes2600_join_work(struct work_struct *work)
wsm_unlock_tx(hw_priv); wsm_unlock_tx(hw_priv);
return; return;
} }
rcu_read_lock();
ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
dtimie = ieee80211_bss_get_ie(bss, WLAN_EID_TIM); dtimie = ieee80211_bss_get_ie(bss, WLAN_EID_TIM);
if (dtimie) if (dtimie)
@@ -2270,8 +2252,6 @@ void bes2600_join_work(struct work_struct *work)
bes2600_rate_mask_to_wsm(hw_priv, 0xFF0); bes2600_rate_mask_to_wsm(hw_priv, 0xFF0);
} }
rcu_read_unlock();
bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_JOIN); bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_JOIN);
wsm_flush_tx(hw_priv); wsm_flush_tx(hw_priv);
@@ -2378,7 +2358,7 @@ void bes2600_unjoin_work(struct work_struct *work)
int i; int i;
struct bes2600_vif *tmp_priv; struct bes2600_vif *tmp_priv;
timer_delete_sync(&hw_priv->ba_timer); del_timer_sync(&hw_priv->ba_timer);
down(&hw_priv->conf_lock); down(&hw_priv->conf_lock);
if (unlikely(atomic_read(&hw_priv->scan.in_progress) if (unlikely(atomic_read(&hw_priv->scan.in_progress)
|| atomic_read(&priv->connect_in_process))) { || atomic_read(&priv->connect_in_process))) {
@@ -2587,7 +2567,7 @@ void bes2600_ba_work(struct work_struct *work)
void bes2600_ba_timer(struct timer_list *t) void bes2600_ba_timer(struct timer_list *t)
{ {
bool ba_ena; bool ba_ena;
struct bes2600_common *hw_priv = timer_container_of(hw_priv, t, ba_timer); struct bes2600_common *hw_priv = from_timer(hw_priv, t, ba_timer);
spin_lock_bh(&hw_priv->ba_lock); spin_lock_bh(&hw_priv->ba_lock);
bes2600_debug_ba(hw_priv, hw_priv->ba_cnt, hw_priv->ba_acc, bes2600_debug_ba(hw_priv, hw_priv->ba_cnt, hw_priv->ba_acc,
@@ -2809,7 +2789,6 @@ void bes2600_dynamic_opt_txrx_work(struct work_struct *work)
if (priv != NULL && priv->join_status > BES2600_JOIN_STATUS_MONITOR) { if (priv != NULL && priv->join_status > BES2600_JOIN_STATUS_MONITOR) {
multivif_connected = true; multivif_connected = true;
} }
bes2600_txrx_opt_multivif_connected_handler(hw_priv, multivif_connected);
} }
+2 -2
View File
@@ -26,7 +26,7 @@ int bes2600_change_interface(struct ieee80211_hw *dev,
enum nl80211_iftype new_type, enum nl80211_iftype new_type,
bool p2p); bool p2p);
int bes2600_config(struct ieee80211_hw *dev, int radio_idx, u32 changed); int bes2600_config(struct ieee80211_hw *dev, u32 changed);
int bes2600_change_interface(struct ieee80211_hw *dev, int bes2600_change_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum nl80211_iftype new_type, enum nl80211_iftype new_type,
@@ -48,7 +48,7 @@ int bes2600_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key); struct ieee80211_key_conf *key);
int bes2600_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value); int bes2600_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
void bes2600_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void bes2600_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop); u32 queues, bool drop);
+1 -24
View File
@@ -21,7 +21,6 @@
#include "debug.h" #include "debug.h"
#include "sta.h" #include "sta.h"
#include "sbus.h" #include "sbus.h"
#include "txrx_opt.h"
#include "bes_log.h" #include "bes_log.h"
#define BES2600_INVALID_RATE_ID (0xFF) #define BES2600_INVALID_RATE_ID (0xFF)
@@ -1474,35 +1473,14 @@ void bes2600_skb_dtor(struct bes2600_common *hw_priv,
struct bes2600_vif *priv = struct bes2600_vif *priv =
__cw12xx_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); __cw12xx_hwpriv_to_vifpriv(hw_priv, txpriv->if_id);
if (!skb)
return;
/*
* There should be no reason for skb buffer being larger
* than the offset..
*/
if(WARN_ON(txpriv->offset > skb->len)) {
ieee80211_free_txskb(hw_priv->hw, skb);
return;
}
bes_devel("%s: txpriv->offset: %d - skb->len: %d\n",
__func__, txpriv->offset, skb->len);
skb_pull(skb, txpriv->offset); skb_pull(skb, txpriv->offset);
if (priv && txpriv->rate_id != BES2600_INVALID_RATE_ID) { if (priv && txpriv->rate_id != BES2600_INVALID_RATE_ID) {
bes2600_notify_buffered_tx(priv, skb, bes2600_notify_buffered_tx(priv, skb,
txpriv->raw_link_id, txpriv->tid); txpriv->raw_link_id, txpriv->tid);
tx_policy_put(hw_priv, txpriv->rate_id); tx_policy_put(hw_priv, txpriv->rate_id);
} }
if (likely(!bes2600_is_itp(hw_priv))) { if (likely(!bes2600_is_itp(hw_priv)))
if (priv) {
/* The interface may be already removed */
bes2600_tx_status(priv, skb);
}
ieee80211_tx_status_skb(hw_priv->hw, skb); ieee80211_tx_status_skb(hw_priv->hw, skb);
}
} }
#ifdef CONFIG_BES2600_TESTMODE #ifdef CONFIG_BES2600_TESTMODE
@@ -1871,7 +1849,6 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
if (ieee80211_is_data(frame->frame_control)) { if (ieee80211_is_data(frame->frame_control)) {
bes2600_rx_h_ba_stat(priv, hdrlen, skb->len); bes2600_rx_h_ba_stat(priv, hdrlen, skb->len);
bes2600_rx_status(priv, skb);
} }
#ifdef CONFIG_BES2600_TESTMODE #ifdef CONFIG_BES2600_TESTMODE
-569
View File
@@ -1,569 +0,0 @@
/***************************************************************************
*
* Copyright 2015-2022 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include "bes2600.h"
#include "wsm.h"
#include "bh.h"
#include "ap.h"
#include "debug.h"
#include "sta.h"
#include "sbus.h"
#include "bes_pwr.h"
#include "txrx_opt.h"
#define TXRX_OPT_CLOSE_EDCA 0
#define TXRX_OPT_EDCA_MAX_LEVEL 4
#define TX_AVG_TIME_COUNT 10
#define TXRX_OPT_PEROID 500
#define TXRX_OPT_DEBUG 1
#define TXRX_HIGH_TP_THRESHOLD_2G4 30000 // unit is kbps
#define TXRX_HIGH_TP_THRESHOLD_5G 40000 // unit is kbps
#define TXRX_HIGH_TP_DELTA_TIME_2G4 8 // unit ms
#define TXRX_HIGH_TP_DELTA_TIME_5G 6 // unit ms
#define TXRX_RTS_PROT_TRIG_THRESH 80 // percent * 100
#define TXRX_RTS_PROT_DURATION 10 // unit second
#define TXRX_RTS_PROT_OPEN(x) (x = 512)
#define TXRX_RTS_PROT_CLOSE(x) (x = 2437)
#define TXRX_RTS_PROT_OPENED(x) (x < 1536)
static uint32_t tx_delta_time_arr[4][TX_AVG_TIME_COUNT];
static uint32_t tx_queue_arr[4] = {0};
static uint32_t tx_delta_time_total = 0;
static uint32_t tx_delta_time_total_cnt = 0;
static u8 cur_pwr_tbl = 1;
static u16 cur_rts_thres = 2437;
static unsigned long last_rts_set_time = -1;
void bes2600_add_tx_delta_time(uint32_t tx_delta_time)
{
tx_delta_time_total += tx_delta_time;
tx_delta_time_total_cnt++;
}
static uint32_t bes2600_get_tx_delta_time(void)
{
if (tx_delta_time_total_cnt != 0)
return tx_delta_time_total / tx_delta_time_total_cnt;
else
return 0;
}
static void bes2600_clear_tx_delta_time(void)
{
tx_delta_time_total_cnt = 0;
tx_delta_time_total = 0;
return ;
}
static uint32_t bes2600_get_tx_ac_delta_time(int ac)
{
uint32_t avg_time = 0;
int i = 0;
for (i = 0; i < TX_AVG_TIME_COUNT; i++) {
avg_time += tx_delta_time_arr[ac][i];
}
return avg_time / TX_AVG_TIME_COUNT;
}
static void bes2600_clear_tx_ac_delta_time(int ac)
{
int i = 0;
for (i = 0; i < TX_AVG_TIME_COUNT; i++) {
tx_delta_time_arr[ac][i] = 0;
}
return ;
}
void bes2600_add_tx_ac_delta_time(int ac, uint32_t del_time)
{
#if 0
if (tx_queue_arr[ac] >= (TX_AVG_TIME_COUNT - 1)) {
static int num = 0;
if ((num ++ % 10) == 0)
bes_devel( "%s %d %d %d %d %d del=%d\n\r", __func__, tx_delta_time_arr[ac][0],
tx_delta_time_arr[ac][2], tx_delta_time_arr[ac][4], tx_delta_time_arr[ac][6],
tx_delta_time_arr[ac][8], del_time);
}
#endif
tx_delta_time_arr[ac][tx_queue_arr[ac]] = del_time;
tx_queue_arr[ac] = (tx_queue_arr[ac] >= (TX_AVG_TIME_COUNT - 1)) ? 0 : (tx_queue_arr[ac] + 1);
}
static int bes2600_set_txrx_opt_param(struct bes2600_common *hw_priv,
struct bes2600_vif *priv,
MIB_TXRX_OPT_PARAM *para)
{
int ret = 0;
ret = WARN_ON(wsm_write_mib(hw_priv,
WSM_MIB_ID_EXT_TXRX_OPT_PARAM,
(u8 *)para,
sizeof(MIB_TXRX_OPT_PARAM),
priv->if_id));
return ret;
}
static int bes2600_enable_tx_shortgi(struct bes2600_common *hw_priv,
struct bes2600_vif *priv,
u8 onoff)
{
int ret = 0;
static u8 en = 0xff;
bes_devel( "%s onoff=%d\n\r", __func__, onoff);
if (en != onoff) {
en = onoff;
ret = WARN_ON(wsm_write_mib(hw_priv,
WSM_MIB_ID_EXT_TX_SHORT_GI_ENABLED,
(u8 *)&onoff,
sizeof(onoff),
priv->if_id));
}
return ret;
}
void bes2600_rx_status(struct bes2600_vif *priv, struct sk_buff *skb)
{
priv->dot11ReceivedFragmentCount++;
priv->dot11ReceivedDataBytes += skb->len;
}
void bes2600_tx_status(struct bes2600_vif *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int i;
int retry_count = -1;
if(WARN_ON(!priv->hw))
return;
if (!ieee80211_is_data(hdr->frame_control))
return;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
if (info->status.rates[i].idx < 0)
break;
retry_count += info->status.rates[i].count;
}
if (retry_count < 0)
retry_count = 0;
if (info->flags & IEEE80211_TX_STAT_ACK) {
priv->dot11TransmittedFrameCount++;
priv->dot11TransmittedDataBytes += (skb->len + 4);
if (retry_count > 0)
priv->dot11RetryCount += retry_count;
} else {
/* tx fail.*/
priv->dot11FailedCount++;
}
}
void bes2600_set_default_params(struct bes2600_common *hw_priv, struct bes2600_vif *priv);
static int bes2600_set_high_edca_params(struct bes2600_common *hw_priv, struct bes2600_vif *priv, int level)
{
struct wsm_edca_params arg;
int i = 0;
static int lev = 0;
bes_devel( "set edca level=%d\n\r", level);
if (lev == level)
return 0;
lev = level;
memcpy(&arg, &(priv->edca), sizeof(struct wsm_edca_params));
if (level == 0) {
bes2600_set_default_params(hw_priv, priv);
return 0;
} else if (level == 1) {
for ( i = 0; i < 4; i++) {
arg.params[i].aifns = 2;
arg.params[i].cwMax = 7;
arg.params[i].cwMin = 3;
/*
* tx op must set 0
* set other, some AP may not response BA when rx data.
*/
arg.params[i].txOpLimit = 0;
arg.params[i].maxReceiveLifetime = 0xc8;
}
} else if (level == 2) {
for ( i = 0; i < 4; i++) {
arg.params[i].aifns = 2;
arg.params[i].cwMax = 5;
arg.params[i].cwMin = 1;
arg.params[i].txOpLimit = 0;
arg.params[i].maxReceiveLifetime = 0xc8;
}
} else if (level == 3) {
for ( i = 0; i < 4; i++) {
arg.params[i].aifns = 2;
arg.params[i].cwMax = 3;
arg.params[i].cwMin = 1;
arg.params[i].txOpLimit = 0;
arg.params[i].maxReceiveLifetime = 0xc8;
}
} else if (level == 4) {
for ( i = 0; i < 4; i++) {
arg.params[i].aifns = 1;
arg.params[i].cwMax = 3;
arg.params[i].cwMin = 1;
arg.params[i].txOpLimit = 0;
arg.params[i].maxReceiveLifetime = 0xc8;
}
}
wsm_set_edca_params(hw_priv, &arg, priv->if_id);
return 0;
}
void bes2600_set_default_params(struct bes2600_common *hw_priv, struct bes2600_vif *priv)
{
bes_devel( "set edca default\n\r");
wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id);
}
static void bes2600_set_cca_method(struct bes2600_common *hw_priv, struct bes2600_vif *priv, int value)
{
// todo set cca alg
}
static void bes2600_set_dynamic_agc(struct bes2600_common *hw_priv, struct bes2600_vif *priv, int value)
{
// todo set agc alg
}
static int bes2600_update_pwr_table(struct bes2600_common *hw_priv,
struct bes2600_vif *priv,
u8 pwr_tbl_idx)
{
int ret = 0;
static u8 cur_pwr_tbl_idx = 0xff;
if (cur_pwr_tbl_idx != pwr_tbl_idx) {
cur_pwr_tbl_idx = pwr_tbl_idx;
ret = WARN_ON(wsm_write_mib(hw_priv,
WSM_MIB_ID_EXT_PWR_TBL_UPDATE,
(u8 *)&cur_pwr_tbl_idx,
sizeof(cur_pwr_tbl_idx),
priv->if_id));
bes_devel( "%s pwr_tbl_idx=%d\n\r", __func__, pwr_tbl_idx);
}
return ret;
}
static int bes2600_get_tx_av_max_delta_time(void)
{
int max_avg = 0;
int i = 0;
for (i = 0; i < 4; i++) {
if (max_avg < bes2600_get_tx_ac_delta_time(i)) {
max_avg = bes2600_get_tx_ac_delta_time(i);
}
//bes2600_clear_tx_ac_delta_time(i);
}
return max_avg;
}
static bool bes2600_station_is_ap_ht40(struct bes2600_common *hw_priv)
{
if (hw_priv->hw) {
struct ieee80211_conf *conf = &hw_priv->hw->conf;
if (conf != NULL)
if (conf->chandef.width == NL80211_CHAN_WIDTH_40)
return true;
}
return false;
}
void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif *priv, int rssi)
{
u32 succPro = 0, tx_cnt, tx_retry, rx_cnt, tx_fail;
static u32 l_tx_cnt = 0, l_tx_fail = 0, l_tx_retry = 0, l_rx_cnt = 0;
static u32 tx_bps = 0, rx_bps = 0;
u32 total_kbps = 0;
static int level;
/* calculate real time throughput */
if (hw_priv == NULL || priv == NULL) {
return;
}
tx_bps = abs (priv->dot11TransmittedDataBytes - tx_bps);
rx_bps = abs (priv->dot11ReceivedDataBytes - rx_bps);
total_kbps = (tx_bps / 128 + rx_bps / 128);
total_kbps *= 1000;
total_kbps /= TXRX_OPT_PEROID;
/* if tx/rx < 100k/s, close*/
if (total_kbps < 100) {
level = 0;
last_rts_set_time = -1;
TXRX_RTS_PROT_CLOSE(cur_rts_thres);
goto txrx_opt_clear;
}
/* calculate tx_cnt, tx_retry, rx_cnt */
tx_cnt = (priv->dot11TransmittedFrameCount - l_tx_cnt);
tx_fail = (priv->dot11FailedCount - l_tx_fail);
tx_retry = (priv->dot11RetryCount - l_tx_retry);
rx_cnt = (priv->dot11ReceivedFragmentCount - l_rx_cnt);
( (tx_cnt + tx_retry) > 0 ) ? (succPro = tx_cnt * 100 / (tx_cnt + tx_retry)) : (succPro = 0);
bes_devel( "%s, tx_cnt:%d prob:%d\n", __func__, tx_cnt, succPro);
/* set rts/cts protection dynamically */
if (tx_cnt > 50 && succPro != 0) {
if (succPro > TXRX_RTS_PROT_TRIG_THRESH &&
TXRX_RTS_PROT_OPENED(cur_rts_thres) &&
time_after(jiffies, last_rts_set_time + TXRX_RTS_PROT_DURATION * HZ)) {
TXRX_RTS_PROT_CLOSE(cur_rts_thres);
} else if (succPro <= TXRX_RTS_PROT_TRIG_THRESH){
TXRX_RTS_PROT_OPEN(cur_rts_thres);
last_rts_set_time = jiffies;
}
}
/* dynamic set edca param */
if (succPro != 0) {
if (bes2600_station_is_ap_ht40(hw_priv)) {
if (bes2600_get_tx_delta_time() > 8 || bes2600_get_tx_av_max_delta_time() > 8) {
if (level < 4)
level++;
} else {
if (level > 0)
level--;
}
/* high throughput force level = 0 */
if (total_kbps > TXRX_HIGH_TP_THRESHOLD_5G && level > 0 && priv->hw_value > 19) {
level = 0;
}
} else {//shiled room 13, office 8
if (bes2600_get_tx_delta_time() > (TXRX_HIGH_TP_DELTA_TIME_5G + total_kbps / 8000)
|| bes2600_get_tx_av_max_delta_time() > (TXRX_HIGH_TP_DELTA_TIME_5G + total_kbps / 8000)) {
if (level < 4)
level++;
} else {
if (level > 0)
level--;
}
/* high throughput force level = 0 */
if (total_kbps > TXRX_HIGH_TP_THRESHOLD_2G4 && level > 0) {
level = 0;
}
}
}
/* dynamic set power table */
if (rssi <= BES2600_TX_RSSI_LOW)
cur_pwr_tbl = 2; // use high power table
else if(rssi >= BES2600_TX_RSSI_HIGH)
cur_pwr_tbl = 1; // use standard power table
#if TXRX_OPT_CLOSE_EDCA
level = 0;
#endif
if (level > TXRX_OPT_EDCA_MAX_LEVEL)
level = TXRX_OPT_EDCA_MAX_LEVEL;
bes_devel( "txrx_opt: tx(cnt=%d retry=%d psr=%d tx_fail=%d (wsm level=%d) tx=%dk/s)\n\r",
tx_cnt, tx_retry, succPro, tx_fail, level, tx_bps / 128);
bes_devel( "txrx_opt: rx(cnt=%d rx=%dk/s) total=%dk/s\n\r", rx_cnt, rx_bps / 128, total_kbps);
bes_devel( "txrx_opt: tx_delta_time=%d [%d %d %d %d] hw_value=%d ht=%d maxtxcnt=%d\n\r",
bes2600_get_tx_delta_time(), bes2600_get_tx_ac_delta_time(0), bes2600_get_tx_ac_delta_time(1),
bes2600_get_tx_ac_delta_time(2), bes2600_get_tx_ac_delta_time(3), priv->hw_value,
bes2600_station_is_ap_ht40(hw_priv), hw_priv->long_frame_max_tx_count);
/* dynamic set cca */
bes2600_set_cca_method(hw_priv, priv, 0);
/* dynamic set agc */
bes2600_set_dynamic_agc(hw_priv, priv, 0);
bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl);
txrx_opt_clear:
bes2600_set_high_edca_params(hw_priv, priv, level);
bes2600_set_rts_threshold(hw_priv->hw, -1, cur_rts_thres);
bes2600_clear_tx_delta_time();
bes2600_clear_tx_ac_delta_time(0);
bes2600_clear_tx_ac_delta_time(1);
bes2600_clear_tx_ac_delta_time(2);
bes2600_clear_tx_ac_delta_time(3);
tx_bps = priv->dot11TransmittedDataBytes;
rx_bps = priv->dot11ReceivedDataBytes;
l_tx_cnt = priv->dot11TransmittedFrameCount;
l_tx_fail = priv->dot11FailedCount;
l_tx_retry = priv->dot11RetryCount;
l_rx_cnt = priv->dot11ReceivedFragmentCount;
return ;
}
static struct bes2600_common *txrx_hw_priv = NULL;
static bool bes2600_is_sta_connected(void)
{
if (txrx_hw_priv == NULL)
return false;
else
return true;
}
void bes2600_txrx_opt_timer_restore(void)
{
if (bes2600_is_sta_connected()) {
mod_timer(&txrx_hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
}
}
static void txrx_opt_timer_callback(struct timer_list* data)
{
bes_devel( "####Timer callback function Called time = %lu\n", jiffies);
queue_work(txrx_hw_priv->workqueue, &txrx_hw_priv->dynamic_opt_txrx_work);
}
static void txrx_opt_timer_start(struct bes2600_common *hw_priv)
{
mod_timer(&hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
}
static void txrx_opt_timer_stop(struct bes2600_common *hw_priv)
{
timer_delete_sync(&hw_priv->txrx_opt_timer);
}
static void bes2600_set_txrx_opt_default_param(struct bes2600_common * hw_priv)
{
MIB_TXRX_OPT_PARAM g_txrx_param = {2, (PROCTECT_MODE_RTS_CTS | PROCTECT_MODE_RTS_CTS_RETRY), 3000};
struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
struct ieee80211_sta *sta = NULL;
int shortgi = 0;
if (priv == NULL)
return;
/* reset states */
cur_pwr_tbl = 1;
TXRX_RTS_PROT_CLOSE(cur_rts_thres);
last_rts_set_time = -1;
memcpy(&hw_priv->txrx_opt_param, &g_txrx_param, sizeof(MIB_TXRX_OPT_PARAM));
/* reset device states */
bes2600_set_txrx_opt_param(hw_priv, priv, &hw_priv->txrx_opt_param);
bes2600_set_rts_threshold(hw_priv->hw, -1, cur_rts_thres); // close rts/cts
bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl); // use standard pwr table
if (priv->join_status == BES2600_JOIN_STATUS_STA) {
rcu_read_lock();
sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid);
if (sta) {
if (sta->deflink.ht_cap.ht_supported &&
((priv->vif->bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20 &&
sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ||
(priv->vif->bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_40 &&
sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40))) {
shortgi = 1;
}
}
rcu_read_unlock();
bes_devel("short gi tx status: %d\n", shortgi);
bes2600_enable_tx_shortgi(hw_priv, priv, shortgi);
}
}
static int bes2600_set_txrx_opt_unjoin_param(struct bes2600_common * hw_priv)
{
MIB_TXRX_OPT_PARAM g_txrx_param = {1, 0, 2002};
struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
if (priv == NULL)
return 0;
/* reset states */
cur_pwr_tbl = 1;
bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl);
memcpy(&hw_priv->txrx_opt_param, &g_txrx_param, sizeof(MIB_TXRX_OPT_PARAM));
bes2600_set_txrx_opt_param(hw_priv, priv, &hw_priv->txrx_opt_param);
return 0;
}
void bes2600_txrx_opt_multivif_connected_handler(struct bes2600_common *hw_priv, bool multivif_connected)
{
struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
if (multivif_connected) {
bes2600_set_txrx_opt_default_param(hw_priv);
} else {
bes_devel("%s, rssi:%d\n", __func__, priv->signal);
bes2600_dynamic_opt_rxtx(hw_priv, priv, priv->signal);
mod_timer(&hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
}
}
int txrx_opt_timer_init(struct bes2600_vif *priv)
{
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
bes_devel( "txrx_opt_timer_init:%p", txrx_hw_priv);
if (priv->if_id != 0)
return 0;
if (!txrx_hw_priv) {
txrx_hw_priv = hw_priv;
bes_devel( "####Timer init hw_priv = %p\n", txrx_hw_priv);
timer_setup(&hw_priv->txrx_opt_timer, txrx_opt_timer_callback, 0);
bes2600_set_txrx_opt_default_param(hw_priv);
}
mod_timer(&hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
bes2600_pwr_register_en_lp_cb(hw_priv, txrx_opt_timer_stop);
bes2600_pwr_register_exit_lp_cb(hw_priv, txrx_opt_timer_start);
return 0;
}
void txrx_opt_timer_exit(struct bes2600_vif *priv)
{
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
bes_devel( "txrx_opt_timer_exit");
if (priv->if_id == 0) {
timer_delete_sync(&hw_priv->txrx_opt_timer);
cancel_work_sync(&hw_priv->dynamic_opt_txrx_work);
bes2600_pwr_unregister_en_lp_cb(hw_priv, txrx_opt_timer_stop);
bes2600_pwr_unregister_exit_lp_cb(hw_priv, txrx_opt_timer_start);
txrx_hw_priv = NULL;
bes2600_set_txrx_opt_unjoin_param(hw_priv);
} else if (priv->if_id == 1) {
bes2600_txrx_opt_timer_restore();
}
}
-38
View File
@@ -1,38 +0,0 @@
/***************************************************************************
*
* Copyright 2015-2022 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#ifndef bes2600_TXRX_OPT_H
#define bes2600_TXRX_OPT_H
#include <linux/list.h>
/* open it for enhance wifi throughput */
#define BES2600_TX_RX_OPT 1
/* Threshold for powrt table switch */
#define BES2600_TX_RSSI_LOW -65
#define BES2600_TX_RSSI_HIGH -60
void bes2600_add_tx_ac_delta_time(int ac, uint32_t del_time);
void bes2600_add_tx_delta_time(uint32_t tx_time);
void bes2600_rx_status(struct bes2600_vif *priv, struct sk_buff *skb);
void bes2600_tx_status(struct bes2600_vif *priv, struct sk_buff *skb);
void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv,struct bes2600_vif *priv, int rssi);
void bes2600_txrx_opt_multivif_connected_handler(struct bes2600_common *hw_priv, bool multivif_connected);
void bes2600_txrx_opt_timer_restore(void);
int txrx_opt_timer_init(struct bes2600_vif *priv);
void txrx_opt_timer_exit(struct bes2600_vif *priv);
#endif
-2
View File
@@ -2236,7 +2236,5 @@ int wsm_cpu_usage_cmd(struct bes2600_common *hw_priv);
int wsm_wifi_status_cmd(struct bes2600_common *hw_priv, uint32_t status); 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); 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 */ #endif /* BES2600_HWIO_H_INCLUDED */