6464#define PLIC_QUIRK_EDGE_INTERRUPT 0
6565
6666struct plic_priv {
67+ struct device * dev ;
6768 struct cpumask lmask ;
6869 struct irq_domain * irqdomain ;
6970 void __iomem * regs ;
@@ -406,30 +407,50 @@ static int plic_starting_cpu(unsigned int cpu)
406407 return 0 ;
407408}
408409
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 )
412421{
413422 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 ;
416425 struct plic_handler * handler ;
426+ struct plic_priv * priv ;
427+ bool cpuhp_setup ;
417428 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+ }
418438
419439 priv = kzalloc (sizeof (* priv ), GFP_KERNEL );
420440 if (!priv )
421441 return - ENOMEM ;
422442
443+ priv -> dev = dev ;
423444 priv -> plic_quirks = plic_quirks ;
424445
425- priv -> regs = of_iomap (node , 0 );
446+ priv -> regs = of_iomap (to_of_node ( dev -> fwnode ) , 0 );
426447 if (WARN_ON (!priv -> regs )) {
427448 error = - EIO ;
428449 goto out_free_priv ;
429450 }
430451
431452 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 );
433454 if (WARN_ON (!nr_irqs ))
434455 goto out_iounmap ;
435456
@@ -439,13 +460,13 @@ static int __init __plic_init(struct device_node *node,
439460 if (!priv -> prio_save )
440461 goto out_free_priority_reg ;
441462
442- nr_contexts = of_irq_count (node );
463+ nr_contexts = of_irq_count (to_of_node ( dev -> fwnode ) );
443464 if (WARN_ON (!nr_contexts ))
444465 goto out_free_priority_reg ;
445466
446467 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 );
449470 if (WARN_ON (!priv -> irqdomain ))
450471 goto out_free_priority_reg ;
451472
@@ -455,7 +476,7 @@ static int __init __plic_init(struct device_node *node,
455476 int cpu ;
456477 unsigned long hartid ;
457478
458- if (of_irq_parse_one (node , i , & parent )) {
479+ if (of_irq_parse_one (to_of_node ( dev -> fwnode ) , i , & parent )) {
459480 pr_err ("failed to parse parent for context %d.\n" , i );
460481 continue ;
461482 }
@@ -491,7 +512,7 @@ static int __init __plic_init(struct device_node *node,
491512
492513 /* Find parent domain and register chained handler */
493514 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 );
495516 if (plic_parent_irq )
496517 irq_set_chained_handler (plic_parent_irq ,
497518 plic_handle_irq );
@@ -533,20 +554,29 @@ static int __init __plic_init(struct device_node *node,
533554
534555 /*
535556 * 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 .
538559 */
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+ }
546576 }
547577
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 );
550580 return 0 ;
551581
552582out_free_enable_reg :
@@ -563,20 +593,11 @@ static int __init __plic_init(struct device_node *node,
563593 return error ;
564594}
565595
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