aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-03-05 03:30:07 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-05 10:57:50 -0500
commitf5f2b13129a6541debf8851bae843cbbf48298b7 (patch)
tree274dc998519074e56259a7dc4bd611652b8d930e
parent58a53b246b4aed95f3f93b45828c8d9f26b1cfcb (diff)
[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>
-rw-r--r--arch/powerpc/kernel/irq.c1
-rw-r--r--drivers/pci/msi.c2
-rw-r--r--drivers/pci/pci.c34
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/quirks.c4
-rw-r--r--include/linux/pci.h1
-rw-r--r--include/linux/pci_regs.h7
7 files changed, 35 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 919fbf568495..100930826850 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -968,7 +968,6 @@ void pci_scan_msi_device(struct pci_dev *dev) {}
968int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} 968int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
969void pci_disable_msix(struct pci_dev *dev) {} 969void pci_disable_msix(struct pci_dev *dev) {}
970void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} 970void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
971void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
972void pci_no_msi(void) {} 971void pci_no_msi(void) {}
973EXPORT_SYMBOL(pci_enable_msix); 972EXPORT_SYMBOL(pci_enable_msix);
974EXPORT_SYMBOL(pci_disable_msix); 973EXPORT_SYMBOL(pci_disable_msix);
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)
211 pci_intx(dev, 0); /* disable intx */ 211 pci_intx(dev, 0); /* disable intx */
212} 212}
213 213
214void disable_msi_mode(struct pci_dev *dev, int pos, int type) 214static void disable_msi_mode(struct pci_dev *dev, int pos, int type)
215{ 215{
216 u16 control; 216 u16 control;
217 217
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)
881 if (atomic_sub_return(1, &dev->enable_cnt) != 0) 881 if (atomic_sub_return(1, &dev->enable_cnt) != 0)
882 return; 882 return;
883 883
884 if (dev->msi_enabled)
885 disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
886 PCI_CAP_ID_MSI);
887 if (dev->msix_enabled)
888 disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
889 PCI_CAP_ID_MSIX);
890
891 pci_read_config_word(dev, PCI_COMMAND, &pci_command); 884 pci_read_config_word(dev, PCI_COMMAND, &pci_command);
892 if (pci_command & PCI_COMMAND_MASTER) { 885 if (pci_command & PCI_COMMAND_MASTER) {
893 pci_command &= ~PCI_COMMAND_MASTER; 886 pci_command &= ~PCI_COMMAND_MASTER;
@@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable)
1277 } 1270 }
1278} 1271}
1279 1272
1273/**
1274 * pci_msi_off - disables any msi or msix capabilities
1275 * @pdev: the PCI device to operate on
1276 *
1277 * If you want to use msi see pci_enable_msi and friends.
1278 * This is a lower level primitive that allows us to disable
1279 * msi operation at the device level.
1280 */
1281void pci_msi_off(struct pci_dev *dev)
1282{
1283 int pos;
1284 u16 control;
1285
1286 pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
1287 if (pos) {
1288 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
1289 control &= ~PCI_MSI_FLAGS_ENABLE;
1290 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
1291 }
1292 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
1293 if (pos) {
1294 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
1295 control &= ~PCI_MSIX_FLAGS_ENABLE;
1296 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
1297 }
1298}
1299
1280#ifndef HAVE_ARCH_PCI_SET_DMA_MASK 1300#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
1281/* 1301/*
1282 * These can be overridden by arch-specific implementations 1302 * 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;
46extern unsigned int pci_pm_d3_delay; 46extern unsigned int pci_pm_d3_delay;
47 47
48#ifdef CONFIG_PCI_MSI 48#ifdef CONFIG_PCI_MSI
49void disable_msi_mode(struct pci_dev *dev, int pos, int type);
50void pci_no_msi(void); 49void pci_no_msi(void);
51#else 50#else
52static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
53static inline void pci_no_msi(void) { } 51static inline void pci_no_msi(void) { }
54#endif 52#endif
55 53
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
1438 */ 1438 */
1439static void __devinit quirk_pcie_pxh(struct pci_dev *dev) 1439static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
1440{ 1440{
1441 disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), 1441 pci_msi_off(dev);
1442 PCI_CAP_ID_MSI); 1442
1443 dev->no_msi = 1; 1443 dev->no_msi = 1;
1444 1444
1445 printk(KERN_WARNING "PCI: PXH quirk detected, " 1445 printk(KERN_WARNING "PCI: PXH quirk detected, "
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2c4b6842dfb9..78417e421b4c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -543,6 +543,7 @@ void pci_set_master(struct pci_dev *dev);
543int __must_check pci_set_mwi(struct pci_dev *dev); 543int __must_check pci_set_mwi(struct pci_dev *dev);
544void pci_clear_mwi(struct pci_dev *dev); 544void pci_clear_mwi(struct pci_dev *dev);
545void pci_intx(struct pci_dev *dev, int enable); 545void pci_intx(struct pci_dev *dev, int enable);
546void pci_msi_off(struct pci_dev *dev);
546int pci_set_dma_mask(struct pci_dev *dev, u64 mask); 547int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
547int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); 548int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
548void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); 549void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 7a6d34ee5ab1..f09cce2357ff 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -292,9 +292,10 @@
292#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ 292#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
293#define PCI_MSI_MASK_BIT 16 /* Mask bits register */ 293#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
294 294
295/* MSI-X registers (these are at offset PCI_MSI_FLAGS) */ 295/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
296#define PCI_MSIX_FLAGS_QSIZE 0x7FF 296#define PCI_MSIX_FLAGS 2
297#define PCI_MSIX_FLAGS_ENABLE (1 << 15) 297#define PCI_MSIX_FLAGS_QSIZE 0x7FF
298#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
298#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) 299#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
299#define PCI_MSIX_FLAGS_BITMASK (1 << 0) 300#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
300 301