Эх сурвалжийг харах

qcacmn: Pktlog dynamic CE config support

Add support to dynamically initialize the CE for PKTLOG
and post buffers on demand.

This helps avoid unnecessary initialization of PKTLOG
ring and save the memory in lowmem platforms

Change-Id: Ib02153b3e7205be30b07e4a4763edf3374827328
Uraj Sasan 4 жил өмнө
parent
commit
180f7b20d9

+ 1 - 0
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

+ 2 - 2
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 */

+ 219 - 79
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;
+		if (attr->flags & CE_ATTR_INIT_ON_DEMAND)
 			continue;
-		}
 
-		if (hif_is_nss_wifi_enabled(scn) && ce_state &&
-				(ce_state->htt_rx_data))
-			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

+ 2 - 0
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;
 };
 
 /*

+ 5 - 14
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;

+ 1 - 1
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);

+ 1 - 0
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);

+ 5 - 0
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);
+}

+ 10 - 0
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_ */

+ 1 - 0
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;
 }
 

+ 1 - 0
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;
 }
 

+ 1 - 0
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_ */

+ 3 - 0
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);

+ 50 - 17
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;
 	}

+ 44 - 23
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],