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

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

DEFINITIONS

This source file includes following definitions.
  1. arch_setup_msi_irq
  2. arch_setup_msi_irqs
  3. arch_teardown_msi_irq
  4. octeon_irq_msi_enable_pcie
  5. octeon_irq_msi_disable_pcie
  6. octeon_irq_msi_enable_pci
  7. octeon_irq_msi_disable_pci
  8. __octeon_msi_do_interrupt
  9. octeon_msi_initialize

   1 /*
   2  * This file is subject to the terms and conditions of the GNU General Public
   3  * License.  See the file "COPYING" in the main directory of this archive
   4  * for more details.
   5  *
   6  * Copyright (C) 2005-2009, 2010 Cavium Networks
   7  */
   8 #include <linux/kernel.h>
   9 #include <linux/init.h>
  10 #include <linux/msi.h>
  11 #include <linux/spinlock.h>
  12 #include <linux/interrupt.h>
  13 
  14 #include <asm/octeon/octeon.h>
  15 #include <asm/octeon/cvmx-npi-defs.h>
  16 #include <asm/octeon/cvmx-pci-defs.h>
  17 #include <asm/octeon/cvmx-npei-defs.h>
  18 #include <asm/octeon/cvmx-sli-defs.h>
  19 #include <asm/octeon/cvmx-pexp-defs.h>
  20 #include <asm/octeon/pci-octeon.h>
  21 
  22 /*
  23  * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
  24  * in use.
  25  */
  26 static u64 msi_free_irq_bitmask[4];
  27 
  28 /*
  29  * Each bit in msi_multiple_irq_bitmask tells that the device using
  30  * this bit in msi_free_irq_bitmask is also using the next bit. This
  31  * is used so we can disable all of the MSI interrupts when a device
  32  * uses multiple.
  33  */
  34 static u64 msi_multiple_irq_bitmask[4];
  35 
  36 /*
  37  * This lock controls updates to msi_free_irq_bitmask and
  38  * msi_multiple_irq_bitmask.
  39  */
  40 static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
  41 
  42 /*
  43  * Number of MSI IRQs used. This variable is set up in
  44  * the module init time.
  45  */
  46 static int msi_irq_size;
  47 
  48 /**
  49  * Called when a driver request MSI interrupts instead of the
  50  * legacy INT A-D. This routine will allocate multiple interrupts
  51  * for MSI devices that support them. A device can override this by
  52  * programming the MSI control bits [6:4] before calling
  53  * pci_enable_msi().
  54  *
  55  * @dev:    Device requesting MSI interrupts
  56  * @desc:   MSI descriptor
  57  *
  58  * Returns 0 on success.
  59  */
  60 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
  61 {
  62         struct msi_msg msg;
  63         u16 control;
  64         int configured_private_bits;
  65         int request_private_bits;
  66         int irq = 0;
  67         int irq_step;
  68         u64 search_mask;
  69         int index;
  70 
  71         /*
  72          * Read the MSI config to figure out how many IRQs this device
  73          * wants.  Most devices only want 1, which will give
  74          * configured_private_bits and request_private_bits equal 0.
  75          */
  76         pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
  77 
  78         /*
  79          * If the number of private bits has been configured then use
  80          * that value instead of the requested number. This gives the
  81          * driver the chance to override the number of interrupts
  82          * before calling pci_enable_msi().
  83          */
  84         configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
  85         if (configured_private_bits == 0) {
  86                 /* Nothing is configured, so use the hardware requested size */
  87                 request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
  88         } else {
  89                 /*
  90                  * Use the number of configured bits, assuming the
  91                  * driver wanted to override the hardware request
  92                  * value.
  93                  */
  94                 request_private_bits = configured_private_bits;
  95         }
  96 
  97         /*
  98          * The PCI 2.3 spec mandates that there are at most 32
  99          * interrupts. If this device asks for more, only give it one.
 100          */
 101         if (request_private_bits > 5)
 102                 request_private_bits = 0;
 103 
 104 try_only_one:
 105         /*
 106          * The IRQs have to be aligned on a power of two based on the
 107          * number being requested.
 108          */
 109         irq_step = 1 << request_private_bits;
 110 
 111         /* Mask with one bit for each IRQ */
 112         search_mask = (1 << irq_step) - 1;
 113 
 114         /*
 115          * We're going to search msi_free_irq_bitmask_lock for zero
 116          * bits. This represents an MSI interrupt number that isn't in
 117          * use.
 118          */
 119         spin_lock(&msi_free_irq_bitmask_lock);
 120         for (index = 0; index < msi_irq_size/64; index++) {
 121                 for (irq = 0; irq < 64; irq += irq_step) {
 122                         if ((msi_free_irq_bitmask[index] & (search_mask << irq)) == 0) {
 123                                 msi_free_irq_bitmask[index] |= search_mask << irq;
 124                                 msi_multiple_irq_bitmask[index] |= (search_mask >> 1) << irq;
 125                                 goto msi_irq_allocated;
 126                         }
 127                 }
 128         }
 129 msi_irq_allocated:
 130         spin_unlock(&msi_free_irq_bitmask_lock);
 131 
 132         /* Make sure the search for available interrupts didn't fail */
 133         if (irq >= 64) {
 134                 if (request_private_bits) {
 135                         pr_err("arch_setup_msi_irq: Unable to find %d free interrupts, trying just one",
 136                                1 << request_private_bits);
 137                         request_private_bits = 0;
 138                         goto try_only_one;
 139                 } else
 140                         panic("arch_setup_msi_irq: Unable to find a free MSI interrupt");
 141         }
 142 
 143         /* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */
 144         irq += index*64;
 145         irq += OCTEON_IRQ_MSI_BIT0;
 146 
 147         switch (octeon_dma_bar_type) {
 148         case OCTEON_DMA_BAR_TYPE_SMALL:
 149                 /* When not using big bar, Bar 0 is based at 128MB */
 150                 msg.address_lo =
 151                         ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
 152                 msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
 153                 break;
 154         case OCTEON_DMA_BAR_TYPE_BIG:
 155                 /* When using big bar, Bar 0 is based at 0 */
 156                 msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
 157                 msg.address_hi = (0 + CVMX_PCI_MSI_RCV) >> 32;
 158                 break;
 159         case OCTEON_DMA_BAR_TYPE_PCIE:
 160                 /* When using PCIe, Bar 0 is based at 0 */
 161                 /* FIXME CVMX_NPEI_MSI_RCV* other than 0? */
 162                 msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff;
 163                 msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;
 164                 break;
 165         case OCTEON_DMA_BAR_TYPE_PCIE2:
 166                 /* When using PCIe2, Bar 0 is based at 0 */
 167                 msg.address_lo = (0 + CVMX_SLI_PCIE_MSI_RCV) & 0xffffffff;
 168                 msg.address_hi = (0 + CVMX_SLI_PCIE_MSI_RCV) >> 32;
 169                 break;
 170         default:
 171                 panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type");
 172         }
 173         msg.data = irq - OCTEON_IRQ_MSI_BIT0;
 174 
 175         /* Update the number of IRQs the device has available to it */
 176         control &= ~PCI_MSI_FLAGS_QSIZE;
 177         control |= request_private_bits << 4;
 178         pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
 179 
 180         irq_set_msi_desc(irq, desc);
 181         pci_write_msi_msg(irq, &msg);
 182         return 0;
 183 }
 184 
 185 int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 186 {
 187         struct msi_desc *entry;
 188         int ret;
 189 
 190         /*
 191          * MSI-X is not supported.
 192          */
 193         if (type == PCI_CAP_ID_MSIX)
 194                 return -EINVAL;
 195 
 196         /*
 197          * If an architecture wants to support multiple MSI, it needs to
 198          * override arch_setup_msi_irqs()
 199          */
 200         if (type == PCI_CAP_ID_MSI && nvec > 1)
 201                 return 1;
 202 
 203         for_each_pci_msi_entry(entry, dev) {
 204                 ret = arch_setup_msi_irq(dev, entry);
 205                 if (ret < 0)
 206                         return ret;
 207                 if (ret > 0)
 208                         return -ENOSPC;
 209         }
 210 
 211         return 0;
 212 }
 213 
 214 /**
 215  * Called when a device no longer needs its MSI interrupts. All
 216  * MSI interrupts for the device are freed.
 217  *
 218  * @irq:    The devices first irq number. There may be multple in sequence.
 219  */
 220 void arch_teardown_msi_irq(unsigned int irq)
 221 {
 222         int number_irqs;
 223         u64 bitmask;
 224         int index = 0;
 225         int irq0;
 226 
 227         if ((irq < OCTEON_IRQ_MSI_BIT0)
 228                 || (irq > msi_irq_size + OCTEON_IRQ_MSI_BIT0))
 229                 panic("arch_teardown_msi_irq: Attempted to teardown illegal "
 230                       "MSI interrupt (%d)", irq);
 231 
 232         irq -= OCTEON_IRQ_MSI_BIT0;
 233         index = irq / 64;
 234         irq0 = irq % 64;
 235 
 236         /*
 237          * Count the number of IRQs we need to free by looking at the
 238          * msi_multiple_irq_bitmask. Each bit set means that the next
 239          * IRQ is also owned by this device.
 240          */
 241         number_irqs = 0;
 242         while ((irq0 + number_irqs < 64) &&
 243                (msi_multiple_irq_bitmask[index]
 244                 & (1ull << (irq0 + number_irqs))))
 245                 number_irqs++;
 246         number_irqs++;
 247         /* Mask with one bit for each IRQ */
 248         bitmask = (1 << number_irqs) - 1;
 249         /* Shift the mask to the correct bit location */
 250         bitmask <<= irq0;
 251         if ((msi_free_irq_bitmask[index] & bitmask) != bitmask)
 252                 panic("arch_teardown_msi_irq: Attempted to teardown MSI "
 253                       "interrupt (%d) not in use", irq);
 254 
 255         /* Checks are done, update the in use bitmask */
 256         spin_lock(&msi_free_irq_bitmask_lock);
 257         msi_free_irq_bitmask[index] &= ~bitmask;
 258         msi_multiple_irq_bitmask[index] &= ~bitmask;
 259         spin_unlock(&msi_free_irq_bitmask_lock);
 260 }
 261 
 262 static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock);
 263 
 264 static u64 msi_rcv_reg[4];
 265 static u64 mis_ena_reg[4];
 266 
 267 static void octeon_irq_msi_enable_pcie(struct irq_data *data)
 268 {
 269         u64 en;
 270         unsigned long flags;
 271         int msi_number = data->irq - OCTEON_IRQ_MSI_BIT0;
 272         int irq_index = msi_number >> 6;
 273         int irq_bit = msi_number & 0x3f;
 274 
 275         raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
 276         en = cvmx_read_csr(mis_ena_reg[irq_index]);
 277         en |= 1ull << irq_bit;
 278         cvmx_write_csr(mis_ena_reg[irq_index], en);
 279         cvmx_read_csr(mis_ena_reg[irq_index]);
 280         raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
 281 }
 282 
 283 static void octeon_irq_msi_disable_pcie(struct irq_data *data)
 284 {
 285         u64 en;
 286         unsigned long flags;
 287         int msi_number = data->irq - OCTEON_IRQ_MSI_BIT0;
 288         int irq_index = msi_number >> 6;
 289         int irq_bit = msi_number & 0x3f;
 290 
 291         raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
 292         en = cvmx_read_csr(mis_ena_reg[irq_index]);
 293         en &= ~(1ull << irq_bit);
 294         cvmx_write_csr(mis_ena_reg[irq_index], en);
 295         cvmx_read_csr(mis_ena_reg[irq_index]);
 296         raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
 297 }
 298 
 299 static struct irq_chip octeon_irq_chip_msi_pcie = {
 300         .name = "MSI",
 301         .irq_enable = octeon_irq_msi_enable_pcie,
 302         .irq_disable = octeon_irq_msi_disable_pcie,
 303 };
 304 
 305 static void octeon_irq_msi_enable_pci(struct irq_data *data)
 306 {
 307         /*
 308          * Octeon PCI doesn't have the ability to mask/unmask MSI
 309          * interrupts individually. Instead of masking/unmasking them
 310          * in groups of 16, we simple assume MSI devices are well
 311          * behaved. MSI interrupts are always enable and the ACK is
 312          * assumed to be enough
 313          */
 314 }
 315 
 316 static void octeon_irq_msi_disable_pci(struct irq_data *data)
 317 {
 318         /* See comment in enable */
 319 }
 320 
 321 static struct irq_chip octeon_irq_chip_msi_pci = {
 322         .name = "MSI",
 323         .irq_enable = octeon_irq_msi_enable_pci,
 324         .irq_disable = octeon_irq_msi_disable_pci,
 325 };
 326 
 327 /*
 328  * Called by the interrupt handling code when an MSI interrupt
 329  * occurs.
 330  */
 331 static irqreturn_t __octeon_msi_do_interrupt(int index, u64 msi_bits)
 332 {
 333         int irq;
 334         int bit;
 335 
 336         bit = fls64(msi_bits);
 337         if (bit) {
 338                 bit--;
 339                 /* Acknowledge it first. */
 340                 cvmx_write_csr(msi_rcv_reg[index], 1ull << bit);
 341 
 342                 irq = bit + OCTEON_IRQ_MSI_BIT0 + 64 * index;
 343                 do_IRQ(irq);
 344                 return IRQ_HANDLED;
 345         }
 346         return IRQ_NONE;
 347 }
 348 
 349 #define OCTEON_MSI_INT_HANDLER_X(x)                                     \
 350 static irqreturn_t octeon_msi_interrupt##x(int cpl, void *dev_id)       \
 351 {                                                                       \
 352         u64 msi_bits = cvmx_read_csr(msi_rcv_reg[(x)]);                 \
 353         return __octeon_msi_do_interrupt((x), msi_bits);                \
 354 }
 355 
 356 /*
 357  * Create octeon_msi_interrupt{0-3} function body
 358  */
 359 OCTEON_MSI_INT_HANDLER_X(0);
 360 OCTEON_MSI_INT_HANDLER_X(1);
 361 OCTEON_MSI_INT_HANDLER_X(2);
 362 OCTEON_MSI_INT_HANDLER_X(3);
 363 
 364 /*
 365  * Initializes the MSI interrupt handling code
 366  */
 367 int __init octeon_msi_initialize(void)
 368 {
 369         int irq;
 370         struct irq_chip *msi;
 371 
 372         if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_INVALID) {
 373                 return 0;
 374         } else if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) {
 375                 msi_rcv_reg[0] = CVMX_PEXP_NPEI_MSI_RCV0;
 376                 msi_rcv_reg[1] = CVMX_PEXP_NPEI_MSI_RCV1;
 377                 msi_rcv_reg[2] = CVMX_PEXP_NPEI_MSI_RCV2;
 378                 msi_rcv_reg[3] = CVMX_PEXP_NPEI_MSI_RCV3;
 379                 mis_ena_reg[0] = CVMX_PEXP_NPEI_MSI_ENB0;
 380                 mis_ena_reg[1] = CVMX_PEXP_NPEI_MSI_ENB1;
 381                 mis_ena_reg[2] = CVMX_PEXP_NPEI_MSI_ENB2;
 382                 mis_ena_reg[3] = CVMX_PEXP_NPEI_MSI_ENB3;
 383                 msi = &octeon_irq_chip_msi_pcie;
 384         } else {
 385                 msi_rcv_reg[0] = CVMX_NPI_NPI_MSI_RCV;
 386 #define INVALID_GENERATE_ADE 0x8700000000000000ULL;
 387                 msi_rcv_reg[1] = INVALID_GENERATE_ADE;
 388                 msi_rcv_reg[2] = INVALID_GENERATE_ADE;
 389                 msi_rcv_reg[3] = INVALID_GENERATE_ADE;
 390                 mis_ena_reg[0] = INVALID_GENERATE_ADE;
 391                 mis_ena_reg[1] = INVALID_GENERATE_ADE;
 392                 mis_ena_reg[2] = INVALID_GENERATE_ADE;
 393                 mis_ena_reg[3] = INVALID_GENERATE_ADE;
 394                 msi = &octeon_irq_chip_msi_pci;
 395         }
 396 
 397         for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++)
 398                 irq_set_chip_and_handler(irq, msi, handle_simple_irq);
 399 
 400         if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
 401                 if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0,
 402                                 0, "MSI[0:63]", octeon_msi_interrupt0))
 403                         panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
 404 
 405                 if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt1,
 406                                 0, "MSI[64:127]", octeon_msi_interrupt1))
 407                         panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
 408 
 409                 if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt2,
 410                                 0, "MSI[127:191]", octeon_msi_interrupt2))
 411                         panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
 412 
 413                 if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt3,
 414                                 0, "MSI[192:255]", octeon_msi_interrupt3))
 415                         panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
 416 
 417                 msi_irq_size = 256;
 418         } else if (octeon_is_pci_host()) {
 419                 if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0,
 420                                 0, "MSI[0:15]", octeon_msi_interrupt0))
 421                         panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
 422 
 423                 if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt0,
 424                                 0, "MSI[16:31]", octeon_msi_interrupt0))
 425                         panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
 426 
 427                 if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt0,
 428                                 0, "MSI[32:47]", octeon_msi_interrupt0))
 429                         panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
 430 
 431                 if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt0,
 432                                 0, "MSI[48:63]", octeon_msi_interrupt0))
 433                         panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
 434                 msi_irq_size = 64;
 435         }
 436         return 0;
 437 }
 438 subsys_initcall(octeon_msi_initialize);

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