64
64
#define PLIC_QUIRK_EDGE_INTERRUPT 0
65
65
66
66
struct plic_priv {
67
+ struct device * dev ;
67
68
struct cpumask lmask ;
68
69
struct irq_domain * irqdomain ;
69
70
void __iomem * regs ;
@@ -406,30 +407,50 @@ static int plic_starting_cpu(unsigned int cpu)
406
407
return 0 ;
407
408
}
408
409
409
- static int __init __plic_init (struct device_node * node ,
410
- struct device_node * parent ,
411
- unsigned long plic_quirks )
410
+ static const struct of_device_id plic_match [] = {
411
+ { .compatible = "sifive,plic-1.0.0" },
412
+ { .compatible = "riscv,plic0" },
413
+ { .compatible = "andestech,nceplic100" ,
414
+ .data = (const void * )BIT (PLIC_QUIRK_EDGE_INTERRUPT ) },
415
+ { .compatible = "thead,c900-plic" ,
416
+ .data = (const void * )BIT (PLIC_QUIRK_EDGE_INTERRUPT ) },
417
+ {}
418
+ };
419
+
420
+ static int plic_probe (struct platform_device * pdev )
412
421
{
413
422
int error = 0 , nr_contexts , nr_handlers = 0 , i ;
414
- u32 nr_irqs ;
415
- struct plic_priv * priv ;
423
+ struct device * dev = & pdev -> dev ;
424
+ unsigned long plic_quirks = 0 ;
416
425
struct plic_handler * handler ;
426
+ struct plic_priv * priv ;
427
+ bool cpuhp_setup ;
417
428
unsigned int cpu ;
429
+ u32 nr_irqs ;
430
+
431
+ if (is_of_node (dev -> fwnode )) {
432
+ const struct of_device_id * id ;
433
+
434
+ id = of_match_node (plic_match , to_of_node (dev -> fwnode ));
435
+ if (id )
436
+ plic_quirks = (unsigned long )id -> data ;
437
+ }
418
438
419
439
priv = kzalloc (sizeof (* priv ), GFP_KERNEL );
420
440
if (!priv )
421
441
return - ENOMEM ;
422
442
443
+ priv -> dev = dev ;
423
444
priv -> plic_quirks = plic_quirks ;
424
445
425
- priv -> regs = of_iomap (node , 0 );
446
+ priv -> regs = of_iomap (to_of_node ( dev -> fwnode ) , 0 );
426
447
if (WARN_ON (!priv -> regs )) {
427
448
error = - EIO ;
428
449
goto out_free_priv ;
429
450
}
430
451
431
452
error = - EINVAL ;
432
- of_property_read_u32 (node , "riscv,ndev" , & nr_irqs );
453
+ of_property_read_u32 (to_of_node ( dev -> fwnode ) , "riscv,ndev" , & nr_irqs );
433
454
if (WARN_ON (!nr_irqs ))
434
455
goto out_iounmap ;
435
456
@@ -439,13 +460,13 @@ static int __init __plic_init(struct device_node *node,
439
460
if (!priv -> prio_save )
440
461
goto out_free_priority_reg ;
441
462
442
- nr_contexts = of_irq_count (node );
463
+ nr_contexts = of_irq_count (to_of_node ( dev -> fwnode ) );
443
464
if (WARN_ON (!nr_contexts ))
444
465
goto out_free_priority_reg ;
445
466
446
467
error = - ENOMEM ;
447
- priv -> irqdomain = irq_domain_add_linear (node , nr_irqs + 1 ,
448
- & plic_irqdomain_ops , priv );
468
+ priv -> irqdomain = irq_domain_add_linear (to_of_node ( dev -> fwnode ) , nr_irqs + 1 ,
469
+ & plic_irqdomain_ops , priv );
449
470
if (WARN_ON (!priv -> irqdomain ))
450
471
goto out_free_priority_reg ;
451
472
@@ -455,7 +476,7 @@ static int __init __plic_init(struct device_node *node,
455
476
int cpu ;
456
477
unsigned long hartid ;
457
478
458
- if (of_irq_parse_one (node , i , & parent )) {
479
+ if (of_irq_parse_one (to_of_node ( dev -> fwnode ) , i , & parent )) {
459
480
pr_err ("failed to parse parent for context %d.\n" , i );
460
481
continue ;
461
482
}
@@ -491,7 +512,7 @@ static int __init __plic_init(struct device_node *node,
491
512
492
513
/* Find parent domain and register chained handler */
493
514
if (!plic_parent_irq && irq_find_host (parent .np )) {
494
- plic_parent_irq = irq_of_parse_and_map (node , i );
515
+ plic_parent_irq = irq_of_parse_and_map (to_of_node ( dev -> fwnode ) , i );
495
516
if (plic_parent_irq )
496
517
irq_set_chained_handler (plic_parent_irq ,
497
518
plic_handle_irq );
@@ -533,20 +554,29 @@ static int __init __plic_init(struct device_node *node,
533
554
534
555
/*
535
556
* We can have multiple PLIC instances so setup cpuhp state
536
- * and register syscore operations only when context handler
537
- * for current/boot CPU is present .
557
+ * and register syscore operations only once after context
558
+ * handlers of all online CPUs are initialized .
538
559
*/
539
- handler = this_cpu_ptr (& plic_handlers );
540
- if (handler -> present && !plic_cpuhp_setup_done ) {
541
- cpuhp_setup_state (CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING ,
542
- "irqchip/sifive/plic:starting" ,
543
- plic_starting_cpu , plic_dying_cpu );
544
- register_syscore_ops (& plic_irq_syscore_ops );
545
- plic_cpuhp_setup_done = true;
560
+ if (!plic_cpuhp_setup_done ) {
561
+ cpuhp_setup = true;
562
+ for_each_online_cpu (cpu ) {
563
+ handler = per_cpu_ptr (& plic_handlers , cpu );
564
+ if (!handler -> present ) {
565
+ cpuhp_setup = false;
566
+ break ;
567
+ }
568
+ }
569
+ if (cpuhp_setup ) {
570
+ cpuhp_setup_state (CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING ,
571
+ "irqchip/sifive/plic:starting" ,
572
+ plic_starting_cpu , plic_dying_cpu );
573
+ register_syscore_ops (& plic_irq_syscore_ops );
574
+ plic_cpuhp_setup_done = true;
575
+ }
546
576
}
547
577
548
- pr_info ("%pOFP: mapped %d interrupts with %d handlers for"
549
- " %d contexts.\n" , node , nr_irqs , nr_handlers , nr_contexts );
578
+ pr_info ("%pOFP: mapped %d interrupts with %d handlers for %d contexts.\n" ,
579
+ to_of_node ( dev -> fwnode ) , nr_irqs , nr_handlers , nr_contexts );
550
580
return 0 ;
551
581
552
582
out_free_enable_reg :
@@ -563,20 +593,11 @@ static int __init __plic_init(struct device_node *node,
563
593
return error ;
564
594
}
565
595
566
- static int __init plic_init (struct device_node * node ,
567
- struct device_node * parent )
568
- {
569
- return __plic_init (node , parent , 0 );
570
- }
571
-
572
- IRQCHIP_DECLARE (sifive_plic , "sifive,plic-1.0.0" , plic_init );
573
- IRQCHIP_DECLARE (riscv_plic0 , "riscv,plic0" , plic_init ); /* for legacy systems */
574
-
575
- static int __init plic_edge_init (struct device_node * node ,
576
- struct device_node * parent )
577
- {
578
- return __plic_init (node , parent , BIT (PLIC_QUIRK_EDGE_INTERRUPT ));
579
- }
580
-
581
- IRQCHIP_DECLARE (andestech_nceplic100 , "andestech,nceplic100" , plic_edge_init );
582
- IRQCHIP_DECLARE (thead_c900_plic , "thead,c900-plic" , plic_edge_init );
596
+ static struct platform_driver plic_driver = {
597
+ .driver = {
598
+ .name = "riscv-plic" ,
599
+ .of_match_table = plic_match ,
600
+ },
601
+ .probe = plic_probe ,
602
+ };
603
+ builtin_platform_driver (plic_driver );
0 commit comments