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 <bmahalin@codeaurora.org>
Signed-off-by: Will Huang <quic_wilhuang@quicinc.com>
This commit is contained in:
Will Huang 2022-06-20 09:56:01 +08:00
commit b4ea3e4d0a
3 changed files with 99 additions and 0 deletions

View file

@ -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;

View file

@ -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,
};

View file

@ -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 */