diff --git a/hif/inc/hif.h b/hif/inc/hif.h index d1c8c77dad..8468117dd4 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -62,6 +62,7 @@ typedef void *hif_handle_t; #define HIF_TYPE_QCA9984 12 #define HIF_TYPE_IPQ4019 13 #define HIF_TYPE_QCA9888 14 +#define HIF_TYPE_QCA8074 15 /* TARGET definition needs to be abstracted in fw common * header files, below is the placeholder till WIN codebase @@ -95,6 +96,9 @@ typedef void *hif_handle_t; /* For Adrastea target */ #define TARGET_TYPE_ADRASTEA 19 #endif /* CONFIG_WIN */ +#ifndef TARGET_TYPE_QCA8074 +#define TARGET_TYPE_QCA8074 20 +#endif struct CE_state; #define CE_COUNT_MAX 12 diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index 362b5f1580..681e962ba5 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -2055,6 +2055,7 @@ QDF_STATUS hif_ce_open(struct hif_softc *hif_sc) { struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + qdf_spinlock_create(&hif_state->irq_reg_lock); qdf_spinlock_create(&hif_state->keep_awake_lock); return QDF_STATUS_SUCCESS; } @@ -2065,6 +2066,9 @@ QDF_STATUS hif_ce_open(struct hif_softc *hif_sc) */ void hif_ce_close(struct hif_softc *hif_sc) { + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + qdf_spinlock_destroy(&hif_state->irq_reg_lock); } /** diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h index b71fd4034e..e58f30aac5 100644 --- a/hif/src/ce/ce_main.h +++ b/hif/src/ce/ce_main.h @@ -122,6 +122,7 @@ struct HIF_CE_state { bool started; struct ce_tasklet_entry tasklets[CE_COUNT_MAX]; qdf_spinlock_t keep_awake_lock; + qdf_spinlock_t irq_reg_lock; unsigned int keep_awake_count; bool verified_awake; bool fake_sleep; diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h index 2bba2ff92d..3a715fd44e 100644 --- a/hif/src/dispatcher/ahb_api.h +++ b/hif/src/dispatcher/ahb_api.h @@ -43,5 +43,6 @@ void hif_ahb_device_reset(struct hif_softc *scn); 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); #endif diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index 1519343b91..96c3241a73 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -680,6 +680,12 @@ int hif_get_device_type(uint32_t device_id, HIF_INFO(" *********** IPQ4019 *************"); break; + case QCA8074_DEVICE_ID: + *hif_type = HIF_TYPE_QCA8074; + *target_type = TARGET_TYPE_QCA8074; + HIF_INFO(" *********** QCA8074 *************\n"); + break; + default: HIF_ERROR("%s: Unsupported device ID!", __func__); ret = -ENODEV; diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 8a44e95ee2..7e5d62c0d9 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -91,6 +91,10 @@ #define QCA9984_DEVICE_ID (0x0046) #define QCA9888_DEVICE_ID (0x0056) #define IPQ4019_DEVICE_ID (0x12ef) +#define QCA8074_DEVICE_ID (0xffff) /* Todo: replace this with + actual number once available. + currently defining this to 0xffff for + emulation purpose */ #define HIF_GET_PCI_SOFTC(scn) ((struct hif_pci_softc *)scn) #define HIF_GET_CE_STATE(scn) ((struct HIF_CE_state *)scn) @@ -127,6 +131,7 @@ struct hif_softc { bool recovery; bool notice_send; + bool per_ce_irq; uint32_t ce_irq_summary; /* No of copy engines supported */ unsigned int ce_count; diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 2caacb46a9..0558d3d966 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -1952,6 +1952,10 @@ int hif_pci_bus_configure(struct hif_softc *hif_sc) } } + if (hif_sc->target_info.target_type == TARGET_TYPE_QCA8074) { + hif_sc->per_ce_irq = true; + } + status = hif_config_ce(hif_sc); if (status) goto disable_wlan; @@ -3319,6 +3323,9 @@ int hif_configure_irq(struct hif_softc *scn) case TARGET_TYPE_IPQ4019: ret = hif_ahb_configure_legacy_irq(sc); break; + case TARGET_TYPE_QCA8074: + ret = hif_ahb_configure_irq(sc); + break; default: ret = hif_pci_configure_legacy_irq(sc); break; diff --git a/hif/src/regtable.c b/hif/src/regtable.c index 19ede4afe9..f96c7689c3 100644 --- a/hif/src/regtable.c +++ b/hif/src/regtable.c @@ -103,6 +103,12 @@ void hif_target_register_tbl_attach(struct hif_softc *scn, u32 target_type) scn->target_ce_def = IPQ4019_CE_TARGETdef; break; #endif +#if defined(QCA8074_HEADERS_DEF) + case TARGET_TYPE_QCA8074: + scn->targetdef = QCA8074_TARGETdef; + scn->target_ce_def = QCA8074_CE_TARGETdef; + break; +#endif #endif default: @@ -167,6 +173,11 @@ void hif_register_tbl_attach(struct hif_softc *scn, u32 hif_type) scn->hostdef = IPQ4019_HOSTdef; break; #endif +#if defined(QCA8074_HEADERS_DEF) + case HIF_TYPE_QCA8074: + scn->hostdef = QCA8074_HOSTdef; + break; +#endif #endif default: diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c index 6f986fd14b..23c2b6a0b3 100644 --- a/hif/src/snoc/if_ahb.c +++ b/hif/src/snoc/if_ahb.c @@ -36,6 +36,69 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) #define IRQF_DISABLED 0x00000020 #endif + +#define HIF_IC_CE0_IRQ_OFFSET 4 +#define HIF_IC_MAX_IRQ 54 + +/* integrated chip irq names */ +const char *ic_irqname[HIF_IC_MAX_IRQ] = { +"misc_pulse1", +"misc_latch", +"sw_exception", +"watchdog", +"ce0", +"ce1", +"ce2", +"ce3", +"ce4", +"ce5", +"ce6", +"ce7", +"ce8", +"ce9", +"ce10", +"ce11", +"ce12", +"ce13", +"host2wbm_desc_feed", +"host2reo_re_injection", +"host2reo_command", +"host2rxdma_monitor_ring3", +"host2rxdma_monitor_ring2", +"host2rxdma_monitor_ring1", +"reo2ost_exception", +"wbm2host_rx_release", +"reo2host_status", +"reo2host_destination_ring4", +"reo2host_destination_ring3", +"reo2host_destination_ring2", +"reo2host_destination_ring1", +"rxdma2host_monitor_destination_mac3", +"rxdma2host_monitor_destination_mac2", +"rxdma2host_monitor_destination_mac1", +"ppdu_end_interrupts_mac3", +"ppdu_end_interrupts_mac2", +"ppdu_end_interrupts_mac1", +"rxdma2host_monitor_status_ring_mac3", +"rxdma2host_monitor_status_ring_mac2", +"rxdma2host_monitor_status_ring_mac1", +"host2rxdma_host_buf_ring_mac3", +"host2rxdma_host_buf_ring_mac2", +"host2rxdma_host_buf_ring_mac1", +"rxdma2host_destination_ring_mac3", +"rxdma2host_destination_ring_mac2", +"rxdma2host_destination_ring_mac1", +"host2tcl_input_ring4", +"host2tcl_input_ring3", +"host2tcl_input_ring2", +"host2tcl_input_ring1", +"wbm2host_tx_completions_ring3", +"wbm2host_tx_completions_ring2", +"wbm2host_tx_completions_ring1", +"tcl2host_status_ring", +}; + +irqreturn_t hif_ahb_interrupt_handler(int irq, void *context); /** * hif_disable_isr() - disable isr * @@ -178,6 +241,41 @@ 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_ce_state = HIF_GET_CE_STATE(scn); + int irq = 0; + int i; + + /* configure per CE interrupts */ + for (i = 0; i < scn->ce_count; i++) { + irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]); + ret = request_irq(irq , + hif_ahb_interrupt_handler, + IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], + &hif_ce_state->tasklets[i]); + if (ret) { + dev_err(&pdev->dev, "ath_request_irq failed\n"); + ret = -1; + goto end; + } + hif_ahb_irq_enable(scn, i); + } + +end: + return ret; +} + +irqreturn_t hif_ahb_interrupt_handler(int irq, void *context) +{ + struct ce_tasklet_entry *tasklet_entry = context; + return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry); +} + + /** * hif_target_sync() : ensure the target is ready * @scn: hif control structure @@ -394,7 +492,33 @@ void hif_ahb_reset_soc(struct hif_softc *hif_ctx) */ void hif_ahb_nointrs(struct hif_softc *scn) { - hif_pci_nointrs(scn); + int i; + int irq; + 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); + + if (scn->request_irq_done == false) + return; + + if (sc->num_msi_intrs > 0) { + /* MSI interrupt(s) */ + for (i = 0; i < sc->num_msi_intrs; i++) { + free_irq(sc->irq + i, sc); + } + sc->num_msi_intrs = 0; + } else { + if (!scn->per_ce_irq) { + free_irq(sc->irq, sc); + } else { + for (i = 0; i < scn->ce_count; i++) { + irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]); + free_irq(irq, sc); + } + } + } + ce_unregister_irq(hif_state, CE_ALL_BITMAP); + scn->request_irq_done = false; } /** @@ -408,7 +532,31 @@ void hif_ahb_nointrs(struct hif_softc *scn) */ void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) { - hif_pci_irq_enable(scn, ce_id); + uint32_t regval; + uint32_t reg_offset = 0; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; + + if (scn->per_ce_irq) { + if (target_ce_conf->pipedir & PIPEDIR_OUT) { + reg_offset = HOST_IE_ADDRESS; + qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); + regval = hif_read32_mb(scn->mem + reg_offset); + regval |= (1 << ce_id); + hif_write32_mb(scn->mem + reg_offset, regval); + qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); + } + if (target_ce_conf->pipedir & PIPEDIR_IN) { + reg_offset = HOST_IE_ADDRESS_2; + qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); + regval = hif_read32_mb(scn->mem + reg_offset); + regval |= (1 << ce_id); + hif_write32_mb(scn->mem + reg_offset, regval); + qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); + } + } else { + hif_pci_irq_enable(scn, ce_id); + } } /** @@ -420,5 +568,27 @@ void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) */ void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id) { + uint32_t regval; + uint32_t reg_offset = 0; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; + if (scn->per_ce_irq) { + if (target_ce_conf->pipedir & PIPEDIR_OUT) { + reg_offset = HOST_IE_ADDRESS; + qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); + regval = hif_read32_mb(scn->mem + reg_offset); + regval &= ~(1 << ce_id); + hif_write32_mb(scn->mem + reg_offset, regval); + qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); + } + if (target_ce_conf->pipedir & PIPEDIR_IN) { + reg_offset = HOST_IE_ADDRESS_2; + qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); + regval = hif_read32_mb(scn->mem + reg_offset); + regval &= ~(1 << ce_id); + hif_write32_mb(scn->mem + reg_offset, regval); + qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); + } + } }