aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci
diff options
context:
space:
mode:
authorGanesan Ramalingam <ganesanr@broadcom.com>2014-05-09 07:05:49 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-05-30 10:51:02 -0400
commitd66f3f0e10b49df8d0cc0d8eb5bf2ef9863a33cf (patch)
tree39f0d8fa0dacfd9f7ab7794bbdd330160af173c9 /arch/mips/pci
parent1c98398662c9b4e2f03f64344f83dd6cb14e0420 (diff)
MIPS: Add MSI support for XLP9XX
In XLP9XX, the interrupt routing table for MSI-X has been moved to the PCIe controller's config space from PIC. There are also 32 MSI-X interrupts available per link on XLP9XX. Update XLP MSI/MSI-X code to handle this. Signed-off-by: Ganesan Ramalingam <ganesanr@broadcom.com> Signed-off-by: Jayachandran C <jchandra@broadcom.com> Cc: g@linux-mips.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6912/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pci')
-rw-r--r--arch/mips/pci/msi-xlp.c184
1 files changed, 135 insertions, 49 deletions
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c
index afd8405e0188..1ef3ed607f47 100644
--- a/arch/mips/pci/msi-xlp.c
+++ b/arch/mips/pci/msi-xlp.c
@@ -56,8 +56,8 @@
56#include <asm/netlogic/xlp-hal/bridge.h> 56#include <asm/netlogic/xlp-hal/bridge.h>
57 57
58#define XLP_MSIVEC_PER_LINK 32 58#define XLP_MSIVEC_PER_LINK 32
59#define XLP_MSIXVEC_TOTAL 32 59#define XLP_MSIXVEC_TOTAL (cpu_is_xlp9xx() ? 128 : 32)
60#define XLP_MSIXVEC_PER_LINK 8 60#define XLP_MSIXVEC_PER_LINK (cpu_is_xlp9xx() ? 32 : 8)
61 61
62/* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ 62/* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */
63static inline int nlm_link_msiirq(int link, int msivec) 63static inline int nlm_link_msiirq(int link, int msivec)
@@ -65,35 +65,44 @@ static inline int nlm_link_msiirq(int link, int msivec)
65 return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; 65 return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec;
66} 66}
67 67
68/* get the link MSI vector from irq number */
68static inline int nlm_irq_msivec(int irq) 69static inline int nlm_irq_msivec(int irq)
69{ 70{
70 return irq % XLP_MSIVEC_PER_LINK; 71 return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK;
71} 72}
72 73
74/* get the link from the irq number */
73static inline int nlm_irq_msilink(int irq) 75static inline int nlm_irq_msilink(int irq)
74{ 76{
75 return (irq % (XLP_MSIVEC_PER_LINK * PCIE_NLINKS)) / 77 int total_msivec = XLP_MSIVEC_PER_LINK * PCIE_NLINKS;
76 XLP_MSIVEC_PER_LINK; 78
79 return ((irq - NLM_MSI_VEC_BASE) % total_msivec) /
80 XLP_MSIVEC_PER_LINK;
77} 81}
78 82
79/* 83/*
80 * Only 32 MSI-X vectors are possible because there are only 32 PIC 84 * For XLP 8xx/4xx/3xx/2xx, only 32 MSI-X vectors are possible because
81 * interrupts for MSI. We split them statically and use 8 MSI-X vectors 85 * there are only 32 PIC interrupts for MSI. We split them statically
82 * per link - this keeps the allocation and lookup simple. 86 * and use 8 MSI-X vectors per link - this keeps the allocation and
87 * lookup simple.
88 * On XLP 9xx, there are 32 vectors per link, and the interrupts are
89 * not routed thru PIC, so we can use all 128 MSI-X vectors.
83 */ 90 */
84static inline int nlm_link_msixirq(int link, int bit) 91static inline int nlm_link_msixirq(int link, int bit)
85{ 92{
86 return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; 93 return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit;
87} 94}
88 95
96/* get the link MSI vector from irq number */
89static inline int nlm_irq_msixvec(int irq) 97static inline int nlm_irq_msixvec(int irq)
90{ 98{
91 return irq % XLP_MSIXVEC_TOTAL; /* works when given xirq */ 99 return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL;
92} 100}
93 101
94static inline int nlm_irq_msixlink(int irq) 102/* get the link from MSIX vec */
103static inline int nlm_irq_msixlink(int msixvec)
95{ 104{
96 return nlm_irq_msixvec(irq) / XLP_MSIXVEC_PER_LINK; 105 return msixvec / XLP_MSIXVEC_PER_LINK;
97} 106}
98 107
99/* 108/*
@@ -129,7 +138,11 @@ static void xlp_msi_enable(struct irq_data *d)
129 vec = nlm_irq_msivec(d->irq); 138 vec = nlm_irq_msivec(d->irq);
130 spin_lock_irqsave(&md->msi_lock, flags); 139 spin_lock_irqsave(&md->msi_lock, flags);
131 md->msi_enabled_mask |= 1u << vec; 140 md->msi_enabled_mask |= 1u << vec;
132 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); 141 if (cpu_is_xlp9xx())
142 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN,
143 md->msi_enabled_mask);
144 else
145 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask);
133 spin_unlock_irqrestore(&md->msi_lock, flags); 146 spin_unlock_irqrestore(&md->msi_lock, flags);
134} 147}
135 148
@@ -142,7 +155,11 @@ static void xlp_msi_disable(struct irq_data *d)
142 vec = nlm_irq_msivec(d->irq); 155 vec = nlm_irq_msivec(d->irq);
143 spin_lock_irqsave(&md->msi_lock, flags); 156 spin_lock_irqsave(&md->msi_lock, flags);
144 md->msi_enabled_mask &= ~(1u << vec); 157 md->msi_enabled_mask &= ~(1u << vec);
145 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); 158 if (cpu_is_xlp9xx())
159 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN,
160 md->msi_enabled_mask);
161 else
162 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask);
146 spin_unlock_irqrestore(&md->msi_lock, flags); 163 spin_unlock_irqrestore(&md->msi_lock, flags);
147} 164}
148 165
@@ -156,11 +173,18 @@ static void xlp_msi_mask_ack(struct irq_data *d)
156 xlp_msi_disable(d); 173 xlp_msi_disable(d);
157 174
158 /* Ack MSI on bridge */ 175 /* Ack MSI on bridge */
159 nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); 176 if (cpu_is_xlp9xx())
177 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_STATUS, 1u << vec);
178 else
179 nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec);
160 180
161 /* Ack at eirr and PIC */ 181 /* Ack at eirr and PIC */
162 ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); 182 ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link));
163 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); 183 if (cpu_is_xlp9xx())
184 nlm_pic_ack(md->node->picbase,
185 PIC_9XX_IRT_PCIE_LINK_INDEX(link));
186 else
187 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link));
164} 188}
165 189
166static struct irq_chip xlp_msi_chip = { 190static struct irq_chip xlp_msi_chip = {
@@ -172,30 +196,45 @@ static struct irq_chip xlp_msi_chip = {
172}; 196};
173 197
174/* 198/*
175 * The MSI-X interrupt handling is different from MSI, there are 32 199 * XLP8XX/4XX/3XX/2XX:
176 * MSI-X interrupts generated by the PIC and each of these correspond 200 * The MSI-X interrupt handling is different from MSI, there are 32 MSI-X
177 * to a MSI-X vector (0-31) that can be assigned. 201 * interrupts generated by the PIC and each of these correspond to a MSI-X
202 * vector (0-31) that can be assigned.
178 * 203 *
179 * We divide the MSI-X vectors to 8 per link and do a per-link 204 * We divide the MSI-X vectors to 8 per link and do a per-link allocation
180 * allocation 205 *
206 * XLP9XX:
207 * 32 MSI-X vectors are available per link, and the interrupts are not routed
208 * thru the PIC. PIC ack not needed.
181 * 209 *
182 * Enable and disable done using standard MSI functions. 210 * Enable and disable done using standard MSI functions.
183 */ 211 */
184static void xlp_msix_mask_ack(struct irq_data *d) 212static void xlp_msix_mask_ack(struct irq_data *d)
185{ 213{
186 struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); 214 struct xlp_msi_data *md;
187 int link, msixvec; 215 int link, msixvec;
216 uint32_t status_reg, bit;
188 217
189 msixvec = nlm_irq_msixvec(d->irq); 218 msixvec = nlm_irq_msixvec(d->irq);
190 link = nlm_irq_msixlink(d->irq); 219 link = nlm_irq_msixlink(msixvec);
191 mask_msi_irq(d); 220 mask_msi_irq(d);
221 md = irq_data_get_irq_handler_data(d);
192 222
193 /* Ack MSI on bridge */ 223 /* Ack MSI on bridge */
194 nlm_write_reg(md->lnkbase, PCIE_MSIX_STATUS, 1u << msixvec); 224 if (cpu_is_xlp9xx()) {
225 status_reg = PCIE_9XX_MSIX_STATUSX(link);
226 bit = msixvec % XLP_MSIXVEC_PER_LINK;
227 } else {
228 status_reg = PCIE_MSIX_STATUS;
229 bit = msixvec;
230 }
231 nlm_write_reg(md->lnkbase, status_reg, 1u << bit);
195 232
196 /* Ack at eirr and PIC */ 233 /* Ack at eirr and PIC */
197 ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); 234 ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link));
198 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_MSIX_INDEX(msixvec)); 235 if (!cpu_is_xlp9xx())
236 nlm_pic_ack(md->node->picbase,
237 PIC_IRT_PCIE_MSIX_INDEX(msixvec));
199} 238}
200 239
201static struct irq_chip xlp_msix_chip = { 240static struct irq_chip xlp_msix_chip = {
@@ -225,10 +264,18 @@ static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr)
225{ 264{
226 u32 val; 265 u32 val;
227 266
228 val = nlm_read_reg(lnkbase, PCIE_INT_EN0); 267 if (cpu_is_xlp9xx()) {
229 if ((val & 0x200) == 0) { 268 val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0);
230 val |= 0x200; /* MSI Interrupt enable */ 269 if ((val & 0x200) == 0) {
231 nlm_write_reg(lnkbase, PCIE_INT_EN0, val); 270 val |= 0x200; /* MSI Interrupt enable */
271 nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val);
272 }
273 } else {
274 val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
275 if ((val & 0x200) == 0) {
276 val |= 0x200;
277 nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
278 }
232 } 279 }
233 280
234 val = nlm_read_reg(lnkbase, 0x1); /* CMD */ 281 val = nlm_read_reg(lnkbase, 0x1); /* CMD */
@@ -275,9 +322,12 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link,
275 322
276 spin_lock_irqsave(&md->msi_lock, flags); 323 spin_lock_irqsave(&md->msi_lock, flags);
277 if (md->msi_alloc_mask == 0) { 324 if (md->msi_alloc_mask == 0) {
278 /* switch the link IRQ to MSI range */
279 xlp_config_link_msi(lnkbase, lirq, msiaddr); 325 xlp_config_link_msi(lnkbase, lirq, msiaddr);
280 irt = PIC_IRT_PCIE_LINK_INDEX(link); 326 /* switch the link IRQ to MSI range */
327 if (cpu_is_xlp9xx())
328 irt = PIC_9XX_IRT_PCIE_LINK_INDEX(link);
329 else
330 irt = PIC_IRT_PCIE_LINK_INDEX(link);
281 nlm_setup_pic_irq(node, lirq, lirq, irt); 331 nlm_setup_pic_irq(node, lirq, lirq, irt);
282 nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, 332 nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq,
283 node * nlm_threads_per_node(), 1 /*en */); 333 node * nlm_threads_per_node(), 1 /*en */);
@@ -319,10 +369,19 @@ static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr)
319 val |= 0x80000000U; 369 val |= 0x80000000U;
320 nlm_write_reg(lnkbase, 0x2C, val); 370 nlm_write_reg(lnkbase, 0x2C, val);
321 } 371 }
322 val = nlm_read_reg(lnkbase, PCIE_INT_EN0); 372
323 if ((val & 0x200) == 0) { 373 if (cpu_is_xlp9xx()) {
324 val |= 0x200; /* MSI Interrupt enable */ 374 val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0);
325 nlm_write_reg(lnkbase, PCIE_INT_EN0, val); 375 if ((val & 0x200) == 0) {
376 val |= 0x200; /* MSI Interrupt enable */
377 nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val);
378 }
379 } else {
380 val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
381 if ((val & 0x200) == 0) {
382 val |= 0x200; /* MSI Interrupt enable */
383 nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
384 }
326 } 385 }
327 386
328 val = nlm_read_reg(lnkbase, 0x1); /* CMD */ 387 val = nlm_read_reg(lnkbase, 0x1); /* CMD */
@@ -337,10 +396,19 @@ static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr)
337 val |= (1 << 8) | lirq; 396 val |= (1 << 8) | lirq;
338 nlm_write_pci_reg(lnkbase, 0xf, val); 397 nlm_write_pci_reg(lnkbase, 0xf, val);
339 398
340 /* MSI-X addresses */ 399 if (cpu_is_xlp9xx()) {
341 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8); 400 /* MSI-X addresses */
342 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, 401 nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_BASE,
343 (msixaddr + MSI_ADDR_SZ) >> 8); 402 msixaddr >> 8);
403 nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT,
404 (msixaddr + MSI_ADDR_SZ) >> 8);
405 } else {
406 /* MSI-X addresses */
407 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE,
408 msixaddr >> 8);
409 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT,
410 (msixaddr + MSI_ADDR_SZ) >> 8);
411 }
344} 412}
345 413
346/* 414/*
@@ -377,6 +445,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link,
377 445
378 xirq += t; 446 xirq += t;
379 msixvec = nlm_irq_msixvec(xirq); 447 msixvec = nlm_irq_msixvec(xirq);
448
380 msg.address_hi = msixaddr >> 32; 449 msg.address_hi = msixaddr >> 32;
381 msg.address_lo = msixaddr & 0xffffffff; 450 msg.address_lo = msixaddr & 0xffffffff;
382 msg.data = 0xc00 | msixvec; 451 msg.data = 0xc00 | msixvec;
@@ -417,7 +486,7 @@ void __init xlp_init_node_msi_irqs(int node, int link)
417{ 486{
418 struct nlm_soc_info *nodep; 487 struct nlm_soc_info *nodep;
419 struct xlp_msi_data *md; 488 struct xlp_msi_data *md;
420 int irq, i, irt, msixvec; 489 int irq, i, irt, msixvec, val;
421 490
422 pr_info("[%d %d] Init node PCI IRT\n", node, link); 491 pr_info("[%d %d] Init node PCI IRT\n", node, link);
423 nodep = nlm_get_node(node); 492 nodep = nlm_get_node(node);
@@ -438,19 +507,28 @@ void __init xlp_init_node_msi_irqs(int node, int link)
438 irq_set_handler_data(i, md); 507 irq_set_handler_data(i, md);
439 } 508 }
440 509
441 for (i = 0; i < XLP_MSIXVEC_PER_LINK; i++) { 510 for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) {
442 /* Initialize MSI-X irts to generate one interrupt per link */ 511 if (cpu_is_xlp9xx()) {
443 msixvec = link * XLP_MSIXVEC_PER_LINK + i; 512 val = ((node * nlm_threads_per_node()) << 7 |
444 irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); 513 PIC_PCIE_MSIX_IRQ(link) << 1 | 0 << 0);
445 nlm_pic_init_irt(nodep->picbase, irt, PIC_PCIE_MSIX_IRQ(link), 514 nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i +
446 node * nlm_threads_per_node(), 1 /* enable */); 515 (link * XLP_MSIXVEC_PER_LINK)), val);
516 } else {
517 /* Initialize MSI-X irts to generate one interrupt
518 * per link
519 */
520 msixvec = link * XLP_MSIXVEC_PER_LINK + i;
521 irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec);
522 nlm_pic_init_irt(nodep->picbase, irt,
523 PIC_PCIE_MSIX_IRQ(link),
524 node * nlm_threads_per_node(), 1);
525 }
447 526
448 /* Initialize MSI-X extended irq space for the link */ 527 /* Initialize MSI-X extended irq space for the link */
449 irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); 528 irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i));
450 irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); 529 irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq);
451 irq_set_handler_data(irq, md); 530 irq_set_handler_data(irq, md);
452 } 531 }
453
454} 532}
455 533
456void nlm_dispatch_msi(int node, int lirq) 534void nlm_dispatch_msi(int node, int lirq)
@@ -462,7 +540,11 @@ void nlm_dispatch_msi(int node, int lirq)
462 link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; 540 link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE;
463 irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); 541 irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
464 md = irq_get_handler_data(irqbase); 542 md = irq_get_handler_data(irqbase);
465 status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & 543 if (cpu_is_xlp9xx())
544 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) &
545 md->msi_enabled_mask;
546 else
547 status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) &
466 md->msi_enabled_mask; 548 md->msi_enabled_mask;
467 while (status) { 549 while (status) {
468 i = __ffs(status); 550 i = __ffs(status);
@@ -480,10 +562,14 @@ void nlm_dispatch_msix(int node, int lirq)
480 link = lirq - PIC_PCIE_MSIX_IRQ_BASE; 562 link = lirq - PIC_PCIE_MSIX_IRQ_BASE;
481 irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); 563 irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0));
482 md = irq_get_handler_data(irqbase); 564 md = irq_get_handler_data(irqbase);
483 status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); 565 if (cpu_is_xlp9xx())
566 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link));
567 else
568 status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS);
484 569
485 /* narrow it down to the MSI-x vectors for our link */ 570 /* narrow it down to the MSI-x vectors for our link */
486 status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & 571 if (!cpu_is_xlp9xx())
572 status = (status >> (link * XLP_MSIXVEC_PER_LINK)) &
487 ((1 << XLP_MSIXVEC_PER_LINK) - 1); 573 ((1 << XLP_MSIXVEC_PER_LINK) - 1);
488 574
489 while (status) { 575 while (status) {