summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CORE/SERVICES/HIF/PCIe/copy_engine.c28
-rw-r--r--CORE/SERVICES/HIF/PCIe/copy_engine_api.h3
-rw-r--r--CORE/SERVICES/HIF/PCIe/copy_engine_internal.h1
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.c17
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.h1
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)