diff options
author | Ganesan Ramalingam <ganesanr@broadcom.com> | 2012-05-08 08:41:56 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-07-03 12:57:19 -0400 |
commit | 249e2a38fbd28ffaadba112290742ada16946900 (patch) | |
tree | 2eefd5b939eff790a01f523a5bf6ec00db6bdbea /arch/mips | |
parent | ea8e867d9b505b1c852f9932ba75504bc4eebeaa (diff) |
MIPS: Netlogic: MSI enable fix for XLS
MSI interrupts do not work on XLS after commit a776c49
( "PCI: msi: Disable msi interrupts when we initialize a pci device" )
because the change disables MSI interrupts on the XLS PCIe bridges
during the PCI enumeration.
Fix this by enabling MSI interrupts on the bridge in the
arch_setup_msi_irq() function. A new function xls_get_pcie_link()
has been introduced to get the PCI device corresponding to the
top level PCIe bridge on which MSI has to be enabled.
Also, update get_irq_vector() to use the new xls_get_pcie_link()
function and PCI_SLOT() macro for determining the IRQ of PCI devices.
Signed-off-by: Ganesan Ramalingam <ganesanr@broadcom.com>
Signed-off-by: Jayachandran C <jayachandranc@netlogicmicro.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3753/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/pci/pci-xlr.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 50ff4dc28b4f..172af1cd5867 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/irq.h> | 41 | #include <linux/irq.h> |
42 | #include <linux/irqdesc.h> | 42 | #include <linux/irqdesc.h> |
43 | #include <linux/console.h> | 43 | #include <linux/console.h> |
44 | #include <linux/pci_regs.h> | ||
44 | 45 | ||
45 | #include <asm/io.h> | 46 | #include <asm/io.h> |
46 | 47 | ||
@@ -156,35 +157,55 @@ struct pci_controller nlm_pci_controller = { | |||
156 | .io_offset = 0x00000000UL, | 157 | .io_offset = 0x00000000UL, |
157 | }; | 158 | }; |
158 | 159 | ||
160 | /* | ||
161 | * The top level PCIe links on the XLS PCIe controller appear as | ||
162 | * bridges. Given a device, this function finds which link it is | ||
163 | * on. | ||
164 | */ | ||
165 | static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev) | ||
166 | { | ||
167 | struct pci_bus *bus, *p; | ||
168 | |||
169 | /* Find the bridge on bus 0 */ | ||
170 | bus = dev->bus; | ||
171 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
172 | bus = p; | ||
173 | |||
174 | return p ? bus->self : NULL; | ||
175 | } | ||
176 | |||
159 | static int get_irq_vector(const struct pci_dev *dev) | 177 | static int get_irq_vector(const struct pci_dev *dev) |
160 | { | 178 | { |
179 | struct pci_dev *lnk; | ||
180 | |||
161 | if (!nlm_chip_is_xls()) | 181 | if (!nlm_chip_is_xls()) |
162 | return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ | 182 | return PIC_PCIX_IRQ; /* for XLR just one IRQ */ |
163 | 183 | ||
164 | /* | 184 | /* |
165 | * For XLS PCIe, there is an IRQ per Link, find out which | 185 | * For XLS PCIe, there is an IRQ per Link, find out which |
166 | * link the device is on to assign interrupts | 186 | * link the device is on to assign interrupts |
167 | */ | 187 | */ |
168 | if (dev->bus->self == NULL) | 188 | lnk = xls_get_pcie_link(dev); |
189 | if (lnk == NULL) | ||
169 | return 0; | 190 | return 0; |
170 | 191 | ||
171 | switch (dev->bus->self->devfn) { | 192 | switch (PCI_SLOT(lnk->devfn)) { |
172 | case 0x0: | 193 | case 0: |
173 | return PIC_PCIE_LINK0_IRQ; | 194 | return PIC_PCIE_LINK0_IRQ; |
174 | case 0x8: | 195 | case 1: |
175 | return PIC_PCIE_LINK1_IRQ; | 196 | return PIC_PCIE_LINK1_IRQ; |
176 | case 0x10: | 197 | case 2: |
177 | if (nlm_chip_is_xls_b()) | 198 | if (nlm_chip_is_xls_b()) |
178 | return PIC_PCIE_XLSB0_LINK2_IRQ; | 199 | return PIC_PCIE_XLSB0_LINK2_IRQ; |
179 | else | 200 | else |
180 | return PIC_PCIE_LINK2_IRQ; | 201 | return PIC_PCIE_LINK2_IRQ; |
181 | case 0x18: | 202 | case 3: |
182 | if (nlm_chip_is_xls_b()) | 203 | if (nlm_chip_is_xls_b()) |
183 | return PIC_PCIE_XLSB0_LINK3_IRQ; | 204 | return PIC_PCIE_XLSB0_LINK3_IRQ; |
184 | else | 205 | else |
185 | return PIC_PCIE_LINK3_IRQ; | 206 | return PIC_PCIE_LINK3_IRQ; |
186 | } | 207 | } |
187 | WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); | 208 | WARN(1, "Unexpected devfn %d\n", lnk->devfn); |
188 | return 0; | 209 | return 0; |
189 | } | 210 | } |
190 | 211 | ||
@@ -202,7 +223,27 @@ void arch_teardown_msi_irq(unsigned int irq) | |||
202 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | 223 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) |
203 | { | 224 | { |
204 | struct msi_msg msg; | 225 | struct msi_msg msg; |
226 | struct pci_dev *lnk; | ||
205 | int irq, ret; | 227 | int irq, ret; |
228 | u16 val; | ||
229 | |||
230 | /* MSI not supported on XLR */ | ||
231 | if (!nlm_chip_is_xls()) | ||
232 | return 1; | ||
233 | |||
234 | /* | ||
235 | * Enable MSI on the XLS PCIe controller bridge which was disabled | ||
236 | * at enumeration, the bridge MSI capability is at 0x50 | ||
237 | */ | ||
238 | lnk = xls_get_pcie_link(dev); | ||
239 | if (lnk == NULL) | ||
240 | return 1; | ||
241 | |||
242 | pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val); | ||
243 | if ((val & PCI_MSI_FLAGS_ENABLE) == 0) { | ||
244 | val |= PCI_MSI_FLAGS_ENABLE; | ||
245 | pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val); | ||
246 | } | ||
206 | 247 | ||
207 | irq = get_irq_vector(dev); | 248 | irq = get_irq_vector(dev); |
208 | if (irq <= 0) | 249 | if (irq <= 0) |