| From 16bba1557e2761fef53f030204d29d65d39fa2af Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 8 Jul 2021 21:51:56 +0530 |
| Subject: cxgb4: fix IRQ free race during driver unload |
| |
| From: Shahjada Abul Husain <shahjada@chelsio.com> |
| |
| [ Upstream commit 015fe6fd29c4b9ac0f61b8c4455ef88e6018b9cc ] |
| |
| IRQs are requested during driver's ndo_open() and then later |
| freed up in disable_interrupts() during driver unload. |
| A race exists where driver can set the CXGB4_FULL_INIT_DONE |
| flag in ndo_open() after the disable_interrupts() in driver |
| unload path checks it, and hence misses calling free_irq(). |
| |
| Fix by unregistering netdevice first and sync with driver's |
| ndo_open(). This ensures disable_interrupts() checks the flag |
| correctly and frees up the IRQs properly. |
| |
| Fixes: b37987e8db5f ("cxgb4: Disable interrupts and napi before unregistering netdev") |
| Signed-off-by: Shahjada Abul Husain <shahjada@chelsio.com> |
| Signed-off-by: Raju Rangoju <rajur@chelsio.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 18 ++++++++++-------- |
| drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 3 +++ |
| 2 files changed, 13 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |
| index 762113a04dde..9f62ffe64781 100644 |
| --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |
| +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |
| @@ -2643,6 +2643,9 @@ static void detach_ulds(struct adapter *adap) |
| { |
| unsigned int i; |
| |
| + if (!is_uld(adap)) |
| + return; |
| + |
| mutex_lock(&uld_mutex); |
| list_del(&adap->list_node); |
| |
| @@ -7141,10 +7144,13 @@ static void remove_one(struct pci_dev *pdev) |
| */ |
| destroy_workqueue(adapter->workq); |
| |
| - if (is_uld(adapter)) { |
| - detach_ulds(adapter); |
| - t4_uld_clean_up(adapter); |
| - } |
| + detach_ulds(adapter); |
| + |
| + for_each_port(adapter, i) |
| + if (adapter->port[i]->reg_state == NETREG_REGISTERED) |
| + unregister_netdev(adapter->port[i]); |
| + |
| + t4_uld_clean_up(adapter); |
| |
| adap_free_hma_mem(adapter); |
| |
| @@ -7152,10 +7158,6 @@ static void remove_one(struct pci_dev *pdev) |
| |
| cxgb4_free_mps_ref_entries(adapter); |
| |
| - for_each_port(adapter, i) |
| - if (adapter->port[i]->reg_state == NETREG_REGISTERED) |
| - unregister_netdev(adapter->port[i]); |
| - |
| debugfs_remove_recursive(adapter->debugfs_root); |
| |
| if (!is_t4(adapter->params.chip)) |
| diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c |
| index 743af9e654aa..17faac715882 100644 |
| --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c |
| +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c |
| @@ -581,6 +581,9 @@ void t4_uld_clean_up(struct adapter *adap) |
| { |
| unsigned int i; |
| |
| + if (!is_uld(adap)) |
| + return; |
| + |
| mutex_lock(&uld_mutex); |
| for (i = 0; i < CXGB4_ULD_MAX; i++) { |
| if (!adap->uld[i].handle) |
| -- |
| 2.30.2 |
| |