Skip to content

Commit 8215458

Browse files
Sebastian Andrzej Siewiorkuba-moo
authored andcommitted
chelsio: cxgb: Disable the card on error in threaded interrupt
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 <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent fec7fa0 commit 8215458

File tree

5 files changed

+44
-27
lines changed

5 files changed

+44
-27
lines changed

drivers/net/ethernet/chelsio/cxgb/common.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
346346
int t1_init_hw_modules(adapter_t *adapter);
347347
int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi);
348348
void t1_free_sw_modules(adapter_t *adapter);
349-
void t1_fatal_err(adapter_t *adapter);
350349
void t1_link_changed(adapter_t *adapter, int port_id);
351350
void t1_link_negotiated(adapter_t *adapter, int port_id, int link_stat,
352351
int speed, int duplex, int pause);

drivers/net/ethernet/chelsio/cxgb/cxgb2.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -917,16 +917,6 @@ static void mac_stats_task(struct work_struct *work)
917917
spin_unlock(&adapter->work_lock);
918918
}
919919

920-
void t1_fatal_err(struct adapter *adapter)
921-
{
922-
if (adapter->flags & FULL_INIT_DONE) {
923-
t1_sge_stop(adapter->sge);
924-
t1_interrupts_disable(adapter);
925-
}
926-
pr_alert("%s: encountered fatal error, operation suspended\n",
927-
adapter->name);
928-
}
929-
930920
static const struct net_device_ops cxgb_netdev_ops = {
931921
.ndo_open = cxgb_open,
932922
.ndo_stop = cxgb_close,

drivers/net/ethernet/chelsio/cxgb/sge.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -940,10 +940,11 @@ void t1_sge_intr_clear(struct sge *sge)
940940
/*
941941
* SGE 'Error' interrupt handler
942942
*/
943-
int t1_sge_intr_error_handler(struct sge *sge)
943+
bool t1_sge_intr_error_handler(struct sge *sge)
944944
{
945945
struct adapter *adapter = sge->adapter;
946946
u32 cause = readl(adapter->regs + A_SG_INT_CAUSE);
947+
bool wake = false;
947948

948949
if (adapter->port[0].dev->hw_features & NETIF_F_TSO)
949950
cause &= ~F_PACKET_TOO_BIG;
@@ -967,11 +968,14 @@ int t1_sge_intr_error_handler(struct sge *sge)
967968
sge->stats.pkt_mismatch++;
968969
pr_alert("%s: SGE packet mismatch\n", adapter->name);
969970
}
970-
if (cause & SGE_INT_FATAL)
971-
t1_fatal_err(adapter);
971+
if (cause & SGE_INT_FATAL) {
972+
t1_interrupts_disable(adapter);
973+
adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR;
974+
wake = true;
975+
}
972976

973977
writel(cause, adapter->regs + A_SG_INT_CAUSE);
974-
return 0;
978+
return wake;
975979
}
976980

977981
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)
16351639
if (pending_thread_intr & F_PL_INTR_EXT)
16361640
t1_elmer0_ext_intr_handler(adapter);
16371641

1642+
/* This error is fatal, interrupts remain off */
1643+
if (pending_thread_intr & F_PL_INTR_SGE_ERR) {
1644+
pr_alert("%s: encountered fatal error, operation suspended\n",
1645+
adapter->name);
1646+
t1_sge_stop(adapter->sge);
1647+
return IRQ_HANDLED;
1648+
}
1649+
16381650
spin_lock_irq(&adapter->async_lock);
16391651
adapter->slow_intr_mask |= F_PL_INTR_EXT;
16401652

drivers/net/ethernet/chelsio/cxgb/sge.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
8282
void t1_vlan_mode(struct adapter *adapter, netdev_features_t features);
8383
void t1_sge_start(struct sge *);
8484
void t1_sge_stop(struct sge *);
85-
int t1_sge_intr_error_handler(struct sge *);
85+
bool t1_sge_intr_error_handler(struct sge *sge);
8686
void t1_sge_intr_enable(struct sge *);
8787
void t1_sge_intr_disable(struct sge *);
8888
void t1_sge_intr_clear(struct sge *);

drivers/net/ethernet/chelsio/cxgb/subr.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void t1_link_changed(adapter_t *adapter, int port_id)
170170
t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc);
171171
}
172172

173-
static int t1_pci_intr_handler(adapter_t *adapter)
173+
static bool t1_pci_intr_handler(adapter_t *adapter)
174174
{
175175
u32 pcix_cause;
176176

@@ -179,9 +179,13 @@ static int t1_pci_intr_handler(adapter_t *adapter)
179179
if (pcix_cause) {
180180
pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE,
181181
pcix_cause);
182-
t1_fatal_err(adapter); /* PCI errors are fatal */
182+
/* PCI errors are fatal */
183+
t1_interrupts_disable(adapter);
184+
adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR;
185+
pr_alert("%s: PCI error encountered.\n", adapter->name);
186+
return true;
183187
}
184-
return 0;
188+
return false;
185189
}
186190

187191
#ifdef CONFIG_CHELSIO_T1_1G
@@ -213,10 +217,13 @@ static int fpga_phy_intr_handler(adapter_t *adapter)
213217
static irqreturn_t fpga_slow_intr(adapter_t *adapter)
214218
{
215219
u32 cause = readl(adapter->regs + A_PL_CAUSE);
220+
irqreturn_t ret = IRQ_NONE;
216221

217222
cause &= ~F_PL_INTR_SGE_DATA;
218-
if (cause & F_PL_INTR_SGE_ERR)
219-
t1_sge_intr_error_handler(adapter->sge);
223+
if (cause & F_PL_INTR_SGE_ERR) {
224+
if (t1_sge_intr_error_handler(adapter->sge))
225+
ret = IRQ_WAKE_THREAD;
226+
}
220227

221228
if (cause & FPGA_PCIX_INTERRUPT_GMAC)
222229
fpga_phy_intr_handler(adapter);
@@ -231,13 +238,18 @@ static irqreturn_t fpga_slow_intr(adapter_t *adapter)
231238
/* Clear TP interrupt */
232239
writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
233240
}
234-
if (cause & FPGA_PCIX_INTERRUPT_PCIX)
235-
t1_pci_intr_handler(adapter);
241+
if (cause & FPGA_PCIX_INTERRUPT_PCIX) {
242+
if (t1_pci_intr_handler(adapter))
243+
ret = IRQ_WAKE_THREAD;
244+
}
236245

237246
/* Clear the interrupts just processed. */
238247
if (cause)
239248
writel(cause, adapter->regs + A_PL_CAUSE);
240249

250+
if (ret != IRQ_NONE)
251+
return ret;
252+
241253
return cause == 0 ? IRQ_NONE : IRQ_HANDLED;
242254
}
243255
#endif
@@ -850,14 +862,18 @@ static irqreturn_t asic_slow_intr(adapter_t *adapter)
850862
cause &= adapter->slow_intr_mask;
851863
if (!cause)
852864
return IRQ_NONE;
853-
if (cause & F_PL_INTR_SGE_ERR)
854-
t1_sge_intr_error_handler(adapter->sge);
865+
if (cause & F_PL_INTR_SGE_ERR) {
866+
if (t1_sge_intr_error_handler(adapter->sge))
867+
ret = IRQ_WAKE_THREAD;
868+
}
855869
if (cause & F_PL_INTR_TP)
856870
t1_tp_intr_handler(adapter->tp);
857871
if (cause & F_PL_INTR_ESPI)
858872
t1_espi_intr_handler(adapter->espi);
859-
if (cause & F_PL_INTR_PCIX)
860-
t1_pci_intr_handler(adapter);
873+
if (cause & F_PL_INTR_PCIX) {
874+
if (t1_pci_intr_handler(adapter))
875+
ret = IRQ_WAKE_THREAD;
876+
}
861877
if (cause & F_PL_INTR_EXT) {
862878
/* Wake the threaded interrupt to handle external interrupts as
863879
* we require a process context. We disable EXT interrupts in

0 commit comments

Comments
 (0)