44 * Copyright (C) 2018 Christoph Hellwig
55 */
66#define pr_fmt (fmt ) "riscv-plic: " fmt
7+ #include <linux/acpi.h>
78#include <linux/cpu.h>
89#include <linux/interrupt.h>
910#include <linux/io.h>
@@ -71,6 +72,8 @@ struct plic_priv {
7172 unsigned long plic_quirks ;
7273 unsigned int nr_irqs ;
7374 unsigned long * prio_save ;
75+ u32 gsi_base ;
76+ int acpi_plic_id ;
7477};
7578
7679struct plic_handler {
@@ -325,6 +328,10 @@ static int plic_irq_domain_translate(struct irq_domain *d,
325328{
326329 struct plic_priv * priv = d -> host_data ;
327330
331+ /* For DT, gsi_base is always zero. */
332+ if (fwspec -> param [0 ] >= priv -> gsi_base )
333+ fwspec -> param [0 ] = fwspec -> param [0 ] - priv -> gsi_base ;
334+
328335 if (test_bit (PLIC_QUIRK_EDGE_INTERRUPT , & priv -> plic_quirks ))
329336 return irq_domain_translate_twocell (d , fwspec , hwirq , type );
330337
@@ -426,17 +433,36 @@ static const struct of_device_id plic_match[] = {
426433 {}
427434};
428435
436+ #ifdef CONFIG_ACPI
437+
438+ static const struct acpi_device_id plic_acpi_match [] = {
439+ { "RSCV0001" , 0 },
440+ {}
441+ };
442+ MODULE_DEVICE_TABLE (acpi , plic_acpi_match );
443+
444+ #endif
429445static int plic_parse_nr_irqs_and_contexts (struct fwnode_handle * fwnode ,
430- u32 * nr_irqs , u32 * nr_contexts )
446+ u32 * nr_irqs , u32 * nr_contexts ,
447+ u32 * gsi_base , u32 * id )
431448{
432449 int rc ;
433450
434- /*
435- * Currently, only OF fwnode is supported so extend this
436- * function for ACPI support.
437- */
438- if (!is_of_node (fwnode ))
439- return - EINVAL ;
451+ if (!is_of_node (fwnode )) {
452+ rc = riscv_acpi_get_gsi_info (fwnode , gsi_base , id , nr_irqs , NULL );
453+ if (rc ) {
454+ pr_err ("%pfwP: failed to find GSI mapping\n" , fwnode );
455+ return rc ;
456+ }
457+
458+ * nr_contexts = acpi_rintc_get_plic_nr_contexts (* id );
459+ if (WARN_ON (!* nr_contexts )) {
460+ pr_err ("%pfwP: no PLIC context available\n" , fwnode );
461+ return - EINVAL ;
462+ }
463+
464+ return 0 ;
465+ }
440466
441467 rc = of_property_read_u32 (to_of_node (fwnode ), "riscv,ndev" , nr_irqs );
442468 if (rc ) {
@@ -450,22 +476,28 @@ static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
450476 return - EINVAL ;
451477 }
452478
479+ * gsi_base = 0 ;
480+ * id = 0 ;
481+
453482 return 0 ;
454483}
455484
456485static int plic_parse_context_parent (struct fwnode_handle * fwnode , u32 context ,
457- u32 * parent_hwirq , int * parent_cpu )
486+ u32 * parent_hwirq , int * parent_cpu , u32 id )
458487{
459488 struct of_phandle_args parent ;
460489 unsigned long hartid ;
461490 int rc ;
462491
463- /*
464- * Currently, only OF fwnode is supported so extend this
465- * function for ACPI support.
466- */
467- if (!is_of_node (fwnode ))
468- return - EINVAL ;
492+ if (!is_of_node (fwnode )) {
493+ hartid = acpi_rintc_ext_parent_to_hartid (id , context );
494+ if (hartid == INVALID_HARTID )
495+ return - EINVAL ;
496+
497+ * parent_cpu = riscv_hartid_to_cpuid (hartid );
498+ * parent_hwirq = RV_IRQ_EXT ;
499+ return 0 ;
500+ }
469501
470502 rc = of_irq_parse_one (to_of_node (fwnode ), context , & parent );
471503 if (rc )
@@ -489,6 +521,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
489521 struct plic_priv * priv ;
490522 irq_hw_number_t hwirq ;
491523 void __iomem * regs ;
524+ int id , context_id ;
525+ u32 gsi_base ;
492526
493527 if (is_of_node (fwnode )) {
494528 const struct of_device_id * id ;
@@ -501,10 +535,12 @@ static int plic_probe(struct fwnode_handle *fwnode)
501535 if (!regs )
502536 return - ENOMEM ;
503537 } else {
504- return - ENODEV ;
538+ regs = devm_platform_ioremap_resource (to_platform_device (fwnode -> dev ), 0 );
539+ if (IS_ERR (regs ))
540+ return PTR_ERR (regs );
505541 }
506542
507- error = plic_parse_nr_irqs_and_contexts (fwnode , & nr_irqs , & nr_contexts );
543+ error = plic_parse_nr_irqs_and_contexts (fwnode , & nr_irqs , & nr_contexts , & gsi_base , & id );
508544 if (error )
509545 goto fail_free_regs ;
510546
@@ -518,6 +554,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
518554 priv -> plic_quirks = plic_quirks ;
519555 priv -> nr_irqs = nr_irqs ;
520556 priv -> regs = regs ;
557+ priv -> gsi_base = gsi_base ;
558+ priv -> acpi_plic_id = id ;
521559
522560 priv -> prio_save = bitmap_zalloc (nr_irqs , GFP_KERNEL );
523561 if (!priv -> prio_save ) {
@@ -526,12 +564,23 @@ static int plic_probe(struct fwnode_handle *fwnode)
526564 }
527565
528566 for (i = 0 ; i < nr_contexts ; i ++ ) {
529- error = plic_parse_context_parent (fwnode , i , & parent_hwirq , & cpu );
567+ error = plic_parse_context_parent (fwnode , i , & parent_hwirq , & cpu ,
568+ priv -> acpi_plic_id );
530569 if (error ) {
531570 pr_warn ("%pfwP: hwirq for context%d not found\n" , fwnode , i );
532571 continue ;
533572 }
534573
574+ if (is_of_node (fwnode )) {
575+ context_id = i ;
576+ } else {
577+ context_id = acpi_rintc_get_plic_context (priv -> acpi_plic_id , i );
578+ if (context_id == INVALID_CONTEXT ) {
579+ pr_warn ("%pfwP: invalid context id for context%d\n" , fwnode , i );
580+ continue ;
581+ }
582+ }
583+
535584 /*
536585 * Skip contexts other than external interrupts for our
537586 * privilege level.
@@ -569,10 +618,10 @@ static int plic_probe(struct fwnode_handle *fwnode)
569618 cpumask_set_cpu (cpu , & priv -> lmask );
570619 handler -> present = true;
571620 handler -> hart_base = priv -> regs + CONTEXT_BASE +
572- i * CONTEXT_SIZE ;
621+ context_id * CONTEXT_SIZE ;
573622 raw_spin_lock_init (& handler -> enable_lock );
574623 handler -> enable_base = priv -> regs + CONTEXT_ENABLE_BASE +
575- i * CONTEXT_ENABLE_SIZE ;
624+ context_id * CONTEXT_ENABLE_SIZE ;
576625 handler -> priv = priv ;
577626
578627 handler -> enable_save = kcalloc (DIV_ROUND_UP (nr_irqs , 32 ),
@@ -588,8 +637,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
588637 nr_handlers ++ ;
589638 }
590639
591- priv -> irqdomain = irq_domain_add_linear ( to_of_node ( fwnode ) , nr_irqs + 1 ,
592- & plic_irqdomain_ops , priv );
640+ priv -> irqdomain = irq_domain_create_linear ( fwnode , nr_irqs + 1 ,
641+ & plic_irqdomain_ops , priv );
593642 if (WARN_ON (!priv -> irqdomain ))
594643 goto fail_cleanup_contexts ;
595644
@@ -626,13 +675,18 @@ static int plic_probe(struct fwnode_handle *fwnode)
626675 }
627676 }
628677
678+ #ifdef CONFIG_ACPI
679+ if (!acpi_disabled )
680+ acpi_dev_clear_dependencies (ACPI_COMPANION (fwnode -> dev ));
681+ #endif
682+
629683 pr_info ("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n" ,
630684 fwnode , nr_irqs , nr_handlers , nr_contexts );
631685 return 0 ;
632686
633687fail_cleanup_contexts :
634688 for (i = 0 ; i < nr_contexts ; i ++ ) {
635- if (plic_parse_context_parent (fwnode , i , & parent_hwirq , & cpu ))
689+ if (plic_parse_context_parent (fwnode , i , & parent_hwirq , & cpu , priv -> acpi_plic_id ))
636690 continue ;
637691 if (parent_hwirq != RV_IRQ_EXT || cpu < 0 )
638692 continue ;
@@ -663,6 +717,7 @@ static struct platform_driver plic_driver = {
663717 .name = "riscv-plic" ,
664718 .of_match_table = plic_match ,
665719 .suppress_bind_attrs = true,
720+ .acpi_match_table = ACPI_PTR (plic_acpi_match ),
666721 },
667722 .probe = plic_platform_probe ,
668723};
0 commit comments