Skip to content

Commit 75b8f78

Browse files
committed
Merge branch 'chelsio-cxgb-use-threaded-interrupts-for-deferred-work'
Sebastian Andrzej Siewior says: ==================== chelsio: cxgb: Use threaded interrupts for deferred work Patch #2 fixes an issue in which del_timer_sync() and tasklet_kill() is invoked from the interrupt handler. This is probably a rare error case since it disables interrupts / the card in that case. Patch #1 converts a worker to use a threaded interrupt which is then also used in patch #2 instead adding another worker for this task (and flush_work() to synchronise vs rmmod). ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 462e99a + 8215458 commit 75b8f78

File tree

5 files changed

+99
-81
lines changed

5 files changed

+99
-81
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ struct adapter {
238238
int msg_enable;
239239
u32 mmio_len;
240240

241-
struct work_struct ext_intr_handler_task;
242241
struct adapter_params params;
243242

244243
/* Terminator modules. */
@@ -257,6 +256,7 @@ struct adapter {
257256

258257
/* guards async operations */
259258
spinlock_t async_lock ____cacheline_aligned;
259+
u32 pending_thread_intr;
260260
u32 slow_intr_mask;
261261
int t1powersave;
262262
};
@@ -334,8 +334,7 @@ void t1_interrupts_enable(adapter_t *adapter);
334334
void t1_interrupts_disable(adapter_t *adapter);
335335
void t1_interrupts_clear(adapter_t *adapter);
336336
int t1_elmer0_ext_intr_handler(adapter_t *adapter);
337-
void t1_elmer0_ext_intr(adapter_t *adapter);
338-
int t1_slow_intr_handler(adapter_t *adapter);
337+
irqreturn_t t1_slow_intr_handler(adapter_t *adapter);
339338

340339
int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
341340
const struct board_info *t1_get_board_info(unsigned int board_id);
@@ -347,7 +346,6 @@ int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
347346
int t1_init_hw_modules(adapter_t *adapter);
348347
int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi);
349348
void t1_free_sw_modules(adapter_t *adapter);
350-
void t1_fatal_err(adapter_t *adapter);
351349
void t1_link_changed(adapter_t *adapter, int port_id);
352350
void t1_link_negotiated(adapter_t *adapter, int port_id, int link_stat,
353351
int speed, int duplex, int pause);

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

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ static int cxgb_up(struct adapter *adapter)
211211
t1_interrupts_clear(adapter);
212212

213213
adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev);
214-
err = request_irq(adapter->pdev->irq, t1_interrupt,
215-
adapter->params.has_msi ? 0 : IRQF_SHARED,
216-
adapter->name, adapter);
214+
err = request_threaded_irq(adapter->pdev->irq, t1_interrupt,
215+
t1_interrupt_thread,
216+
adapter->params.has_msi ? 0 : IRQF_SHARED,
217+
adapter->name, adapter);
217218
if (err) {
218219
if (adapter->params.has_msi)
219220
pci_disable_msi(adapter->pdev);
@@ -916,51 +917,6 @@ static void mac_stats_task(struct work_struct *work)
916917
spin_unlock(&adapter->work_lock);
917918
}
918919

919-
/*
920-
* Processes elmer0 external interrupts in process context.
921-
*/
922-
static void ext_intr_task(struct work_struct *work)
923-
{
924-
struct adapter *adapter =
925-
container_of(work, struct adapter, ext_intr_handler_task);
926-
927-
t1_elmer0_ext_intr_handler(adapter);
928-
929-
/* Now reenable external interrupts */
930-
spin_lock_irq(&adapter->async_lock);
931-
adapter->slow_intr_mask |= F_PL_INTR_EXT;
932-
writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE);
933-
writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
934-
adapter->regs + A_PL_ENABLE);
935-
spin_unlock_irq(&adapter->async_lock);
936-
}
937-
938-
/*
939-
* Interrupt-context handler for elmer0 external interrupts.
940-
*/
941-
void t1_elmer0_ext_intr(struct adapter *adapter)
942-
{
943-
/*
944-
* Schedule a task to handle external interrupts as we require
945-
* a process context. We disable EXT interrupts in the interim
946-
* and let the task reenable them when it's done.
947-
*/
948-
adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
949-
writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
950-
adapter->regs + A_PL_ENABLE);
951-
schedule_work(&adapter->ext_intr_handler_task);
952-
}
953-
954-
void t1_fatal_err(struct adapter *adapter)
955-
{
956-
if (adapter->flags & FULL_INIT_DONE) {
957-
t1_sge_stop(adapter->sge);
958-
t1_interrupts_disable(adapter);
959-
}
960-
pr_alert("%s: encountered fatal error, operation suspended\n",
961-
adapter->name);
962-
}
963-
964920
static const struct net_device_ops cxgb_netdev_ops = {
965921
.ndo_open = cxgb_open,
966922
.ndo_stop = cxgb_close,
@@ -1062,8 +1018,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
10621018
spin_lock_init(&adapter->async_lock);
10631019
spin_lock_init(&adapter->mac_lock);
10641020

1065-
INIT_WORK(&adapter->ext_intr_handler_task,
1066-
ext_intr_task);
10671021
INIT_DELAYED_WORK(&adapter->stats_update_task,
10681022
mac_stats_task);
10691023

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

Lines changed: 46 additions & 7 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)
@@ -1619,11 +1623,46 @@ int t1_poll(struct napi_struct *napi, int budget)
16191623
return work_done;
16201624
}
16211625

1626+
irqreturn_t t1_interrupt_thread(int irq, void *data)
1627+
{
1628+
struct adapter *adapter = data;
1629+
u32 pending_thread_intr;
1630+
1631+
spin_lock_irq(&adapter->async_lock);
1632+
pending_thread_intr = adapter->pending_thread_intr;
1633+
adapter->pending_thread_intr = 0;
1634+
spin_unlock_irq(&adapter->async_lock);
1635+
1636+
if (!pending_thread_intr)
1637+
return IRQ_NONE;
1638+
1639+
if (pending_thread_intr & F_PL_INTR_EXT)
1640+
t1_elmer0_ext_intr_handler(adapter);
1641+
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+
1650+
spin_lock_irq(&adapter->async_lock);
1651+
adapter->slow_intr_mask |= F_PL_INTR_EXT;
1652+
1653+
writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE);
1654+
writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
1655+
adapter->regs + A_PL_ENABLE);
1656+
spin_unlock_irq(&adapter->async_lock);
1657+
1658+
return IRQ_HANDLED;
1659+
}
1660+
16221661
irqreturn_t t1_interrupt(int irq, void *data)
16231662
{
16241663
struct adapter *adapter = data;
16251664
struct sge *sge = adapter->sge;
1626-
int handled;
1665+
irqreturn_t handled;
16271666

16281667
if (likely(responses_pending(adapter))) {
16291668
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
@@ -1645,10 +1684,10 @@ irqreturn_t t1_interrupt(int irq, void *data)
16451684
handled = t1_slow_intr_handler(adapter);
16461685
spin_unlock(&adapter->async_lock);
16471686

1648-
if (!handled)
1687+
if (handled == IRQ_NONE)
16491688
sge->stats.unhandled_irqs++;
16501689

1651-
return IRQ_RETVAL(handled != 0);
1690+
return handled;
16521691
}
16531692

16541693
/*

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,15 @@ struct sge *t1_sge_create(struct adapter *, struct sge_params *);
7474
int t1_sge_configure(struct sge *, struct sge_params *);
7575
int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
7676
void t1_sge_destroy(struct sge *);
77+
irqreturn_t t1_interrupt_thread(int irq, void *data);
7778
irqreturn_t t1_interrupt(int irq, void *cookie);
7879
int t1_poll(struct napi_struct *, int);
7980

8081
netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
8182
void t1_vlan_mode(struct adapter *adapter, netdev_features_t features);
8283
void t1_sge_start(struct sge *);
8384
void t1_sge_stop(struct sge *);
84-
int t1_sge_intr_error_handler(struct sge *);
85+
bool t1_sge_intr_error_handler(struct sge *sge);
8586
void t1_sge_intr_enable(struct sge *);
8687
void t1_sge_intr_disable(struct sge *);
8788
void t1_sge_intr_clear(struct sge *);

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

Lines changed: 45 additions & 19 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
@@ -210,13 +214,16 @@ static int fpga_phy_intr_handler(adapter_t *adapter)
210214
/*
211215
* Slow path interrupt handler for FPGAs.
212216
*/
213-
static int fpga_slow_intr(adapter_t *adapter)
217+
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,14 +238,19 @@ static int 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

241-
return cause != 0;
250+
if (ret != IRQ_NONE)
251+
return ret;
252+
253+
return cause == 0 ? IRQ_NONE : IRQ_HANDLED;
242254
}
243255
#endif
244256

@@ -842,31 +854,45 @@ void t1_interrupts_clear(adapter_t* adapter)
842854
/*
843855
* Slow path interrupt handler for ASICs.
844856
*/
845-
static int asic_slow_intr(adapter_t *adapter)
857+
static irqreturn_t asic_slow_intr(adapter_t *adapter)
846858
{
847859
u32 cause = readl(adapter->regs + A_PL_CAUSE);
860+
irqreturn_t ret = IRQ_HANDLED;
848861

849862
cause &= adapter->slow_intr_mask;
850863
if (!cause)
851-
return 0;
852-
if (cause & F_PL_INTR_SGE_ERR)
853-
t1_sge_intr_error_handler(adapter->sge);
864+
return IRQ_NONE;
865+
if (cause & F_PL_INTR_SGE_ERR) {
866+
if (t1_sge_intr_error_handler(adapter->sge))
867+
ret = IRQ_WAKE_THREAD;
868+
}
854869
if (cause & F_PL_INTR_TP)
855870
t1_tp_intr_handler(adapter->tp);
856871
if (cause & F_PL_INTR_ESPI)
857872
t1_espi_intr_handler(adapter->espi);
858-
if (cause & F_PL_INTR_PCIX)
859-
t1_pci_intr_handler(adapter);
860-
if (cause & F_PL_INTR_EXT)
861-
t1_elmer0_ext_intr(adapter);
873+
if (cause & F_PL_INTR_PCIX) {
874+
if (t1_pci_intr_handler(adapter))
875+
ret = IRQ_WAKE_THREAD;
876+
}
877+
if (cause & F_PL_INTR_EXT) {
878+
/* Wake the threaded interrupt to handle external interrupts as
879+
* we require a process context. We disable EXT interrupts in
880+
* the interim and let the thread reenable them when it's done.
881+
*/
882+
adapter->pending_thread_intr |= F_PL_INTR_EXT;
883+
adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
884+
writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
885+
adapter->regs + A_PL_ENABLE);
886+
ret = IRQ_WAKE_THREAD;
887+
}
862888

863889
/* Clear the interrupts just processed. */
864890
writel(cause, adapter->regs + A_PL_CAUSE);
865891
readl(adapter->regs + A_PL_CAUSE); /* flush writes */
866-
return 1;
892+
return ret;
867893
}
868894

869-
int t1_slow_intr_handler(adapter_t *adapter)
895+
irqreturn_t t1_slow_intr_handler(adapter_t *adapter)
870896
{
871897
#ifdef CONFIG_CHELSIO_T1_1G
872898
if (!t1_is_asic(adapter))

0 commit comments

Comments
 (0)