5656
5757/* List of flags for specific v2m implementation */
5858#define GICV2M_NEEDS_SPI_OFFSET 0x00000001
59+ #define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
5960
6061static LIST_HEAD (v2m_nodes );
6162static DEFINE_SPINLOCK (v2m_lock );
@@ -98,15 +99,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
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+
101110static 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,
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)
307319
308320static 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,
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,
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,
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,
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)
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+
454497static int __init
455498acpi_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,
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,
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,
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
0 commit comments