Lines Matching +full:d +full:- +full:link
2 * Copyright (c) 2003-2012 Broadcom Corporation
50 #include <asm/netlogic/mips-extns.h>
52 #include <asm/netlogic/xlp-hal/iomap.h>
53 #include <asm/netlogic/xlp-hal/xlp.h>
54 #include <asm/netlogic/xlp-hal/pic.h>
55 #include <asm/netlogic/xlp-hal/pcibus.h>
56 #include <asm/netlogic/xlp-hal/bridge.h>
63 static inline int nlm_link_msiirq(int link, int msivec) in nlm_link_msiirq() argument
65 return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; in nlm_link_msiirq()
68 /* get the link MSI vector from irq number */
71 return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK; in nlm_irq_msivec()
74 /* get the link from the irq number */
79 return ((irq - NLM_MSI_VEC_BASE) % total_msivec) / in nlm_irq_msilink()
84 * For XLP 8xx/4xx/3xx/2xx, only 32 MSI-X vectors are possible because
86 * and use 8 MSI-X vectors per link - this keeps the allocation and
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.
91 static inline int nlm_link_msixirq(int link, int bit) in nlm_link_msixirq() argument
93 return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; in nlm_link_msixirq()
96 /* get the link MSI vector from irq number */
99 return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL; in nlm_irq_msixvec()
102 /* get the link from MSIX vec */
109 * Per link MSI and MSI-X information, set as IRQ handler data for
110 * MSI and MSI-X interrupts.
124 * On XLP, there is a PIC interrupt associated with each PCIe link on the
126 * per link and 128 overall.
128 * When a device connected to the link raises a MSI interrupt, we get a
129 * link interrupt and we then have to look at PCIE_MSI_STATUS register at
132 static void xlp_msi_enable(struct irq_data *d) in xlp_msi_enable() argument
134 struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); in xlp_msi_enable()
138 vec = nlm_irq_msivec(d->irq); in xlp_msi_enable()
139 spin_lock_irqsave(&md->msi_lock, flags); in xlp_msi_enable()
140 md->msi_enabled_mask |= 1u << vec; in xlp_msi_enable()
142 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, in xlp_msi_enable()
143 md->msi_enabled_mask); in xlp_msi_enable()
145 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); in xlp_msi_enable()
146 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_msi_enable()
149 static void xlp_msi_disable(struct irq_data *d) in xlp_msi_disable() argument
151 struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); in xlp_msi_disable()
155 vec = nlm_irq_msivec(d->irq); in xlp_msi_disable()
156 spin_lock_irqsave(&md->msi_lock, flags); in xlp_msi_disable()
157 md->msi_enabled_mask &= ~(1u << vec); in xlp_msi_disable()
159 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, in xlp_msi_disable()
160 md->msi_enabled_mask); in xlp_msi_disable()
162 nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); in xlp_msi_disable()
163 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_msi_disable()
166 static void xlp_msi_mask_ack(struct irq_data *d) in xlp_msi_mask_ack() argument
168 struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); in xlp_msi_mask_ack()
169 int link, vec; in xlp_msi_mask_ack() local
171 link = nlm_irq_msilink(d->irq); in xlp_msi_mask_ack()
172 vec = nlm_irq_msivec(d->irq); in xlp_msi_mask_ack()
173 xlp_msi_disable(d); in xlp_msi_mask_ack()
177 nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_STATUS, 1u << vec); in xlp_msi_mask_ack()
179 nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); in xlp_msi_mask_ack()
184 .name = "XLP-MSI",
193 * The MSI-X interrupt handling is different from MSI, there are 32 MSI-X
194 * interrupts generated by the PIC and each of these correspond to a MSI-X
195 * vector (0-31) that can be assigned.
197 * We divide the MSI-X vectors to 8 per link and do a per-link allocation
200 * 32 MSI-X vectors are available per link, and the interrupts are not routed
205 static void xlp_msix_mask_ack(struct irq_data *d) in xlp_msix_mask_ack() argument
208 int link, msixvec; in xlp_msix_mask_ack() local
211 msixvec = nlm_irq_msixvec(d->irq); in xlp_msix_mask_ack()
212 link = nlm_irq_msixlink(msixvec); in xlp_msix_mask_ack()
213 pci_msi_mask_irq(d); in xlp_msix_mask_ack()
214 md = irq_data_get_irq_chip_data(d); in xlp_msix_mask_ack()
218 status_reg = PCIE_9XX_MSIX_STATUSX(link); in xlp_msix_mask_ack()
224 nlm_write_reg(md->lnkbase, status_reg, 1u << bit); in xlp_msix_mask_ack()
227 nlm_pic_ack(md->node->picbase, in xlp_msix_mask_ack()
232 .name = "XLP-MSIX",
244 * Setup a PCIe link for MSI. By default, the links are in
291 * Allocate a MSI vector on a link
293 static int xlp_setup_msi(uint64_t lnkbase, int node, int link, in xlp_setup_msi() argument
302 /* Get MSI data for the link */ in xlp_setup_msi()
303 lirq = PIC_PCIE_LINK_MSI_IRQ(link); in xlp_setup_msi()
304 xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); in xlp_setup_msi()
306 msiaddr = MSI_LINK_ADDR(node, link); in xlp_setup_msi()
308 spin_lock_irqsave(&md->msi_lock, flags); in xlp_setup_msi()
309 if (md->msi_alloc_mask == 0) { in xlp_setup_msi()
311 /* switch the link IRQ to MSI range */ in xlp_setup_msi()
313 irt = PIC_9XX_IRT_PCIE_LINK_INDEX(link); in xlp_setup_msi()
315 irt = PIC_IRT_PCIE_LINK_INDEX(link); in xlp_setup_msi()
317 nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, in xlp_setup_msi()
322 msivec = fls(md->msi_alloc_mask); in xlp_setup_msi()
324 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_setup_msi()
325 return -ENOMEM; in xlp_setup_msi()
327 md->msi_alloc_mask |= (1u << msivec); in xlp_setup_msi()
328 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_setup_msi()
344 * Switch a link to MSI-X mode
383 /* MSI-X addresses */ in xlp_config_link_msix()
389 /* MSI-X addresses */ in xlp_config_link_msix()
398 * Allocate a MSI-X vector
400 static int xlp_setup_msix(uint64_t lnkbase, int node, int link, in xlp_setup_msix() argument
409 /* Get MSI data for the link */ in xlp_setup_msix()
410 lirq = PIC_PCIE_MSIX_IRQ(link); in xlp_setup_msix()
411 xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); in xlp_setup_msix()
413 msixaddr = MSIX_LINK_ADDR(node, link); in xlp_setup_msix()
415 spin_lock_irqsave(&md->msi_lock, flags); in xlp_setup_msix()
416 /* switch the PCIe link to MSI-X mode at the first alloc */ in xlp_setup_msix()
417 if (md->msix_alloc_mask == 0) in xlp_setup_msix()
420 /* allocate a MSI-X vec, and tell the bridge about it */ in xlp_setup_msix()
421 t = fls(md->msix_alloc_mask); in xlp_setup_msix()
423 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_setup_msix()
424 return -ENOMEM; in xlp_setup_msix()
426 md->msix_alloc_mask |= (1u << t); in xlp_setup_msix()
427 spin_unlock_irqrestore(&md->msi_lock, flags); in xlp_setup_msix()
448 int node, link, slot; in arch_setup_msi_irq() local
452 dev_err(&dev->dev, "Could not find bridge\n"); in arch_setup_msi_irq()
455 slot = PCI_SLOT(lnkdev->devfn); in arch_setup_msi_irq()
456 link = PCI_FUNC(lnkdev->devfn); in arch_setup_msi_irq()
458 lnkbase = nlm_get_pcie_base(node, link); in arch_setup_msi_irq()
460 if (desc->msi_attrib.is_msix) in arch_setup_msi_irq()
461 return xlp_setup_msix(lnkbase, node, link, desc); in arch_setup_msi_irq()
463 return xlp_setup_msi(lnkbase, node, link, desc); in arch_setup_msi_irq()
466 void __init xlp_init_node_msi_irqs(int node, int link) in xlp_init_node_msi_irqs() argument
472 pr_info("[%d %d] Init node PCI IRT\n", node, link); in xlp_init_node_msi_irqs()
475 /* Alloc an MSI block for the link */ in xlp_init_node_msi_irqs()
477 spin_lock_init(&md->msi_lock); in xlp_init_node_msi_irqs()
478 md->msi_enabled_mask = 0; in xlp_init_node_msi_irqs()
479 md->msi_alloc_mask = 0; in xlp_init_node_msi_irqs()
480 md->msix_alloc_mask = 0; in xlp_init_node_msi_irqs()
481 md->node = nodep; in xlp_init_node_msi_irqs()
482 md->lnkbase = nlm_get_pcie_base(node, link); in xlp_init_node_msi_irqs()
485 irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); in xlp_init_node_msi_irqs()
494 PIC_PCIE_MSIX_IRQ(link) << 1 | 0 << 0); in xlp_init_node_msi_irqs()
495 nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i + in xlp_init_node_msi_irqs()
496 (link * XLP_MSIXVEC_PER_LINK)), val); in xlp_init_node_msi_irqs()
498 /* Initialize MSI-X irts to generate one interrupt in xlp_init_node_msi_irqs()
499 * per link in xlp_init_node_msi_irqs()
501 msixvec = link * XLP_MSIXVEC_PER_LINK + i; in xlp_init_node_msi_irqs()
503 nlm_pic_init_irt(nodep->picbase, irt, in xlp_init_node_msi_irqs()
504 PIC_PCIE_MSIX_IRQ(link), in xlp_init_node_msi_irqs()
508 /* Initialize MSI-X extended irq space for the link */ in xlp_init_node_msi_irqs()
509 irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); in xlp_init_node_msi_irqs()
518 int link, i, irqbase; in nlm_dispatch_msi() local
521 link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; in nlm_dispatch_msi()
522 irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); in nlm_dispatch_msi()
525 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & in nlm_dispatch_msi()
526 md->msi_enabled_mask; in nlm_dispatch_msi()
528 status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & in nlm_dispatch_msi()
529 md->msi_enabled_mask; in nlm_dispatch_msi()
533 status &= status - 1; in nlm_dispatch_msi()
537 ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); in nlm_dispatch_msi()
539 nlm_pic_ack(md->node->picbase, in nlm_dispatch_msi()
540 PIC_9XX_IRT_PCIE_LINK_INDEX(link)); in nlm_dispatch_msi()
542 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); in nlm_dispatch_msi()
548 int link, i, irqbase; in nlm_dispatch_msix() local
551 link = lirq - PIC_PCIE_MSIX_IRQ_BASE; in nlm_dispatch_msix()
552 irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); in nlm_dispatch_msix()
555 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); in nlm_dispatch_msix()
557 status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); in nlm_dispatch_msix()
559 /* narrow it down to the MSI-x vectors for our link */ in nlm_dispatch_msix()
561 status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & in nlm_dispatch_msix()
562 ((1 << XLP_MSIXVEC_PER_LINK) - 1); in nlm_dispatch_msix()
567 status &= status - 1; in nlm_dispatch_msix()
570 ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); in nlm_dispatch_msix()