From: Dean Nelson <dnelson@redhat.com> Date: Wed, 30 Jun 2010 15:54:22 -0400 Subject: [net] e1000e: don't inadvertently re-set INTX_DISABLE Message-id: <20100630155422.6314.66800.send-patch@localhost.localdomain> Patchwork-id: 26642 O-Subject: [RHEL5.6 PATCH] e1000e: don't inadvertently re-set INTX_DISABLE Bugzilla: 496127 RH-Acked-by: Andy Gospodarek <gospo@redhat.com> RH-Acked-by: Prarit Bhargava <prarit@redhat.com> RH-Acked-by: David S. Miller <davem@redhat.com> Resolves RHBZ 496127. Backport of net-next-2.6 commit 36f2407fe52c55566221f8c68c8fb808abffd2f5. 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. Tested by myself on a number of Beaker systems by commenting out the clearing of FLAG_MSI_TEST_FAILED in e1000_intr_msi_test(). The patch was also tested by khali @linux-fr.org as reported in RHBZ 477774. Brew build: https://brewweb.devel.redhat.com/taskinfo?taskID=2561998 diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 5c858f3..43c8b89 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3109,13 +3109,18 @@ static int e1000_test_msi(struct e1000_adapter *adapter) /* disable SERR in case the MSI write causes a master abort */ pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); - pci_write_config_word(adapter->pdev, PCI_COMMAND, - pci_cmd & ~PCI_COMMAND_SERR); + if (pci_cmd & PCI_COMMAND_SERR) + pci_write_config_word(adapter->pdev, PCI_COMMAND, + pci_cmd & ~PCI_COMMAND_SERR); err = e1000_test_msi_interrupt(adapter); - /* restore previous setting of command word */ - pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd); + /* re-enable SERR */ + if (pci_cmd & PCI_COMMAND_SERR) { + pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); + pci_cmd |= PCI_COMMAND_SERR; + pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd); + } /* success ! */ if (!err)