diff options
Diffstat (limited to '')
-rw-r--r-- | debian/patches-rt/0153-chelsio-cxgb-Disable-the-card-on-error-in-threaded-i.patch | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/debian/patches-rt/0153-chelsio-cxgb-Disable-the-card-on-error-in-threaded-i.patch b/debian/patches-rt/0153-chelsio-cxgb-Disable-the-card-on-error-in-threaded-i.patch new file mode 100644 index 000000000..910927009 --- /dev/null +++ b/debian/patches-rt/0153-chelsio-cxgb-Disable-the-card-on-error-in-threaded-i.patch @@ -0,0 +1,215 @@ +From 676e60d5a1de49b6188285212b7655ccd463f984 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Tue, 2 Feb 2021 18:01:04 +0100 +Subject: [PATCH 153/323] chelsio: cxgb: Disable the card on error in threaded + interrupt +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.204-rt100.tar.xz + +t1_fatal_err() is invoked from the interrupt handler. The bad part is +that it invokes (via t1_sge_stop()) del_timer_sync() and tasklet_kill(). +Both functions must not be called from an interrupt because it is +possible that it will wait for the completion of the timer/tasklet it +just interrupted. + +In case of a fatal error, use t1_interrupts_disable() to disable all +interrupt sources and then wake the interrupt thread with +F_PL_INTR_SGE_ERR as pending flag. The threaded-interrupt will stop the +card via t1_sge_stop() and not re-enable the interrupts again. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/net/ethernet/chelsio/cxgb/common.h | 1 - + drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 10 ------ + drivers/net/ethernet/chelsio/cxgb/sge.c | 20 +++++++++--- + drivers/net/ethernet/chelsio/cxgb/sge.h | 2 +- + drivers/net/ethernet/chelsio/cxgb/subr.c | 38 +++++++++++++++------- + 5 files changed, 44 insertions(+), 27 deletions(-) + +diff --git a/drivers/net/ethernet/chelsio/cxgb/common.h b/drivers/net/ethernet/chelsio/cxgb/common.h +index e999a9b9fe6c..0321be77366c 100644 +--- a/drivers/net/ethernet/chelsio/cxgb/common.h ++++ b/drivers/net/ethernet/chelsio/cxgb/common.h +@@ -346,7 +346,6 @@ int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, + int t1_init_hw_modules(adapter_t *adapter); + int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi); + void t1_free_sw_modules(adapter_t *adapter); +-void t1_fatal_err(adapter_t *adapter); + void t1_link_changed(adapter_t *adapter, int port_id); + void t1_link_negotiated(adapter_t *adapter, int port_id, int link_stat, + int speed, int duplex, int pause); +diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +index 737c24136e2f..2a28a38da036 100644 +--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c ++++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +@@ -917,16 +917,6 @@ static void mac_stats_task(struct work_struct *work) + spin_unlock(&adapter->work_lock); + } + +-void t1_fatal_err(struct adapter *adapter) +-{ +- if (adapter->flags & FULL_INIT_DONE) { +- t1_sge_stop(adapter->sge); +- t1_interrupts_disable(adapter); +- } +- pr_alert("%s: encountered fatal error, operation suspended\n", +- adapter->name); +-} +- + static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, +diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c +index 5aef9ae1ecfe..cda01f22c71c 100644 +--- a/drivers/net/ethernet/chelsio/cxgb/sge.c ++++ b/drivers/net/ethernet/chelsio/cxgb/sge.c +@@ -940,10 +940,11 @@ void t1_sge_intr_clear(struct sge *sge) + /* + * SGE 'Error' interrupt handler + */ +-int t1_sge_intr_error_handler(struct sge *sge) ++bool t1_sge_intr_error_handler(struct sge *sge) + { + struct adapter *adapter = sge->adapter; + u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); ++ bool wake = false; + + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) + cause &= ~F_PACKET_TOO_BIG; +@@ -967,11 +968,14 @@ int t1_sge_intr_error_handler(struct sge *sge) + sge->stats.pkt_mismatch++; + pr_alert("%s: SGE packet mismatch\n", adapter->name); + } +- if (cause & SGE_INT_FATAL) +- t1_fatal_err(adapter); ++ if (cause & SGE_INT_FATAL) { ++ t1_interrupts_disable(adapter); ++ adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR; ++ wake = true; ++ } + + writel(cause, adapter->regs + A_SG_INT_CAUSE); +- return 0; ++ return wake; + } + + const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge) +@@ -1635,6 +1639,14 @@ irqreturn_t t1_interrupt_thread(int irq, void *data) + if (pending_thread_intr & F_PL_INTR_EXT) + t1_elmer0_ext_intr_handler(adapter); + ++ /* This error is fatal, interrupts remain off */ ++ if (pending_thread_intr & F_PL_INTR_SGE_ERR) { ++ pr_alert("%s: encountered fatal error, operation suspended\n", ++ adapter->name); ++ t1_sge_stop(adapter->sge); ++ return IRQ_HANDLED; ++ } ++ + spin_lock_irq(&adapter->async_lock); + adapter->slow_intr_mask |= F_PL_INTR_EXT; + +diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h +index 76516d2a8aa9..716705b96f26 100644 +--- a/drivers/net/ethernet/chelsio/cxgb/sge.h ++++ b/drivers/net/ethernet/chelsio/cxgb/sge.h +@@ -82,7 +82,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); + void t1_vlan_mode(struct adapter *adapter, netdev_features_t features); + void t1_sge_start(struct sge *); + void t1_sge_stop(struct sge *); +-int t1_sge_intr_error_handler(struct sge *); ++bool t1_sge_intr_error_handler(struct sge *sge); + void t1_sge_intr_enable(struct sge *); + void t1_sge_intr_disable(struct sge *); + void t1_sge_intr_clear(struct sge *); +diff --git a/drivers/net/ethernet/chelsio/cxgb/subr.c b/drivers/net/ethernet/chelsio/cxgb/subr.c +index d90ad07ff1a4..310add28fcf5 100644 +--- a/drivers/net/ethernet/chelsio/cxgb/subr.c ++++ b/drivers/net/ethernet/chelsio/cxgb/subr.c +@@ -170,7 +170,7 @@ void t1_link_changed(adapter_t *adapter, int port_id) + t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc); + } + +-static int t1_pci_intr_handler(adapter_t *adapter) ++static bool t1_pci_intr_handler(adapter_t *adapter) + { + u32 pcix_cause; + +@@ -179,9 +179,13 @@ static int t1_pci_intr_handler(adapter_t *adapter) + if (pcix_cause) { + pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, + pcix_cause); +- t1_fatal_err(adapter); /* PCI errors are fatal */ ++ /* PCI errors are fatal */ ++ t1_interrupts_disable(adapter); ++ adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR; ++ pr_alert("%s: PCI error encountered.\n", adapter->name); ++ return true; + } +- return 0; ++ return false; + } + + #ifdef CONFIG_CHELSIO_T1_1G +@@ -213,10 +217,13 @@ static int fpga_phy_intr_handler(adapter_t *adapter) + static irqreturn_t fpga_slow_intr(adapter_t *adapter) + { + u32 cause = readl(adapter->regs + A_PL_CAUSE); ++ irqreturn_t ret = IRQ_NONE; + + cause &= ~F_PL_INTR_SGE_DATA; +- if (cause & F_PL_INTR_SGE_ERR) +- t1_sge_intr_error_handler(adapter->sge); ++ if (cause & F_PL_INTR_SGE_ERR) { ++ if (t1_sge_intr_error_handler(adapter->sge)) ++ ret = IRQ_WAKE_THREAD; ++ } + + if (cause & FPGA_PCIX_INTERRUPT_GMAC) + fpga_phy_intr_handler(adapter); +@@ -231,13 +238,18 @@ static irqreturn_t fpga_slow_intr(adapter_t *adapter) + /* Clear TP interrupt */ + writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); + } +- if (cause & FPGA_PCIX_INTERRUPT_PCIX) +- t1_pci_intr_handler(adapter); ++ if (cause & FPGA_PCIX_INTERRUPT_PCIX) { ++ if (t1_pci_intr_handler(adapter)) ++ ret = IRQ_WAKE_THREAD; ++ } + + /* Clear the interrupts just processed. */ + if (cause) + writel(cause, adapter->regs + A_PL_CAUSE); + ++ if (ret != IRQ_NONE) ++ return ret; ++ + return cause == 0 ? IRQ_NONE : IRQ_HANDLED; + } + #endif +@@ -850,14 +862,18 @@ static irqreturn_t asic_slow_intr(adapter_t *adapter) + cause &= adapter->slow_intr_mask; + if (!cause) + return IRQ_NONE; +- if (cause & F_PL_INTR_SGE_ERR) +- t1_sge_intr_error_handler(adapter->sge); ++ if (cause & F_PL_INTR_SGE_ERR) { ++ if (t1_sge_intr_error_handler(adapter->sge)) ++ ret = IRQ_WAKE_THREAD; ++ } + if (cause & F_PL_INTR_TP) + t1_tp_intr_handler(adapter->tp); + if (cause & F_PL_INTR_ESPI) + t1_espi_intr_handler(adapter->espi); +- if (cause & F_PL_INTR_PCIX) +- t1_pci_intr_handler(adapter); ++ if (cause & F_PL_INTR_PCIX) { ++ if (t1_pci_intr_handler(adapter)) ++ ret = IRQ_WAKE_THREAD; ++ } + 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 +-- +2.43.0 + |