Lines Matching +full:msi +full:- +full:x

2  * Copyright (c) 2003-2012 Broadcom Corporation
39 #include <linux/msi.h>
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>
62 /* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */
68 /* get the link MSI vector from irq number */
71 return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK; in nlm_irq_msivec()
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
85 * there are only 32 PIC interrupts for MSI. We split them statically
86 * and use 8 MSI-X vectors per link - this keeps the allocation and
89 * not routed thru PIC, so we can use all 128 MSI-X vectors.
96 /* get the link MSI vector from irq number */
99 return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL; in nlm_irq_msixvec()
109 * Per link MSI and MSI-X information, set as IRQ handler data for
110 * MSI and MSI-X interrupts.
122 * MSI Chip definitions
125 * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa
128 * When a device connected to the link raises a MSI interrupt, we get a
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()
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()
171 link = nlm_irq_msilink(d->irq); in xlp_msi_mask_ack()
172 vec = nlm_irq_msivec(d->irq); in xlp_msi_mask_ack()
175 /* Ack MSI on bridge */ 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
203 * Enable and disable done using standard MSI functions.
211 msixvec = nlm_irq_msixvec(d->irq); in xlp_msix_mask_ack()
216 /* Ack MSI on bridge */ 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
245 * legacy interrupt mode. We will switch them to MSI mode
246 * at the first MSI request.
255 val |= 0x200; /* MSI Interrupt enable */ in xlp_config_link_msi()
278 /* MSI addr */ in xlp_config_link_msi()
282 /* MSI cap for bridge */ in xlp_config_link_msi()
285 val |= 0xb << 16; /* mmc32, msi enable */ in xlp_config_link_msi()
291 * Allocate a MSI vector on a link
302 /* Get MSI data for the 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()
317 nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, in xlp_setup_msi()
321 /* allocate a MSI vec, and tell the bridge about it */ 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()
334 xirq = xirq + msivec; /* msi mapped to global irq space */ in xlp_setup_msi()
344 * Switch a link to MSI-X mode
359 val |= 0x200; /* MSI Interrupt enable */ in xlp_config_link_msix()
365 val |= 0x200; /* MSI Interrupt enable */ in xlp_config_link_msix()
383 /* MSI-X addresses */ in xlp_config_link_msix()
389 /* MSI-X addresses */ in xlp_config_link_msix()
398 * Allocate a MSI-X vector
409 /* Get MSI data for the 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()
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()
460 if (desc->msi_attrib.is_msix) in arch_setup_msi_irq()
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()
484 /* extended space for MSI interrupts */ in xlp_init_node_msi_irqs()
495 nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i + in xlp_init_node_msi_irqs()
498 /* Initialize MSI-X irts to generate one interrupt in xlp_init_node_msi_irqs()
503 nlm_pic_init_irt(nodep->picbase, irt, in xlp_init_node_msi_irqs()
508 /* Initialize MSI-X extended irq space for the link */ in xlp_init_node_msi_irqs()
521 link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; 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()
539 nlm_pic_ack(md->node->picbase, in nlm_dispatch_msi()
542 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); in nlm_dispatch_msi()
551 link = lirq - PIC_PCIE_MSIX_IRQ_BASE; 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()
562 ((1 << XLP_MSIXVEC_PER_LINK) - 1); in nlm_dispatch_msix()
567 status &= status - 1; in nlm_dispatch_msix()