diff options
| -rw-r--r-- | CORE/SERVICES/HIF/PCIe/copy_engine.c | 28 | ||||
| -rw-r--r-- | CORE/SERVICES/HIF/PCIe/copy_engine_api.h | 3 | ||||
| -rw-r--r-- | CORE/SERVICES/HIF/PCIe/copy_engine_internal.h | 1 | ||||
| -rw-r--r-- | CORE/SERVICES/HIF/PCIe/if_pci.c | 17 | ||||
| -rw-r--r-- | CORE/SERVICES/HIF/PCIe/if_pci.h | 1 |
5 files changed, 48 insertions, 2 deletions
diff --git a/CORE/SERVICES/HIF/PCIe/copy_engine.c b/CORE/SERVICES/HIF/PCIe/copy_engine.c index 093931174e9d..6499d8c9e16f 100644 --- a/CORE/SERVICES/HIF/PCIe/copy_engine.c +++ b/CORE/SERVICES/HIF/PCIe/copy_engine.c @@ -885,6 +885,7 @@ more_completions: /* Break the receive processes by force if force_break set up */ if (adf_os_unlikely(sc->force_break)) { + adf_os_atomic_set(&CE_state->rx_pending, 1); CE_ENGINE_INT_STATUS_CLEAR(targid, ctrl_addr, HOST_IS_COPY_COMPLETE_MASK); A_TARGET_ACCESS_END(targid); return; @@ -978,6 +979,7 @@ more_watermarks: } adf_os_spin_unlock(&sc->target_lock); + adf_os_atomic_set(&CE_state->rx_pending, 0); A_TARGET_ACCESS_END(targid); } @@ -996,6 +998,19 @@ CE_per_engine_service_any(int irq, void *arg) A_UINT32 intr_summary; A_TARGET_ACCESS_BEGIN(targid); + if (!adf_os_atomic_read(&sc->tasklet_from_intr)) { + for (CE_id=0; CE_id < sc->ce_count; CE_id++) { + struct CE_state *CE_state = sc->CE_id_to_state[CE_id]; + if (adf_os_atomic_read(&CE_state->rx_pending)) { + adf_os_atomic_set(&CE_state->rx_pending, 0); + CE_per_engine_service(sc, CE_id); + } + } + + A_TARGET_ACCESS_END(targid); + return; + } + intr_summary = CE_INTERRUPT_SUMMARY(targid); for (CE_id=0; intr_summary && (CE_id < sc->ce_count); CE_id++) { @@ -1183,6 +1198,18 @@ roundup_pwr2(unsigned int n) return 0; } +bool CE_get_rx_pending(struct hif_pci_softc *sc) +{ + int CE_id; + + for (CE_id=0; CE_id < sc->ce_count; CE_id++) { + struct CE_state *CE_state = sc->CE_id_to_state[CE_id]; + if (adf_os_atomic_read(&CE_state->rx_pending)) + return true; + } + + return false; +} /* * Initialize a Copy Engine based on caller-supplied attributes. * This may be called once to initialize both source and destination @@ -1234,6 +1261,7 @@ CE_init(struct hif_pci_softc *sc, } adf_os_spin_unlock(&sc->target_lock); + adf_os_atomic_init(&CE_state->rx_pending); if (attr == NULL) { /* Already initialized; caller wants the handle */ return (struct CE_handle *)CE_state; diff --git a/CORE/SERVICES/HIF/PCIe/copy_engine_api.h b/CORE/SERVICES/HIF/PCIe/copy_engine_api.h index 885f074fecd4..deb683ea6fce 100644 --- a/CORE/SERVICES/HIF/PCIe/copy_engine_api.h +++ b/CORE/SERVICES/HIF/PCIe/copy_engine_api.h @@ -367,6 +367,9 @@ void CE_enable_any_copy_compl_intr(struct hif_pci_softc *sc); void CE_disable_any_copy_compl_intr_nolock(struct hif_pci_softc *sc); void CE_enable_any_copy_compl_intr_nolock(struct hif_pci_softc *sc); +/* API to check if any of the copy engine pipes has pending frames for prcoessing */ +bool CE_get_rx_pending(struct hif_pci_softc *sc); + /* CE_attr.flags values */ #define CE_ATTR_NO_SNOOP 0x01 /* Use NonSnooping PCIe accesses? */ #define CE_ATTR_BYTE_SWAP_DATA 0x02 /* Byte swap data words */ diff --git a/CORE/SERVICES/HIF/PCIe/copy_engine_internal.h b/CORE/SERVICES/HIF/PCIe/copy_engine_internal.h index c298271a78ab..ad54f2bdfc86 100644 --- a/CORE/SERVICES/HIF/PCIe/copy_engine_internal.h +++ b/CORE/SERVICES/HIF/PCIe/copy_engine_internal.h @@ -122,6 +122,7 @@ struct CE_state { unsigned int src_sz_max; struct CE_ring_state *src_ring; struct CE_ring_state *dest_ring; + atomic_t rx_pending; }; /* Descriptor rings must be aligned to this boundary */ diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.c b/CORE/SERVICES/HIF/PCIe/if_pci.c index ba597c9e2aa0..901ebfb66c4e 100644 --- a/CORE/SERVICES/HIF/PCIe/if_pci.c +++ b/CORE/SERVICES/HIF/PCIe/if_pci.c @@ -56,6 +56,8 @@ #define AR9888_DEVICE_ID (0x003c) #define AR6320_DEVICE_ID (0x003e) +#define MAX_NUM_OF_RECEIVES 1000 /* Maximum number of Rx buf to process before break out */ + unsigned int msienable = 0; module_param(msienable, int, 0644); @@ -101,6 +103,7 @@ hif_pci_interrupt_handler(int irq, void *arg) /* TBDXXX: Add support for WMAC */ sc->irq_event = irq; + adf_os_atomic_set(&sc->tasklet_from_intr, 1); tasklet_schedule(&sc->intr_tq); return IRQ_HANDLED; @@ -134,8 +137,7 @@ bool hif_max_num_receives_reached(unsigned int count) #ifdef EPPING_TEST return (count > 120); #else - /* Not implemented yet */ - return 0; + return (count > MAX_NUM_OF_RECEIVES); #endif } @@ -337,6 +339,16 @@ wlan_tasklet(unsigned long data) (irqreturn_t)HIF_fw_interrupt_handler(sc->irq_event, sc); CE_per_engine_service_any(sc->irq_event, sc); + adf_os_atomic_set(&sc->tasklet_from_intr, 0); + if (CE_get_rx_pending(sc)) { + /* + * There are frames pending, schedule tasklet to process them. + * Enable the interrupt only when there is no pending frames in + * any of the Copy Engine pipes. + */ + tasklet_schedule(&sc->intr_tq); + return; + } if (LEGACY_INTERRUPTS(sc)) { /* Enable Legacy PCI line interrupts */ A_PCI_WRITE32(sc->mem+(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS), @@ -548,6 +560,7 @@ again: ol_sc->enablefwlog = 0; ol_sc->enablesinglebinary = FALSE; + adf_os_atomic_init(&sc->tasklet_from_intr); init_waitqueue_head(&ol_sc->sc_osdev->event_queue); ret = hdd_wlan_startup(&pdev->dev, ol_sc); diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.h b/CORE/SERVICES/HIF/PCIe/if_pci.h index 886161dae20a..3ad2aae4f230 100644 --- a/CORE/SERVICES/HIF/PCIe/if_pci.h +++ b/CORE/SERVICES/HIF/PCIe/if_pci.h @@ -85,6 +85,7 @@ struct hif_pci_softc { u16 devid; struct targetdef_s *targetdef; struct hostdef_s *hostdef; + atomic_t tasklet_from_intr; }; #define TARGID(sc) ((A_target_id_t)(&(sc)->mem)) #define TARGID_TO_HIF(targid) (((struct hif_pci_softc *)((char *)(targid) - (char *)&(((struct hif_pci_softc *)0)->mem)))->hif_device) |
