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) { |