diff --git a/hif/src/ce/ce_api.h b/hif/src/ce/ce_api.h index 828a8e8682..d2b0f31530 100644 --- a/hif/src/ce/ce_api.h +++ b/hif/src/ce/ce_api.h @@ -437,6 +437,7 @@ void war_ce_src_ring_write_idx_set(struct hif_softc *scn, #define CE_ATTR_DISABLE_INTR 0x08 /* no interrupt on copy completion */ #define CE_ATTR_ENABLE_POLL 0x10 /* poll for residue descriptors */ #define CE_ATTR_DIAG 0x20 /* Diag CE */ +#define CE_ATTR_INIT_ON_DEMAND 0x40 /* Initialized on demand */ /** * struct CE_attr - Attributes of an instance of a Copy Engine diff --git a/hif/src/ce/ce_assignment.h b/hif/src/ce/ce_assignment.h index e749ef2dae..a8dacf1a85 100644 --- a/hif/src/ce/ce_assignment.h +++ b/hif/src/ce/ce_assignment.h @@ -1001,7 +1001,7 @@ static struct CE_attr host_ce_config_wlan_qca5018[] = { #ifdef REMOVE_PKT_LOG { /* CE5 */ 0, 0, 0, 0, 0, NULL,}, #else - {/*CE5*/ (CE_ATTR_FLAGS), 0, 0, 2048, + {/*CE5*/ (CE_ATTR_FLAGS | CE_ATTR_INIT_ON_DEMAND), 0, 0, 2048, 512, NULL,}, #endif /* Target autonomous HIF_memcpy */ @@ -1057,7 +1057,7 @@ static struct CE_attr host_ce_config_wlan_qcn9000[] = { #ifdef REMOVE_PKT_LOG { /* CE5 */ 0, 0, 0, 0, 0, NULL,}, #else - {/*CE5*/ (CE_ATTR_FLAGS), 0, 0, 2048, + {/*CE5*/ (CE_ATTR_FLAGS | CE_ATTR_INIT_ON_DEMAND), 0, 0, 2048, 512, NULL,}, #endif /* Target autonomous HIF_memcpy */ diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index d461b994d3..e8d768b681 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -87,7 +87,6 @@ QDF_STATUS hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info); #endif /* ENABLE_10_4_FW_HDR == 1 */ #endif /* ENABLE_10_4_FW_HDR */ -QDF_STATUS hif_post_recv_buffers(struct hif_softc *scn); static void hif_config_rri_on_ddr(struct hif_softc *scn); /** @@ -849,6 +848,7 @@ static void hif_select_service_to_pipe_map(struct hif_softc *scn, uint32_t *sz_tgt_svc_map_to_use) { uint32_t mode = hif_get_conparam(scn); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); struct hif_target_info *tgt_info = &scn->target_info; if (QDF_IS_EPPING_ENABLED(mode)) { @@ -927,6 +927,9 @@ static void hif_select_service_to_pipe_map(struct hif_softc *scn, break; } } + hif_state->tgt_svc_map = *tgt_svc_map_to_use; + hif_state->sz_tgt_svc_map = *sz_tgt_svc_map_to_use / + sizeof(struct service_to_pipe); } /** @@ -1837,6 +1840,18 @@ bool hif_is_polled_mode_enabled(struct hif_opaque_softc *hif_ctx) } qdf_export_symbol(hif_is_polled_mode_enabled); +static int hif_get_pktlog_ce_num(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int id; + + for (id = 0; id < hif_state->sz_tgt_svc_map; id++) { + if (hif_state->tgt_svc_map[id].service_id == PACKET_LOG_SVC) + return hif_state->tgt_svc_map[id].pipenum; + } + return -EINVAL; +} + #ifdef WLAN_FEATURE_FASTPATH /** * hif_enable_fastpath() Update that we have enabled fastpath mode @@ -2350,13 +2365,61 @@ hif_post_init(struct hif_opaque_softc *hif_ctx, void *unused, } -static int hif_completion_thread_startup(struct HIF_CE_state *hif_state) +static int hif_completion_thread_startup_by_ceid(struct HIF_CE_state *hif_state, + int pipe_num) { - struct CE_handle *ce_diag = hif_state->ce_diag; - int pipe_num; + struct CE_attr attr; struct hif_softc *scn = HIF_GET_SOFTC(hif_state); struct hif_msg_callbacks *hif_msg_callbacks = &hif_state->msg_callbacks_current; + struct HIF_CE_pipe_info *pipe_info; + + if (pipe_num >= CE_COUNT_MAX) + return -EINVAL; + + pipe_info = &hif_state->pipe_info[pipe_num]; + + if (!hif_msg_callbacks || + !hif_msg_callbacks->rxCompletionHandler || + !hif_msg_callbacks->txCompletionHandler) { + hif_err("%s: no completion handler registered", __func__); + return -EFAULT; + } + + attr = hif_state->host_ce_config[pipe_num]; + if (attr.src_nentries) { + /* pipe used to send to target */ + hif_debug("%s: pipe_num:%d pipe_info:0x%pK\n", + __func__, pipe_num, pipe_info); + ce_send_cb_register(pipe_info->ce_hdl, + hif_pci_ce_send_done, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + pipe_info->num_sends_allowed = attr.src_nentries - 1; + } + if (attr.dest_nentries) { + hif_debug("%s: pipe_num:%d pipe_info:0x%pK\n", + __func__, pipe_num, pipe_info); + /* pipe used to receive from target */ + ce_recv_cb_register(pipe_info->ce_hdl, + hif_pci_ce_recv_data, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + } + + if (attr.src_nentries) + qdf_spinlock_create(&pipe_info->completion_freeq_lock); + + /* PKTLOG callback is already updated from htt_htc_soc_attach() */ + if (pipe_num != hif_get_pktlog_ce_num(scn)) + qdf_mem_copy(&pipe_info->pipe_callbacks, hif_msg_callbacks, + sizeof(pipe_info->pipe_callbacks)); + return 0; +} + +static int hif_completion_thread_startup(struct HIF_CE_state *hif_state) +{ + struct CE_handle *ce_diag = hif_state->ce_diag; + int pipe_num, ret; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); /* daemonize("hif_compl_thread"); */ @@ -2365,43 +2428,20 @@ static int hif_completion_thread_startup(struct HIF_CE_state *hif_state) return -EINVAL; } - if (!hif_msg_callbacks || - !hif_msg_callbacks->rxCompletionHandler || - !hif_msg_callbacks->txCompletionHandler) { - hif_err("no completion handler registered"); - return -EFAULT; - } A_TARGET_ACCESS_LIKELY(scn); for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { - struct CE_attr attr; struct HIF_CE_pipe_info *pipe_info; pipe_info = &hif_state->pipe_info[pipe_num]; if (pipe_info->ce_hdl == ce_diag) continue; /* Handle Diagnostic CE specially */ - attr = hif_state->host_ce_config[pipe_num]; - if (attr.src_nentries) { - /* pipe used to send to target */ - hif_debug("pipe_num:%d pipe_info:0x%pK", - pipe_num, pipe_info); - ce_send_cb_register(pipe_info->ce_hdl, - hif_pci_ce_send_done, pipe_info, - attr.flags & CE_ATTR_DISABLE_INTR); - pipe_info->num_sends_allowed = attr.src_nentries - 1; - } - if (attr.dest_nentries) { - /* pipe used to receive from target */ - ce_recv_cb_register(pipe_info->ce_hdl, - hif_pci_ce_recv_data, pipe_info, - attr.flags & CE_ATTR_DISABLE_INTR); - } - if (attr.src_nentries) - qdf_spinlock_create(&pipe_info->completion_freeq_lock); + ret = hif_completion_thread_startup_by_ceid(hif_state, + pipe_num); + if (ret < 0) + return ret; - qdf_mem_copy(&pipe_info->pipe_callbacks, hif_msg_callbacks, - sizeof(pipe_info->pipe_callbacks)); } A_TARGET_ACCESS_UNLIKELY(scn); @@ -2604,7 +2644,7 @@ QDF_STATUS hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info) * failures, non-zero if unable to completely replenish * receive buffers for fastpath rx Copy engine. */ -QDF_STATUS hif_post_recv_buffers(struct hif_softc *scn) +static QDF_STATUS hif_post_recv_buffers(struct hif_softc *scn) { struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); int pipe_num; @@ -2618,6 +2658,13 @@ QDF_STATUS hif_post_recv_buffers(struct hif_softc *scn) ce_state = scn->ce_id_to_state[pipe_num]; pipe_info = &hif_state->pipe_info[pipe_num]; + if (!ce_state) + continue; + + /* Do not init dynamic CEs, during initial load */ + if (ce_state->attr_flags & CE_ATTR_INIT_ON_DEMAND) + continue; + if (hif_is_nss_wifi_enabled(scn) && ce_state && (ce_state->htt_rx_data)) continue; @@ -3522,6 +3569,79 @@ static int hif_srng_sleep_state_adjust(struct hif_softc *scn, bool sleep_ok, return 0; } +int hif_config_ce_by_id(struct hif_softc *scn, int pipe_num) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct HIF_CE_pipe_info *pipe_info; + struct CE_state *ce_state = NULL; + struct CE_attr *attr; + int rv = 0; + + if (pipe_num >= CE_COUNT_MAX) + return -EINVAL; + + pipe_info = &hif_state->pipe_info[pipe_num]; + pipe_info->pipe_num = pipe_num; + pipe_info->HIF_CE_state = hif_state; + attr = &hif_state->host_ce_config[pipe_num]; + ce_state = scn->ce_id_to_state[pipe_num]; + + if (ce_state) { + /* Do not reinitialize the CE if its done already */ + rv = QDF_STATUS_E_BUSY; + goto err; + } + + pipe_info->ce_hdl = ce_init(scn, pipe_num, attr); + ce_state = scn->ce_id_to_state[pipe_num]; + if (!ce_state) { + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + qdf_spinlock_create(&pipe_info->recv_bufs_needed_lock); + QDF_ASSERT(pipe_info->ce_hdl); + if (!pipe_info->ce_hdl) { + rv = QDF_STATUS_E_FAILURE; + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + + ce_state->lro_data = qdf_lro_init(); + + if (attr->flags & CE_ATTR_DIAG) { + /* Reserve the ultimate CE for + * Diagnostic Window support + */ + hif_state->ce_diag = pipe_info->ce_hdl; + goto skip; + } + + if (hif_is_nss_wifi_enabled(scn) && ce_state && + (ce_state->htt_rx_data)) { + goto skip; + } + + pipe_info->buf_sz = (qdf_size_t)(attr->src_sz_max); + if (attr->dest_nentries > 0) { + atomic_set(&pipe_info->recv_bufs_needed, + init_buffer_count(attr->dest_nentries - 1)); + /*SRNG based CE has one entry less */ + if (ce_srng_based(scn)) + atomic_dec(&pipe_info->recv_bufs_needed); + } else { + atomic_set(&pipe_info->recv_bufs_needed, 0); + } + ce_tasklet_init(hif_state, (1 << pipe_num)); + ce_register_irq(hif_state, (1 << pipe_num)); + + init_tasklet_worker_by_ceid(hif_hdl, pipe_num); +skip: + return 0; +err: + return rv; +} + /** * hif_config_ce() - configure copy engines * @scn: hif context @@ -3536,10 +3656,8 @@ static int hif_srng_sleep_state_adjust(struct hif_softc *scn, bool sleep_ok, int hif_config_ce(struct hif_softc *scn) { struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); - struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); struct HIF_CE_pipe_info *pipe_info; int pipe_num; - struct CE_state *ce_state = NULL; #ifdef ADRASTEA_SHADOW_REGISTERS int i; @@ -3568,50 +3686,13 @@ int hif_config_ce(struct hif_softc *scn) struct CE_attr *attr; pipe_info = &hif_state->pipe_info[pipe_num]; - pipe_info->pipe_num = pipe_num; - pipe_info->HIF_CE_state = hif_state; attr = &hif_state->host_ce_config[pipe_num]; - pipe_info->ce_hdl = ce_init(scn, pipe_num, attr); - ce_state = scn->ce_id_to_state[pipe_num]; - if (!ce_state) { - A_TARGET_ACCESS_UNLIKELY(scn); - goto err; - } - qdf_spinlock_create(&pipe_info->recv_bufs_needed_lock); - QDF_ASSERT(pipe_info->ce_hdl); - if (!pipe_info->ce_hdl) { - rv = QDF_STATUS_E_FAILURE; - A_TARGET_ACCESS_UNLIKELY(scn); - goto err; - } - - ce_state->lro_data = qdf_lro_init(); - - if (attr->flags & CE_ATTR_DIAG) { - /* Reserve the ultimate CE for - * Diagnostic Window support - */ - hif_state->ce_diag = pipe_info->ce_hdl; - continue; - } - - if (hif_is_nss_wifi_enabled(scn) && ce_state && - (ce_state->htt_rx_data)) + if (attr->flags & CE_ATTR_INIT_ON_DEMAND) continue; - pipe_info->buf_sz = (qdf_size_t) (attr->src_sz_max); - if (attr->dest_nentries > 0) { - atomic_set(&pipe_info->recv_bufs_needed, - init_buffer_count(attr->dest_nentries - 1)); - /*SRNG based CE has one entry less */ - if (ce_srng_based(scn)) - atomic_dec(&pipe_info->recv_bufs_needed); - } else { - atomic_set(&pipe_info->recv_bufs_needed, 0); - } - ce_tasklet_init(hif_state, (1 << pipe_num)); - ce_register_irq(hif_state, (1 << pipe_num)); + if (hif_config_ce_by_id(scn, pipe_num)) + goto err; } if (athdiag_procfs_init(scn) != 0) { @@ -3621,10 +3702,7 @@ int hif_config_ce(struct hif_softc *scn) scn->athdiag_procfs_inited = true; hif_debug("ce_init done"); - - init_tasklet_workers(hif_hdl); - - hif_debug("X, ret = %d", rv); + hif_debug("%s: X, ret = %d", __func__, rv); #ifdef ADRASTEA_SHADOW_REGISTERS hif_debug("Using Shadow Registers instead of CE Registers"); @@ -3636,7 +3714,6 @@ int hif_config_ce(struct hif_softc *scn) #endif return rv != QDF_STATUS_SUCCESS; - err: /* Failure, so clean up */ hif_unconfig_ce(scn); @@ -3644,6 +3721,69 @@ err: return QDF_STATUS_SUCCESS != QDF_STATUS_E_FAILURE; } +/** + * hif_config_ce_pktlog() - configure copy engines + * @scn: hif context + * + * Prepares fw, copy engine hardware and host sw according + * to the attributes selected by hif_ce_prepare_config. + * + * also calls athdiag_procfs_init + * + * return: 0 for success nonzero for failure. + */ +int hif_config_ce_pktlog(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int pipe_num; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct HIF_CE_pipe_info *pipe_info; + + if (!scn) + goto err; + + if (scn->pktlog_init) + return QDF_STATUS_SUCCESS; + + pipe_num = hif_get_pktlog_ce_num(scn); + if (pipe_num < 0) { + qdf_status = QDF_STATUS_E_FAILURE; + goto err; + } + + pipe_info = &hif_state->pipe_info[pipe_num]; + + qdf_status = hif_config_ce_by_id(scn, pipe_num); + /* CE Already initialized. Do not try to reinitialized again */ + if (qdf_status == QDF_STATUS_E_BUSY) + return QDF_STATUS_SUCCESS; + + qdf_status = hif_config_irq_by_ceid(scn, pipe_num); + if (qdf_status < 0) + goto err; + + qdf_status = hif_completion_thread_startup_by_ceid(hif_state, pipe_num); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hif_err("%s:failed to start hif thread", __func__); + goto err; + } + + /* Post buffers for pktlog copy engine. */ + qdf_status = hif_post_recv_buffers_for_pipe(pipe_info); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* cleanup is done in hif_ce_disable */ + hif_err("%s:failed to post buffers", __func__); + return qdf_status; + } + scn->pktlog_init = true; + return qdf_status != QDF_STATUS_SUCCESS; + +err: + hif_debug("%s: X, ret = %d", __func__, qdf_status); + return QDF_STATUS_SUCCESS != QDF_STATUS_E_FAILURE; +} + #ifdef IPA_OFFLOAD /** * hif_ce_ipa_get_ce_resource() - get uc resource on hif diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h index d287534364..1b680e7d2c 100644 --- a/hif/src/ce/ce_main.h +++ b/hif/src/ce/ce_main.h @@ -221,6 +221,8 @@ struct HIF_CE_state { struct CE_handle *ce_diag; struct ce_stats stats; struct ce_ops *ce_services; + struct service_to_pipe *tgt_svc_map; + int sz_tgt_svc_map; }; /* diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index e88a6e913d..991ed1e707 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -77,7 +77,6 @@ static void reschedule_ce_tasklet_work_handler(struct work_struct *work) } static struct tasklet_work tasklet_workers[CE_ID_MAX]; -static bool work_initialized; /** * init_tasklet_work() - init_tasklet_work @@ -98,17 +97,13 @@ static void init_tasklet_work(struct work_struct *work, * * Return: N/A */ -void init_tasklet_workers(struct hif_opaque_softc *scn) +void init_tasklet_worker_by_ceid(struct hif_opaque_softc *scn, int ce_id) { - uint32_t id; - for (id = 0; id < CE_ID_MAX; id++) { - tasklet_workers[id].id = id; - tasklet_workers[id].data = scn; - init_tasklet_work(&tasklet_workers[id].work, - reschedule_ce_tasklet_work_handler); - } - work_initialized = true; + tasklet_workers[ce_id].id = ce_id; + tasklet_workers[ce_id].data = scn; + init_tasklet_work(&tasklet_workers[ce_id].work, + reschedule_ce_tasklet_work_handler); } /** @@ -123,8 +118,6 @@ void deinit_tasklet_workers(struct hif_opaque_softc *scn) for (id = 0; id < CE_ID_MAX; id++) cancel_work_sync(&tasklet_workers[id].work); - - work_initialized = false; } /** @@ -428,8 +421,6 @@ void ce_tasklet_kill(struct hif_softc *scn) int i; struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn); - work_initialized = false; - for (i = 0; i < CE_COUNT_MAX; i++) { if (hif_ce_state->tasklets[i].inited) { hif_ce_state->tasklets[i].inited = false; diff --git a/hif/src/ce/ce_tasklet.h b/hif/src/ce/ce_tasklet.h index d5ab58cefb..7d78fa2cf2 100644 --- a/hif/src/ce/ce_tasklet.h +++ b/hif/src/ce/ce_tasklet.h @@ -19,7 +19,7 @@ #ifndef __CE_TASKLET_H__ #define __CE_TASKLET_H__ #include "ce_main.h" -void init_tasklet_workers(struct hif_opaque_softc *scn); +void init_tasklet_worker_by_ceid(struct hif_opaque_softc *scn, int pipe_num); void deinit_tasklet_workers(struct hif_opaque_softc *scn); void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask); void ce_tasklet_kill(struct hif_softc *scn); diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h index 1657cbc337..87e64d3494 100644 --- a/hif/src/dispatcher/ahb_api.h +++ b/hif/src/dispatcher/ahb_api.h @@ -47,6 +47,7 @@ int hif_ahb_enable_radio(struct hif_pci_softc *sc, struct platform_device *pdev, const struct platform_device_id *id); int hif_ahb_configure_irq(struct hif_pci_softc *sc); +int hif_ahb_configure_irq_by_ceid(struct hif_softc *sc, int ce_id); int hif_ahb_configure_grp_irq(struct hif_softc *scn, struct hif_exec_context *hif_ext_grp); bool hif_ahb_needs_bmi(struct hif_softc *scn); diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c index 6eedb80888..9845618bb2 100644 --- a/hif/src/dispatcher/multibus.c +++ b/hif/src/dispatcher/multibus.c @@ -568,3 +568,8 @@ void hif_config_irq_affinity(struct hif_softc *hif_sc) { hif_sc->bus_ops.hif_config_irq_affinity(hif_sc); } + +int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id) +{ + return hif_sc->bus_ops.hif_config_irq_by_ceid(hif_sc, ce_id); +} diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h index 8adb745417..9ae40367b0 100644 --- a/hif/src/dispatcher/multibus.h +++ b/hif/src/dispatcher/multibus.h @@ -86,6 +86,7 @@ struct hif_bus_ops { int (*hif_addr_in_boundary)(struct hif_softc *scn, uint32_t offset); bool (*hif_needs_bmi)(struct hif_softc *hif_sc); void (*hif_config_irq_affinity)(struct hif_softc *hif_sc); + int (*hif_config_irq_by_ceid)(struct hif_softc *hif_sc, int ce_id); }; #ifdef HIF_SNOC @@ -254,4 +255,13 @@ static inline int hif_usb_get_context_size(void) * Return: None */ void hif_config_irq_affinity(struct hif_softc *hif_sc); + +/** + * hif_config_irq_by_ceid() - register irq by CE id + * @hif_sc - hif context + * @ce_id - Copy Engine id for which the irq need to be configured + * + * Return: 0 on success, negative value on error. + */ +int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id); #endif /* _MULTIBUS_H_ */ diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c index 8645b76365..19c13d2df5 100644 --- a/hif/src/dispatcher/multibus_ahb.c +++ b/hif/src/dispatcher/multibus_ahb.c @@ -73,6 +73,7 @@ QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops) bus_ops->hif_clear_stats = &hif_ahb_clear_stats; bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; + bus_ops->hif_config_irq_by_ceid = &hif_ahb_configure_irq_by_ceid; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_pci.c b/hif/src/dispatcher/multibus_pci.c index d982cafa8b..4783fef75e 100644 --- a/hif/src/dispatcher/multibus_pci.c +++ b/hif/src/dispatcher/multibus_pci.c @@ -91,6 +91,7 @@ QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc) bus_ops->hif_config_irq_affinity = &hif_pci_config_irq_affinity; + bus_ops->hif_config_irq_by_ceid = &hif_ce_msi_configure_irq_by_ceid; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/pci_api.h b/hif/src/dispatcher/pci_api.h index f9140cd025..ac873a8e04 100644 --- a/hif/src/dispatcher/pci_api.h +++ b/hif/src/dispatcher/pci_api.h @@ -67,4 +67,5 @@ const char *hif_pci_get_irq_name(int irq_no); * Return: None */ void hif_pci_config_irq_affinity(struct hif_softc *scn); +int hif_ce_msi_configure_irq_by_ceid(struct hif_softc *scn, int ce_id); #endif /* _PCI_API_H_ */ diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 94512a4dbb..34220d4f68 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -259,6 +259,7 @@ struct hif_softc { /* Should the unlzay support for interrupt delivery be disabled */ /* Flag to indicate whether bus is suspended */ bool bus_suspended; + bool pktlog_init; }; static inline @@ -331,6 +332,8 @@ void hif_shutdown_device(struct hif_opaque_softc *hif_ctx); int hif_bus_configure(struct hif_softc *scn); void hif_cancel_deferred_target_sleep(struct hif_softc *scn); int hif_config_ce(struct hif_softc *scn); +int hif_config_ce_pktlog(struct hif_opaque_softc *hif_ctx); +int hif_config_ce_by_id(struct hif_softc *scn, int pipe_num); void hif_unconfig_ce(struct hif_softc *scn); void hif_ce_prepare_config(struct hif_softc *scn); QDF_STATUS hif_ce_open(struct hif_softc *scn); diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 331a59f0bd..095ac2e4d9 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -2809,6 +2809,52 @@ static void hif_ce_legacy_msi_irq_enable(struct hif_softc *hif_sc, int ce_id) enable_irq(hif_ce_msi_map_ce_to_irq(hif_sc, ce_id)); } +int hif_ce_msi_configure_irq_by_ceid(struct hif_softc *scn, int ce_id) +{ + int ret = 0; + int irq; + uint32_t msi_data_start; + uint32_t msi_data_count; + unsigned int msi_data; + uint32_t msi_irq_start; + struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn); + struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(scn); + int pci_slot; + + if (ce_id >= CE_COUNT_MAX) + return -EINVAL; + + /* do ce irq assignments */ + ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE", + &msi_data_count, &msi_data_start, + &msi_irq_start); + + /* needs to match the ce_id -> irq data mapping + * used in the srng parameter configuration + */ + pci_slot = hif_get_pci_slot(scn); + msi_data = (ce_id % msi_data_count) + msi_irq_start; + irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data); + hif_debug("%s: (ce_id %d, msi_data %d, irq %d tasklet %pK)", + __func__, ce_id, msi_data, irq, + &ce_sc->tasklets[ce_id]); + + /* implies the ce is also initialized */ + if (!ce_sc->tasklets[ce_id].inited) + goto skip; + + pci_sc->ce_msi_irq_num[ce_id] = irq; + ret = pfrm_request_irq(scn->qdf_dev->dev, + irq, hif_ce_interrupt_handler, IRQF_SHARED, + ce_irqname[pci_slot][ce_id], + &ce_sc->tasklets[ce_id]); + if (ret) + return -EINVAL; + +skip: + return ret; +} + static int hif_ce_msi_configure_irq(struct hif_softc *scn) { int ret; @@ -2817,7 +2863,6 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn) uint32_t msi_data_count; uint32_t msi_irq_start; struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn); - struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(scn); struct CE_attr *host_ce_conf = ce_sc->host_ce_config; int pci_slot; @@ -2843,8 +2888,8 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn) /* do ce irq assignments */ ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE", - &msi_data_count, &msi_data_start, - &msi_irq_start); + &msi_data_count, &msi_data_start, + &msi_irq_start); if (ret) goto free_wake_irq; @@ -2863,25 +2908,13 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn) */ pci_slot = hif_get_pci_slot(scn); for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { - unsigned int msi_data = (ce_id % msi_data_count) + - msi_irq_start; if (host_ce_conf[ce_id].flags & CE_ATTR_DISABLE_INTR) continue; - irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data); - hif_debug("(ce_id %d, msi_data %d, irq %d tasklet %pK)", - ce_id, msi_data, irq, - &ce_sc->tasklets[ce_id]); - /* implies the ce is also initialized */ - if (!ce_sc->tasklets[ce_id].inited) + if (host_ce_conf[ce_id].flags & CE_ATTR_INIT_ON_DEMAND) continue; - pci_sc->ce_msi_irq_num[ce_id] = irq; - ret = pfrm_request_irq(scn->qdf_dev->dev, - irq, hif_ce_interrupt_handler, - IRQF_SHARED, - ce_irqname[pci_slot][ce_id], - &ce_sc->tasklets[ce_id]); + ret = hif_ce_msi_configure_irq_by_ceid(scn, ce_id); if (ret) goto free_irq; } diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c index dca1d3dedd..e44f1abdf7 100644 --- a/hif/src/snoc/if_ahb.c +++ b/hif/src/snoc/if_ahb.c @@ -126,7 +126,6 @@ const char *hif_ahb_get_irq_name(int irq_no) void hif_ahb_disable_isr(struct hif_softc *scn) { struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); - hif_exec_kill(&scn->osc); hif_nointrs(scn); ce_tasklet_kill(scn); @@ -268,41 +267,62 @@ static void hif_ahb_get_soc_info_pld(struct hif_pci_softc *sc, sc->ce_sc.ol_sc.mem_pa = info.p_addr; } +int hif_ahb_configure_irq_by_ceid(struct hif_softc *scn, int ce_id) +{ + int ret = 0; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct platform_device *pdev = (struct platform_device *)sc->pdev; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int irq = 0; + + if (ce_id >= CE_COUNT_MAX) + return -EINVAL; + + ret = pfrm_get_irq(&pdev->dev, (struct qdf_pfm_hndl *)pdev, + ic_irqname[HIF_IC_CE0_IRQ_OFFSET + ce_id], + HIF_IC_CE0_IRQ_OFFSET + ce_id, &irq); + if (ret) { + dev_err(&pdev->dev, "get irq failed\n"); + ret = -EFAULT; + goto end; + } + + ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + ce_id] = irq; + ret = pfrm_request_irq(&pdev->dev, irq, + hif_ahb_interrupt_handler, + IRQF_TRIGGER_RISING, + ic_irqname[HIF_IC_CE0_IRQ_OFFSET + ce_id], + &hif_state->tasklets[ce_id]); + if (ret) { + dev_err(&pdev->dev, "ath_request_irq failed\n"); + ret = -EFAULT; + goto end; + } + hif_ahb_irq_enable(scn, ce_id); + +end: + return ret; +} + int hif_ahb_configure_irq(struct hif_pci_softc *sc) { int ret = 0; struct hif_softc *scn = HIF_GET_SOFTC(sc); - struct platform_device *pdev = (struct platform_device *)sc->pdev; struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); struct CE_attr *host_ce_conf = hif_state->host_ce_config; - int irq = 0; int i; /* configure per CE interrupts */ for (i = 0; i < scn->ce_count; i++) { if (host_ce_conf[i].flags & CE_ATTR_DISABLE_INTR) continue; - ret = pfrm_get_irq(&pdev->dev, (struct qdf_pfm_hndl *)pdev, - ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], - HIF_IC_CE0_IRQ_OFFSET + i, &irq); - if (ret) { - dev_err(&pdev->dev, "get irq failed\n"); - ret = -EFAULT; - goto end; - } - ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq; - ret = pfrm_request_irq(&pdev->dev, irq, - hif_ahb_interrupt_handler, - IRQF_TRIGGER_RISING, - ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], - &hif_state->tasklets[i]); - if (ret) { - dev_err(&pdev->dev, "ath_request_irq failed\n"); - ret = -EFAULT; + if (host_ce_conf[i].flags & CE_ATTR_INIT_ON_DEMAND) + continue; + + ret = hif_ahb_configure_irq_by_ceid(scn, i); + if (ret) goto end; - } - hif_ahb_irq_enable(scn, i); } end: @@ -726,7 +746,8 @@ void hif_ahb_nointrs(struct hif_softc *scn) if (host_ce_conf[i].flags & CE_ATTR_DISABLE_INTR) continue; - + if (!hif_state->tasklets[i].inited) + continue; pfrm_free_irq( scn->qdf_dev->dev, ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],