aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-03-05 00:30:07 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-05 07:57:50 -0800
commitf5f2b13129a6541debf8851bae843cbbf48298b7 (patch)
tree274dc998519074e56259a7dc4bd611652b8d930e /drivers/pci/pci.c
parent[PATCH] io_apic.h needs apicdef.h (diff)
downloadlinux-dev-f5f2b13129a6541debf8851bae843cbbf48298b7.tar.xz
linux-dev-f5f2b13129a6541debf8851bae843cbbf48298b7.zip
[PATCH] msi: sanely support hardware level msi disabling
In some cases when we are not using msi we need a way to ensure that the hardware does not have an msi capability enabled. Currently the code has been calling disable_msi_mode to try and achieve that. However disable_msi_mode has several other side effects and is only available when msi support is compiled in so it isn't really appropriate. Instead this patch implements pci_msi_off which disables all msi and msix capabilities unconditionally with no additional side effects. pci_disable_device was redundantly clearing the bus master enable flag and clearing the msi enable bit. A device that is not allowed to perform bus mastering operations cannot generate intx or msi interrupt messages as those are essentially a special case of dma, and require bus mastering. So the call in pci_disable_device to disable msi capabilities was redundant. quirk_pcie_pxh also called disable_msi_mode and is updated to use pci_msi_off. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Michael Ellerman <michael@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1e74e1ee8bd8..df495300ce3d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev)
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
- if (dev->msi_enabled)
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSI);
- if (dev->msix_enabled)
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSIX);
-
pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER;
@@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable)
}
}
+/**
+ * pci_msi_off - disables any msi or msix capabilities
+ * @pdev: the PCI device to operate on
+ *
+ * If you want to use msi see pci_enable_msi and friends.
+ * This is a lower level primitive that allows us to disable
+ * msi operation at the device level.
+ */
+void pci_msi_off(struct pci_dev *dev)
+{
+ int pos;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ control &= ~PCI_MSI_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ }
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ }
+}
+
#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
/*
* These can be overridden by arch-specific implementations