Files
bes2600-dkms/bes2600/bes_fw.c
T
test0r ebb5c57988 bes2600: drop orphan DATA_DUMP_OBSERVE and access_file() file I/O
Two dead-in-default-build file-I/O sites remain in the driver
after the factory and chardev kernel_*() removals in the preceding
patches:

  - bes_fw.c DATA_DUMP_OBSERVE: four #ifdef DATA_DUMP_OBSERVE
    blocks built around the firmware-download path that open
    /lib/firmware/bes2002_fw_write.bin via filp_open(O_CREAT |
    O_RDWR), then log every transmitted firmware chunk via
    vfs_write() inside a get_fs()/set_fs(KERNEL_DS) wrapper. The
    controlling #define at bes_fw.c line 128 is commented out
    ('//#define DATA_DUMP_OBSERVE'), so none of this is ever
    compiled in a stock build.

  - main.c access_file(): a helper gated on
    GET_MAC_ADDR_METHOD == 2 || == 3 (default 4) using the same
    get_fs()/set_fs()/vfs_read()/vfs_write() pattern. No caller
    in the tree references it -- it was orphaned when the methods
    that consumed it were refactored out.

Both sites are unbuildable on modern kernels anyway: get_fs() /
set_fs() were removed from arm64 and the generic uaccess path in
the v5.10 era, and the legacy vfs_read() / vfs_write() variants
that took userspace-typed buffers went with them. The in-kernel
replacements would be kernel_read() / kernel_write(), which this
series is explicitly removing from the driver.

Remove both blocks, the commented-out '//#define DATA_DUMP_OBSERVE'
line, and the access_file() definition and its #if gate. No
behaviour change in any default or non-default build, because
nothing compiled or linked in the first place. After this patch
the driver contains zero filp_open / kernel_read / kernel_write /
vfs_read / vfs_write references -- a precondition for a
drivers/staging/bes2600/ linux-wireless RFC.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-24 08:55:10 +02:00

1084 lines
27 KiB
C

/*
* Mac80211 driver for BES2600 device
*
* Copyright (c) 2022, Bestechnic
* Author:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "bes_fw_common.h"
#include "bes2600.h"
#include "hwio.h"
#include "sbus.h"
#include "bes_chardev.h"
#include <linux/string.h>
#include "bes2600_factory.h"
#include "bes_log.h"
// fw blob names
#define BES2600_LOAD_BOOT_NAME "bes2600/best2002_fw_boot_sdio.bin"
#define BES2600_LOAD_FW_NAME "bes2600/best2002_fw_sdio.bin"
#define BES2600_LOAD_NOSIGNAL_FW_NAME "bes2600/best2002_fw_sdio_nosignal.bin"
#define BES2600_LOAD_BTRF_FW_NAME "bes2600/best2002_fw_sdio_btrf.bin"
int bes2600_load_firmware_sdio(struct sbus_ops *ops, struct sbus_priv *priv);
struct platform_fw_t {
struct delayed_work work_data;
struct sdio_func *func;
struct completion completion_data;
const struct sbus_ops *sbus_ops;
struct sbus_priv *sbus_priv;
};
static void bes_fw_irq_handler(void *priv)
{
struct platform_fw_t *fw_data = (struct platform_fw_t *)priv;
bes_devel("%s\n", __func__);
complete(&fw_data->completion_data);
}
//#define BES_SLAVE_RX_DOUBLE_CHECK
static int bes_slave_rx_ready(struct platform_fw_t *fw_data, u8* buf_cnt,
u16* buf_len, int timeout)
{
int ret;
unsigned long start = jiffies;
do {
ret = bes2600_reg_read(0x108, buf_cnt, 1);
if (!(ret || buf_cnt)) {
mdelay(50);
continue;
} else if (ret) {
bes_err("%s,%d err=%d\n", __func__, __LINE__, ret);
} else {
ret = bes2600_reg_read_16(0x109, buf_len);
}
break;
} while(time_before(jiffies, start + timeout));
return ret;
}
//#define BES_SLAVE_TX_DOUBLE_CHECK
//#define MISSED_INTERRUPT_WORKAROUND
static int bes_slave_tx_ready(struct platform_fw_t *fw_data, u16 *tx_len, int timeout)
{
int ret, retry = 0;
bes_devel("%s now=%lu\n", __func__, jiffies);
msleep(2);
ret = wait_for_completion_interruptible_timeout(&fw_data->completion_data, timeout);
if (ret > 0) {
#ifdef MISSED_INTERRUPT_WORKAROUND
test_read_tx:
#endif
do {
ret = bes2600_reg_read_16(0, tx_len);
if (!ret && (*tx_len))
break;
else
bes_err("%s,%d ret=%d tx_len=%x retry=%d\n",
__func__, __LINE__, ret, *tx_len, retry);
retry++;
} while(retry <= 5);
reinit_completion(&fw_data->completion_data);
} else if(!ret) {
bes_err("%s now=%lu delta=%d\n", __func__, jiffies, timeout);
#ifndef MISSED_INTERRUPT_WORKAROUND
ret = -110;
#else
goto test_read_tx;
#endif
} else {
// ret = -ERESTARTSYS, to be continued;
}
return ret;
}
// UNUSED
/*
int bes_host_slave_sync(struct bes2600_common *hw_priv)
{
u8 val;
int ret;
ret = bes2600_reg_read(BES_HOST_INT_REG_ID, &val, 1);
if (ret) {
bes_err("%s,%d err=%d\n", __func__, __LINE__, ret);
return ret;
}
val |= BES_HOST_INT;
ret = bes2600_reg_write(BES_HOST_INT_REG_ID, &val, 1);
if (ret) {
bes_err("%s,%d err=%d\n", __func__, __LINE__, ret);
}
return ret;
}
*/
static int bes_firmware_download_write_reg(struct platform_fw_t *fw_data, u32 addr, u32 val)
{
u8 frame_num = 0;
u8 buf_cnt = 0;
u16 tx_size = 0;
u16 rx_size = 0;
u32 length = 0;
u8 *short_buf;
int ret;
struct fw_msg_hdr_t header;
struct fw_info_t fw_info;
struct download_fw_t download_addr;
fw_info.addr = addr;
fw_info.len = 4;
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (!ret) {
bes_devel("sdio slave rx buf cnt:%d,buf len max:%d\n", buf_cnt, tx_size);
} else {
bes_err("wait bes sdio slave rx ready tiemout:%d\n", ret);
return ret;
}
short_buf = kzalloc(512, GFP_KERNEL);
if (!short_buf)
return -ENOMEM;
header.type = FRAME_HEADER_DOWNLOAD_INFO;
header.seq = frame_num;
header.len = sizeof(struct fw_info_t);
frame_num++;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&fw_info, sizeof(struct fw_info_t));
length = BES_FW_MSG_TOTAL_LEN(header);
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx download firmware info err:%d\n", ret);
goto err;
}
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("sdio slave tx ready %d bytes\n", rx_size);
} else {
bes_err("wait slave process failed:%d\n", ret);
goto err;
}
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx download firmware info rsp err:%d\n", ret);
goto err;
}
header.type = FRAME_HEADER_DOWNLOAD_DATA;
header.seq = frame_num;
header.len = 8;
frame_num++;
download_addr.addr = fw_info.addr;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), &download_addr.addr, sizeof(struct download_fw_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t), &val, 4);
length = BES_FW_MSG_TOTAL_LEN(header);
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx download fw data err:%d\n", ret);
goto err;
}
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process download fw data err:%d\n", ret);
goto err;
}
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx tx download fw data rsp err:%d\n", ret);
goto err;
}
err:
kfree(short_buf);
return ret;
}
static int bes_firmware_download_write_mem(struct platform_fw_t *fw_data, const u32 addr, const u8 *data, const u32 len)
{
u8 frame_num = 0;
u8 last_frame_num = 0;
u8 buf_cnt = 0;
u16 tx_size = 0;
u16 rx_size = 0;
u32 length = 0;
u32 code_length = len;
u32 retry_cnt = 0;
int ret;
const u8 *data_p;
u8 *short_buf, *long_buf;
struct fw_msg_hdr_t header;
struct fw_info_t fw_info;
struct download_fw_t download_addr;
struct fw_crc_t crc32_t;
retry:
fw_info.addr = addr;
fw_info.len = len;
data_p = data;
crc32_t.crc32 = 0;
crc32_t.crc32 ^= 0xffffffffL;
crc32_t.crc32 = crc32_le(crc32_t.crc32, (u8 *)data, len);
crc32_t.crc32 ^= 0xffffffffL;
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (!ret) {
bes_devel("sdio slave rx buf cnt:%d,buf len max:%d\n", buf_cnt, tx_size);
} else {
bes_devel("wait bes sdio slave rx ready tiemout:%d\n", ret);
return ret;
}
header.type = FRAME_HEADER_DOWNLOAD_INFO;
header.seq = frame_num;
header.len = sizeof(struct fw_info_t);
last_frame_num = frame_num;
frame_num++;
short_buf = kzalloc(512, GFP_KERNEL);
if (!short_buf)
return -ENOMEM;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&fw_info, sizeof(struct fw_info_t));
length = BES_FW_MSG_TOTAL_LEN(header);
if (tx_size > length) {
bes_devel("%s", "tx download firmware info\n");
} else {
bes_devel("%s:%d bes slave has no enough buffer%d/%d\n", __func__, __LINE__, tx_size, length);
goto err1;
}
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx download firmware info err:%d\n", ret);
goto err1;
}
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("sdio slave tx ready %d bytes\n", rx_size);
} else {
bes_devel("wait slave process failed:%d\n", ret);
goto err1;
}
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx download firmware info rsp err:%d\n", ret);
goto err1;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp download firmware info err:%d\n", ret);
goto err1;
}
//download firmware
long_buf = kmalloc(1024 * 32, GFP_KERNEL);
if (!long_buf) {
bes_err("%s:%d fw failed to allocate memory\n",__func__, __LINE__);
ret = -ENOMEM;
goto err1;
}
download_addr.addr = fw_info.addr;
while (code_length) {
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (ret) {
goto err2;
} else {
bes_devel("bes salve rx ready %d bytes\n", tx_size);
}
if ((tx_size < 4) || (tx_size % 4)) {
bes_err("%s:%d tx size=%d\n", __func__, __LINE__, tx_size);
ret = -203;
goto err2;
}
if ((code_length + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t)) < tx_size) {
length = code_length + sizeof(struct download_fw_t);
} else {
length = tx_size - sizeof(struct fw_msg_hdr_t);
}
header.type = FRAME_HEADER_DOWNLOAD_DATA;
header.seq = frame_num;
header.len = length;
last_frame_num = frame_num;
frame_num++;
memcpy(long_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(long_buf + sizeof(struct fw_msg_hdr_t), &download_addr.addr, sizeof(struct download_fw_t));
length -= sizeof(struct download_fw_t);//real data length
memcpy(long_buf + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t), data_p, length);
length += (sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
bes_devel("tx_download_firmware_data:%x %d\n", download_addr.addr, length);
ret = bes2600_data_write(long_buf, length > 512 ? length : 512);
if (ret) {
bes_err("tx download fw data err:%d\n", ret);
goto err2;
}
length -= (sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process download fw data err:%d\n", ret);
goto err2;
}
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx tx download fw data rsp err:%d\n", ret);
goto err2;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp tx download fw err:%d\n", ret);
goto err2;
}
code_length -= length;
data_p += length;
download_addr.addr += length;
bes_devel("already tx fw size:%x/%x\n", download_addr.addr - fw_info.addr, fw_info.len);
}
//Notify Device:The firmware download is complete
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (ret) {
goto err2;
} else {
bes_devel("bes salve rx ready %d bytes\n", tx_size);
}
header.type = FRAME_HEADER_DOWNLOAD_END;
header.seq = frame_num;
header.len = sizeof(struct fw_crc_t);
last_frame_num = frame_num;
frame_num++;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&crc32_t.crc32, sizeof(struct fw_crc_t));
length = BES_FW_MSG_TOTAL_LEN(header);
bes_devel("%s", "tx download firmware complete command\n");
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx downlod firmware complete command err:%d\n", ret);
goto err2;
}
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process download fw data err:%d\n", ret);
goto err2;
}
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("receive download firmware complete cmd rsp err:%d\n", ret);
goto err2;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp download firmware complete err:%d\n", ret);
goto err2;
}
err2:
kfree(long_buf);
err1:
kfree(short_buf);
if (ret && retry_cnt < 3) {
retry_cnt++;
goto retry;
}
return ret;
}
static int bes_firmware_download(struct platform_fw_t *fw_data, const char *fw_name, bool auto_run)
{
u8 frame_num = 0;
u8 last_frame_num = 0;
u8 buf_cnt = 0;
u16 tx_size = 0;
u16 rx_size = 0;
u32 length = 0;
u32 code_length = 0;
u32 retry_cnt = 0;
int ret;
const u8 *fw_ver_ptr;
const u8 *data_p;
u8 *short_buf, *long_buf;
const struct firmware *fw_bin;
struct fw_msg_hdr_t header;
struct fw_info_t fw_info;
struct download_fw_t download_addr;
struct fw_crc_t crc32_t;
struct run_fw_t run_addr;
retry:
ret = request_firmware(&fw_bin, fw_name, NULL);
if (ret) {
bes_err("request firmware err:%d\n", ret);
return ret;
}
bes_parse_fw_info(fw_bin->data, fw_bin->size, &fw_info.addr, &crc32_t.crc32);
fw_ver_ptr = bes2600_get_firmware_version_info(fw_bin->data, fw_bin->size);
if(fw_ver_ptr == NULL)
bes_err("------Firmware version get failed\n");
else
bes_devel("------Firmware: %s version :%s\n", fw_name ,fw_ver_ptr);
bes_devel("------load addr :0x%08X\n", fw_info.addr);
bes_devel("------data crc :0x%08X\n", crc32_t.crc32);
code_length = fw_bin->size - CODE_DATA_USELESS_SIZE;
bes_devel("------code size :%d\n", code_length);
fw_info.len = code_length;
data_p = fw_bin->data;
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (!ret) {
bes_devel("sdio slave rx buf cnt:%d,buf len max:%d\n", buf_cnt, tx_size);
} else {
bes_devel("wait bes sdio slave rx ready tiemout:%d\n", ret);
return ret;
}
header.type = FRAME_HEADER_DOWNLOAD_INFO;
header.seq = frame_num;
header.len = sizeof(struct fw_info_t);
last_frame_num = frame_num;
frame_num++;
short_buf = kzalloc(512, GFP_KERNEL);
if (!short_buf)
return -ENOMEM;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&fw_info, sizeof(struct fw_info_t));
length = BES_FW_MSG_TOTAL_LEN(header);
//mdelay(5000);
print_hex_dump(KERN_DEBUG, "FW info: ", DUMP_PREFIX_NONE, 16, 1, short_buf, length, false);
if (tx_size > length) {
bes_devel("%s", "tx download firmware info\n");
} else {
bes_devel("%s:%d bes slave has no enough buffer%d/%d\n", __func__, __LINE__, tx_size, length);
goto err1;
}
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx download firmware info err:%d\n", ret);
goto err1;
}
#if 1
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("sdio slave tx ready %d bytes\n", rx_size);
} else {
bes_devel("wait slave process failed:%d\n", ret);
goto err1;
}
#ifdef BES_SLAVE_TX_DOUBLE_CHECK
if (rx_size != 8)
rx_size = 8;
#endif
#else
mdelay(100);
rx_size = 8;
#endif
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx download firmware info rsp err:%d\n", ret);
goto err1;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp download firmware info err:%d\n", ret);
goto err1;
}
//download firmware
long_buf = kmalloc(1024 * 32, GFP_KERNEL);
if (!long_buf) {
bes_err("%s:%d fw failed to allocate memory\n",__func__, __LINE__);
ret = -ENOMEM;
goto err1;
}
download_addr.addr = fw_info.addr;
while (code_length) {
#if 1
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (ret) {
goto err2;
} else {
bes_devel("bes salve rx ready %d bytes\n", tx_size);
}
#endif
#ifdef BES_SLAVE_RX_DOUBLE_CHECK
tx_size = 512;
#endif
if ((tx_size < 4) || (tx_size % 4)) {
bes_err("%s:%d tx size=%d\n", __func__, __LINE__, tx_size);
ret = -203;
goto err2;
}
if ((code_length + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t)) < tx_size) {
length = code_length + sizeof(struct download_fw_t);
} else {
length = tx_size - sizeof(struct fw_msg_hdr_t);
}
#if 0 // for SDIO_USE_V2
if (length + sizeof(struct fw_msg_hdr_t) > func->cur_blksize) {
length = (length + sizeof(struct fw_msg_hdr_t)) / func->cur_blksize * func->cur_blksize;
length -= sizeof(struct fw_msg_hdr_t);
}
#endif
header.type = FRAME_HEADER_DOWNLOAD_DATA;
header.seq = frame_num;
header.len = length;
last_frame_num = frame_num;
frame_num++;
memcpy(long_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(long_buf + sizeof(struct fw_msg_hdr_t), &download_addr.addr, sizeof(struct download_fw_t));
length -= sizeof(struct download_fw_t);//real data length
memcpy(long_buf + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t), data_p, length);
length += (sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
//mdelay(5000);
bes_devel("tx_download_firmware_data:%x %d\n", download_addr.addr, length);
ret = bes2600_data_write(long_buf, length > 512 ? length : 512);
if (ret) {
bes_err("tx download fw data err:%d\n", ret);
goto err2;
}
length -= (sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
#if 1
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process download fw data err:%d\n", ret);
goto err2;
}
#ifdef BES_SLAVE_TX_DOUBLE_CHECK
if (rx_size != 8)
rx_size = 8;
#endif
#else
mdelay(100);
rx_size = 8;
#endif
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx tx download fw data rsp err:%d\n", ret);
goto err2;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp tx download fw err:%d\n", ret);
goto err2;
}
code_length -= length;
data_p += length;
download_addr.addr += length;
bes_devel("already tx fw size:%x/%x\n", download_addr.addr - fw_info.addr, fw_info.len);
}
//Notify Device:The firmware download is complete
#if 1
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (ret) {
goto err2;
} else {
bes_devel("bes salve rx ready %d bytes\n", tx_size);
}
#endif
#ifdef BES_SLAVE_RX_DOUBLE_CHECK
tx_size = 512;
#endif
header.type = FRAME_HEADER_DOWNLOAD_END;
header.seq = frame_num;
header.len = sizeof(struct fw_crc_t);
last_frame_num = frame_num;
frame_num++;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&crc32_t.crc32, sizeof(struct fw_crc_t));
length = BES_FW_MSG_TOTAL_LEN(header);
bes_devel("%s", "tx download firmware complete command\n");
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx downlod firmware complete command err:%d\n", ret);
goto err2;
}
#if 1
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process download fw data err:%d\n", ret);
goto err2;
}
#ifdef BES_SLAVE_TX_DOUBLE_CHECK
if (rx_size != 8)
rx_size = 8;
#endif
#else
mdelay(100);
rx_size = 8;
bes_devel("enter sdio irqs:%d", enter_sdio_irqs);
#endif
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("receive download firmware complete cmd rsp err:%d\n", ret);
goto err2;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp download firmware complete err:%d\n", ret);
goto err2;
}
if (auto_run == false) {
bes_devel("partial firmware(%s) is downloaded successfully\n", fw_name);
goto err2;
}
#if 1
ret = bes_slave_rx_ready(fw_data, &buf_cnt, &tx_size, HZ);
if (ret) {
goto err2;
} else {
bes_devel("bes salve rx ready %d bytes\n", tx_size);
}
#endif
#ifdef BES_SLAVE_RX_DOUBLE_CHECK
tx_size = 512;
#endif
//Notify Device:Run firmware
run_addr.addr = fw_info.addr;
header.type = FRAME_HEADER_RUN_CODE;
header.seq = frame_num;
header.len = sizeof(struct run_fw_t);
last_frame_num = frame_num;
frame_num++;
memcpy(short_buf, (u8 *)&header, sizeof(struct fw_msg_hdr_t));
memcpy(short_buf + sizeof(struct fw_msg_hdr_t), (u8 *)&run_addr.addr, sizeof(struct run_fw_t));
length = BES_FW_MSG_TOTAL_LEN(header);
bes_devel("tx run firmware command:0x%X\n", run_addr.addr);
length = length > 512 ? length : 512;
ret = bes2600_data_write(short_buf, length);
if (ret) {
bes_err("tx run firmware command err:%d\n", ret);
goto err2;
}
#if 1
ret = bes_slave_tx_ready(fw_data, &rx_size, HZ);
if (!ret) {
bes_devel("bes_slave ready tx %d bytes\n", rx_size);
} else {
bes_err("wait slave process run fw cmd err:%d\n", ret);
goto err2;
}
#ifdef BES_SLAVE_TX_DOUBLE_CHECK
if (rx_size != 8)
rx_size = 8;
#endif
#else
mdelay(100);
rx_size = 8;
#endif
ret = bes2600_data_read(short_buf, rx_size);
if (ret) {
bes_err("rx run firmware command err:%d\n", ret);
goto err2;
}
//check device rx status
ret = bes_frame_rsp_check(short_buf, last_frame_num);
if (ret) {
bes_err("rsp run firmware command err:%d\n", ret);
goto err2;
}
bes_devel("%s", "firmware is downloaded successfully and is already running\n");
msleep(500);
err2:
kfree(long_buf);
err1:
kfree(short_buf);
release_firmware(fw_bin);
if (ret && retry_cnt < 3) {
retry_cnt++;
goto retry;
}
return ret;
}
static int bes_read_dpd_data(struct platform_fw_t *fw_data)
{
u16 dpd_size = 0;
int ret = 0;
u8 *dpd_buf = NULL;
u8 mcu_status = 0;
unsigned long wait_timeout;
/* wait for device ready */
wait_timeout = jiffies + 15 * HZ;
do {
msleep(100);
ret = bes2600_reg_read(BES_SLAVE_STATUS_REG_ID, &mcu_status, 1);
} while(((ret == 0) || (ret == -84)) &&
!(mcu_status & BES_SLAVE_STATUS_DPD_READY) &&
time_before(jiffies, wait_timeout));
/* check if read dpd error */
if(ret < 0 || time_after(jiffies, wait_timeout)) {
bes_err("wait dpd data ready failed:%d\n", ret);
return -1;
}
/* wait dpd read ready */
ret = bes_slave_tx_ready(fw_data, &dpd_size, HZ);
if (ret) {
bes_err("wait dpd data failed:%d\n", ret);
return -1;
}
/* dpd size check */
if (dpd_size != DPD_BIN_SIZE) {
bes_err("get dpd data size err:%u\n", dpd_size);
return -1;
}
/* read dpd data */
dpd_buf = bes2600_chrdev_get_dpd_buffer(DPD_BIN_FILE_SIZE);
if(!dpd_buf) {
bes_err("allocate dpd buffer failed.\n");
return -1;
}
ret = bes2600_data_read(dpd_buf, dpd_size);
bes_devel("read dpd data size:%d\n", dpd_size);
if (ret) {
bes_err("read dpd data failed:%d\n", ret);
bes2600_chrdev_free_dpd_data();
return -1;
}
/* update dpd data */
ret = bes2600_chrdev_update_dpd_data();
if (ret)
bes2600_chrdev_free_dpd_data();
return ret;
}
#ifdef BES2600_DUMP_FW_DPD_LOG
static int bes_read_dpd_log(struct platform_fw_t *fw_data)
{
u16 dpd_log_size = 0;
int ret = 0;
u8 mcu_status = 0;
u8 *dpd_log = NULL;
unsigned long wait_timeout;
/* wait for device ready */
wait_timeout = jiffies + 5 * HZ;
do {
msleep(10);
ret = bes2600_reg_read(BES_SLAVE_STATUS_REG_ID, &mcu_status, 1);
} while(((ret == 0) || (ret == -84)) &&
!(mcu_status & BES_SLAVE_STATUS_DPD_LOG_READY) &&
time_before(jiffies, wait_timeout));
if(ret < 0 || time_after(jiffies, wait_timeout)) {
bes_err("wait dpd log ready failed:%d\n", ret);
return -1;
}
/* wait dpd log dump data ready */
ret = bes_slave_tx_ready(fw_data, &dpd_log_size, HZ);
if (ret) {
bes_err("wait dpd log failed:%d\n", ret);
return -1;
}
dpd_log = bes2600_alloc_dpd_log_buffer((dpd_log_size + 3) & (~0x3));
if(!dpd_log) {
bes_err("dpd log buffer alloc fail");
return -1;
}
ret = bes2600_data_read(dpd_log, (dpd_log_size + 3) & (~0x3));
if (ret) {
bes_err("read dpd log failed:%d\n", ret);
bes2600_free_dpd_log_buffer();
return -1;
}
bes_devel("read dpd log size: %u\n", dpd_log_size);
return ret;
}
#endif /* BES2600_DUMP_FW_DPD_LOG */
static int bes2600_load_wifi_firmware(struct platform_fw_t *fw_data)
{
int ret = 0;
const char *fw_name_tbl[3];
int fw_type = bes2600_chrdev_get_fw_type();
fw_name_tbl[0] = BES2600_LOAD_FW_NAME;
fw_name_tbl[1] = BES2600_LOAD_NOSIGNAL_FW_NAME;
fw_name_tbl[2] = BES2600_LOAD_BTRF_FW_NAME;
bes_devel("bes2600 download cali and wifi signal firmware.\n");
ret = bes_firmware_download(fw_data, BES2600_LOAD_BOOT_NAME, true);
if (ret)
bes_err("download dpd cali firmware failed\n");
if (!ret) {
bes_devel("bes2600 read dpd cali data.\n");
ret = bes_read_dpd_data(fw_data);
if (ret)
bes_err("read dpd data failed.\n");
}
#ifdef BES2600_DUMP_FW_DPD_LOG
if (!ret) {
bes_devel("bes2600 read dpd log data.\n");
ret = bes_read_dpd_log(fw_data);
if (ret)
bes_err("dump dpd log failed.\n");
}
#endif
/* for wifi non-signal mode, download second firmware directly */
if (!ret && bes2600_chrdev_check_system_close()) {
bes_devel("bes2600 device power down.\n");
ret = bes2600_chrdev_do_system_close(fw_data->sbus_ops, fw_data->sbus_priv);
if (ret)
bes_err("device down fail.\n");
} else if (!ret) {
ret = bes_firmware_download(fw_data, fw_name_tbl[fw_type], true);
if (ret)
bes_err("download normal firmware failed.\n");
}
return ret;
}
static int bes2600_load_wifi_firmware_with_dpd(struct platform_fw_t *fw_data)
{
int ret = 0;
u32 dpd_data_len = 0;
const u8 *dpd_data = NULL;
const char *fw_name_tbl[3];
int fw_type = bes2600_chrdev_get_fw_type();
fw_name_tbl[0] = BES2600_LOAD_FW_NAME;
fw_name_tbl[1] = BES2600_LOAD_NOSIGNAL_FW_NAME;
fw_name_tbl[2] = BES2600_LOAD_BTRF_FW_NAME;
dpd_data = bes2600_chrdev_get_dpd_data(&dpd_data_len);
BUG_ON(!dpd_data);
bes_devel("bes2600 download firmware with dpd.\n");
ret = bes_firmware_download_write_mem(fw_data, BES2600_DPD_ADDR, dpd_data, dpd_data_len);
if (ret)
bes_err("download dpd data failed.\n");
if (!ret) {
ret = bes_firmware_download(fw_data, fw_name_tbl[fw_type], true);
if (ret)
bes_err("download firmware failed after dpd download.\n");
}
return ret;
}
static int bes2600_load_bt_firmware(struct platform_fw_t *fw_data)
{
int ret = 0;
/* for bt mode, don't need to download dpd cali firmware*/
bes_devel("download bt test firmware.\n");
ret = bes_firmware_download(fw_data, BES2600_LOAD_BTRF_FW_NAME, true);
if (ret)
bes_err("download normal firmware failed.\n");
return ret;
}
int bes2600_load_firmware_sdio(struct sbus_ops *ops, struct sbus_priv *priv)
{
int ret = 0;
struct platform_fw_t *temp_fw_data;
u32 dpd_data_len = 0;
const u8 *dpd_data = NULL;
int fw_type = bes2600_chrdev_get_fw_type();
#ifdef CONFIG_BES2600_CALIB_FROM_LINUX
u8 *factory_data = NULL;
u8 *file_buffer = NULL;
u32 factory_data_len = 0;
#endif
temp_fw_data = kzalloc(sizeof(struct platform_fw_t), GFP_KERNEL);
if (!temp_fw_data)
return -ENOMEM;
init_completion(&temp_fw_data->completion_data);
temp_fw_data->sbus_ops = ops;
temp_fw_data->sbus_priv = priv;
temp_fw_data->sbus_ops->irq_subscribe(temp_fw_data->sbus_priv,
(sbus_irq_handler)bes_fw_irq_handler, temp_fw_data);
bes_firmware_download_write_reg(temp_fw_data, 0x40100000, 0x802006);
bes_firmware_download_write_reg(temp_fw_data, 0x4008602C, 0x3E00C000);
#ifdef CONFIG_BES2600_CALIB_FROM_LINUX
if (!(file_buffer = bes2600_factory_get_file_buffer()))
return -ENOMEM;
bes2600_factory_lock();
if (!(factory_data = bes2600_get_factory_cali_data(file_buffer, &factory_data_len, FACTORY_PATH))) {
bes_warn("factory cali data get failed.\n");
} else {
bes2600_factory_data_check(factory_data);
factory_little_endian_cvrt(factory_data);
ret = bes_firmware_download_write_mem(temp_fw_data, BES2600_FACTORY_ADDR, factory_data, factory_data_len);
if (ret)
bes_err("download factory data failed.\n");
}
bes2600_factory_free_file_buffer(file_buffer);
bes2600_factory_unlock();
#endif
bes_devel("%s fw_type:%d.\n", __func__, fw_type);
if(fw_type == BES2600_FW_TYPE_BT) {
ret = bes2600_load_bt_firmware(temp_fw_data);
} else {
dpd_data = bes2600_chrdev_get_dpd_data(&dpd_data_len);
if(dpd_data) {
ret = bes2600_load_wifi_firmware_with_dpd(temp_fw_data);
} else {
ret = bes2600_load_wifi_firmware(temp_fw_data);
}
}
/* don't register net device when wifi is closed */
if(!ret && !bes2600_chrdev_is_wifi_opened()) {
ret = 1;
}
temp_fw_data->sbus_ops->irq_unsubscribe(temp_fw_data->sbus_priv);
kfree(temp_fw_data);
bes_devel("download finished ,wifi_state:%d result is %d\n", bes2600_chrdev_is_wifi_opened(), ret);
return ret;
}