From d4a1bd480003f3e1a0590bc46fbcb24f05652ca7 Mon Sep 17 00:00:00 2001 From: tzh <tanzhtanzh@gmail.com> Date: Thu, 15 Aug 2024 06:56:47 +0000 Subject: [PATCH] feat(wfit/bt): update aic8800 wifi/bt drive and hal --- longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c | 495 ++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 326 insertions(+), 169 deletions(-) diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c old mode 100644 new mode 100755 index 996ea71..8d3b269 --- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c +++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c @@ -13,9 +13,21 @@ #include <linux/list.h> #include <linux/version.h> +#include <linux/firmware.h> #include "aicsdio_txrxif.h" #include "aicsdio.h" #include "aic_bsp_driver.h" + +static u8 binding_enc_data[16]; +static bool need_binding_verify; + +int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout); +#ifndef CONFIG_PLATFORM_ALLWINNER +int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout) +{ + return 0; +} +#endif static void cmd_dump(const struct rwnx_cmd *cmd) { @@ -45,6 +57,7 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd) { bool defer_push = false; + int err = 0; spin_lock_bh(&cmd_mgr->lock); @@ -98,7 +111,7 @@ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) { unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz); - if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) { + if (!wait_for_completion_timeout(&cmd->complete, tout)) { printk(KERN_CRIT"cmd timed-out\n"); cmd_dump(cmd); spin_lock_bh(&cmd_mgr->lock); @@ -108,6 +121,7 @@ cmd_complete(cmd_mgr, cmd); } spin_unlock_bh(&cmd_mgr->lock); + err = -ETIMEDOUT; } else { kfree(cmd); } @@ -115,7 +129,7 @@ cmd->result = 0; } - return 0; + return err; } static int cmd_mgr_run_callback(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd, @@ -178,9 +192,6 @@ struct rwnx_cmd *cur; spin_lock_bh(&cmd_mgr->lock); - printk("q_sz/max: %2d / %2d - next tkn: %d\n", - cmd_mgr->queue_sz, cmd_mgr->max_queue_sz, - cmd_mgr->next_tkn); list_for_each_entry(cur, &cmd_mgr->cmds, list) { cmd_dump(cur); } @@ -301,7 +312,7 @@ struct lmac_msg *msg; struct rwnx_cmd *cmd; bool nonblock; - int ret; + int ret = 0; msg = container_of((void *)msg_params, struct lmac_msg, param); if (sdiodev->bus_if->state == BUS_DOWN_ST) { @@ -332,7 +343,7 @@ if (!reqcfm) kfree(cmd); - return 0; + return ret; } @@ -413,27 +424,53 @@ return rwnx_send_msg(sdiodev, mem_mask_write_req, 1, DBG_MEM_MASK_WRITE_CFM, NULL); } +int rwnx_send_dbg_binding_req(struct aic_sdio_dev *sdiodev, u8 *dout, u8 *binding_status) +{ + struct dbg_binding_req *binding_req; -int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type) + /* Build the DBG_BINDING_REQ message */ + binding_req = rwnx_msg_zalloc(DBG_BINDING_REQ, TASK_DBG, DRV_TASK_ID, + sizeof(struct dbg_binding_req)); + if (!binding_req) + return -ENOMEM; + + memcpy(binding_req->driver_data, dout, 16); + + /* Send the DBG_MEM_MASK_WRITE_REQ message to LMAC FW */ + return rwnx_send_msg(sdiodev, binding_req, 1, DBG_BINDING_CFM, binding_status); +} + +int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type, struct dbg_start_app_cfm *start_app_cfm) { struct dbg_start_app_req *start_app_req; /* Build the DBG_START_APP_REQ message */ start_app_req = rwnx_msg_zalloc(DBG_START_APP_REQ, TASK_DBG, DRV_TASK_ID, sizeof(struct dbg_start_app_req)); - if (!start_app_req) + if (!start_app_req) { + printk("start app nomen\n"); return -ENOMEM; + } /* Set parameters for the DBG_START_APP_REQ message */ start_app_req->bootaddr = boot_addr; start_app_req->boottype = boot_type; /* Send the DBG_START_APP_REQ message to LMAC FW */ - return rwnx_send_msg(sdiodev, start_app_req, 1, DBG_START_APP_CFM, NULL); + return rwnx_send_msg(sdiodev, start_app_req, 1, DBG_START_APP_CFM, start_app_cfm); } +static inline int dbg_binding_ind(struct rwnx_cmd *cmd, struct ipc_e2a_msg *msg) +{ + struct dbg_binding_ind *ind = (struct dbg_binding_ind *)msg->param; + memcpy(binding_enc_data, ind->enc_data, 16); + need_binding_verify = true; + + return 0; +} static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = { + [MSG_I(DBG_BINDING_IND)] = (msg_cb_fct)dbg_binding_ind, }; static msg_cb_fct *msg_hdlrs[] = { @@ -446,129 +483,29 @@ msg_hdlrs[MSG_T(msg->id)][MSG_I(msg->id)]); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) -MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); -#endif - -static int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *device) -{ - void *buffer = NULL; - char *path = NULL; - struct file *fp = NULL; - int size = 0, len = 0, i = 0; - ssize_t rdlen = 0; - u32 *src = NULL, *dst = NULL; - - /* get the firmware path */ - path = __getname(); - if (!path) { - *fw_buf = NULL; - return -1; - } - - len = snprintf(path, AICBSP_FW_PATH_MAX, "%s/%s", AICBSP_FW_PATH, name); - if (len >= AICBSP_FW_PATH_MAX) { - printk("%s: %s file's path too long\n", __func__, name); - *fw_buf = NULL; - __putname(path); - return -1; - } - - printk("%s :firmware path = %s \n", __func__, path); - - /* open the firmware file */ - fp = filp_open(path, O_RDONLY, 0); - if (IS_ERR_OR_NULL(fp)) { - printk("%s: %s file failed to open\n", __func__, name); - *fw_buf = NULL; - __putname(path); - fp = NULL; - return -1; - } - - size = i_size_read(file_inode(fp)); - if (size <= 0) { - printk("%s: %s file size invalid %d\n", __func__, name, size); - *fw_buf = NULL; - __putname(path); - filp_close(fp, NULL); - fp = NULL; - return -1; - } - - /* start to read from firmware file */ - buffer = kzalloc(size, GFP_KERNEL); - if (!buffer) { - *fw_buf = NULL; - __putname(path); - filp_close(fp, NULL); - fp = NULL; - return -1; - } - -#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 16) - rdlen = kernel_read(fp, buffer, size, &fp->f_pos); -#else - rdlen = kernel_read(fp, fp->f_pos, buffer, size); -#endif - - if (size != rdlen) { - printk("%s: %s file rdlen invalid %ld\n", __func__, name, rdlen); - *fw_buf = NULL; - __putname(path); - filp_close(fp, NULL); - fp = NULL; - kfree(buffer); - buffer = NULL; - return -1; - } - if (rdlen > 0) { - fp->f_pos += rdlen; - } - - /*start to transform the data format*/ - src = (u32 *)buffer; - dst = (u32 *)kzalloc(size, GFP_KERNEL); - - if (!dst) { - *fw_buf = NULL; - __putname(path); - filp_close(fp, NULL); - fp = NULL; - kfree(buffer); - buffer = NULL; - return -1; - } - - for (i = 0; i < (size/4); i++) { - dst[i] = src[i]; - } - - __putname(path); - filp_close(fp, NULL); - fp = NULL; - kfree(buffer); - buffer = NULL; - *fw_buf = dst; - - return size; -} - int rwnx_plat_bin_fw_upload_android(struct aic_sdio_dev *sdiodev, u32 fw_addr, const char *filename) { - struct device *dev = sdiodev->dev; unsigned int i = 0; int size; u32 *dst = NULL; int err = 0; - /* load aic firmware */ - size = rwnx_load_firmware(&dst, filename, dev); + const struct firmware *fw = NULL; + int ret = request_firmware(&fw, filename, NULL); + + printk("rwnx_request_firmware, name: %s\n", filename); + if (ret < 0) { + printk("Load %s fail\n", filename); + return ret; + } + + size = fw->size; + dst = (u32 *)fw->data; + if (size <= 0) { printk("wrong size of firmware file\n"); - kfree(dst); - dst = NULL; + release_firmware(fw); return -1; } @@ -590,11 +527,7 @@ } } - if (dst) { - kfree(dst); - dst = NULL; - } - + release_firmware(fw); return err; } @@ -618,8 +551,18 @@ int size; struct aicbt_patch_table *head = NULL, *new = NULL, *cur = NULL; - /* load aic firmware */ - size = rwnx_load_firmware((u32 **)&rawdata, filename, NULL); + const struct firmware *fw = NULL; + int ret = request_firmware(&fw, filename, NULL); + + printk("rwnx_request_firmware, name: %s\n", filename); + if (ret < 0) { + printk("Load %s fail\n", filename); + return NULL; + } + + rawdata = (uint8_t *)fw->data; + size = fw->size; + if (size <= 0) { printk("wrong size of firmware file\n"); goto err; @@ -657,40 +600,66 @@ memcpy(cur->data, p, cur->len * 8); p += cur->len * 8; } - kfree(rawdata); + release_firmware(fw); return head; err: aicbt_patch_table_free(&head); - if (rawdata) - kfree(rawdata); + release_firmware(fw); return NULL; } -bool aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev) +int aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev) { - if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_ADID_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_adid)) - return false; - if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_PATCH_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_patch)) - return false; - if (aicbsp_firmware_list[aicbsp_mode_index].bt_patch_test && - rwnx_plat_bin_fw_upload_android(sdiodev, FW_PATCH_TEST_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_patch_test)) - return false; - return true; + uint32_t fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR; + if (aicbsp_info.chip_rev != CHIP_REV_U02) + fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR_U03; + + if (rwnx_plat_bin_fw_upload_android(sdiodev, fw_ram_adid_base_addr, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid)) + return -1; + if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_PATCH_BASE_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch)) + return -1; + return 0; } + +static struct aicbt_info_t aicbt_info = { + .btmode = AICBT_BTMODE_DEFAULT, + .btport = AICBT_BTPORT_DEFAULT, + .uart_baud = AICBT_UART_BAUD_DEFAULT, + .uart_flowctrl = AICBT_UART_FC_DEFAULT, + .lpm_enable = AICBT_LPM_ENABLE_DEFAULT, + .txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT, +}; int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev) { struct aicbt_patch_table *head, *p; int ret = 0, i; uint32_t *data = NULL; - head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_mode_index].bt_table); + head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table); for (p = head; p != NULL; p = p->next) { data = p->data; if (AICBT_PT_BTMODE == p->type) { - ret = rwnx_send_dbg_mem_write_req(sdiodev, *data, aicbsp_mode_index); + *(data + 1) = aicbsp_info.hwinfo < 0; + *(data + 3) = aicbsp_info.hwinfo; + *(data + 5) = aicbsp_info.cpmode; + + *(data + 7) = aicbt_info.btmode; + *(data + 9) = aicbt_info.btport; + *(data + 11) = aicbt_info.uart_baud; + *(data + 13) = aicbt_info.uart_flowctrl; + *(data + 15) = aicbt_info.lpm_enable; + *(data + 17) = aicbt_info.txpwr_lvl; + + printk("%s bt uart baud: %d, flowctrl: %d, lpm_enable: %d, tx_pwr: %d\n", __func__, + aicbt_info.uart_baud, aicbt_info.uart_flowctrl, aicbt_info.lpm_enable, aicbt_info.txpwr_lvl); + } + + if (AICBT_PT_VER == p->type) { + printk("aicbsp: bt patch version: %s\n", (char *)p->data); continue; } + for (i = 0; i < p->len; i++) { ret = rwnx_send_dbg_mem_write_req(sdiodev, *data, *(data + 1)); if (ret != 0) @@ -704,10 +673,19 @@ return 0; } -void aicbt_init(struct aic_sdio_dev *sdiodev) +int aicbt_init(struct aic_sdio_dev *sdiodev) { - aicbt_patch_trap_data_load(sdiodev); - aicbt_patch_table_load(sdiodev); + if (aicbt_patch_trap_data_load(sdiodev)) { + printk("aicbt_patch_trap_data_load fail\n"); + return -1; + } + + if (aicbt_patch_table_load(sdiodev)) { + printk("aicbt_patch_table_load fail\n"); + return -1; + } + + return 0; } static int aicwifi_start_from_bootrom(struct aic_sdio_dev *sdiodev) @@ -716,12 +694,15 @@ /* memory access */ const u32 fw_addr = RAM_FMAC_FW_ADDR; + struct dbg_start_app_cfm start_app_cfm; /* fw start */ - ret = rwnx_send_dbg_start_app_req(sdiodev, fw_addr, HOST_START_APP_AUTO); + ret = rwnx_send_dbg_start_app_req(sdiodev, fw_addr, HOST_START_APP_AUTO, &start_app_cfm); if (ret) { return -1; } + aicbsp_info.hwinfo_r = start_app_cfm.bootstatus & 0xFF; + return 0; } @@ -736,7 +717,7 @@ {0x40344058, 0x00800000, 0x00000000},// pll trx }; -static void aicwifi_sys_config(struct aic_sdio_dev *sdiodev) +static int aicwifi_sys_config(struct aic_sdio_dev *sdiodev) { int ret, cnt; int syscfg_num = sizeof(syscfg_tbl_masked) / sizeof(u32) / 3; @@ -745,6 +726,7 @@ syscfg_tbl_masked[cnt][0], syscfg_tbl_masked[cnt][1], syscfg_tbl_masked[cnt][2]); if (ret) { printk("%x mask write fail: %d\n", syscfg_tbl_masked[cnt][0], ret); + return ret; } } @@ -752,10 +734,13 @@ rf_tbl_masked[0][0], rf_tbl_masked[0][1], rf_tbl_masked[0][2]); if (ret) { printk("rf config %x write fail: %d\n", rf_tbl_masked[0][0], ret); + return ret; } + + return 0; } -static void aicwifi_patch_config(struct aic_sdio_dev *sdiodev) +static int aicwifi_patch_config(struct aic_sdio_dev *sdiodev) { const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0180; u32 config_base; @@ -765,53 +750,79 @@ struct dbg_mem_read_cfm rd_patch_addr_cfm; int ret = 0; u16 cnt = 0; + u32 patch_addr_reg = 0x1e5318; + u32 patch_num_reg = 0x1e531c; + + if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) { + patch_addr_reg = 0x1e5304; + patch_num_reg = 0x1e5308; + } ret = rwnx_send_dbg_mem_read_req(sdiodev, rd_patch_addr, &rd_patch_addr_cfm); if (ret) { printk("patch rd fail\n"); + return ret; } config_base = rd_patch_addr_cfm.memdata; - ret = rwnx_send_dbg_mem_write_req(sdiodev, 0x1e4d28, patch_addr); + ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_addr_reg, patch_addr); if (ret) { - printk("%x write fail\n", 0x1e4d28); + printk("0x%x write fail\n", patch_addr_reg); + return ret; } - ret = rwnx_send_dbg_mem_write_req(sdiodev, 0x1e4d2c, patch_num); + ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, patch_num); if (ret) { - printk("%x write fail\n", 0x1e4d2c); + printk("0x%x write fail\n", patch_num_reg); + return ret; } for (cnt = 0; cnt < patch_num/2; cnt += 1) { ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, patch_tbl[cnt][0]+config_base); if (ret) { printk("%x write fail\n", start_addr+8*cnt); + return ret; } ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, patch_tbl[cnt][1]); if (ret) { printk("%x write fail\n", start_addr+8*cnt+4); + return ret; } } + + return 0; } -void aicwifi_init(struct aic_sdio_dev *sdiodev) +int aicwifi_init(struct aic_sdio_dev *sdiodev) { - if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_WIFI_RAM_ADDR, aicbsp_firmware_list[aicbsp_mode_index].wl_fw)) { + if (rwnx_plat_bin_fw_upload_android(sdiodev, RAM_FMAC_FW_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) { printk("download wifi fw fail\n"); - return; + return -1; } - aicwifi_patch_config(sdiodev); - aicwifi_sys_config(sdiodev); + if (aicwifi_patch_config(sdiodev)) { + printk("aicwifi_patch_config fail\n"); + return -1; + } - aicwifi_start_from_bootrom(sdiodev); + if (aicwifi_sys_config(sdiodev)) { + printk("aicwifi_sys_config fail\n"); + return -1; + } + + if (aicwifi_start_from_bootrom(sdiodev)) { + printk("wifi start fail\n"); + return -1; + } + + return 0; } u32 aicbsp_syscfg_tbl[][2] = { - {0x40500014, 0x00000102}, // 1) - {0x40500018, 0x0000010D}, // 2) + {0x40500014, 0x00000101}, // 1) + {0x40500018, 0x00000109}, // 2) {0x40500004, 0x00000010}, // 3) the order should not be changed // def CONFIG_PMIC_SETTING @@ -826,7 +837,7 @@ {0x50017008, 0x00000000}, // 4) stop wdg }; -static void aicbsp_system_config(struct aic_sdio_dev *sdiodev) +static int aicbsp_system_config(struct aic_sdio_dev *sdiodev) { int syscfg_num = sizeof(aicbsp_syscfg_tbl) / sizeof(u32) / 2; int ret, cnt; @@ -834,15 +845,16 @@ ret = rwnx_send_dbg_mem_write_req(sdiodev, aicbsp_syscfg_tbl[cnt][0], aicbsp_syscfg_tbl[cnt][1]); if (ret) { sdio_err("%x write fail: %d\n", aicbsp_syscfg_tbl[cnt][0], ret); + return ret; } } + return 0; } int aicbsp_platform_init(struct aic_sdio_dev *sdiodev) { rwnx_cmd_mgr_init(&sdiodev->cmd_mgr); sdiodev->cmd_mgr.sdiodev = (void *)sdiodev; - aicbsp_system_config(sdiodev); return 0; } @@ -851,18 +863,163 @@ (void)sdiodev; } -void aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev) +int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev) { - aicbt_init(sdiodev); - aicwifi_init(sdiodev); + const u32 mem_addr = 0x40500000; + struct dbg_mem_read_cfm rd_mem_addr_cfm; + + uint8_t binding_status; + uint8_t dout[16]; + + need_binding_verify = false; + + if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm)) + return -1; + + aicbsp_info.chip_rev = (u8)(rd_mem_addr_cfm.memdata >> 16); + if (aicbsp_info.chip_rev != CHIP_REV_U02 && + aicbsp_info.chip_rev != CHIP_REV_U03 && + aicbsp_info.chip_rev != CHIP_REV_U04) { + pr_err("aicbsp: %s, unsupport chip rev: %d\n", __func__, aicbsp_info.chip_rev); + return -1; + } + + printk("aicbsp: %s, chip rev: %d\n", __func__, aicbsp_info.chip_rev); + + if (aicbsp_info.chip_rev != CHIP_REV_U02) + aicbsp_firmware_list = fw_u03; + + if (aicbsp_system_config(sdiodev)) + return -1; + + if (aicbt_init(sdiodev)) + return -1; + + if (aicwifi_init(sdiodev)) + return -1; + + if (need_binding_verify) { + printk("aicbsp: crypto data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", + binding_enc_data[0], binding_enc_data[1], binding_enc_data[2], binding_enc_data[3], + binding_enc_data[4], binding_enc_data[5], binding_enc_data[6], binding_enc_data[7], + binding_enc_data[8], binding_enc_data[9], binding_enc_data[10], binding_enc_data[11], + binding_enc_data[12], binding_enc_data[13], binding_enc_data[14], binding_enc_data[15]); + + /* calculate verify data from crypto data */ + if (wcn_bind_verify_calculate_verify_data(binding_enc_data, dout)) { + pr_err("aicbsp: %s, binding encrypt data incorrect\n", __func__); + return -1; + } + + printk("aicbsp: verify data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", + dout[0], dout[1], dout[2], dout[3], + dout[4], dout[5], dout[6], dout[7], + dout[8], dout[9], dout[10], dout[11], + dout[12], dout[13], dout[14], dout[15]); + + if (rwnx_send_dbg_binding_req(sdiodev, dout, &binding_status)) { + pr_err("aicbsp: %s, send binding request failn", __func__); + return -1; + } + + if (binding_status) { + pr_err("aicbsp: %s, binding verify fail\n", __func__); + return -1; + } + } + + if (aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 4)) { + sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG); + return -1; + } + + return 0; } int aicbsp_get_feature(struct aicbsp_feature_t *feature) { feature->sdio_clock = FEATURE_SDIO_CLOCK; feature->sdio_phase = FEATURE_SDIO_PHASE; - if (aicbsp_mode_index == AICBSP_MODE_BT_ONLY_SW && FEATURE_5G_SUPPORT) - feature->band_5g_support = true; + feature->hwinfo = aicbsp_info.hwinfo; + feature->fwlog_en = aicbsp_info.fwlog_en; return 0; } EXPORT_SYMBOL_GPL(aicbsp_get_feature); + +#ifdef AICBSP_RESV_MEM_SUPPORT +static struct skb_buff_pool resv_skb[] = { + {AIC_RESV_MEM_TXDATA, 1536*64, "resv_mem_txdata", 0, NULL}, +}; + +int aicbsp_resv_mem_init(void) +{ + int i = 0; + for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) { + resv_skb[i].skb = dev_alloc_skb(resv_skb[i].size); + } + return 0; +} + +int aicbsp_resv_mem_deinit(void) +{ + int i = 0; + for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) { + if (resv_skb[i].used == 0 && resv_skb[i].skb) + dev_kfree_skb(resv_skb[i].skb); + } + return 0; +} + +struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id) +{ + if (resv_skb[id].size < length) { + pr_err("aicbsp: %s, no enough mem\n", __func__); + goto fail; + } + + if (resv_skb[id].used) { + pr_err("aicbsp: %s, mem in use\n", __func__); + goto fail; + } + + if (resv_skb[id].skb == NULL) { + pr_err("aicbsp: %s, mem not initialazed\n", __func__); + resv_skb[id].skb = dev_alloc_skb(resv_skb[id].size); + if (resv_skb[id].skb == NULL) { + pr_err("aicbsp: %s, mem reinitial still fail\n", __func__); + goto fail; + } + } + + printk("aicbsp: %s, alloc %s succuss, id: %d, size: %d\n", __func__, + resv_skb[id].name, resv_skb[id].id, resv_skb[id].size); + + resv_skb[id].used = 1; + return resv_skb[id].skb; + +fail: + return NULL; +} +EXPORT_SYMBOL_GPL(aicbsp_resv_mem_alloc_skb); + +void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id) +{ + resv_skb[id].used = 0; + printk("aicbsp: %s, free %s succuss, id: %d, size: %d\n", __func__, + resv_skb[id].name, resv_skb[id].id, resv_skb[id].size); +} +EXPORT_SYMBOL_GPL(aicbsp_resv_mem_kfree_skb); + +#else + +int aicbsp_resv_mem_init(void) +{ + return 0; +} + +int aicbsp_resv_mem_deinit(void) +{ + return 0; +} + +#endif -- Gitblit v1.6.2