diff options
author | Olof Johansson <olof@lixom.net> | 2013-08-29 13:06:50 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-08-29 13:06:50 -0400 |
commit | 158a71f83800f07c0da0f0159d2670bdf4bdd852 (patch) | |
tree | d71c9a520d7a968cf221c4a65fe67003de3e1f5a /drivers | |
parent | aaf75e454cc5e16e7f24bd87590b2d882ddb1671 (diff) | |
parent | 6a4324ebf5cf412d55fd1ea259d4dd29fb8f90e8 (diff) |
Merge tag 'msi-3.12' of git://git.infradead.org/linux-mvebu into next/drivers
From Jason Cooper:
mvebu msi pci changes for v3.12
- introduce support for MSI on PCI
- fix s390 build breakage when !HAVE_GENERIC_HARDIRQS
NOTE: This branch is a dependency for changes going though arm-soc from both
Thomas Petazzoni and Thierry Reding.
* tag 'msi-3.12' of git://git.infradead.org/linux-mvebu:
PCI: msi: add default MSI operations for !HAVE_GENERIC_HARDIRQS platforms
ARM: pci: add ->add_bus() and ->remove_bus() hooks to hw_pci
of: pci: add registry of MSI chips
PCI: Introduce new MSI chip infrastructure
PCI: remove ARCH_SUPPORTS_MSI kconfig option
PCI: use weak functions for MSI arch-specific functions
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers')
-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 |
4 files changed, 108 insertions, 27 deletions
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 | ||