History

irqchip/gic-v2m: Add support for Amazon Graviton variant of GICv3+GICv2m

Add support for Amazon Graviton custom variant of GICv2m, where the message is encoded using the MSI message address, as opposed to standard GICv2m, where the SPI number is encoded in the MSI message data. In addition, the Graviton flavor of GICv2m is used along GICv3 (and not GICv2).

Zeev Zilberman committed 7 years ago

Commit 90b4c551 parent 47705334 files · +76 −20Browse files

Unified · Split

4 files
  1. drivers/irqchip/irq-gic-v2m.c +68 −17
  2. drivers/irqchip/irq-gic-v3.c +3 −0
  3. include/linux/irqchip/arm-gic-common.h +5 −0
  4. include/linux/irqchip/arm-gic.h +0 −3
drivers/irqchip/irq-gic-v2m.c+68−17
@@ -56,6 +56,7 @@ · 55 unmodified lines
5656
5757 /* List of flags for specific v2m implementation */
5858 #define GICV2M_NEEDS_SPI_OFFSET 0x00000001
59+#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
5960
6061 static LIST_HEAD(v2m_nodes);
6162 static DEFINE_SPINLOCK(v2m_lock);
@@ -98,15 +99,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = { · 36 unmodified lines
9899 .chip = &gicv2m_msi_irq_chip,
99100 };
100101
102+static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq)
103+{
104+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
105+ return v2m->res.start | ((hwirq - 32) << 3);
106+ else
107+ return v2m->res.start + V2M_MSI_SETSPI_NS;
108+}
109+
101110 static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
102111 {
103112 struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
104− phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS;
113+ phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq);
105114
106115 msg->address_hi = upper_32_bits(addr);
107116 msg->address_lo = lower_32_bits(addr);
108− msg->data = data->hwirq;
109117
118+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
119+ msg->data = 0;
120+ else
121+ msg->data = data->hwirq;
110122 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
111123 msg->data -= v2m->spi_offset;
112124
@@ -188,7 +200,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, · 75 unmodified lines
188200 hwirq = v2m->spi_start + offset;
189201
190202 err = iommu_dma_prepare_msi(info->desc,
191− v2m->res.start + V2M_MSI_SETSPI_NS);
203+ gicv2m_get_msi_addr(v2m, hwirq));
192204 if (err)
193205 return err;
194206
@@ -307,7 +319,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent) · 112 unmodified lines
307319
308320 static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
309321 u32 spi_start, u32 nr_spis,
310− struct resource *res)
322+ struct resource *res, u32 flags)
311323 {
312324 int ret;
313325 struct v2m_data *v2m;
@@ -320,6 +332,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, · 6 unmodified lines
320332
321333 INIT_LIST_HEAD(&v2m->entry);
322334 v2m->fwnode = fwnode;
335+ v2m->flags = flags;
323336
324337 memcpy(&v2m->res, res, sizeof(struct resource));
325338
@@ -334,7 +347,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, · 8 unmodified lines
334347 v2m->spi_start = spi_start;
335348 v2m->nr_spis = nr_spis;
336349 } else {
337− u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
350+ u32 typer;
351+
352+ /* Graviton should always have explicit spi_start/nr_spis */
353+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) {
354+ ret = -EINVAL;
355+ goto err_iounmap;
356+ }
357+ typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
338358
339359 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
340360 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
@@ -355,18 +375,21 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, · 14 unmodified lines
355375 *
356376 * Broadom NS2 GICv2m implementation has an erratum where the MSI data
357377 * is 'spi_number - 32'
378+ *
379+ * Reading that register fails on the Graviton implementation
358380 */
359− switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
360− case XGENE_GICV2M_MSI_IIDR:
361− v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
362− v2m->spi_offset = v2m->spi_start;
363− break;
364− case BCM_NS2_GICV2M_MSI_IIDR:
365− v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
366− v2m->spi_offset = 32;
367− break;
381+ if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) {
382+ switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
383+ case XGENE_GICV2M_MSI_IIDR:
384+ v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
385+ v2m->spi_offset = v2m->spi_start;
386+ break;
387+ case BCM_NS2_GICV2M_MSI_IIDR:
388+ v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
389+ v2m->spi_offset = 32;
390+ break;
391+ }
368392 }
369−
370393 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),
371394 GFP_KERNEL);
372395 if (!v2m->bm) {
@@ -419,7 +442,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, · 46 unmodified lines
419442 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
420443 spi_start, nr_spis);
421444
422− ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res);
445+ ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis,
446+ &res, 0);
423447 if (ret) {
424448 of_node_put(child);
425449 break;
@@ -451,6 +475,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) · 25 unmodified lines
451475 return data->fwnode;
452476 }
453477
478+static bool acpi_check_amazon_graviton_quirks(void)
479+{
480+ static struct acpi_table_madt *madt;
481+ acpi_status status;
482+ bool rc = false;
483+
484+#define ACPI_AMZN_OEM_ID "AMAZON"
485+
486+ status = acpi_get_table(ACPI_SIG_MADT, 0,
487+ (struct acpi_table_header **)&madt);
488+
489+ if (ACPI_FAILURE(status) || !madt)
490+ return rc;
491+ rc = !memcmp(madt->header.oem_id, ACPI_AMZN_OEM_ID, ACPI_OEM_ID_SIZE);
492+ acpi_put_table((struct acpi_table_header *)madt);
493+
494+ return rc;
495+}
496+
454497 static int __init
455498 acpi_parse_madt_msi(union acpi_subtable_headers *header,
456499 const unsigned long end)
@@ -460,6 +503,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 3 unmodified lines
460503 u32 spi_start = 0, nr_spis = 0;
461504 struct acpi_madt_generic_msi_frame *m;
462505 struct fwnode_handle *fwnode;
506+ u32 flags = 0;
463507
464508 m = (struct acpi_madt_generic_msi_frame *)header;
465509 if (BAD_MADT_ENTRY(m, end))
@@ -469,6 +513,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 3 unmodified lines
469513 res.end = m->base_address + SZ_4K - 1;
470514 res.flags = IORESOURCE_MEM;
471515
516+ if (acpi_check_amazon_graviton_quirks()) {
517+ pr_info("applying Amazon Graviton quirk\n");
518+ res.end = res.start + SZ_8K - 1;
519+ flags |= GICV2M_GRAVITON_ADDRESS_ONLY;
520+ gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI;
521+ }
522+
472523 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
473524 spi_start = m->spi_base;
474525 nr_spis = m->spi_count;
@@ -483,7 +534,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 8 unmodified lines
483534 return -EINVAL;
484535 }
485536
486− ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
537+ ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags);
487538 if (ret)
488539 irq_domain_free_fwnode(fwnode);
489540
drivers/irqchip/irq-gic-v3.c+3−0
@@ -1343,6 +1343,9 @@ static int __init gic_init_bases(void __iomem *dist_base, · 1342 unmodified lines
13431343 if (gic_dist_supports_lpis()) {
13441344 its_init(handle, &gic_data.rdists, gic_data.domain);
13451345 its_cpu_init();
1346+ } else {
1347+ if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1348+ gicv2m_init(handle, gic_data.domain);
13461349 }
13471350
13481351 if (gic_prio_masking_enabled()) {
include/linux/irqchip/arm-gic-common.h+5−0
@@ -39,4 +39,9 @@ struct gic_kvm_info { · 38 unmodified lines
3939
4040 const struct gic_kvm_info *gic_get_kvm_info(void);
4141
42+struct irq_domain;
43+struct fwnode_handle;
44+int gicv2m_init(struct fwnode_handle *parent_handle,
45+ struct irq_domain *parent);
46+
4247 #endif /* __LINUX_IRQCHIP_ARM_GIC_COMMON_H */
include/linux/irqchip/arm-gic.h+0−3
@@ -160,9 +160,6 @@ int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq); · 159 unmodified lines
160160 */
161161 void gic_init(void __iomem *dist , void __iomem *cpu);
162162
163−int gicv2m_init(struct fwnode_handle *parent_handle,
164− struct irq_domain *parent);
165−
166163 void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
167164 int gic_get_cpu_id(unsigned int cpu);
168165 void gic_migrate_target(unsigned int new_cpu_id);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t