aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDean Nelson <dnelson@redhat.com>2010-06-29 14:12:05 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 02:09:18 -0400
commit36f2407fe52c55566221f8c68c8fb808abffd2f5 (patch)
tree6de3622f8c40351e801015389d3809224055a6b8
parent6c057573f21db0ef85f78318875269a2159af35c (diff)
e1000e: don't inadvertently re-set INTX_DISABLE
Should e1000_test_msi() fail to see an msi interrupt, it attempts to fallback to legacy INTx interrupts. But an error in the code may prevent this from happening correctly. Before calling e1000_test_msi_interrupt(), e1000_test_msi() disables SERR by clearing the SERR bit from the just read PCI_COMMAND bits as it writes them back out. Upon return from calling e1000_test_msi_interrupt(), it re-enables SERR by writing out the version of PCI_COMMAND it had previously read. The problem with this is that e1000_test_msi_interrupt() calls pci_disable_msi(), which eventually ends up in pci_intx(). And because pci_intx() was called with enable set to 1, the INTX_DISABLE bit gets cleared from PCI_COMMAND, which is what we want. But when we get back to e1000_test_msi(), the INTX_DISABLE bit gets inadvertently re-set because of the attempt by e1000_test_msi() to re-enable SERR. The solution is to have e1000_test_msi() re-read the PCI_COMMAND bits as part of its attempt to re-enable SERR. During debugging/testing of this issue I found that not all the systems I ran on had the SERR bit set to begin with. And on some of the systems the same could be said for the INTX_DISABLE bit. Needless to say these latter systems didn't have a problem falling back to legacy INTx interrupts with the code as is. Signed-off-by: Dean Nelson <dnelson@redhat.com> CC: stable@kernel.org Tested-by: Emil Tantilov <emil.s.tantilov@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/e1000e/netdev.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 71592ed2e686..3e53ca723435 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3439,13 +3439,18 @@ static int e1000_test_msi(struct e1000_adapter *adapter)
3439 3439
3440 /* disable SERR in case the MSI write causes a master abort */ 3440 /* disable SERR in case the MSI write causes a master abort */
3441 pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); 3441 pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
3442 pci_write_config_word(adapter->pdev, PCI_COMMAND, 3442 if (pci_cmd & PCI_COMMAND_SERR)
3443 pci_cmd & ~PCI_COMMAND_SERR); 3443 pci_write_config_word(adapter->pdev, PCI_COMMAND,
3444 pci_cmd & ~PCI_COMMAND_SERR);
3444 3445
3445 err = e1000_test_msi_interrupt(adapter); 3446 err = e1000_test_msi_interrupt(adapter);
3446 3447
3447 /* restore previous setting of command word */ 3448 /* re-enable SERR */
3448 pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd); 3449 if (pci_cmd & PCI_COMMAND_SERR) {
3450 pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
3451 pci_cmd |= PCI_COMMAND_SERR;
3452 pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
3453 }
3449 3454
3450 /* success ! */ 3455 /* success ! */
3451 if (!err) 3456 if (!err)