summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch')
-rw-r--r--debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch257
1 files changed, 257 insertions, 0 deletions
diff --git a/debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch b/debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch
new file mode 100644
index 000000000..4a5836c06
--- /dev/null
+++ b/debian/patches-rt/0001-chelsio-cxgb-Replace-the-workqueue-with-threaded-int.patch
@@ -0,0 +1,257 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Tue, 2 Feb 2021 18:01:03 +0100
+Subject: [PATCH 1/2] chelsio: cxgb: Replace the workqueue with threaded
+ interrupt
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.21-rt34.tar.xz
+
+The external interrupt (F_PL_INTR_EXT) needs to be handled in a process
+context and this is accomplished by utilizing a workqueue.
+
+The process context can also be provided by a threaded interrupt instead
+of a workqueue. The threaded interrupt can be used later for other
+interrupt related processing which require non-atomic context without
+using yet another workqueue. free_irq() also ensures that the thread is
+done which is currently missing (the worker could continue after the
+module has been removed).
+
+Save pending flags in pending_thread_intr. Use the same mechanism
+to disable F_PL_INTR_EXT as interrupt source like it is used before the
+worker is scheduled. Enable the interrupt again once
+t1_elmer0_ext_intr_handler() is done.
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ drivers/net/ethernet/chelsio/cxgb/common.h | 5 +--
+ drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 44 ++---------------------------
+ drivers/net/ethernet/chelsio/cxgb/sge.c | 33 +++++++++++++++++++--
+ drivers/net/ethernet/chelsio/cxgb/sge.h | 1
+ drivers/net/ethernet/chelsio/cxgb/subr.c | 26 +++++++++++------
+ 5 files changed, 55 insertions(+), 54 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb/common.h
++++ b/drivers/net/ethernet/chelsio/cxgb/common.h
+@@ -238,7 +238,6 @@ struct adapter {
+ int msg_enable;
+ u32 mmio_len;
+
+- struct work_struct ext_intr_handler_task;
+ struct adapter_params params;
+
+ /* Terminator modules. */
+@@ -257,6 +256,7 @@ struct adapter {
+
+ /* guards async operations */
+ spinlock_t async_lock ____cacheline_aligned;
++ u32 pending_thread_intr;
+ u32 slow_intr_mask;
+ int t1powersave;
+ };
+@@ -334,8 +334,7 @@ void t1_interrupts_enable(adapter_t *ada
+ void t1_interrupts_disable(adapter_t *adapter);
+ void t1_interrupts_clear(adapter_t *adapter);
+ int t1_elmer0_ext_intr_handler(adapter_t *adapter);
+-void t1_elmer0_ext_intr(adapter_t *adapter);
+-int t1_slow_intr_handler(adapter_t *adapter);
++irqreturn_t t1_slow_intr_handler(adapter_t *adapter);
+
+ int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+ const struct board_info *t1_get_board_info(unsigned int board_id);
+--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
++++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+@@ -211,9 +211,10 @@ static int cxgb_up(struct adapter *adapt
+ t1_interrupts_clear(adapter);
+
+ adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev);
+- err = request_irq(adapter->pdev->irq, t1_interrupt,
+- adapter->params.has_msi ? 0 : IRQF_SHARED,
+- adapter->name, adapter);
++ err = request_threaded_irq(adapter->pdev->irq, t1_interrupt,
++ t1_interrupt_thread,
++ adapter->params.has_msi ? 0 : IRQF_SHARED,
++ adapter->name, adapter);
+ if (err) {
+ if (adapter->params.has_msi)
+ pci_disable_msi(adapter->pdev);
+@@ -916,41 +917,6 @@ static void mac_stats_task(struct work_s
+ spin_unlock(&adapter->work_lock);
+ }
+
+-/*
+- * Processes elmer0 external interrupts in process context.
+- */
+-static void ext_intr_task(struct work_struct *work)
+-{
+- struct adapter *adapter =
+- container_of(work, struct adapter, ext_intr_handler_task);
+-
+- t1_elmer0_ext_intr_handler(adapter);
+-
+- /* Now reenable external interrupts */
+- spin_lock_irq(&adapter->async_lock);
+- adapter->slow_intr_mask |= F_PL_INTR_EXT;
+- writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE);
+- writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
+- adapter->regs + A_PL_ENABLE);
+- spin_unlock_irq(&adapter->async_lock);
+-}
+-
+-/*
+- * Interrupt-context handler for elmer0 external interrupts.
+- */
+-void t1_elmer0_ext_intr(struct adapter *adapter)
+-{
+- /*
+- * Schedule a task to handle external interrupts as we require
+- * a process context. We disable EXT interrupts in the interim
+- * and let the task reenable them when it's done.
+- */
+- adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
+- writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
+- adapter->regs + A_PL_ENABLE);
+- schedule_work(&adapter->ext_intr_handler_task);
+-}
+-
+ void t1_fatal_err(struct adapter *adapter)
+ {
+ if (adapter->flags & FULL_INIT_DONE) {
+@@ -1062,8 +1028,6 @@ static int init_one(struct pci_dev *pdev
+ spin_lock_init(&adapter->async_lock);
+ spin_lock_init(&adapter->mac_lock);
+
+- INIT_WORK(&adapter->ext_intr_handler_task,
+- ext_intr_task);
+ INIT_DELAYED_WORK(&adapter->stats_update_task,
+ mac_stats_task);
+
+--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
++++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
+@@ -1619,11 +1619,38 @@ int t1_poll(struct napi_struct *napi, in
+ return work_done;
+ }
+
++irqreturn_t t1_interrupt_thread(int irq, void *data)
++{
++ struct adapter *adapter = data;
++ u32 pending_thread_intr;
++
++ spin_lock_irq(&adapter->async_lock);
++ pending_thread_intr = adapter->pending_thread_intr;
++ adapter->pending_thread_intr = 0;
++ spin_unlock_irq(&adapter->async_lock);
++
++ if (!pending_thread_intr)
++ return IRQ_NONE;
++
++ if (pending_thread_intr & F_PL_INTR_EXT)
++ t1_elmer0_ext_intr_handler(adapter);
++
++ spin_lock_irq(&adapter->async_lock);
++ adapter->slow_intr_mask |= F_PL_INTR_EXT;
++
++ writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE);
++ writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
++ adapter->regs + A_PL_ENABLE);
++ spin_unlock_irq(&adapter->async_lock);
++
++ return IRQ_HANDLED;
++}
++
+ irqreturn_t t1_interrupt(int irq, void *data)
+ {
+ struct adapter *adapter = data;
+ struct sge *sge = adapter->sge;
+- int handled;
++ irqreturn_t handled;
+
+ if (likely(responses_pending(adapter))) {
+ writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+@@ -1645,10 +1672,10 @@ irqreturn_t t1_interrupt(int irq, void *
+ handled = t1_slow_intr_handler(adapter);
+ spin_unlock(&adapter->async_lock);
+
+- if (!handled)
++ if (handled == IRQ_NONE)
+ sge->stats.unhandled_irqs++;
+
+- return IRQ_RETVAL(handled != 0);
++ return handled;
+ }
+
+ /*
+--- a/drivers/net/ethernet/chelsio/cxgb/sge.h
++++ b/drivers/net/ethernet/chelsio/cxgb/sge.h
+@@ -74,6 +74,7 @@ struct sge *t1_sge_create(struct adapter
+ int t1_sge_configure(struct sge *, struct sge_params *);
+ int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
+ void t1_sge_destroy(struct sge *);
++irqreturn_t t1_interrupt_thread(int irq, void *data);
+ irqreturn_t t1_interrupt(int irq, void *cookie);
+ int t1_poll(struct napi_struct *, int);
+
+--- a/drivers/net/ethernet/chelsio/cxgb/subr.c
++++ b/drivers/net/ethernet/chelsio/cxgb/subr.c
+@@ -210,7 +210,7 @@ static int fpga_phy_intr_handler(adapter
+ /*
+ * Slow path interrupt handler for FPGAs.
+ */
+-static int fpga_slow_intr(adapter_t *adapter)
++static irqreturn_t fpga_slow_intr(adapter_t *adapter)
+ {
+ u32 cause = readl(adapter->regs + A_PL_CAUSE);
+
+@@ -238,7 +238,7 @@ static int fpga_slow_intr(adapter_t *ada
+ if (cause)
+ writel(cause, adapter->regs + A_PL_CAUSE);
+
+- return cause != 0;
++ return cause == 0 ? IRQ_NONE : IRQ_HANDLED;
+ }
+ #endif
+
+@@ -842,13 +842,14 @@ void t1_interrupts_clear(adapter_t* adap
+ /*
+ * Slow path interrupt handler for ASICs.
+ */
+-static int asic_slow_intr(adapter_t *adapter)
++static irqreturn_t asic_slow_intr(adapter_t *adapter)
+ {
+ u32 cause = readl(adapter->regs + A_PL_CAUSE);
++ irqreturn_t ret = IRQ_HANDLED;
+
+ cause &= adapter->slow_intr_mask;
+ if (!cause)
+- return 0;
++ return IRQ_NONE;
+ if (cause & F_PL_INTR_SGE_ERR)
+ t1_sge_intr_error_handler(adapter->sge);
+ if (cause & F_PL_INTR_TP)
+@@ -857,16 +858,25 @@ static int asic_slow_intr(adapter_t *ada
+ t1_espi_intr_handler(adapter->espi);
+ if (cause & F_PL_INTR_PCIX)
+ t1_pci_intr_handler(adapter);
+- if (cause & F_PL_INTR_EXT)
+- t1_elmer0_ext_intr(adapter);
++ if (cause & F_PL_INTR_EXT) {
++ /* Wake the threaded interrupt to handle external interrupts as
++ * we require a process context. We disable EXT interrupts in
++ * the interim and let the thread reenable them when it's done.
++ */
++ adapter->pending_thread_intr |= F_PL_INTR_EXT;
++ adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
++ writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
++ adapter->regs + A_PL_ENABLE);
++ ret = IRQ_WAKE_THREAD;
++ }
+
+ /* Clear the interrupts just processed. */
+ writel(cause, adapter->regs + A_PL_CAUSE);
+ readl(adapter->regs + A_PL_CAUSE); /* flush writes */
+- return 1;
++ return ret;
+ }
+
+-int t1_slow_intr_handler(adapter_t *adapter)
++irqreturn_t t1_slow_intr_handler(adapter_t *adapter)
+ {
+ #ifdef CONFIG_CHELSIO_T1_1G
+ if (!t1_is_asic(adapter))