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
56 56
57/* List of flags for specific v2m implementation */57/* List of flags for specific v2m implementation */
58#define GICV2M_NEEDS_SPI_OFFSET 0x0000000158#define GICV2M_NEEDS_SPI_OFFSET 0x00000001
59#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
59 60
60static LIST_HEAD(v2m_nodes);61static LIST_HEAD(v2m_nodes);
61static DEFINE_SPINLOCK(v2m_lock);62static DEFINE_SPINLOCK(v2m_lock);
@@ -98,15 +99,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = { · 36 unmodified lines
98 .chip = &gicv2m_msi_irq_chip,99 .chip = &gicv2m_msi_irq_chip,
99};100};
100 101
102static 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
101static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)110static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
102{111{
103 struct v2m_data *v2m = irq_data_get_irq_chip_data(data);112 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);
105 114
106 msg->address_hi = upper_32_bits(addr);115 msg->address_hi = upper_32_bits(addr);
107 msg->address_lo = lower_32_bits(addr);116 msg->address_lo = lower_32_bits(addr);
108 msg->data = data->hwirq;
109 117
118 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
119 msg->data = 0;
120 else
121 msg->data = data->hwirq;
110 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)122 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
111 msg->data -= v2m->spi_offset;123 msg->data -= v2m->spi_offset;
112 124
@@ -188,7 +200,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, · 75 unmodified lines
188 hwirq = v2m->spi_start + offset;200 hwirq = v2m->spi_start + offset;
189 201
190 err = iommu_dma_prepare_msi(info->desc,202 err = iommu_dma_prepare_msi(info->desc,
191 v2m->res.start + V2M_MSI_SETSPI_NS);203 gicv2m_get_msi_addr(v2m, hwirq));
192 if (err)204 if (err)
193 return err;205 return err;
194 206
@@ -307,7 +319,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent) · 112 unmodified lines
307 319
308static int __init gicv2m_init_one(struct fwnode_handle *fwnode,320static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
309 u32 spi_start, u32 nr_spis,321 u32 spi_start, u32 nr_spis,
310 struct resource *res)322 struct resource *res, u32 flags)
311{323{
312 int ret;324 int ret;
313 struct v2m_data *v2m;325 struct v2m_data *v2m;
@@ -320,6 +332,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, · 6 unmodified lines
320 332
321 INIT_LIST_HEAD(&v2m->entry);333 INIT_LIST_HEAD(&v2m->entry);
322 v2m->fwnode = fwnode;334 v2m->fwnode = fwnode;
335 v2m->flags = flags;
323 336
324 memcpy(&v2m->res, res, sizeof(struct resource));337 memcpy(&v2m->res, res, sizeof(struct resource));
325 338
@@ -334,7 +347,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, · 8 unmodified lines
334 v2m->spi_start = spi_start;347 v2m->spi_start = spi_start;
335 v2m->nr_spis = nr_spis;348 v2m->nr_spis = nr_spis;
336 } else {349 } 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);
338 358
339 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);359 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
340 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);360 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
355 *375 *
356 * Broadom NS2 GICv2m implementation has an erratum where the MSI data376 * Broadom NS2 GICv2m implementation has an erratum where the MSI data
357 * is 'spi_number - 32'377 * is 'spi_number - 32'
378 *
379 * Reading that register fails on the Graviton implementation
358 */380 */
359 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {381 if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) {
360 case XGENE_GICV2M_MSI_IIDR:382 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
361 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;383 case XGENE_GICV2M_MSI_IIDR:
362 v2m->spi_offset = v2m->spi_start;384 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
363 break;385 v2m->spi_offset = v2m->spi_start;
364 case BCM_NS2_GICV2M_MSI_IIDR:386 break;
365 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;387 case BCM_NS2_GICV2M_MSI_IIDR:
366 v2m->spi_offset = 32;388 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
367 break;389 v2m->spi_offset = 32;
390 break;
391 }
368 }392 }
369
370 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),393 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),
371 GFP_KERNEL);394 GFP_KERNEL);
372 if (!v2m->bm) {395 if (!v2m->bm) {
@@ -419,7 +442,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, · 46 unmodified lines
419 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",442 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
420 spi_start, nr_spis);443 spi_start, nr_spis);
421 444
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);
423 if (ret) {447 if (ret) {
424 of_node_put(child);448 of_node_put(child);
425 break;449 break;
@@ -451,6 +475,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) · 25 unmodified lines
451 return data->fwnode;475 return data->fwnode;
452}476}
453 477
478static 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
454static int __init497static int __init
455acpi_parse_madt_msi(union acpi_subtable_headers *header,498acpi_parse_madt_msi(union acpi_subtable_headers *header,
456 const unsigned long end)499 const unsigned long end)
@@ -460,6 +503,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 3 unmodified lines
460 u32 spi_start = 0, nr_spis = 0;503 u32 spi_start = 0, nr_spis = 0;
461 struct acpi_madt_generic_msi_frame *m;504 struct acpi_madt_generic_msi_frame *m;
462 struct fwnode_handle *fwnode;505 struct fwnode_handle *fwnode;
506 u32 flags = 0;
463 507
464 m = (struct acpi_madt_generic_msi_frame *)header;508 m = (struct acpi_madt_generic_msi_frame *)header;
465 if (BAD_MADT_ENTRY(m, end))509 if (BAD_MADT_ENTRY(m, end))
@@ -469,6 +513,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 3 unmodified lines
469 res.end = m->base_address + SZ_4K - 1;513 res.end = m->base_address + SZ_4K - 1;
470 res.flags = IORESOURCE_MEM;514 res.flags = IORESOURCE_MEM;
471 515
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
472 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {523 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
473 spi_start = m->spi_base;524 spi_start = m->spi_base;
474 nr_spis = m->spi_count;525 nr_spis = m->spi_count;
@@ -483,7 +534,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, · 8 unmodified lines
483 return -EINVAL;534 return -EINVAL;
484 }535 }
485 536
486 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);537 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags);
487 if (ret)538 if (ret)
488 irq_domain_free_fwnode(fwnode);539 irq_domain_free_fwnode(fwnode);
489 540
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
1343 if (gic_dist_supports_lpis()) {1343 if (gic_dist_supports_lpis()) {
1344 its_init(handle, &gic_data.rdists, gic_data.domain);1344 its_init(handle, &gic_data.rdists, gic_data.domain);
1345 its_cpu_init();1345 its_cpu_init();
1346 } else {
1347 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1348 gicv2m_init(handle, gic_data.domain);
1346 }1349 }
1347 1350
1348 if (gic_prio_masking_enabled()) {1351 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
39 39
40const struct gic_kvm_info *gic_get_kvm_info(void);40const struct gic_kvm_info *gic_get_kvm_info(void);
41 41
42struct irq_domain;
43struct fwnode_handle;
44int gicv2m_init(struct fwnode_handle *parent_handle,
45 struct irq_domain *parent);
46
42#endif /* __LINUX_IRQCHIP_ARM_GIC_COMMON_H */47#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
160 */160 */
161void gic_init(void __iomem *dist , void __iomem *cpu);161void gic_init(void __iomem *dist , void __iomem *cpu);
162 162
163int gicv2m_init(struct fwnode_handle *parent_handle,
164 struct irq_domain *parent);
165
166void gic_send_sgi(unsigned int cpu_id, unsigned int irq);163void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
167int gic_get_cpu_id(unsigned int cpu);164int gic_get_cpu_id(unsigned int cpu);
168void gic_migrate_target(unsigned int new_cpu_id);165void 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