From 15010778ea4b2003f70a02f54d097f87311d1d4c Mon Sep 17 00:00:00 2001 From: Houston Hoffman Date: Fri, 16 Sep 2016 14:01:13 -0700 Subject: [PATCH] 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 --- hif/src/ce/ce_service_srng.c | 45 ++++++++++++++++ hif/src/pcie/if_pci.c | 100 ++++++++++++++++++++++++++++++++++- pld_stub/inc/pld_common.h | 22 ++++++++ 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/hif/src/ce/ce_service_srng.c b/hif/src/ce/ce_service_srng.c index 352b968d0f..a5df6b759b 100644 --- a/hif/src/ce/ce_service_srng.c +++ b/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; diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index d5f1fc5b1f..489442a6ea 100644 --- a/hif/src/pcie/if_pci.c +++ b/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) diff --git a/pld_stub/inc/pld_common.h b/pld_stub/inc/pld_common.h index 83ed961f4e..1f064befa0 100644 --- a/pld_stub/inc/pld_common.h +++ b/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,