From f5f2b13129a6541debf8851bae843cbbf48298b7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 5 Mar 2007 00:30:07 -0800 Subject: [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 Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/msi.c | 2 +- drivers/pci/pci.c | 34 +++++++++++++++++++++++++++------- drivers/pci/pci.h | 2 -- drivers/pci/quirks.c | 4 ++-- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 68555c11f556..fd1068b59b0c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -211,7 +211,7 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) pci_intx(dev, 0); /* disable intx */ } -void disable_msi_mode(struct pci_dev *dev, int pos, int type) +static void disable_msi_mode(struct pci_dev *dev, int pos, int type) { u16 control; 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 diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a4f2d580625e..ae7a975995a5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem; extern unsigned int pci_pm_d3_delay; #ifdef CONFIG_PCI_MSI -void disable_msi_mode(struct pci_dev *dev, int pos, int type); void pci_no_msi(void); #else -static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1bf548287564..7f94fc098cd3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1438,8 +1438,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir */ static void __devinit quirk_pcie_pxh(struct pci_dev *dev) { - disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), - PCI_CAP_ID_MSI); + pci_msi_off(dev); + dev->no_msi = 1; printk(KERN_WARNING "PCI: PXH quirk detected, " -- cgit v1.2.1