diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-03-05 03:30:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-05 10:57:50 -0500 |
commit | f5f2b13129a6541debf8851bae843cbbf48298b7 (patch) | |
tree | 274dc998519074e56259a7dc4bd611652b8d930e | |
parent | 58a53b246b4aed95f3f93b45828c8d9f26b1cfcb (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.c | 1 | ||||
-rw-r--r-- | drivers/pci/msi.c | 2 | ||||
-rw-r--r-- | drivers/pci/pci.c | 34 | ||||
-rw-r--r-- | drivers/pci/pci.h | 2 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 4 | ||||
-rw-r--r-- | include/linux/pci.h | 1 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 7 |
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) {} | |||
968 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} | 968 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} |
969 | void pci_disable_msix(struct pci_dev *dev) {} | 969 | void pci_disable_msix(struct pci_dev *dev) {} |
970 | void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} | 970 | void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} |
971 | void disable_msi_mode(struct pci_dev *dev, int pos, int type) {} | ||
972 | void pci_no_msi(void) {} | 971 | void pci_no_msi(void) {} |
973 | EXPORT_SYMBOL(pci_enable_msix); | 972 | EXPORT_SYMBOL(pci_enable_msix); |
974 | EXPORT_SYMBOL(pci_disable_msix); | 973 | EXPORT_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 | ||
214 | void disable_msi_mode(struct pci_dev *dev, int pos, int type) | 214 | static 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 | */ | ||
1281 | void 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; | |||
46 | extern unsigned int pci_pm_d3_delay; | 46 | extern unsigned int pci_pm_d3_delay; |
47 | 47 | ||
48 | #ifdef CONFIG_PCI_MSI | 48 | #ifdef CONFIG_PCI_MSI |
49 | void disable_msi_mode(struct pci_dev *dev, int pos, int type); | ||
50 | void pci_no_msi(void); | 49 | void pci_no_msi(void); |
51 | #else | 50 | #else |
52 | static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } | ||
53 | static inline void pci_no_msi(void) { } | 51 | static 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 | */ |
1439 | static void __devinit quirk_pcie_pxh(struct pci_dev *dev) | 1439 | static 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); | |||
543 | int __must_check pci_set_mwi(struct pci_dev *dev); | 543 | int __must_check pci_set_mwi(struct pci_dev *dev); |
544 | void pci_clear_mwi(struct pci_dev *dev); | 544 | void pci_clear_mwi(struct pci_dev *dev); |
545 | void pci_intx(struct pci_dev *dev, int enable); | 545 | void pci_intx(struct pci_dev *dev, int enable); |
546 | void pci_msi_off(struct pci_dev *dev); | ||
546 | int pci_set_dma_mask(struct pci_dev *dev, u64 mask); | 547 | int pci_set_dma_mask(struct pci_dev *dev, u64 mask); |
547 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); | 548 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); |
548 | void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); | 549 | void 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 | ||