Commit 025d0973 authored by Guilherme G. Piccoli's avatar Guilherme G. Piccoli Committed by David S. Miller

cxgb4: avoid crash on PCI error recovery path

During PCI error recovery process, specifically on eeh_err_detected()
we might have a NULL netdev struct, hence a direct dereference will
lead to a kernel oops. This was observed with latest upstream kernel
(v4.12-rc2) on Chelsio adapter T422-CR in PowerPC machines.

This patch checks for NULL pointer and avoids the crash, both in
eeh_err_detected() and eeh_resume(). Also, we avoid to trigger
a fatal error or to try disabling interrupts on FW during PCI
error recovery, because: (a) driver might not be able to accurately
access PCI regions in this case, and (b) trigger a fatal error
_during_ the recovery steps is a mistake that could prevent the
recovery path to complete successfully.
Reported-by: default avatarHarsha Thyagaraja <hathyaga@in.ibm.com>
Signed-off-by: default avatarGuilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 468b0df6
...@@ -2771,6 +2771,9 @@ void t4_fatal_err(struct adapter *adap) ...@@ -2771,6 +2771,9 @@ void t4_fatal_err(struct adapter *adap)
{ {
int port; int port;
if (pci_channel_offline(adap->pdev))
return;
/* Disable the SGE since ULDs are going to free resources that /* Disable the SGE since ULDs are going to free resources that
* could be exposed to the adapter. RDMA MWs for example... * could be exposed to the adapter. RDMA MWs for example...
*/ */
...@@ -3882,10 +3885,11 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, ...@@ -3882,10 +3885,11 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
spin_lock(&adap->stats_lock); spin_lock(&adap->stats_lock);
for_each_port(adap, i) { for_each_port(adap, i) {
struct net_device *dev = adap->port[i]; struct net_device *dev = adap->port[i];
if (dev) {
netif_device_detach(dev); netif_device_detach(dev);
netif_carrier_off(dev); netif_carrier_off(dev);
} }
}
spin_unlock(&adap->stats_lock); spin_unlock(&adap->stats_lock);
disable_interrupts(adap); disable_interrupts(adap);
if (adap->flags & FULL_INIT_DONE) if (adap->flags & FULL_INIT_DONE)
...@@ -3963,13 +3967,14 @@ static void eeh_resume(struct pci_dev *pdev) ...@@ -3963,13 +3967,14 @@ static void eeh_resume(struct pci_dev *pdev)
rtnl_lock(); rtnl_lock();
for_each_port(adap, i) { for_each_port(adap, i) {
struct net_device *dev = adap->port[i]; struct net_device *dev = adap->port[i];
if (dev) {
if (netif_running(dev)) { if (netif_running(dev)) {
link_start(dev); link_start(dev);
cxgb_set_rxmode(dev); cxgb_set_rxmode(dev);
} }
netif_device_attach(dev); netif_device_attach(dev);
} }
}
rtnl_unlock(); rtnl_unlock();
} }
......
...@@ -4557,8 +4557,13 @@ void t4_intr_enable(struct adapter *adapter) ...@@ -4557,8 +4557,13 @@ void t4_intr_enable(struct adapter *adapter)
*/ */
void t4_intr_disable(struct adapter *adapter) void t4_intr_disable(struct adapter *adapter)
{ {
u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A); u32 whoami, pf;
u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ?
if (pci_channel_offline(adapter->pdev))
return;
whoami = t4_read_reg(adapter, PL_WHOAMI_A);
pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ?
SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami);
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0); t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment