Commit 90d9dd66957a744831146dbb1a9e4f96a9106100
1 parent
803c874abe
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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); |