Commit 90d9dd66957a744831146dbb1a9e4f96a9106100

Authored by Chris Metcalf
1 parent 803c874abe

tile PCI RC: support more MSI-X interrupt vectors

To support PCIe devices with higher number of MSI-X interrupt vectors,
e.g. 16 for the LSI RAID card, enhance the Gx RC stack to provide more
MSI-X vectors by using the TRIO Scatter Queues, which provide 8 more
vectors in addition to ~10 from the Map Mem regions.

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

Showing 4 changed files with 106 additions and 20 deletions Side-by-side Diff

arch/tile/gxio/iorpc_trio.c
... ... @@ -61,6 +61,29 @@
61 61  
62 62 EXPORT_SYMBOL(gxio_trio_alloc_memory_maps);
63 63  
  64 +struct alloc_scatter_queues_param {
  65 + unsigned int count;
  66 + unsigned int first;
  67 + unsigned int flags;
  68 +};
  69 +
  70 +int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
  71 + unsigned int count, unsigned int first,
  72 + unsigned int flags)
  73 +{
  74 + struct alloc_scatter_queues_param temp;
  75 + struct alloc_scatter_queues_param *params = &temp;
  76 +
  77 + params->count = count;
  78 + params->first = first;
  79 + params->flags = flags;
  80 +
  81 + return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
  82 + sizeof(*params),
  83 + GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES);
  84 +}
  85 +
  86 +EXPORT_SYMBOL(gxio_trio_alloc_scatter_queues);
64 87  
65 88 struct alloc_pio_regions_param {
66 89 unsigned int count;
arch/tile/include/arch/trio.h
... ... @@ -23,6 +23,45 @@
23 23 #ifndef __ASSEMBLER__
24 24  
25 25 /*
  26 + * Map SQ Doorbell Format.
  27 + * This describes the format of the write-only doorbell register that exists
  28 + * in the last 8-bytes of the MAP_SQ_BASE/LIM range. This register is only
  29 + * writable from PCIe space. Writes to this register will not be written to
  30 + * Tile memory space and thus no IO VA translation is required if the last
  31 + * page of the BASE/LIM range is not otherwise written.
  32 + */
  33 +
  34 +__extension__
  35 +typedef union
  36 +{
  37 + struct
  38 + {
  39 +#ifndef __BIG_ENDIAN__
  40 + /*
  41 + * When written with a 1, the associated MAP_SQ region's doorbell
  42 + * interrupt will be triggered once all previous writes are visible to
  43 + * Tile software.
  44 + */
  45 + uint_reg_t doorbell : 1;
  46 + /*
  47 + * When written with a 1, the descriptor at the head of the associated
  48 + * MAP_SQ's FIFO will be dequeued.
  49 + */
  50 + uint_reg_t pop : 1;
  51 + /* Reserved. */
  52 + uint_reg_t __reserved : 62;
  53 +#else /* __BIG_ENDIAN__ */
  54 + uint_reg_t __reserved : 62;
  55 + uint_reg_t pop : 1;
  56 + uint_reg_t doorbell : 1;
  57 +#endif
  58 + };
  59 +
  60 + uint_reg_t word;
  61 +} TRIO_MAP_SQ_DOORBELL_FMT_t;
  62 +
  63 +
  64 +/*
26 65 * Tile PIO Region Configuration - CFG Address Format.
27 66 * This register describes the address format for PIO accesses when the
28 67 * associated region is setup with TYPE=CFG.
arch/tile/include/gxio/iorpc_trio.h
... ... @@ -30,6 +30,7 @@
30 30  
31 31 #define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404)
32 32  
  33 +#define GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
33 34 #define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412)
34 35  
35 36 #define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414)
... ... @@ -53,6 +54,10 @@
53 54 unsigned int count, unsigned int first,
54 55 unsigned int flags);
55 56  
  57 +
  58 +int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
  59 + unsigned int count, unsigned int first,
  60 + unsigned int flags);
56 61  
57 62 int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
58 63 unsigned int count, unsigned int first,
arch/tile/kernel/pci_gx.c
... ... @@ -1474,32 +1474,55 @@
1474 1474 trio_context = controller->trio;
1475 1475  
1476 1476 /*
1477   - * Allocate the Mem-Map that will accept the MSI write and
1478   - * trigger the TILE-side interrupts.
  1477 + * Allocate a scatter-queue that will accept the MSI write and
  1478 + * trigger the TILE-side interrupts. We use the scatter-queue regions
  1479 + * before the mem map regions, because the latter are needed by more
  1480 + * applications.
1479 1481 */
1480   - mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0);
1481   - if (mem_map < 0) {
1482   - dev_printk(KERN_INFO, &pdev->dev,
1483   - "%s Mem-Map alloc failure. "
1484   - "Failed to initialize MSI interrupts. "
1485   - "Falling back to legacy interrupts.\n",
1486   - desc->msi_attrib.is_msix ? "MSI-X" : "MSI");
  1482 + mem_map = gxio_trio_alloc_scatter_queues(trio_context, 1, 0, 0);
  1483 + if (mem_map >= 0) {
  1484 + TRIO_MAP_SQ_DOORBELL_FMT_t doorbell_template = {{
  1485 + .pop = 0,
  1486 + .doorbell = 1,
  1487 + }};
1487 1488  
1488   - ret = -ENOMEM;
1489   - goto msi_mem_map_alloc_failure;
  1489 + mem_map += TRIO_NUM_MAP_MEM_REGIONS;
  1490 + mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
  1491 + mem_map * MEM_MAP_INTR_REGION_SIZE;
  1492 + mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1;
  1493 +
  1494 + msi_addr = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 8;
  1495 + msg.data = (unsigned int)doorbell_template.word;
  1496 + } else {
  1497 + /* SQ regions are out, allocate from map mem regions. */
  1498 + mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0);
  1499 + if (mem_map < 0) {
  1500 + dev_printk(KERN_INFO, &pdev->dev,
  1501 + "%s Mem-Map alloc failure. "
  1502 + "Failed to initialize MSI interrupts. "
  1503 + "Falling back to legacy interrupts.\n",
  1504 + desc->msi_attrib.is_msix ? "MSI-X" : "MSI");
  1505 + ret = -ENOMEM;
  1506 + goto msi_mem_map_alloc_failure;
  1507 + }
  1508 +
  1509 + mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
  1510 + mem_map * MEM_MAP_INTR_REGION_SIZE;
  1511 + mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1;
  1512 +
  1513 + msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 -
  1514 + TRIO_MAP_MEM_REG_INT0;
  1515 +
  1516 + msg.data = mem_map;
1490 1517 }
1491 1518  
1492 1519 /* We try to distribute different IRQs to different tiles. */
1493 1520 cpu = tile_irq_cpu(irq);
1494 1521  
1495 1522 /*
1496   - * Now call up to the HV to configure the Mem-Map interrupt and
  1523 + * Now call up to the HV to configure the MSI interrupt and
1497 1524 * set up the IPI binding.
1498 1525 */
1499   - mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
1500   - mem_map * MEM_MAP_INTR_REGION_SIZE;
1501   - mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1;
1502   -
1503 1526 ret = gxio_trio_config_msi_intr(trio_context, cpu_x(cpu), cpu_y(cpu),
1504 1527 KERNEL_PL, irq, controller->mac,
1505 1528 mem_map, mem_map_base, mem_map_limit,
1506 1529  
... ... @@ -1512,12 +1535,8 @@
1512 1535  
1513 1536 irq_set_msi_desc(irq, desc);
1514 1537  
1515   - msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 - TRIO_MAP_MEM_REG_INT0;
1516   -
1517 1538 msg.address_hi = msi_addr >> 32;
1518 1539 msg.address_lo = msi_addr & 0xffffffff;
1519   -
1520   - msg.data = mem_map;
1521 1540  
1522 1541 write_msi_msg(irq, &msg);
1523 1542 irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq);