diff options
author | Stephen Warren <swarren@nvidia.com> | 2013-08-13 14:07:26 -0400 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2013-08-13 14:07:26 -0400 |
commit | 734a0f6bb93d6f2c27a2b2976e9da1e31905facd (patch) | |
tree | 9bfd05c893da5c37318f5ca0147898f1d9f1fe09 | |
parent | e9f624499cc84a625648ccfbd550b74d17d52fb2 (diff) | |
parent | 6a4324ebf5cf412d55fd1ea259d4dd29fb8f90e8 (diff) |
Merge tag 'msi-3.12-2' into for-3.12/soc
pci msi changes for v3.12 (round 2)
- fix build breakage for s390 allyesconfig due to !HAVE_GENERIC_HARDIRQS
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/mach/pci.h | 4 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 16 | ||||
-rw-r--r-- | arch/ia64/Kconfig | 1 | ||||
-rw-r--r-- | arch/mips/Kconfig | 2 | ||||
-rw-r--r-- | arch/mips/include/asm/pci.h | 5 | ||||
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/pci.h | 5 | ||||
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/pci.h | 4 | ||||
-rw-r--r-- | arch/sparc/Kconfig | 1 | ||||
-rw-r--r-- | arch/tile/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/pci.h | 30 | ||||
-rw-r--r-- | arch/x86/kernel/x86_init.c | 24 | ||||
-rw-r--r-- | drivers/of/of_pci.c | 45 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pci/msi.c | 85 | ||||
-rw-r--r-- | drivers/pci/probe.c | 1 | ||||
-rw-r--r-- | include/linux/msi.h | 21 | ||||
-rw-r--r-- | include/linux/of_pci.h | 12 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
22 files changed, 185 insertions, 81 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e02ec0c..b173c1d8721f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -441,7 +441,6 @@ config ARCH_NETX | |||
441 | config ARCH_IOP13XX | 441 | config ARCH_IOP13XX |
442 | bool "IOP13xx-based" | 442 | bool "IOP13xx-based" |
443 | depends on MMU | 443 | depends on MMU |
444 | select ARCH_SUPPORTS_MSI | ||
445 | select CPU_XSC3 | 444 | select CPU_XSC3 |
446 | select NEED_MACH_MEMORY_H | 445 | select NEED_MACH_MEMORY_H |
447 | select NEED_RET_TO_USER | 446 | select NEED_RET_TO_USER |
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index a1c90d7feb0e..454d642a4070 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h | |||
@@ -36,6 +36,8 @@ struct hw_pci { | |||
36 | resource_size_t start, | 36 | resource_size_t start, |
37 | resource_size_t size, | 37 | resource_size_t size, |
38 | resource_size_t align); | 38 | resource_size_t align); |
39 | void (*add_bus)(struct pci_bus *bus); | ||
40 | void (*remove_bus)(struct pci_bus *bus); | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | /* | 43 | /* |
@@ -63,6 +65,8 @@ struct pci_sys_data { | |||
63 | resource_size_t start, | 65 | resource_size_t start, |
64 | resource_size_t size, | 66 | resource_size_t size, |
65 | resource_size_t align); | 67 | resource_size_t align); |
68 | void (*add_bus)(struct pci_bus *bus); | ||
69 | void (*remove_bus)(struct pci_bus *bus); | ||
66 | void *private_data; /* platform controller private data */ | 70 | void *private_data; /* platform controller private data */ |
67 | }; | 71 | }; |
68 | 72 | ||
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 261fcc826169..1ec9c8701c26 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -363,6 +363,20 @@ void pcibios_fixup_bus(struct pci_bus *bus) | |||
363 | } | 363 | } |
364 | EXPORT_SYMBOL(pcibios_fixup_bus); | 364 | EXPORT_SYMBOL(pcibios_fixup_bus); |
365 | 365 | ||
366 | void pcibios_add_bus(struct pci_bus *bus) | ||
367 | { | ||
368 | struct pci_sys_data *sys = bus->sysdata; | ||
369 | if (sys->add_bus) | ||
370 | sys->add_bus(bus); | ||
371 | } | ||
372 | |||
373 | void pcibios_remove_bus(struct pci_bus *bus) | ||
374 | { | ||
375 | struct pci_sys_data *sys = bus->sysdata; | ||
376 | if (sys->remove_bus) | ||
377 | sys->remove_bus(bus); | ||
378 | } | ||
379 | |||
366 | /* | 380 | /* |
367 | * Swizzle the device pin each time we cross a bridge. If a platform does | 381 | * Swizzle the device pin each time we cross a bridge. If a platform does |
368 | * not provide a swizzle function, we perform the standard PCI swizzling. | 382 | * not provide a swizzle function, we perform the standard PCI swizzling. |
@@ -464,6 +478,8 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, | |||
464 | sys->swizzle = hw->swizzle; | 478 | sys->swizzle = hw->swizzle; |
465 | sys->map_irq = hw->map_irq; | 479 | sys->map_irq = hw->map_irq; |
466 | sys->align_resource = hw->align_resource; | 480 | sys->align_resource = hw->align_resource; |
481 | sys->add_bus = hw->add_bus; | ||
482 | sys->remove_bus = hw->remove_bus; | ||
467 | INIT_LIST_HEAD(&sys->resources); | 483 | INIT_LIST_HEAD(&sys->resources); |
468 | 484 | ||
469 | if (hw->private_data) | 485 | if (hw->private_data) |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 5a768ad8e893..098602b939a9 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -9,7 +9,6 @@ config IA64 | |||
9 | select PCI if (!IA64_HP_SIM) | 9 | select PCI if (!IA64_HP_SIM) |
10 | select ACPI if (!IA64_HP_SIM) | 10 | select ACPI if (!IA64_HP_SIM) |
11 | select PM if (!IA64_HP_SIM) | 11 | select PM if (!IA64_HP_SIM) |
12 | select ARCH_SUPPORTS_MSI | ||
13 | select HAVE_UNSTABLE_SCHED_CLOCK | 12 | select HAVE_UNSTABLE_SCHED_CLOCK |
14 | select HAVE_IDE | 13 | select HAVE_IDE |
15 | select HAVE_OPROFILE | 14 | select HAVE_OPROFILE |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4758a8fd3e99..00b26986cd05 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -726,7 +726,6 @@ config CAVIUM_OCTEON_SOC | |||
726 | select SYS_HAS_CPU_CAVIUM_OCTEON | 726 | select SYS_HAS_CPU_CAVIUM_OCTEON |
727 | select SWAP_IO_SPACE | 727 | select SWAP_IO_SPACE |
728 | select HW_HAS_PCI | 728 | select HW_HAS_PCI |
729 | select ARCH_SUPPORTS_MSI | ||
730 | select ZONE_DMA32 | 729 | select ZONE_DMA32 |
731 | select USB_ARCH_HAS_OHCI | 730 | select USB_ARCH_HAS_OHCI |
732 | select USB_ARCH_HAS_EHCI | 731 | select USB_ARCH_HAS_EHCI |
@@ -762,7 +761,6 @@ config NLM_XLR_BOARD | |||
762 | select CEVT_R4K | 761 | select CEVT_R4K |
763 | select CSRC_R4K | 762 | select CSRC_R4K |
764 | select IRQ_CPU | 763 | select IRQ_CPU |
765 | select ARCH_SUPPORTS_MSI | ||
766 | select ZONE_DMA32 if 64BIT | 764 | select ZONE_DMA32 if 64BIT |
767 | select SYNC_R4K | 765 | select SYNC_R4K |
768 | select SYS_HAS_EARLY_PRINTK | 766 | select SYS_HAS_EARLY_PRINTK |
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index fa8e0aa250ca..f194c08bd057 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h | |||
@@ -136,11 +136,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) | |||
136 | return channel ? 15 : 14; | 136 | return channel ? 15 : 14; |
137 | } | 137 | } |
138 | 138 | ||
139 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
140 | /* MSI arch hook for OCTEON */ | ||
141 | #define arch_setup_msi_irqs arch_setup_msi_irqs | ||
142 | #endif | ||
143 | |||
144 | extern char * (*pcibios_plat_setup)(char *str); | 139 | extern char * (*pcibios_plat_setup)(char *str); |
145 | 140 | ||
146 | #ifdef CONFIG_OF | 141 | #ifdef CONFIG_OF |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 3bf72cd2c8fc..183a16509e8f 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -727,7 +727,6 @@ config PCI | |||
727 | default y if !40x && !CPM2 && !8xx && !PPC_83xx \ | 727 | default y if !40x && !CPM2 && !8xx && !PPC_83xx \ |
728 | && !PPC_85xx && !PPC_86xx && !GAMECUBE_COMMON | 728 | && !PPC_85xx && !PPC_86xx && !GAMECUBE_COMMON |
729 | default PCI_QSPAN if !4xx && !CPM2 && 8xx | 729 | default PCI_QSPAN if !4xx && !CPM2 && 8xx |
730 | select ARCH_SUPPORTS_MSI | ||
731 | select GENERIC_PCI_IOMAP | 730 | select GENERIC_PCI_IOMAP |
732 | help | 731 | help |
733 | Find out whether your system includes a PCI bus. PCI is the name of | 732 | Find out whether your system includes a PCI bus. PCI is the name of |
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 6653f2743c4e..95145a15c708 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h | |||
@@ -113,11 +113,6 @@ extern int pci_domain_nr(struct pci_bus *bus); | |||
113 | /* Decide whether to display the domain number in /proc */ | 113 | /* Decide whether to display the domain number in /proc */ |
114 | extern int pci_proc_domain(struct pci_bus *bus); | 114 | extern int pci_proc_domain(struct pci_bus *bus); |
115 | 115 | ||
116 | /* MSI arch hooks */ | ||
117 | #define arch_setup_msi_irqs arch_setup_msi_irqs | ||
118 | #define arch_teardown_msi_irqs arch_teardown_msi_irqs | ||
119 | #define arch_msi_check_device arch_msi_check_device | ||
120 | |||
121 | struct vm_area_struct; | 116 | struct vm_area_struct; |
122 | /* Map a range of PCI memory or I/O space for a device into user space */ | 117 | /* Map a range of PCI memory or I/O space for a device into user space */ |
123 | int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, | 118 | int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 22f75b504f7f..e9982a353b55 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -428,7 +428,6 @@ menuconfig PCI | |||
428 | bool "PCI support" | 428 | bool "PCI support" |
429 | default n | 429 | default n |
430 | depends on 64BIT | 430 | depends on 64BIT |
431 | select ARCH_SUPPORTS_MSI | ||
432 | select PCI_MSI | 431 | select PCI_MSI |
433 | help | 432 | help |
434 | Enable PCI support. | 433 | Enable PCI support. |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 6e577ba0e5da..262b91bb8811 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
@@ -21,10 +21,6 @@ void pci_iounmap(struct pci_dev *, void __iomem *); | |||
21 | int pci_domain_nr(struct pci_bus *); | 21 | int pci_domain_nr(struct pci_bus *); |
22 | int pci_proc_domain(struct pci_bus *); | 22 | int pci_proc_domain(struct pci_bus *); |
23 | 23 | ||
24 | /* MSI arch hooks */ | ||
25 | #define arch_setup_msi_irqs arch_setup_msi_irqs | ||
26 | #define arch_teardown_msi_irqs arch_teardown_msi_irqs | ||
27 | |||
28 | #define ZPCI_BUS_NR 0 /* default bus number */ | 24 | #define ZPCI_BUS_NR 0 /* default bus number */ |
29 | #define ZPCI_DEVFN 0 /* default device number */ | 25 | #define ZPCI_DEVFN 0 /* default device number */ |
30 | 26 | ||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index a00cbd356db5..1570ad2802b3 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -52,7 +52,6 @@ config SPARC32 | |||
52 | 52 | ||
53 | config SPARC64 | 53 | config SPARC64 |
54 | def_bool 64BIT | 54 | def_bool 64BIT |
55 | select ARCH_SUPPORTS_MSI | ||
56 | select HAVE_FUNCTION_TRACER | 55 | select HAVE_FUNCTION_TRACER |
57 | select HAVE_FUNCTION_GRAPH_TRACER | 56 | select HAVE_FUNCTION_GRAPH_TRACER |
58 | select HAVE_FUNCTION_GRAPH_FP_TEST | 57 | select HAVE_FUNCTION_GRAPH_FP_TEST |
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 24565a7ffe6d..74dff908a70f 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -380,7 +380,6 @@ config PCI | |||
380 | select PCI_DOMAINS | 380 | select PCI_DOMAINS |
381 | select GENERIC_PCI_IOMAP | 381 | select GENERIC_PCI_IOMAP |
382 | select TILE_GXIO_TRIO if TILEGX | 382 | select TILE_GXIO_TRIO if TILEGX |
383 | select ARCH_SUPPORTS_MSI if TILEGX | ||
384 | select PCI_MSI if TILEGX | 383 | select PCI_MSI if TILEGX |
385 | ---help--- | 384 | ---help--- |
386 | Enable PCI root complex support, so PCIe endpoint devices can | 385 | Enable PCI root complex support, so PCIe endpoint devices can |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b32ebf92b0ce..5db62ef37804 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -2014,7 +2014,6 @@ menu "Bus options (PCI etc.)" | |||
2014 | config PCI | 2014 | config PCI |
2015 | bool "PCI support" | 2015 | bool "PCI support" |
2016 | default y | 2016 | default y |
2017 | select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC) | ||
2018 | ---help--- | 2017 | ---help--- |
2019 | Find out whether you have a PCI motherboard. PCI is the name of a | 2018 | Find out whether you have a PCI motherboard. PCI is the name of a |
2020 | bus system, i.e. the way the CPU talks to the other stuff inside | 2019 | bus system, i.e. the way the CPU talks to the other stuff inside |
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index d9e9e6c7ed32..7d7443283a9d 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
@@ -100,29 +100,6 @@ static inline void early_quirks(void) { } | |||
100 | extern void pci_iommu_alloc(void); | 100 | extern void pci_iommu_alloc(void); |
101 | 101 | ||
102 | #ifdef CONFIG_PCI_MSI | 102 | #ifdef CONFIG_PCI_MSI |
103 | /* MSI arch specific hooks */ | ||
104 | static inline int x86_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
105 | { | ||
106 | return x86_msi.setup_msi_irqs(dev, nvec, type); | ||
107 | } | ||
108 | |||
109 | static inline void x86_teardown_msi_irqs(struct pci_dev *dev) | ||
110 | { | ||
111 | x86_msi.teardown_msi_irqs(dev); | ||
112 | } | ||
113 | |||
114 | static inline void x86_teardown_msi_irq(unsigned int irq) | ||
115 | { | ||
116 | x86_msi.teardown_msi_irq(irq); | ||
117 | } | ||
118 | static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) | ||
119 | { | ||
120 | x86_msi.restore_msi_irqs(dev, irq); | ||
121 | } | ||
122 | #define arch_setup_msi_irqs x86_setup_msi_irqs | ||
123 | #define arch_teardown_msi_irqs x86_teardown_msi_irqs | ||
124 | #define arch_teardown_msi_irq x86_teardown_msi_irq | ||
125 | #define arch_restore_msi_irqs x86_restore_msi_irqs | ||
126 | /* implemented in arch/x86/kernel/apic/io_apic. */ | 103 | /* implemented in arch/x86/kernel/apic/io_apic. */ |
127 | struct msi_desc; | 104 | struct msi_desc; |
128 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 105 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
@@ -130,16 +107,9 @@ void native_teardown_msi_irq(unsigned int irq); | |||
130 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); | 107 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); |
131 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | 108 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
132 | unsigned int irq_base, unsigned int irq_offset); | 109 | unsigned int irq_base, unsigned int irq_offset); |
133 | /* default to the implementation in drivers/lib/msi.c */ | ||
134 | #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS | ||
135 | #define HAVE_DEFAULT_MSI_RESTORE_IRQS | ||
136 | void default_teardown_msi_irqs(struct pci_dev *dev); | ||
137 | void default_restore_msi_irqs(struct pci_dev *dev, int irq); | ||
138 | #else | 110 | #else |
139 | #define native_setup_msi_irqs NULL | 111 | #define native_setup_msi_irqs NULL |
140 | #define native_teardown_msi_irq NULL | 112 | #define native_teardown_msi_irq NULL |
141 | #define default_teardown_msi_irqs NULL | ||
142 | #define default_restore_msi_irqs NULL | ||
143 | #endif | 113 | #endif |
144 | 114 | ||
145 | #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) | 115 | #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) |
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 45a14dbbddaf..5587f991d111 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
@@ -107,6 +107,8 @@ struct x86_platform_ops x86_platform = { | |||
107 | }; | 107 | }; |
108 | 108 | ||
109 | EXPORT_SYMBOL_GPL(x86_platform); | 109 | EXPORT_SYMBOL_GPL(x86_platform); |
110 | |||
111 | #if defined(CONFIG_PCI_MSI) | ||
110 | struct x86_msi_ops x86_msi = { | 112 | struct x86_msi_ops x86_msi = { |
111 | .setup_msi_irqs = native_setup_msi_irqs, | 113 | .setup_msi_irqs = native_setup_msi_irqs, |
112 | .compose_msi_msg = native_compose_msi_msg, | 114 | .compose_msi_msg = native_compose_msi_msg, |
@@ -116,6 +118,28 @@ struct x86_msi_ops x86_msi = { | |||
116 | .setup_hpet_msi = default_setup_hpet_msi, | 118 | .setup_hpet_msi = default_setup_hpet_msi, |
117 | }; | 119 | }; |
118 | 120 | ||
121 | /* MSI arch specific hooks */ | ||
122 | int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
123 | { | ||
124 | return x86_msi.setup_msi_irqs(dev, nvec, type); | ||
125 | } | ||
126 | |||
127 | void arch_teardown_msi_irqs(struct pci_dev *dev) | ||
128 | { | ||
129 | x86_msi.teardown_msi_irqs(dev); | ||
130 | } | ||
131 | |||
132 | void arch_teardown_msi_irq(unsigned int irq) | ||
133 | { | ||
134 | x86_msi.teardown_msi_irq(irq); | ||
135 | } | ||
136 | |||
137 | void arch_restore_msi_irqs(struct pci_dev *dev, int irq) | ||
138 | { | ||
139 | x86_msi.restore_msi_irqs(dev, irq); | ||
140 | } | ||
141 | #endif | ||
142 | |||
119 | struct x86_io_apic_ops x86_io_apic_ops = { | 143 | struct x86_io_apic_ops x86_io_apic_ops = { |
120 | .init = native_io_apic_init_mappings, | 144 | .init = native_io_apic_init_mappings, |
121 | .read = native_io_apic_read, | 145 | .read = native_io_apic_read, |
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 42c687a820ac..e5ca00893c0c 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c | |||
@@ -89,3 +89,48 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res) | |||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); | 91 | EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); |
92 | |||
93 | #ifdef CONFIG_PCI_MSI | ||
94 | |||
95 | static LIST_HEAD(of_pci_msi_chip_list); | ||
96 | static DEFINE_MUTEX(of_pci_msi_chip_mutex); | ||
97 | |||
98 | int of_pci_msi_chip_add(struct msi_chip *chip) | ||
99 | { | ||
100 | if (!of_property_read_bool(chip->of_node, "msi-controller")) | ||
101 | return -EINVAL; | ||
102 | |||
103 | mutex_lock(&of_pci_msi_chip_mutex); | ||
104 | list_add(&chip->list, &of_pci_msi_chip_list); | ||
105 | mutex_unlock(&of_pci_msi_chip_mutex); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | EXPORT_SYMBOL_GPL(of_pci_msi_chip_add); | ||
110 | |||
111 | void of_pci_msi_chip_remove(struct msi_chip *chip) | ||
112 | { | ||
113 | mutex_lock(&of_pci_msi_chip_mutex); | ||
114 | list_del(&chip->list); | ||
115 | mutex_unlock(&of_pci_msi_chip_mutex); | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(of_pci_msi_chip_remove); | ||
118 | |||
119 | struct msi_chip *of_pci_find_msi_chip_by_node(struct device_node *of_node) | ||
120 | { | ||
121 | struct msi_chip *c; | ||
122 | |||
123 | mutex_lock(&of_pci_msi_chip_mutex); | ||
124 | list_for_each_entry(c, &of_pci_msi_chip_list, list) { | ||
125 | if (c->of_node == of_node) { | ||
126 | mutex_unlock(&of_pci_msi_chip_mutex); | ||
127 | return c; | ||
128 | } | ||
129 | } | ||
130 | mutex_unlock(&of_pci_msi_chip_mutex); | ||
131 | |||
132 | return NULL; | ||
133 | } | ||
134 | EXPORT_SYMBOL_GPL(of_pci_find_msi_chip_by_node); | ||
135 | |||
136 | #endif /* CONFIG_PCI_MSI */ | ||
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 81944fb73116..b6a99f7a9b20 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig | |||
@@ -1,13 +1,9 @@ | |||
1 | # | 1 | # |
2 | # PCI configuration | 2 | # PCI configuration |
3 | # | 3 | # |
4 | config ARCH_SUPPORTS_MSI | ||
5 | bool | ||
6 | |||
7 | config PCI_MSI | 4 | config PCI_MSI |
8 | bool "Message Signaled Interrupts (MSI and MSI-X)" | 5 | bool "Message Signaled Interrupts (MSI and MSI-X)" |
9 | depends on PCI | 6 | depends on PCI |
10 | depends on ARCH_SUPPORTS_MSI | ||
11 | help | 7 | help |
12 | This allows device drivers to enable MSI (Message Signaled | 8 | This allows device drivers to enable MSI (Message Signaled |
13 | Interrupts). Message Signaled Interrupts enable a device to | 9 | Interrupts). Message Signaled Interrupts enable a device to |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index aca7578b05e5..b35f93c232cf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -30,20 +30,60 @@ static int pci_msi_enable = 1; | |||
30 | 30 | ||
31 | /* Arch hooks */ | 31 | /* Arch hooks */ |
32 | 32 | ||
33 | #ifndef arch_msi_check_device | 33 | #if defined(CONFIG_GENERIC_HARDIRQS) |
34 | int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) | 34 | int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) |
35 | { | 35 | { |
36 | struct msi_chip *chip = dev->bus->msi; | ||
37 | int err; | ||
38 | |||
39 | if (!chip || !chip->setup_irq) | ||
40 | return -EINVAL; | ||
41 | |||
42 | err = chip->setup_irq(chip, dev, desc); | ||
43 | if (err < 0) | ||
44 | return err; | ||
45 | |||
46 | irq_set_chip_data(desc->irq, chip); | ||
47 | |||
36 | return 0; | 48 | return 0; |
37 | } | 49 | } |
38 | #endif | ||
39 | 50 | ||
40 | #ifndef arch_setup_msi_irqs | 51 | void __weak arch_teardown_msi_irq(unsigned int irq) |
41 | # define arch_setup_msi_irqs default_setup_msi_irqs | 52 | { |
42 | # define HAVE_DEFAULT_MSI_SETUP_IRQS | 53 | struct msi_chip *chip = irq_get_chip_data(irq); |
43 | #endif | ||
44 | 54 | ||
45 | #ifdef HAVE_DEFAULT_MSI_SETUP_IRQS | 55 | if (!chip || !chip->teardown_irq) |
46 | int default_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 56 | return; |
57 | |||
58 | chip->teardown_irq(chip, irq); | ||
59 | } | ||
60 | |||
61 | int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) | ||
62 | { | ||
63 | struct msi_chip *chip = dev->bus->msi; | ||
64 | |||
65 | if (!chip || !chip->check_device) | ||
66 | return 0; | ||
67 | |||
68 | return chip->check_device(chip, dev, nvec, type); | ||
69 | } | ||
70 | #else | ||
71 | int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | ||
72 | { | ||
73 | return -ENOSYS; | ||
74 | } | ||
75 | |||
76 | void __weak arch_teardown_msi_irq(unsigned int irq) | ||
77 | { | ||
78 | } | ||
79 | |||
80 | int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) | ||
81 | { | ||
82 | return 0; | ||
83 | } | ||
84 | #endif /* CONFIG_GENERIC_HARDIRQS */ | ||
85 | |||
86 | int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
47 | { | 87 | { |
48 | struct msi_desc *entry; | 88 | struct msi_desc *entry; |
49 | int ret; | 89 | int ret; |
@@ -65,14 +105,11 @@ int default_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
65 | 105 | ||
66 | return 0; | 106 | return 0; |
67 | } | 107 | } |
68 | #endif | ||
69 | |||
70 | #ifndef arch_teardown_msi_irqs | ||
71 | # define arch_teardown_msi_irqs default_teardown_msi_irqs | ||
72 | # define HAVE_DEFAULT_MSI_TEARDOWN_IRQS | ||
73 | #endif | ||
74 | 108 | ||
75 | #ifdef HAVE_DEFAULT_MSI_TEARDOWN_IRQS | 109 | /* |
110 | * We have a default implementation available as a separate non-weak | ||
111 | * function, as it is used by the Xen x86 PCI code | ||
112 | */ | ||
76 | void default_teardown_msi_irqs(struct pci_dev *dev) | 113 | void default_teardown_msi_irqs(struct pci_dev *dev) |
77 | { | 114 | { |
78 | struct msi_desc *entry; | 115 | struct msi_desc *entry; |
@@ -89,14 +126,12 @@ void default_teardown_msi_irqs(struct pci_dev *dev) | |||
89 | arch_teardown_msi_irq(entry->irq + i); | 126 | arch_teardown_msi_irq(entry->irq + i); |
90 | } | 127 | } |
91 | } | 128 | } |
92 | #endif | ||
93 | 129 | ||
94 | #ifndef arch_restore_msi_irqs | 130 | void __weak arch_teardown_msi_irqs(struct pci_dev *dev) |
95 | # define arch_restore_msi_irqs default_restore_msi_irqs | 131 | { |
96 | # define HAVE_DEFAULT_MSI_RESTORE_IRQS | 132 | return default_teardown_msi_irqs(dev); |
97 | #endif | 133 | } |
98 | 134 | ||
99 | #ifdef HAVE_DEFAULT_MSI_RESTORE_IRQS | ||
100 | void default_restore_msi_irqs(struct pci_dev *dev, int irq) | 135 | void default_restore_msi_irqs(struct pci_dev *dev, int irq) |
101 | { | 136 | { |
102 | struct msi_desc *entry; | 137 | struct msi_desc *entry; |
@@ -114,7 +149,11 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq) | |||
114 | if (entry) | 149 | if (entry) |
115 | write_msi_msg(irq, &entry->msg); | 150 | write_msi_msg(irq, &entry->msg); |
116 | } | 151 | } |
117 | #endif | 152 | |
153 | void __weak arch_restore_msi_irqs(struct pci_dev *dev, int irq) | ||
154 | { | ||
155 | return default_restore_msi_irqs(dev, irq); | ||
156 | } | ||
118 | 157 | ||
119 | static void msi_set_enable(struct pci_dev *dev, int enable) | 158 | static void msi_set_enable(struct pci_dev *dev, int enable) |
120 | { | 159 | { |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 46ada5c098eb..b8eaa8167849 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -666,6 +666,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, | |||
666 | 666 | ||
667 | child->parent = parent; | 667 | child->parent = parent; |
668 | child->ops = parent->ops; | 668 | child->ops = parent->ops; |
669 | child->msi = parent->msi; | ||
669 | child->sysdata = parent->sysdata; | 670 | child->sysdata = parent->sysdata; |
670 | child->bus_flags = parent->bus_flags; | 671 | child->bus_flags = parent->bus_flags; |
671 | 672 | ||
diff --git a/include/linux/msi.h b/include/linux/msi.h index ee66f3a12fb6..b17ead818aec 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h | |||
@@ -51,12 +51,31 @@ struct msi_desc { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * The arch hook for setup up msi irqs | 54 | * The arch hooks to setup up msi irqs. Those functions are |
55 | * implemented as weak symbols so that they /can/ be overriden by | ||
56 | * architecture specific code if needed. | ||
55 | */ | 57 | */ |
56 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); | 58 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); |
57 | void arch_teardown_msi_irq(unsigned int irq); | 59 | void arch_teardown_msi_irq(unsigned int irq); |
58 | int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 60 | int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
59 | void arch_teardown_msi_irqs(struct pci_dev *dev); | 61 | void arch_teardown_msi_irqs(struct pci_dev *dev); |
60 | int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); | 62 | int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); |
63 | void arch_restore_msi_irqs(struct pci_dev *dev, int irq); | ||
64 | |||
65 | void default_teardown_msi_irqs(struct pci_dev *dev); | ||
66 | void default_restore_msi_irqs(struct pci_dev *dev, int irq); | ||
67 | |||
68 | struct msi_chip { | ||
69 | struct module *owner; | ||
70 | struct device *dev; | ||
71 | struct device_node *of_node; | ||
72 | struct list_head list; | ||
73 | |||
74 | int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev, | ||
75 | struct msi_desc *desc); | ||
76 | void (*teardown_irq)(struct msi_chip *chip, unsigned int irq); | ||
77 | int (*check_device)(struct msi_chip *chip, struct pci_dev *dev, | ||
78 | int nvec, int type); | ||
79 | }; | ||
61 | 80 | ||
62 | #endif /* LINUX_MSI_H */ | 81 | #endif /* LINUX_MSI_H */ |
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 7a04826018c0..fd9c408631a0 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __OF_PCI_H | 2 | #define __OF_PCI_H |
3 | 3 | ||
4 | #include <linux/pci.h> | 4 | #include <linux/pci.h> |
5 | #include <linux/msi.h> | ||
5 | 6 | ||
6 | struct pci_dev; | 7 | struct pci_dev; |
7 | struct of_irq; | 8 | struct of_irq; |
@@ -13,4 +14,15 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, | |||
13 | int of_pci_get_devfn(struct device_node *np); | 14 | int of_pci_get_devfn(struct device_node *np); |
14 | int of_pci_parse_bus_range(struct device_node *node, struct resource *res); | 15 | int of_pci_parse_bus_range(struct device_node *node, struct resource *res); |
15 | 16 | ||
17 | #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) | ||
18 | int of_pci_msi_chip_add(struct msi_chip *chip); | ||
19 | void of_pci_msi_chip_remove(struct msi_chip *chip); | ||
20 | struct msi_chip *of_pci_find_msi_chip_by_node(struct device_node *of_node); | ||
21 | #else | ||
22 | static inline int of_pci_msi_chip_add(struct msi_chip *chip) { return -EINVAL; } | ||
23 | static inline void of_pci_msi_chip_remove(struct msi_chip *chip) { } | ||
24 | static inline struct msi_chip * | ||
25 | of_pci_find_msi_chip_by_node(struct device_node *of_node) { return NULL; } | ||
26 | #endif | ||
27 | |||
16 | #endif | 28 | #endif |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 0fd1f1582fa1..4044e3c00609 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -433,6 +433,7 @@ struct pci_bus { | |||
433 | struct resource busn_res; /* bus numbers routed to this bus */ | 433 | struct resource busn_res; /* bus numbers routed to this bus */ |
434 | 434 | ||
435 | struct pci_ops *ops; /* configuration access functions */ | 435 | struct pci_ops *ops; /* configuration access functions */ |
436 | struct msi_chip *msi; /* MSI controller */ | ||
436 | void *sysdata; /* hook for sys-specific extension */ | 437 | void *sysdata; /* hook for sys-specific extension */ |
437 | struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ | 438 | struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ |
438 | 439 | ||