diff options
| author | Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> | 2013-11-22 15:43:06 +0530 |
|---|---|---|
| committer | Prakash Dhavali <pdhavali@qca.qualcomm.com> | 2013-12-03 14:39:38 -0800 |
| commit | 05cfca341f3b68445e4da007f4d00273cb896864 (patch) | |
| tree | a6cb027d8ebc23d82cb44c5af45eef9eb325697e | |
| parent | fad474d0dc880a94fd7cb965ccc2c32bd5f87b1d (diff) | |
cld/hif: Fix device hang during UDP downlink
Spending too much time in processing Rx frames
in tasklet makes system unresponsive and hang,
the reason for the hang is that the CPU is not
able to scale up due to the higher priority
task (wlan_tasklet) which is hogging the CPU.
To come out of this condition, process 1000
rx packets in a single tasklet run and schedule
the tasklet to process the rest. This would
allow the process which takes care of CPU scaling
to run and increase the CPU frequency.
Change-Id: I4d1e302ccb52bdf268879ead9b2493f8c4bda99b
CRs-Fixed: 566643
| -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) |
