aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorGanesan Ramalingam <ganesanr@broadcom.com>2012-05-08 08:41:56 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-07-03 12:57:19 -0400
commit249e2a38fbd28ffaadba112290742ada16946900 (patch)
tree2eefd5b939eff790a01f523a5bf6ec00db6bdbea /arch/mips
parentea8e867d9b505b1c852f9932ba75504bc4eebeaa (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.c59
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 */
165static 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
159static int get_irq_vector(const struct pci_dev *dev) 177static 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)
202int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) 223int 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)