Kaynağa Gözat

qcacmn: Use pld msi allocation for CE

Use the msi vectors allocated by the platform driver
for the copy engine interrupts.

Change-Id: I3fa96daa3222524ffe31659c12b3c0f5a2725e18
CRs-Fixed: 1093364
Houston Hoffman 8 yıl önce
ebeveyn
işleme
15010778ea
3 değiştirilmiş dosya ile 165 ekleme ve 2 silme
  1. 45 0
      hif/src/ce/ce_service_srng.c
  2. 98 2
      hif/src/pcie/if_pci.c
  3. 22 0
      pld_stub/inc/pld_common.h

+ 45 - 0
hif/src/ce/ce_service_srng.c

@@ -28,6 +28,7 @@
 #include "hif_main.h"
 #include "hif_debug.h"
 #include "hal_api.h"
+#include "pld_common.h"
 
 /*
  * Support for Copy Engine hardware, which is mainly used for
@@ -584,11 +585,47 @@ uint32_t ce_get_desc_size_srng(uint8_t ring_type)
 	return 0;
 }
 
+static void ce_srng_msi_ring_params_setup(struct hif_softc *scn, uint32_t ce_id,
+			      struct hal_srng_params *ring_params)
+{
+	uint32_t addr_low;
+	uint32_t addr_high;
+	uint32_t msi_data_start;
+	uint32_t msi_data_count;
+	uint32_t msi_irq_start;
+	int ret;
+
+	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
+					  &msi_data_count, &msi_data_start,
+					  &msi_irq_start);
+
+	/* msi config not found */
+	if (ret)
+		return;
+
+	HIF_INFO("%s: ce_id %d, msi_start: %d, msi_count %d", __func__, ce_id,
+		  msi_data_start, msi_data_count);
+
+	pld_get_msi_address(scn->qdf_dev->dev, &addr_low, &addr_high);
+
+	ring_params->msi_addr = addr_low;
+	ring_params->msi_addr |= (qdf_dma_addr_t)(((uint64_t)addr_high) << 32);
+	ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start;
+	ring_params->flags |= HAL_SRNG_MSI_INTR;
+
+	HIF_INFO("%s: ce_id %d, msi_addr %p, msi_data %d", __func__, ce_id,
+		  (void *)ring_params->msi_addr, ring_params->msi_data);
+}
+
 void ce_srng_src_ring_setup(struct hif_softc *scn, uint32_t ce_id,
 			struct CE_ring_state *src_ring)
 {
 	struct hal_srng_params ring_params = {0};
 
+	HIF_INFO("%s: ce_id %d", __func__, ce_id);
+
+	ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
+
 	ring_params.ring_base_paddr = src_ring->base_addr_CE_space;
 	ring_params.ring_base_vaddr = src_ring->base_addr_owner_space;
 	ring_params.num_entries = src_ring->nentries;
@@ -617,6 +654,10 @@ void ce_srng_dest_ring_setup(struct hif_softc *scn, uint32_t ce_id,
 {
 	struct hal_srng_params ring_params = {0};
 
+	HIF_INFO("%s: ce_id %d", __func__, ce_id);
+
+	ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
+
 	ring_params.ring_base_paddr = dest_ring->base_addr_CE_space;
 	ring_params.ring_base_vaddr = dest_ring->base_addr_owner_space;
 	ring_params.num_entries = dest_ring->nentries;
@@ -640,6 +681,10 @@ void ce_srng_status_ring_setup(struct hif_softc *scn, uint32_t ce_id,
 {
 	struct hal_srng_params ring_params = {0};
 
+	HIF_INFO("%s: ce_id %d", __func__, ce_id);
+
+	ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
+
 	ring_params.ring_base_paddr = status_ring->base_addr_CE_space;
 	ring_params.ring_base_vaddr = status_ring->base_addr_owner_space;
 	ring_params.num_entries = status_ring->nentries;

+ 98 - 2
hif/src/pcie/if_pci.c

@@ -2546,6 +2546,38 @@ end:
 	return ret;
 }
 
+static int hif_ce_srng_msi_free_irq(struct hif_softc *scn)
+{
+	int ret;
+	int ce_id, irq;
+	uint32_t msi_data_start;
+	uint32_t msi_data_count;
+	uint32_t msi_irq_start;
+	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
+
+	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
+					    &msi_data_count, &msi_data_start,
+					    &msi_irq_start);
+	if (ret)
+		return ret;
+
+	/* needs to match the ce_id -> irq data mapping
+	 * used in the srng parameter configuration
+	 */
+	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
+		unsigned int msi_data;
+		msi_data = (ce_id % msi_data_count) + msi_irq_start;
+		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
+
+		HIF_INFO("%s: (ce_id %d, msi_data %d, irq %d)", __func__,
+			  ce_id, msi_data, irq);
+
+		free_irq(irq, &ce_sc->tasklets[ce_id]);
+	}
+
+	return ret;
+}
+
 /**
  * hif_nointrs(): disable IRQ
  *
@@ -2557,13 +2589,15 @@ end:
  */
 void hif_pci_nointrs(struct hif_softc *scn)
 {
-	int i;
+	int i, ret;
 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
 
 	if (scn->request_irq_done == false)
 		return;
-	if (sc->num_msi_intrs > 0) {
+
+	ret = hif_ce_srng_msi_free_irq(scn);
+	if (ret != 0 && sc->num_msi_intrs > 0) {
 		/* MSI interrupt(s) */
 		for (i = 0; i < sc->num_msi_intrs; i++) {
 			free_irq(sc->irq + i, sc);
@@ -3510,6 +3544,63 @@ int hif_ahb_configure_irq(struct hif_pci_softc *sc)
 }
 #endif
 
+irqreturn_t hif_ce_interrupt_handler(int irq, void *context)
+{
+	struct ce_tasklet_entry *tasklet_entry = context;
+	return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
+}
+extern const char *ce_name[];
+
+static int hif_ce_srng_msi_request_irq(struct hif_softc *scn)
+{
+	int ret;
+	int ce_id, irq;
+	uint32_t msi_data_start;
+	uint32_t msi_data_count;
+	uint32_t msi_irq_start;
+	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
+
+	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
+					    &msi_data_count, &msi_data_start,
+					    &msi_irq_start);
+
+	if (ret)
+		return ret;
+
+	/* needs to match the ce_id -> irq data mapping
+	 * used in the srng parameter configuration
+	 */
+	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
+		unsigned int msi_data = (ce_id % msi_data_count) +
+			msi_irq_start;
+		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
+
+		HIF_INFO("%s: (ce_id %d, msi_data %d, irq %d tasklet %p)",
+			 __func__, ce_id, msi_data, irq,
+			 &ce_sc->tasklets[ce_id]);
+		ret = request_irq(irq, hif_ce_interrupt_handler,
+				  IRQF_SHARED,
+				  ce_name[ce_id],
+				  &ce_sc->tasklets[ce_id]);
+		if (ret)
+			goto free_irq;
+	}
+
+	return ret;
+
+free_irq:
+	/* the request_irq for the last ce_id failed so skip it. */
+	while (ce_id > 0 && ce_id < scn->ce_count) {
+		unsigned int msi_data;
+
+		ce_id--;
+		msi_data = (ce_id % msi_data_count) + msi_data_start;
+		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
+		free_irq(irq, &ce_sc->tasklets[ce_id]);
+	}
+	return ret;
+}
+
 /**
  * hif_configure_irq() - configure interrupt
  *
@@ -3529,6 +3620,11 @@ int hif_configure_irq(struct hif_softc *scn)
 
 	hif_init_reschedule_tasklet_work(sc);
 
+	ret = hif_ce_srng_msi_request_irq(scn);
+	if (ret == 0) {
+		goto end;
+	}
+
 	if (ENABLE_MSI) {
 		ret = hif_configure_msi(sc);
 		if (ret == 0)

+ 22 - 0
pld_stub/inc/pld_common.h

@@ -176,6 +176,28 @@ static inline void pld_intr_notify_q6(struct device *dev)
 {
 	return;
 }
+
+static inline int pld_get_user_msi_assignment(struct device *dev,
+			char *user_name, int *num_vectors,
+			uint32_t *user_base_data, uint32_t *base_vector)
+{
+	return -EINVAL;
+}
+
+/* should not be called if pld_get_user_msi_assignment returns error */
+static inline int pld_get_msi_irq(struct device *dev, unsigned int vector)
+{
+	return -EINVAL;
+}
+
+/* should not be called if pld_get_user_msi_assignment returns error */
+static inline void pld_get_msi_address(struct device *dev,
+				       uint32_t *msi_addr_low,
+				       uint32_t *msi_addr_high)
+{
+	return;
+}
+
 static inline int pld_ce_request_irq(struct device *dev, unsigned int ce_id,
 				     irqreturn_t (*handler)(int, void *),
 				     unsigned long flags, const char *name,