4
4
* Copyright (C) 2018 Christoph Hellwig
5
5
*/
6
6
#define pr_fmt (fmt ) "riscv-plic: " fmt
7
+ #include <linux/acpi.h>
7
8
#include <linux/cpu.h>
8
9
#include <linux/interrupt.h>
9
10
#include <linux/io.h>
@@ -71,6 +72,8 @@ struct plic_priv {
71
72
unsigned long plic_quirks ;
72
73
unsigned int nr_irqs ;
73
74
unsigned long * prio_save ;
75
+ u32 gsi_base ;
76
+ int acpi_plic_id ;
74
77
};
75
78
76
79
struct plic_handler {
@@ -325,6 +328,10 @@ static int plic_irq_domain_translate(struct irq_domain *d,
325
328
{
326
329
struct plic_priv * priv = d -> host_data ;
327
330
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
+
328
335
if (test_bit (PLIC_QUIRK_EDGE_INTERRUPT , & priv -> plic_quirks ))
329
336
return irq_domain_translate_twocell (d , fwspec , hwirq , type );
330
337
@@ -426,17 +433,36 @@ static const struct of_device_id plic_match[] = {
426
433
{}
427
434
};
428
435
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
429
445
static 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 )
431
448
{
432
449
int rc ;
433
450
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
+ }
440
466
441
467
rc = of_property_read_u32 (to_of_node (fwnode ), "riscv,ndev" , nr_irqs );
442
468
if (rc ) {
@@ -450,22 +476,28 @@ static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
450
476
return - EINVAL ;
451
477
}
452
478
479
+ * gsi_base = 0 ;
480
+ * id = 0 ;
481
+
453
482
return 0 ;
454
483
}
455
484
456
485
static 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 )
458
487
{
459
488
struct of_phandle_args parent ;
460
489
unsigned long hartid ;
461
490
int rc ;
462
491
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
+ }
469
501
470
502
rc = of_irq_parse_one (to_of_node (fwnode ), context , & parent );
471
503
if (rc )
@@ -489,6 +521,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
489
521
struct plic_priv * priv ;
490
522
irq_hw_number_t hwirq ;
491
523
void __iomem * regs ;
524
+ int id , context_id ;
525
+ u32 gsi_base ;
492
526
493
527
if (is_of_node (fwnode )) {
494
528
const struct of_device_id * id ;
@@ -501,10 +535,12 @@ static int plic_probe(struct fwnode_handle *fwnode)
501
535
if (!regs )
502
536
return - ENOMEM ;
503
537
} 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 );
505
541
}
506
542
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 );
508
544
if (error )
509
545
goto fail_free_regs ;
510
546
@@ -518,6 +554,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
518
554
priv -> plic_quirks = plic_quirks ;
519
555
priv -> nr_irqs = nr_irqs ;
520
556
priv -> regs = regs ;
557
+ priv -> gsi_base = gsi_base ;
558
+ priv -> acpi_plic_id = id ;
521
559
522
560
priv -> prio_save = bitmap_zalloc (nr_irqs , GFP_KERNEL );
523
561
if (!priv -> prio_save ) {
@@ -526,12 +564,23 @@ static int plic_probe(struct fwnode_handle *fwnode)
526
564
}
527
565
528
566
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 );
530
569
if (error ) {
531
570
pr_warn ("%pfwP: hwirq for context%d not found\n" , fwnode , i );
532
571
continue ;
533
572
}
534
573
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
+
535
584
/*
536
585
* Skip contexts other than external interrupts for our
537
586
* privilege level.
@@ -569,10 +618,10 @@ static int plic_probe(struct fwnode_handle *fwnode)
569
618
cpumask_set_cpu (cpu , & priv -> lmask );
570
619
handler -> present = true;
571
620
handler -> hart_base = priv -> regs + CONTEXT_BASE +
572
- i * CONTEXT_SIZE ;
621
+ context_id * CONTEXT_SIZE ;
573
622
raw_spin_lock_init (& handler -> enable_lock );
574
623
handler -> enable_base = priv -> regs + CONTEXT_ENABLE_BASE +
575
- i * CONTEXT_ENABLE_SIZE ;
624
+ context_id * CONTEXT_ENABLE_SIZE ;
576
625
handler -> priv = priv ;
577
626
578
627
handler -> enable_save = kcalloc (DIV_ROUND_UP (nr_irqs , 32 ),
@@ -588,8 +637,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
588
637
nr_handlers ++ ;
589
638
}
590
639
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 );
593
642
if (WARN_ON (!priv -> irqdomain ))
594
643
goto fail_cleanup_contexts ;
595
644
@@ -626,13 +675,18 @@ static int plic_probe(struct fwnode_handle *fwnode)
626
675
}
627
676
}
628
677
678
+ #ifdef CONFIG_ACPI
679
+ if (!acpi_disabled )
680
+ acpi_dev_clear_dependencies (ACPI_COMPANION (fwnode -> dev ));
681
+ #endif
682
+
629
683
pr_info ("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n" ,
630
684
fwnode , nr_irqs , nr_handlers , nr_contexts );
631
685
return 0 ;
632
686
633
687
fail_cleanup_contexts :
634
688
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 ))
636
690
continue ;
637
691
if (parent_hwirq != RV_IRQ_EXT || cpu < 0 )
638
692
continue ;
@@ -663,6 +717,7 @@ static struct platform_driver plic_driver = {
663
717
.name = "riscv-plic" ,
664
718
.of_match_table = plic_match ,
665
719
.suppress_bind_attrs = true,
720
+ .acpi_match_table = ACPI_PTR (plic_acpi_match ),
666
721
},
667
722
.probe = plic_platform_probe ,
668
723
};
0 commit comments