From b4ea3e4d0a61fa186a8873df6c607c7be25b99cc Mon Sep 17 00:00:00 2001 From: Will Huang Date: Mon, 20 Jun 2022 09:56:01 +0800 Subject: [PATCH] cnss2: Add support for handling AFC memory request from FW Add APIs for handling AFC memory request from FW: cnss_send_buffer_to_afcmem() and cnss_reset_afcmem(). cnss_send_buffer_to_afcmem() will be called if receive valid AFC response data, cnss_reset_afcmem() will be called if receive invalid AFC response data. After memory copy done, another WMI command will indicate FW ready to read. Add FW memory type QMI_WLFW_AFC_MEM_V01. Change-Id: I34b9add3d7721d778e5474d9b11ad64adb4f04f0 CRs-Fixed: 3223607 Signed-off-by: Balamurugan Mahalingam Signed-off-by: Will Huang --- drivers/net/wireless/cnss2/pci.c | 95 +++++++++++++++++++ .../cnss_utils/wlan_firmware_service_v01.h | 1 + include/net/cnss2.h | 3 + 3 files changed, 99 insertions(+) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 4b8f78da518d..1428c2493d56 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -89,6 +89,13 @@ static DEFINE_SPINLOCK(time_sync_lock); #define MHI_SUSPEND_RETRY_CNT 3 +#define AFC_SLOT_SIZE 0x1000 +#define AFC_MAX_SLOT 2 +#define AFC_MEM_SIZE (AFC_SLOT_SIZE * AFC_MAX_SLOT) +#define AFC_AUTH_STATUS_OFFSET 1 +#define AFC_AUTH_SUCCESS 1 +#define AFC_AUTH_ERROR 0 + static struct cnss_pci_reg ce_src[] = { { "SRC_RING_BASE_LSB", QCA6390_CE_SRC_RING_BASE_LSB_OFFSET }, { "SRC_RING_BASE_MSB", QCA6390_CE_SRC_RING_BASE_MSB_OFFSET }, @@ -3977,6 +3984,94 @@ int cnss_pci_qmi_send_put(struct cnss_pci_data *pci_priv) return ret; } +int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb, uint32_t len, + uint8_t slotid) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + struct cnss_fw_mem *fw_mem; + void *mem = NULL; + int i, ret; + u32 *status; + + if (!plat_priv) + return -EINVAL; + + fw_mem = plat_priv->fw_mem; + if (slotid >= AFC_MAX_SLOT) { + cnss_pr_err("Invalid slot id %d\n", slotid); + ret = -EINVAL; + goto err; + } + if (len > AFC_SLOT_SIZE) { + cnss_pr_err("len %d greater than slot size", len); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + if (fw_mem[i].type == QMI_WLFW_AFC_MEM_V01) { + mem = fw_mem[i].va; + status = mem + (slotid * AFC_SLOT_SIZE); + break; + } + } + + if (!mem) { + cnss_pr_err("AFC mem is not available\n"); + ret = -ENOMEM; + goto err; + } + + memcpy(mem + (slotid * AFC_SLOT_SIZE), afcdb, len); + if (len < AFC_SLOT_SIZE) + memset(mem + (slotid * AFC_SLOT_SIZE) + len, + 0, AFC_SLOT_SIZE - len); + status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_SUCCESS); + + return 0; +err: + return ret; +} +EXPORT_SYMBOL(cnss_send_buffer_to_afcmem); + +int cnss_reset_afcmem(struct device *dev, uint8_t slotid) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + struct cnss_fw_mem *fw_mem; + void *mem = NULL; + int i, ret; + + if (!plat_priv) + return -EINVAL; + + fw_mem = plat_priv->fw_mem; + if (slotid >= AFC_MAX_SLOT) { + cnss_pr_err("Invalid slot id %d\n", slotid); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + if (fw_mem[i].type == QMI_WLFW_AFC_MEM_V01) { + mem = fw_mem[i].va; + break; + } + } + + if (!mem) { + cnss_pr_err("AFC mem is not available\n"); + ret = -ENOMEM; + goto err; + } + + memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE); + return 0; + +err: + return ret; +} +EXPORT_SYMBOL(cnss_reset_afcmem); + int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; diff --git a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h index eb89ad4176ad..4145358c86bd 100644 --- a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h +++ b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h @@ -168,6 +168,7 @@ enum wlfw_mem_type_enum_v01 { QMI_WLFW_MEM_HANG_DATA_V01 = 7, QMI_WLFW_MLO_GLOBAL_MEM_V01 = 8, QMI_WLFW_PAGEABLE_MEM_V01 = 9, + QMI_WLFW_AFC_MEM_V01 = 10, WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX, }; diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 2cbfd3136d82..dbb0ea5978fb 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -278,4 +278,7 @@ extern int cnss_get_mem_seg_count(enum cnss_remote_mem_type type, u32 *seg); extern int cnss_get_mem_segment_info(enum cnss_remote_mem_type type, struct cnss_mem_segment segment[], u32 segment_count); +extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb, + uint32_t len, uint8_t slotid); +extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid); #endif /* _NET_CNSS2_H */