Loading drivers/net/wireless/cnss2/bus.c +31 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,37 @@ int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv) } } int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv) { if (!plat_priv) return -ENODEV; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: return cnss_pci_alloc_qdss_mem(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); return -EINVAL; } } void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv) { if (!plat_priv) return; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: cnss_pci_free_qdss_mem(plat_priv->bus_priv); return; default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); return; } } u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv) { if (!plat_priv) Loading drivers/net/wireless/cnss2/bus.h +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ int cnss_bus_init(struct cnss_plat_data *plat_priv); void cnss_bus_deinit(struct cnss_plat_data *plat_priv); int cnss_bus_load_m3(struct cnss_plat_data *plat_priv); int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv); int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv); void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv); u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv); int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv); void cnss_bus_fw_boot_timeout_hdlr(struct timer_list *t); Loading drivers/net/wireless/cnss2/main.c +119 −0 Original line number Diff line number Diff line Loading @@ -485,6 +485,12 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type) return "POWER_UP"; case CNSS_DRIVER_EVENT_POWER_DOWN: return "POWER_DOWN"; case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: return "QDSS_TRACE_REQ_MEM"; case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: return "QDSS_TRACE_SAVE"; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: return "QDSS_TRACE_FREE"; case CNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } Loading Loading @@ -1138,6 +1144,109 @@ static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv) return 0; } static int cnss_qdss_trace_req_mem_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; ret = cnss_bus_alloc_qdss_mem(plat_priv); if (ret < 0) return ret; return cnss_wlfw_qdss_trace_mem_info_send_sync(plat_priv); } static void *cnss_qdss_trace_pa_to_va(struct cnss_plat_data *plat_priv, u64 pa, u32 size, int *seg_id) { int i = 0; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; u64 offset = 0; void *va = NULL; u64 local_pa; u32 local_size; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { local_pa = (u64)qdss_mem[i].pa; local_size = (u32)qdss_mem[i].size; if (pa == local_pa && size <= local_size) { va = qdss_mem[i].va; break; } if (pa > local_pa && pa < local_pa + local_size && pa + size <= local_pa + local_size) { offset = pa - local_pa; va = qdss_mem[i].va + offset; break; } } *seg_id = i; return va; } static int cnss_qdss_trace_save_hdlr(struct cnss_plat_data *plat_priv, void *data) { struct cnss_qmi_event_qdss_trace_save_data *event_data = data; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int ret = 0; int i; void *va = NULL; u64 pa; u32 size; int seg_id = 0; if (!plat_priv->qdss_mem_seg_len) { cnss_pr_err("Memory for QDSS trace is not available\n"); return -ENOMEM; } if (event_data->mem_seg_len == 0) { for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { ret = cnss_genl_send_msg(qdss_mem[i].va, CNSS_GENL_MSG_TYPE_QDSS, event_data->file_name, qdss_mem[i].size); if (ret < 0) { cnss_pr_err("Fail to save QDSS data: %d\n", ret); break; } } } else { for (i = 0; i < event_data->mem_seg_len; i++) { pa = event_data->mem_seg[i].addr; size = event_data->mem_seg[i].size; va = cnss_qdss_trace_pa_to_va(plat_priv, pa, size, &seg_id); if (!va) { cnss_pr_err("Fail to find matching va for pa %pa\n", pa); ret = -EINVAL; break; } ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS, event_data->file_name, size); if (ret < 0) { cnss_pr_err("Fail to save QDSS data: %d\n", ret); break; } } } kfree(data); return ret; } static int cnss_qdss_trace_free_hdlr(struct cnss_plat_data *plat_priv) { cnss_bus_free_qdss_mem(plat_priv); return 0; } static void cnss_driver_event_work(struct work_struct *work) { struct cnss_plat_data *plat_priv = Loading Loading @@ -1211,6 +1320,16 @@ static void cnss_driver_event_work(struct work_struct *work) case CNSS_DRIVER_EVENT_POWER_DOWN: ret = cnss_power_down_hdlr(plat_priv); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: ret = cnss_qdss_trace_req_mem_hdlr(plat_priv); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: ret = cnss_qdss_trace_save_hdlr(plat_priv, event->data); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: ret = cnss_qdss_trace_free_hdlr(plat_priv); break; default: cnss_pr_err("Invalid driver event type: %d", event->type); Loading drivers/net/wireless/cnss2/main.h +5 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,9 @@ enum cnss_driver_event_type { CNSS_DRIVER_EVENT_FORCE_FW_ASSERT, CNSS_DRIVER_EVENT_POWER_UP, CNSS_DRIVER_EVENT_POWER_DOWN, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM, CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE, CNSS_DRIVER_EVENT_QDSS_TRACE_FREE, CNSS_DRIVER_EVENT_MAX, }; Loading Loading @@ -274,6 +277,8 @@ struct cnss_plat_data { u32 fw_mem_seg_len; struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; struct cnss_fw_mem m3_mem; u32 qdss_mem_seg_len; struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; struct cnss_pin_connect_result pin_result; struct dentry *root_dentry; atomic_t pm_count; Loading drivers/net/wireless/cnss2/pci.c +58 −0 Original line number Diff line number Diff line Loading @@ -1493,6 +1493,63 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) return 0; } int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int i, j; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { if (!qdss_mem[i].va && qdss_mem[i].size) { qdss_mem[i].va = dma_alloc_coherent(&pci_priv->pci_dev->dev, qdss_mem[i].size, &qdss_mem[i].pa, GFP_KERNEL); if (!qdss_mem[i].va) { cnss_pr_err("Failed to allocate QDSS memory for FW, size: 0x%zx, type: %u, chuck-ID: %d\n", qdss_mem[i].size, qdss_mem[i].type, i); break; } } } /* Best-effort allocation for QDSS trace */ if (i < plat_priv->qdss_mem_seg_len) { for (j = i; j < plat_priv->qdss_mem_seg_len; j++) { qdss_mem[j].type = 0; qdss_mem[j].size = 0; } plat_priv->qdss_mem_seg_len = i; } return 0; } void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int i; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { if (qdss_mem[i].va && qdss_mem[i].size) { cnss_pr_dbg("Freeing memory for QDSS: pa: %pa, size: 0x%zx, type: %u\n", &qdss_mem[i].pa, qdss_mem[i].size, qdss_mem[i].type); dma_free_coherent(&pci_priv->pci_dev->dev, qdss_mem[i].size, qdss_mem[i].va, qdss_mem[i].pa); qdss_mem[i].va = NULL; qdss_mem[i].pa = 0; qdss_mem[i].size = 0; qdss_mem[i].type = 0; } } plat_priv->qdss_mem_seg_len = 0; } static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; Loading Loading @@ -2687,6 +2744,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) cnss_pci_free_m3_mem(pci_priv); cnss_pci_free_fw_mem(pci_priv); cnss_pci_free_qdss_mem(pci_priv); switch (pci_dev->device) { case QCA6290_DEVICE_ID: Loading Loading
drivers/net/wireless/cnss2/bus.c +31 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,37 @@ int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv) } } int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv) { if (!plat_priv) return -ENODEV; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: return cnss_pci_alloc_qdss_mem(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); return -EINVAL; } } void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv) { if (!plat_priv) return; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: cnss_pci_free_qdss_mem(plat_priv->bus_priv); return; default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); return; } } u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv) { if (!plat_priv) Loading
drivers/net/wireless/cnss2/bus.h +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ int cnss_bus_init(struct cnss_plat_data *plat_priv); void cnss_bus_deinit(struct cnss_plat_data *plat_priv); int cnss_bus_load_m3(struct cnss_plat_data *plat_priv); int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv); int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv); void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv); u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv); int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv); void cnss_bus_fw_boot_timeout_hdlr(struct timer_list *t); Loading
drivers/net/wireless/cnss2/main.c +119 −0 Original line number Diff line number Diff line Loading @@ -485,6 +485,12 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type) return "POWER_UP"; case CNSS_DRIVER_EVENT_POWER_DOWN: return "POWER_DOWN"; case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: return "QDSS_TRACE_REQ_MEM"; case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: return "QDSS_TRACE_SAVE"; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: return "QDSS_TRACE_FREE"; case CNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } Loading Loading @@ -1138,6 +1144,109 @@ static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv) return 0; } static int cnss_qdss_trace_req_mem_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; ret = cnss_bus_alloc_qdss_mem(plat_priv); if (ret < 0) return ret; return cnss_wlfw_qdss_trace_mem_info_send_sync(plat_priv); } static void *cnss_qdss_trace_pa_to_va(struct cnss_plat_data *plat_priv, u64 pa, u32 size, int *seg_id) { int i = 0; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; u64 offset = 0; void *va = NULL; u64 local_pa; u32 local_size; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { local_pa = (u64)qdss_mem[i].pa; local_size = (u32)qdss_mem[i].size; if (pa == local_pa && size <= local_size) { va = qdss_mem[i].va; break; } if (pa > local_pa && pa < local_pa + local_size && pa + size <= local_pa + local_size) { offset = pa - local_pa; va = qdss_mem[i].va + offset; break; } } *seg_id = i; return va; } static int cnss_qdss_trace_save_hdlr(struct cnss_plat_data *plat_priv, void *data) { struct cnss_qmi_event_qdss_trace_save_data *event_data = data; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int ret = 0; int i; void *va = NULL; u64 pa; u32 size; int seg_id = 0; if (!plat_priv->qdss_mem_seg_len) { cnss_pr_err("Memory for QDSS trace is not available\n"); return -ENOMEM; } if (event_data->mem_seg_len == 0) { for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { ret = cnss_genl_send_msg(qdss_mem[i].va, CNSS_GENL_MSG_TYPE_QDSS, event_data->file_name, qdss_mem[i].size); if (ret < 0) { cnss_pr_err("Fail to save QDSS data: %d\n", ret); break; } } } else { for (i = 0; i < event_data->mem_seg_len; i++) { pa = event_data->mem_seg[i].addr; size = event_data->mem_seg[i].size; va = cnss_qdss_trace_pa_to_va(plat_priv, pa, size, &seg_id); if (!va) { cnss_pr_err("Fail to find matching va for pa %pa\n", pa); ret = -EINVAL; break; } ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS, event_data->file_name, size); if (ret < 0) { cnss_pr_err("Fail to save QDSS data: %d\n", ret); break; } } } kfree(data); return ret; } static int cnss_qdss_trace_free_hdlr(struct cnss_plat_data *plat_priv) { cnss_bus_free_qdss_mem(plat_priv); return 0; } static void cnss_driver_event_work(struct work_struct *work) { struct cnss_plat_data *plat_priv = Loading Loading @@ -1211,6 +1320,16 @@ static void cnss_driver_event_work(struct work_struct *work) case CNSS_DRIVER_EVENT_POWER_DOWN: ret = cnss_power_down_hdlr(plat_priv); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: ret = cnss_qdss_trace_req_mem_hdlr(plat_priv); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: ret = cnss_qdss_trace_save_hdlr(plat_priv, event->data); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: ret = cnss_qdss_trace_free_hdlr(plat_priv); break; default: cnss_pr_err("Invalid driver event type: %d", event->type); Loading
drivers/net/wireless/cnss2/main.h +5 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,9 @@ enum cnss_driver_event_type { CNSS_DRIVER_EVENT_FORCE_FW_ASSERT, CNSS_DRIVER_EVENT_POWER_UP, CNSS_DRIVER_EVENT_POWER_DOWN, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM, CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE, CNSS_DRIVER_EVENT_QDSS_TRACE_FREE, CNSS_DRIVER_EVENT_MAX, }; Loading Loading @@ -274,6 +277,8 @@ struct cnss_plat_data { u32 fw_mem_seg_len; struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; struct cnss_fw_mem m3_mem; u32 qdss_mem_seg_len; struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; struct cnss_pin_connect_result pin_result; struct dentry *root_dentry; atomic_t pm_count; Loading
drivers/net/wireless/cnss2/pci.c +58 −0 Original line number Diff line number Diff line Loading @@ -1493,6 +1493,63 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) return 0; } int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int i, j; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { if (!qdss_mem[i].va && qdss_mem[i].size) { qdss_mem[i].va = dma_alloc_coherent(&pci_priv->pci_dev->dev, qdss_mem[i].size, &qdss_mem[i].pa, GFP_KERNEL); if (!qdss_mem[i].va) { cnss_pr_err("Failed to allocate QDSS memory for FW, size: 0x%zx, type: %u, chuck-ID: %d\n", qdss_mem[i].size, qdss_mem[i].type, i); break; } } } /* Best-effort allocation for QDSS trace */ if (i < plat_priv->qdss_mem_seg_len) { for (j = i; j < plat_priv->qdss_mem_seg_len; j++) { qdss_mem[j].type = 0; qdss_mem[j].size = 0; } plat_priv->qdss_mem_seg_len = i; } return 0; } void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; int i; for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { if (qdss_mem[i].va && qdss_mem[i].size) { cnss_pr_dbg("Freeing memory for QDSS: pa: %pa, size: 0x%zx, type: %u\n", &qdss_mem[i].pa, qdss_mem[i].size, qdss_mem[i].type); dma_free_coherent(&pci_priv->pci_dev->dev, qdss_mem[i].size, qdss_mem[i].va, qdss_mem[i].pa); qdss_mem[i].va = NULL; qdss_mem[i].pa = 0; qdss_mem[i].size = 0; qdss_mem[i].type = 0; } } plat_priv->qdss_mem_seg_len = 0; } static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; Loading Loading @@ -2687,6 +2744,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) cnss_pci_free_m3_mem(pci_priv); cnss_pci_free_fw_mem(pci_priv); cnss_pci_free_qdss_mem(pci_priv); switch (pci_dev->device) { case QCA6290_DEVICE_ID: Loading