root/arch/mips/pci/msi-xlp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nlm_link_msiirq
  2. nlm_irq_msivec
  3. nlm_irq_msilink
  4. nlm_link_msixirq
  5. nlm_irq_msixvec
  6. nlm_irq_msixlink
  7. xlp_msi_enable
  8. xlp_msi_disable
  9. xlp_msi_mask_ack
  10. xlp_msix_mask_ack
  11. arch_teardown_msi_irq
  12. xlp_config_link_msi
  13. xlp_setup_msi
  14. xlp_config_link_msix
  15. xlp_setup_msix
  16. arch_setup_msi_irq
  17. xlp_init_node_msi_irqs
  18. nlm_dispatch_msi
  19. nlm_dispatch_msix

   1 /*
   2  * Copyright (c) 2003-2012 Broadcom Corporation
   3  * All Rights Reserved
   4  *
   5  * This software is available to you under a choice of one of two
   6  * licenses.  You may choose to be licensed under the terms of the GNU
   7  * General Public License (GPL) Version 2, available from the file
   8  * COPYING in the main directory of this source tree, or the Broadcom
   9  * license below:
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions and the following disclaimer.
  17  * 2. Redistributions in binary form must reproduce the above copyright
  18  *    notice, this list of conditions and the following disclaimer in
  19  *    the documentation and/or other materials provided with the
  20  *    distribution.
  21  *
  22  * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
  23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25  * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
  26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33  */
  34 
  35 #include <linux/types.h>
  36 #include <linux/pci.h>
  37 #include <linux/kernel.h>
  38 #include <linux/init.h>
  39 #include <linux/msi.h>
  40 #include <linux/mm.h>
  41 #include <linux/irq.h>
  42 #include <linux/irqdesc.h>
  43 #include <linux/console.h>
  44 
  45 #include <asm/io.h>
  46 
  47 #include <asm/netlogic/interrupt.h>
  48 #include <asm/netlogic/haldefs.h>
  49 #include <asm/netlogic/common.h>
  50 #include <asm/netlogic/mips-extns.h>
  51 
  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>
  57 
  58 #define XLP_MSIVEC_PER_LINK     32
  59 #define XLP_MSIXVEC_TOTAL       (cpu_is_xlp9xx() ? 128 : 32)
  60 #define XLP_MSIXVEC_PER_LINK    (cpu_is_xlp9xx() ? 32 : 8)
  61 
  62 /* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */
  63 static inline int nlm_link_msiirq(int link, int msivec)
  64 {
  65         return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec;
  66 }
  67 
  68 /* get the link MSI vector from irq number */
  69 static inline int nlm_irq_msivec(int irq)
  70 {
  71         return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK;
  72 }
  73 
  74 /* get the link from the irq number */
  75 static inline int nlm_irq_msilink(int irq)
  76 {
  77         int total_msivec = XLP_MSIVEC_PER_LINK * PCIE_NLINKS;
  78 
  79         return ((irq - NLM_MSI_VEC_BASE) % total_msivec) /
  80                 XLP_MSIVEC_PER_LINK;
  81 }
  82 
  83 /*
  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
  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.
  90  */
  91 static inline int nlm_link_msixirq(int link, int bit)
  92 {
  93         return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit;
  94 }
  95 
  96 /* get the link MSI vector from irq number */
  97 static inline int nlm_irq_msixvec(int irq)
  98 {
  99         return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL;
 100 }
 101 
 102 /* get the link from MSIX vec */
 103 static inline int nlm_irq_msixlink(int msixvec)
 104 {
 105         return msixvec / XLP_MSIXVEC_PER_LINK;
 106 }
 107 
 108 /*
 109  * Per link MSI and MSI-X information, set as IRQ handler data for
 110  * MSI and MSI-X interrupts.
 111  */
 112 struct xlp_msi_data {
 113         struct nlm_soc_info *node;
 114         uint64_t        lnkbase;
 115         uint32_t        msi_enabled_mask;
 116         uint32_t        msi_alloc_mask;
 117         uint32_t        msix_alloc_mask;
 118         spinlock_t      msi_lock;
 119 };
 120 
 121 /*
 122  * MSI Chip definitions
 123  *
 124  * On XLP, there is a PIC interrupt associated with each PCIe link on the
 125  * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa
 126  * per link and 128 overall.
 127  *
 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
 130  * the bridge to map it to the IRQ
 131  */
 132 static void xlp_msi_enable(struct irq_data *d)
 133 {
 134         struct xlp_msi_data *md = irq_data_get_irq_chip_data(d);
 135         unsigned long flags;
 136         int vec;
 137 
 138         vec = nlm_irq_msivec(d->irq);
 139         spin_lock_irqsave(&md->msi_lock, flags);
 140         md->msi_enabled_mask |= 1u << vec;
 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);
 146         spin_unlock_irqrestore(&md->msi_lock, flags);
 147 }
 148 
 149 static void xlp_msi_disable(struct irq_data *d)
 150 {
 151         struct xlp_msi_data *md = irq_data_get_irq_chip_data(d);
 152         unsigned long flags;
 153         int vec;
 154 
 155         vec = nlm_irq_msivec(d->irq);
 156         spin_lock_irqsave(&md->msi_lock, flags);
 157         md->msi_enabled_mask &= ~(1u << vec);
 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);
 163         spin_unlock_irqrestore(&md->msi_lock, flags);
 164 }
 165 
 166 static void xlp_msi_mask_ack(struct irq_data *d)
 167 {
 168         struct xlp_msi_data *md = irq_data_get_irq_chip_data(d);
 169         int link, vec;
 170 
 171         link = nlm_irq_msilink(d->irq);
 172         vec = nlm_irq_msivec(d->irq);
 173         xlp_msi_disable(d);
 174 
 175         /* Ack MSI on bridge */
 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);
 180 
 181 }
 182 
 183 static struct irq_chip xlp_msi_chip = {
 184         .name           = "XLP-MSI",
 185         .irq_enable     = xlp_msi_enable,
 186         .irq_disable    = xlp_msi_disable,
 187         .irq_mask_ack   = xlp_msi_mask_ack,
 188         .irq_unmask     = xlp_msi_enable,
 189 };
 190 
 191 /*
 192  * XLP8XX/4XX/3XX/2XX:
 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.
 196  *
 197  * We divide the MSI-X vectors to 8 per link and do a per-link allocation
 198  *
 199  * XLP9XX:
 200  * 32 MSI-X vectors are available per link, and the interrupts are not routed
 201  * thru the PIC. PIC ack not needed.
 202  *
 203  * Enable and disable done using standard MSI functions.
 204  */
 205 static void xlp_msix_mask_ack(struct irq_data *d)
 206 {
 207         struct xlp_msi_data *md;
 208         int link, msixvec;
 209         uint32_t status_reg, bit;
 210 
 211         msixvec = nlm_irq_msixvec(d->irq);
 212         link = nlm_irq_msixlink(msixvec);
 213         pci_msi_mask_irq(d);
 214         md = irq_data_get_irq_chip_data(d);
 215 
 216         /* Ack MSI on bridge */
 217         if (cpu_is_xlp9xx()) {
 218                 status_reg = PCIE_9XX_MSIX_STATUSX(link);
 219                 bit = msixvec % XLP_MSIXVEC_PER_LINK;
 220         } else {
 221                 status_reg = PCIE_MSIX_STATUS;
 222                 bit = msixvec;
 223         }
 224         nlm_write_reg(md->lnkbase, status_reg, 1u << bit);
 225 
 226         if (!cpu_is_xlp9xx())
 227                 nlm_pic_ack(md->node->picbase,
 228                                 PIC_IRT_PCIE_MSIX_INDEX(msixvec));
 229 }
 230 
 231 static struct irq_chip xlp_msix_chip = {
 232         .name           = "XLP-MSIX",
 233         .irq_enable     = pci_msi_unmask_irq,
 234         .irq_disable    = pci_msi_mask_irq,
 235         .irq_mask_ack   = xlp_msix_mask_ack,
 236         .irq_unmask     = pci_msi_unmask_irq,
 237 };
 238 
 239 void arch_teardown_msi_irq(unsigned int irq)
 240 {
 241 }
 242 
 243 /*
 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.
 247  */
 248 static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr)
 249 {
 250         u32 val;
 251 
 252         if (cpu_is_xlp9xx()) {
 253                 val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0);
 254                 if ((val & 0x200) == 0) {
 255                         val |= 0x200;           /* MSI Interrupt enable */
 256                         nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val);
 257                 }
 258         } else {
 259                 val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
 260                 if ((val & 0x200) == 0) {
 261                         val |= 0x200;
 262                         nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
 263                 }
 264         }
 265 
 266         val = nlm_read_reg(lnkbase, 0x1);       /* CMD */
 267         if ((val & 0x0400) == 0) {
 268                 val |= 0x0400;
 269                 nlm_write_reg(lnkbase, 0x1, val);
 270         }
 271 
 272         /* Update IRQ in the PCI irq reg */
 273         val = nlm_read_pci_reg(lnkbase, 0xf);
 274         val &= ~0x1fu;
 275         val |= (1 << 8) | lirq;
 276         nlm_write_pci_reg(lnkbase, 0xf, val);
 277 
 278         /* MSI addr */
 279         nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32);
 280         nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff);
 281 
 282         /* MSI cap for bridge */
 283         val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP);
 284         if ((val & (1 << 16)) == 0) {
 285                 val |= 0xb << 16;               /* mmc32, msi enable */
 286                 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val);
 287         }
 288 }
 289 
 290 /*
 291  * Allocate a MSI vector on a link
 292  */
 293 static int xlp_setup_msi(uint64_t lnkbase, int node, int link,
 294         struct msi_desc *desc)
 295 {
 296         struct xlp_msi_data *md;
 297         struct msi_msg msg;
 298         unsigned long flags;
 299         int msivec, irt, lirq, xirq, ret;
 300         uint64_t msiaddr;
 301 
 302         /* Get MSI data for the link */
 303         lirq = PIC_PCIE_LINK_MSI_IRQ(link);
 304         xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
 305         md = irq_get_chip_data(xirq);
 306         msiaddr = MSI_LINK_ADDR(node, link);
 307 
 308         spin_lock_irqsave(&md->msi_lock, flags);
 309         if (md->msi_alloc_mask == 0) {
 310                 xlp_config_link_msi(lnkbase, lirq, msiaddr);
 311                 /* switch the link IRQ to MSI range */
 312                 if (cpu_is_xlp9xx())
 313                         irt = PIC_9XX_IRT_PCIE_LINK_INDEX(link);
 314                 else
 315                         irt = PIC_IRT_PCIE_LINK_INDEX(link);
 316                 nlm_setup_pic_irq(node, lirq, lirq, irt);
 317                 nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq,
 318                                  node * nlm_threads_per_node(), 1 /*en */);
 319         }
 320 
 321         /* allocate a MSI vec, and tell the bridge about it */
 322         msivec = fls(md->msi_alloc_mask);
 323         if (msivec == XLP_MSIVEC_PER_LINK) {
 324                 spin_unlock_irqrestore(&md->msi_lock, flags);
 325                 return -ENOMEM;
 326         }
 327         md->msi_alloc_mask |= (1u << msivec);
 328         spin_unlock_irqrestore(&md->msi_lock, flags);
 329 
 330         msg.address_hi = msiaddr >> 32;
 331         msg.address_lo = msiaddr & 0xffffffff;
 332         msg.data = 0xc00 | msivec;
 333 
 334         xirq = xirq + msivec;           /* msi mapped to global irq space */
 335         ret = irq_set_msi_desc(xirq, desc);
 336         if (ret < 0)
 337                 return ret;
 338 
 339         pci_write_msi_msg(xirq, &msg);
 340         return 0;
 341 }
 342 
 343 /*
 344  * Switch a link to MSI-X mode
 345  */
 346 static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr)
 347 {
 348         u32 val;
 349 
 350         val = nlm_read_reg(lnkbase, 0x2C);
 351         if ((val & 0x80000000U) == 0) {
 352                 val |= 0x80000000U;
 353                 nlm_write_reg(lnkbase, 0x2C, val);
 354         }
 355 
 356         if (cpu_is_xlp9xx()) {
 357                 val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0);
 358                 if ((val & 0x200) == 0) {
 359                         val |= 0x200;           /* MSI Interrupt enable */
 360                         nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val);
 361                 }
 362         } else {
 363                 val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
 364                 if ((val & 0x200) == 0) {
 365                         val |= 0x200;           /* MSI Interrupt enable */
 366                         nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
 367                 }
 368         }
 369 
 370         val = nlm_read_reg(lnkbase, 0x1);       /* CMD */
 371         if ((val & 0x0400) == 0) {
 372                 val |= 0x0400;
 373                 nlm_write_reg(lnkbase, 0x1, val);
 374         }
 375 
 376         /* Update IRQ in the PCI irq reg */
 377         val = nlm_read_pci_reg(lnkbase, 0xf);
 378         val &= ~0x1fu;
 379         val |= (1 << 8) | lirq;
 380         nlm_write_pci_reg(lnkbase, 0xf, val);
 381 
 382         if (cpu_is_xlp9xx()) {
 383                 /* MSI-X addresses */
 384                 nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_BASE,
 385                                 msixaddr >> 8);
 386                 nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT,
 387                                 (msixaddr + MSI_ADDR_SZ) >> 8);
 388         } else {
 389                 /* MSI-X addresses */
 390                 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE,
 391                                 msixaddr >> 8);
 392                 nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT,
 393                                 (msixaddr + MSI_ADDR_SZ) >> 8);
 394         }
 395 }
 396 
 397 /*
 398  *  Allocate a MSI-X vector
 399  */
 400 static int xlp_setup_msix(uint64_t lnkbase, int node, int link,
 401         struct msi_desc *desc)
 402 {
 403         struct xlp_msi_data *md;
 404         struct msi_msg msg;
 405         unsigned long flags;
 406         int t, msixvec, lirq, xirq, ret;
 407         uint64_t msixaddr;
 408 
 409         /* Get MSI data for the link */
 410         lirq = PIC_PCIE_MSIX_IRQ(link);
 411         xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0));
 412         md = irq_get_chip_data(xirq);
 413         msixaddr = MSIX_LINK_ADDR(node, link);
 414 
 415         spin_lock_irqsave(&md->msi_lock, flags);
 416         /* switch the PCIe link to MSI-X mode at the first alloc */
 417         if (md->msix_alloc_mask == 0)
 418                 xlp_config_link_msix(lnkbase, lirq, msixaddr);
 419 
 420         /* allocate a MSI-X vec, and tell the bridge about it */
 421         t = fls(md->msix_alloc_mask);
 422         if (t == XLP_MSIXVEC_PER_LINK) {
 423                 spin_unlock_irqrestore(&md->msi_lock, flags);
 424                 return -ENOMEM;
 425         }
 426         md->msix_alloc_mask |= (1u << t);
 427         spin_unlock_irqrestore(&md->msi_lock, flags);
 428 
 429         xirq += t;
 430         msixvec = nlm_irq_msixvec(xirq);
 431 
 432         msg.address_hi = msixaddr >> 32;
 433         msg.address_lo = msixaddr & 0xffffffff;
 434         msg.data = 0xc00 | msixvec;
 435 
 436         ret = irq_set_msi_desc(xirq, desc);
 437         if (ret < 0)
 438                 return ret;
 439 
 440         pci_write_msi_msg(xirq, &msg);
 441         return 0;
 442 }
 443 
 444 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 445 {
 446         struct pci_dev *lnkdev;
 447         uint64_t lnkbase;
 448         int node, link, slot;
 449 
 450         lnkdev = xlp_get_pcie_link(dev);
 451         if (lnkdev == NULL) {
 452                 dev_err(&dev->dev, "Could not find bridge\n");
 453                 return 1;
 454         }
 455         slot = PCI_SLOT(lnkdev->devfn);
 456         link = PCI_FUNC(lnkdev->devfn);
 457         node = slot / 8;
 458         lnkbase = nlm_get_pcie_base(node, link);
 459 
 460         if (desc->msi_attrib.is_msix)
 461                 return xlp_setup_msix(lnkbase, node, link, desc);
 462         else
 463                 return xlp_setup_msi(lnkbase, node, link, desc);
 464 }
 465 
 466 void __init xlp_init_node_msi_irqs(int node, int link)
 467 {
 468         struct nlm_soc_info *nodep;
 469         struct xlp_msi_data *md;
 470         int irq, i, irt, msixvec, val;
 471 
 472         pr_info("[%d %d] Init node PCI IRT\n", node, link);
 473         nodep = nlm_get_node(node);
 474 
 475         /* Alloc an MSI block for the link */
 476         md = kzalloc(sizeof(*md), GFP_KERNEL);
 477         spin_lock_init(&md->msi_lock);
 478         md->msi_enabled_mask = 0;
 479         md->msi_alloc_mask = 0;
 480         md->msix_alloc_mask = 0;
 481         md->node = nodep;
 482         md->lnkbase = nlm_get_pcie_base(node, link);
 483 
 484         /* extended space for MSI interrupts */
 485         irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
 486         for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) {
 487                 irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq);
 488                 irq_set_chip_data(i, md);
 489         }
 490 
 491         for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) {
 492                 if (cpu_is_xlp9xx()) {
 493                         val = ((node * nlm_threads_per_node()) << 7 |
 494                                 PIC_PCIE_MSIX_IRQ(link) << 1 | 0 << 0);
 495                         nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i +
 496                                         (link * XLP_MSIXVEC_PER_LINK)), val);
 497                 } else {
 498                         /* Initialize MSI-X irts to generate one interrupt
 499                          * per link
 500                          */
 501                         msixvec = link * XLP_MSIXVEC_PER_LINK + i;
 502                         irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec);
 503                         nlm_pic_init_irt(nodep->picbase, irt,
 504                                         PIC_PCIE_MSIX_IRQ(link),
 505                                         node * nlm_threads_per_node(), 1);
 506                 }
 507 
 508                 /* Initialize MSI-X extended irq space for the link  */
 509                 irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i));
 510                 irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq);
 511                 irq_set_chip_data(irq, md);
 512         }
 513 }
 514 
 515 void nlm_dispatch_msi(int node, int lirq)
 516 {
 517         struct xlp_msi_data *md;
 518         int link, i, irqbase;
 519         u32 status;
 520 
 521         link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE;
 522         irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
 523         md = irq_get_chip_data(irqbase);
 524         if (cpu_is_xlp9xx())
 525                 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) &
 526                                                 md->msi_enabled_mask;
 527         else
 528                 status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) &
 529                                                 md->msi_enabled_mask;
 530         while (status) {
 531                 i = __ffs(status);
 532                 do_IRQ(irqbase + i);
 533                 status &= status - 1;
 534         }
 535 
 536         /* Ack at eirr and PIC */
 537         ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link));
 538         if (cpu_is_xlp9xx())
 539                 nlm_pic_ack(md->node->picbase,
 540                                 PIC_9XX_IRT_PCIE_LINK_INDEX(link));
 541         else
 542                 nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link));
 543 }
 544 
 545 void nlm_dispatch_msix(int node, int lirq)
 546 {
 547         struct xlp_msi_data *md;
 548         int link, i, irqbase;
 549         u32 status;
 550 
 551         link = lirq - PIC_PCIE_MSIX_IRQ_BASE;
 552         irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0));
 553         md = irq_get_chip_data(irqbase);
 554         if (cpu_is_xlp9xx())
 555                 status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link));
 556         else
 557                 status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS);
 558 
 559         /* narrow it down to the MSI-x vectors for our link */
 560         if (!cpu_is_xlp9xx())
 561                 status = (status >> (link * XLP_MSIXVEC_PER_LINK)) &
 562                         ((1 << XLP_MSIXVEC_PER_LINK) - 1);
 563 
 564         while (status) {
 565                 i = __ffs(status);
 566                 do_IRQ(irqbase + i);
 567                 status &= status - 1;
 568         }
 569         /* Ack at eirr and PIC */
 570         ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link));
 571 }

/* [<][>][^][v][top][bottom][index][help] */