Commit f5f2b131 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds

[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: default avatarEric 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 58a53b24
...@@ -968,7 +968,6 @@ void pci_scan_msi_device(struct pci_dev *dev) {} ...@@ -968,7 +968,6 @@ void pci_scan_msi_device(struct pci_dev *dev) {}
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
void pci_disable_msix(struct pci_dev *dev) {} void pci_disable_msix(struct pci_dev *dev) {}
void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
void pci_no_msi(void) {} void pci_no_msi(void) {}
EXPORT_SYMBOL(pci_enable_msix); EXPORT_SYMBOL(pci_enable_msix);
EXPORT_SYMBOL(pci_disable_msix); EXPORT_SYMBOL(pci_disable_msix);
......
...@@ -211,7 +211,7 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) ...@@ -211,7 +211,7 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
pci_intx(dev, 0); /* disable intx */ 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; u16 control;
......
...@@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev) ...@@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev)
if (atomic_sub_return(1, &dev->enable_cnt) != 0) if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return; 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); pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) { if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER; pci_command &= ~PCI_COMMAND_MASTER;
...@@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable) ...@@ -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 #ifndef HAVE_ARCH_PCI_SET_DMA_MASK
/* /*
* These can be overridden by arch-specific implementations * These can be overridden by arch-specific implementations
......
...@@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem; ...@@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem;
extern unsigned int pci_pm_d3_delay; extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void); void pci_no_msi(void);
#else #else
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { } static inline void pci_no_msi(void) { }
#endif #endif
......
...@@ -1438,8 +1438,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir ...@@ -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) static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
{ {
disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), pci_msi_off(dev);
PCI_CAP_ID_MSI);
dev->no_msi = 1; dev->no_msi = 1;
printk(KERN_WARNING "PCI: PXH quirk detected, " printk(KERN_WARNING "PCI: PXH quirk detected, "
......
...@@ -543,6 +543,7 @@ void pci_set_master(struct pci_dev *dev); ...@@ -543,6 +543,7 @@ void pci_set_master(struct pci_dev *dev);
int __must_check pci_set_mwi(struct pci_dev *dev); int __must_check pci_set_mwi(struct pci_dev *dev);
void pci_clear_mwi(struct pci_dev *dev); void pci_clear_mwi(struct pci_dev *dev);
void pci_intx(struct pci_dev *dev, int enable); void pci_intx(struct pci_dev *dev, int enable);
void pci_msi_off(struct pci_dev *dev);
int pci_set_dma_mask(struct pci_dev *dev, u64 mask); int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
......
...@@ -292,9 +292,10 @@ ...@@ -292,9 +292,10 @@
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */ #define PCI_MSI_MASK_BIT 16 /* Mask bits register */
/* MSI-X registers (these are at offset PCI_MSI_FLAGS) */ /* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
#define PCI_MSIX_FLAGS_QSIZE 0x7FF #define PCI_MSIX_FLAGS 2
#define PCI_MSIX_FLAGS_ENABLE (1 << 15) #define PCI_MSIX_FLAGS_QSIZE 0x7FF
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) #define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_MSIX_FLAGS_BITMASK (1 << 0) #define PCI_MSIX_FLAGS_BITMASK (1 << 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