diff options
| author | Ganapatrao Kulkarni <gkulkarni@caviumnetworks.com> | 2016-05-25 09:29:20 -0400 |
|---|---|---|
| committer | Marc Zyngier <marc.zyngier@arm.com> | 2016-06-02 13:01:07 -0400 |
| commit | fbf8f40e1658cb2f17452dbd3c708e329c5d27e0 (patch) | |
| tree | e8602c06525eb7d69a4f99b71fe6a4e7f9c36dde | |
| parent | cf1d9d11e25053a264c0001aa86be7680bb1ecc1 (diff) | |
irqchip/gicv3-its: numa: Enable workaround for Cavium thunderx erratum 23144
The erratum fixes the hang of ITS SYNC command by avoiding inter node
io and collections/cpu mapping on thunderx dual-socket platform.
This fix is only applicable for Cavium's ThunderX dual-socket platform.
Reviewed-by: Robert Richter <rrichter@cavium.com>
Signed-off-by: Ganapatrao Kulkarni <gkulkarni@caviumnetworks.com>
Signed-off-by: Robert Richter <rrichter@cavium.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
| -rw-r--r-- | Documentation/arm64/silicon-errata.txt | 1 | ||||
| -rw-r--r-- | arch/arm64/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 49 |
3 files changed, 57 insertions, 2 deletions
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt index c6938e50e71f..4da60b463995 100644 --- a/Documentation/arm64/silicon-errata.txt +++ b/Documentation/arm64/silicon-errata.txt | |||
| @@ -56,6 +56,7 @@ stable kernels. | |||
| 56 | | ARM | MMU-500 | #841119,#826419 | N/A | | 56 | | ARM | MMU-500 | #841119,#826419 | N/A | |
| 57 | | | | | | | 57 | | | | | | |
| 58 | | Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 | | 58 | | Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 | |
| 59 | | Cavium | ThunderX ITS | #23144 | CAVIUM_ERRATUM_23144 | | ||
| 59 | | Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 | | 60 | | Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 | |
| 60 | | Cavium | ThunderX Core | #27456 | CAVIUM_ERRATUM_27456 | | 61 | | Cavium | ThunderX Core | #27456 | CAVIUM_ERRATUM_27456 | |
| 61 | | Cavium | ThunderX SMMUv2 | #27704 | N/A | | 62 | | Cavium | ThunderX SMMUv2 | #27704 | N/A | |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 76747d92bc72..57a9f67971d3 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
| @@ -426,6 +426,15 @@ config CAVIUM_ERRATUM_22375 | |||
| 426 | 426 | ||
| 427 | If unsure, say Y. | 427 | If unsure, say Y. |
| 428 | 428 | ||
| 429 | config CAVIUM_ERRATUM_23144 | ||
| 430 | bool "Cavium erratum 23144: ITS SYNC hang on dual socket system" | ||
| 431 | depends on NUMA | ||
| 432 | default y | ||
| 433 | help | ||
| 434 | ITS SYNC command hang for cross node io and collections/cpu mapping. | ||
| 435 | |||
| 436 | If unsure, say Y. | ||
| 437 | |||
| 429 | config CAVIUM_ERRATUM_23154 | 438 | config CAVIUM_ERRATUM_23154 |
| 430 | bool "Cavium erratum 23154: Access to ICC_IAR1_EL1 is not sync'ed" | 439 | bool "Cavium erratum 23154: Access to ICC_IAR1_EL1 is not sync'ed" |
| 431 | default y | 440 | default y |
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 6bd881be24ea..5eb1f9e17a98 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | 41 | ||
| 42 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) | 42 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) |
| 43 | #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) | 43 | #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) |
| 44 | #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) | ||
| 44 | 45 | ||
| 45 | #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) | 46 | #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) |
| 46 | 47 | ||
| @@ -82,6 +83,7 @@ struct its_node { | |||
| 82 | u64 flags; | 83 | u64 flags; |
| 83 | u32 ite_size; | 84 | u32 ite_size; |
| 84 | u32 device_ids; | 85 | u32 device_ids; |
| 86 | int numa_node; | ||
| 85 | }; | 87 | }; |
| 86 | 88 | ||
| 87 | #define ITS_ITT_ALIGN SZ_256 | 89 | #define ITS_ITT_ALIGN SZ_256 |
| @@ -613,11 +615,23 @@ static void its_unmask_irq(struct irq_data *d) | |||
| 613 | static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | 615 | static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, |
| 614 | bool force) | 616 | bool force) |
| 615 | { | 617 | { |
| 616 | unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); | 618 | unsigned int cpu; |
| 619 | const struct cpumask *cpu_mask = cpu_online_mask; | ||
| 617 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); | 620 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); |
| 618 | struct its_collection *target_col; | 621 | struct its_collection *target_col; |
| 619 | u32 id = its_get_event_id(d); | 622 | u32 id = its_get_event_id(d); |
| 620 | 623 | ||
| 624 | /* lpi cannot be routed to a redistributor that is on a foreign node */ | ||
| 625 | if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { | ||
| 626 | if (its_dev->its->numa_node >= 0) { | ||
| 627 | cpu_mask = cpumask_of_node(its_dev->its->numa_node); | ||
| 628 | if (!cpumask_intersects(mask_val, cpu_mask)) | ||
| 629 | return -EINVAL; | ||
| 630 | } | ||
| 631 | } | ||
| 632 | |||
| 633 | cpu = cpumask_any_and(mask_val, cpu_mask); | ||
| 634 | |||
| 621 | if (cpu >= nr_cpu_ids) | 635 | if (cpu >= nr_cpu_ids) |
| 622 | return -EINVAL; | 636 | return -EINVAL; |
| 623 | 637 | ||
| @@ -1101,6 +1115,16 @@ static void its_cpu_init_collection(void) | |||
| 1101 | list_for_each_entry(its, &its_nodes, entry) { | 1115 | list_for_each_entry(its, &its_nodes, entry) { |
| 1102 | u64 target; | 1116 | u64 target; |
| 1103 | 1117 | ||
| 1118 | /* avoid cross node collections and its mapping */ | ||
| 1119 | if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { | ||
| 1120 | struct device_node *cpu_node; | ||
| 1121 | |||
| 1122 | cpu_node = of_get_cpu_node(cpu, NULL); | ||
| 1123 | if (its->numa_node != NUMA_NO_NODE && | ||
| 1124 | its->numa_node != of_node_to_nid(cpu_node)) | ||
| 1125 | continue; | ||
| 1126 | } | ||
| 1127 | |||
| 1104 | /* | 1128 | /* |
| 1105 | * We now have to bind each collection to its target | 1129 | * We now have to bind each collection to its target |
| 1106 | * redistributor. | 1130 | * redistributor. |
| @@ -1351,9 +1375,14 @@ static void its_irq_domain_activate(struct irq_domain *domain, | |||
| 1351 | { | 1375 | { |
| 1352 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); | 1376 | struct its_device *its_dev = irq_data_get_irq_chip_data(d); |
| 1353 | u32 event = its_get_event_id(d); | 1377 | u32 event = its_get_event_id(d); |
| 1378 | const struct cpumask *cpu_mask = cpu_online_mask; | ||
| 1379 | |||
| 1380 | /* get the cpu_mask of local node */ | ||
| 1381 | if (its_dev->its->numa_node >= 0) | ||
| 1382 | cpu_mask = cpumask_of_node(its_dev->its->numa_node); | ||
| 1354 | 1383 | ||
| 1355 | /* Bind the LPI to the first possible CPU */ | 1384 | /* Bind the LPI to the first possible CPU */ |
| 1356 | its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask); | 1385 | its_dev->event_map.col_map[event] = cpumask_first(cpu_mask); |
| 1357 | 1386 | ||
| 1358 | /* Map the GIC IRQ and event to the device */ | 1387 | /* Map the GIC IRQ and event to the device */ |
| 1359 | its_send_mapvi(its_dev, d->hwirq, event); | 1388 | its_send_mapvi(its_dev, d->hwirq, event); |
| @@ -1443,6 +1472,13 @@ static void __maybe_unused its_enable_quirk_cavium_22375(void *data) | |||
| 1443 | its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375; | 1472 | its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375; |
| 1444 | } | 1473 | } |
| 1445 | 1474 | ||
| 1475 | static void __maybe_unused its_enable_quirk_cavium_23144(void *data) | ||
| 1476 | { | ||
| 1477 | struct its_node *its = data; | ||
| 1478 | |||
| 1479 | its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_23144; | ||
| 1480 | } | ||
| 1481 | |||
| 1446 | static const struct gic_quirk its_quirks[] = { | 1482 | static const struct gic_quirk its_quirks[] = { |
| 1447 | #ifdef CONFIG_CAVIUM_ERRATUM_22375 | 1483 | #ifdef CONFIG_CAVIUM_ERRATUM_22375 |
| 1448 | { | 1484 | { |
| @@ -1452,6 +1488,14 @@ static const struct gic_quirk its_quirks[] = { | |||
| 1452 | .init = its_enable_quirk_cavium_22375, | 1488 | .init = its_enable_quirk_cavium_22375, |
| 1453 | }, | 1489 | }, |
| 1454 | #endif | 1490 | #endif |
| 1491 | #ifdef CONFIG_CAVIUM_ERRATUM_23144 | ||
| 1492 | { | ||
| 1493 | .desc = "ITS: Cavium erratum 23144", | ||
| 1494 | .iidr = 0xa100034c, /* ThunderX pass 1.x */ | ||
| 1495 | .mask = 0xffff0fff, | ||
| 1496 | .init = its_enable_quirk_cavium_23144, | ||
| 1497 | }, | ||
| 1498 | #endif | ||
| 1455 | { | 1499 | { |
| 1456 | } | 1500 | } |
| 1457 | }; | 1501 | }; |
| @@ -1514,6 +1558,7 @@ static int __init its_probe(struct device_node *node, | |||
| 1514 | its->base = its_base; | 1558 | its->base = its_base; |
| 1515 | its->phys_base = res.start; | 1559 | its->phys_base = res.start; |
| 1516 | its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; | 1560 | its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; |
| 1561 | its->numa_node = of_node_to_nid(node); | ||
| 1517 | 1562 | ||
| 1518 | its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); | 1563 | its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); |
| 1519 | if (!its->cmd_base) { | 1564 | if (!its->cmd_base) { |
