@@ -436,6 +436,135 @@ void bcmasp_core_clock_set_intf(struct bcmasp_intf *intf, bool en)
436436 spin_unlock_irqrestore (& priv -> clk_lock , flags );
437437}
438438
439+ static irqreturn_t bcmasp_isr_wol (int irq , void * data )
440+ {
441+ struct bcmasp_priv * priv = data ;
442+ u32 status ;
443+
444+ /* No L3 IRQ, so we good */
445+ if (priv -> wol_irq <= 0 )
446+ goto irq_handled ;
447+
448+ status = wakeup_intr2_core_rl (priv , ASP_WAKEUP_INTR2_STATUS ) &
449+ ~wakeup_intr2_core_rl (priv , ASP_WAKEUP_INTR2_MASK_STATUS );
450+ wakeup_intr2_core_wl (priv , status , ASP_WAKEUP_INTR2_CLEAR );
451+
452+ irq_handled :
453+ pm_wakeup_event (& priv -> pdev -> dev , 0 );
454+ return IRQ_HANDLED ;
455+ }
456+
457+ static int bcmasp_get_and_request_irq (struct bcmasp_priv * priv , int i )
458+ {
459+ struct platform_device * pdev = priv -> pdev ;
460+ int irq , ret ;
461+
462+ irq = platform_get_irq_optional (pdev , i );
463+ if (irq < 0 )
464+ return irq ;
465+
466+ ret = devm_request_irq (& pdev -> dev , irq , bcmasp_isr_wol , 0 ,
467+ pdev -> name , priv );
468+ if (ret )
469+ return ret ;
470+
471+ return irq ;
472+ }
473+
474+ static void bcmasp_init_wol_shared (struct bcmasp_priv * priv )
475+ {
476+ struct platform_device * pdev = priv -> pdev ;
477+ struct device * dev = & pdev -> dev ;
478+ int irq ;
479+
480+ irq = bcmasp_get_and_request_irq (priv , 1 );
481+ if (irq < 0 ) {
482+ dev_warn (dev , "Failed to init WoL irq: %d\n" , irq );
483+ return ;
484+ }
485+
486+ priv -> wol_irq = irq ;
487+ priv -> wol_irq_enabled_mask = 0 ;
488+ device_set_wakeup_capable (& pdev -> dev , 1 );
489+ }
490+
491+ static void bcmasp_enable_wol_shared (struct bcmasp_intf * intf , bool en )
492+ {
493+ struct bcmasp_priv * priv = intf -> parent ;
494+ struct device * dev = & priv -> pdev -> dev ;
495+
496+ if (en ) {
497+ if (priv -> wol_irq_enabled_mask ) {
498+ set_bit (intf -> port , & priv -> wol_irq_enabled_mask );
499+ return ;
500+ }
501+
502+ /* First enable */
503+ set_bit (intf -> port , & priv -> wol_irq_enabled_mask );
504+ enable_irq_wake (priv -> wol_irq );
505+ device_set_wakeup_enable (dev , 1 );
506+ } else {
507+ if (!priv -> wol_irq_enabled_mask )
508+ return ;
509+
510+ clear_bit (intf -> port , & priv -> wol_irq_enabled_mask );
511+ if (priv -> wol_irq_enabled_mask )
512+ return ;
513+
514+ /* Last disable */
515+ disable_irq_wake (priv -> wol_irq );
516+ device_set_wakeup_enable (dev , 0 );
517+ }
518+ }
519+
520+ static void bcmasp_wol_irq_destroy_shared (struct bcmasp_priv * priv )
521+ {
522+ if (priv -> wol_irq > 0 )
523+ free_irq (priv -> wol_irq , priv );
524+ }
525+
526+ static void bcmasp_init_wol_per_intf (struct bcmasp_priv * priv )
527+ {
528+ struct platform_device * pdev = priv -> pdev ;
529+ struct device * dev = & pdev -> dev ;
530+ struct bcmasp_intf * intf ;
531+ int irq ;
532+
533+ list_for_each_entry (intf , & priv -> intfs , list ) {
534+ irq = bcmasp_get_and_request_irq (priv , intf -> port + 1 );
535+ if (irq < 0 ) {
536+ dev_warn (dev , "Failed to init WoL irq(port %d): %d\n" ,
537+ intf -> port , irq );
538+ continue ;
539+ }
540+
541+ intf -> wol_irq = irq ;
542+ intf -> wol_irq_enabled = false;
543+ device_set_wakeup_capable (& pdev -> dev , 1 );
544+ }
545+ }
546+
547+ static void bcmasp_enable_wol_per_intf (struct bcmasp_intf * intf , bool en )
548+ {
549+ struct device * dev = & intf -> parent -> pdev -> dev ;
550+
551+ if (en ^ intf -> wol_irq_enabled )
552+ irq_set_irq_wake (intf -> wol_irq , en );
553+
554+ intf -> wol_irq_enabled = en ;
555+ device_set_wakeup_enable (dev , en );
556+ }
557+
558+ static void bcmasp_wol_irq_destroy_per_intf (struct bcmasp_priv * priv )
559+ {
560+ struct bcmasp_intf * intf ;
561+
562+ list_for_each_entry (intf , & priv -> intfs , list ) {
563+ if (intf -> wol_irq > 0 )
564+ free_irq (intf -> wol_irq , priv );
565+ }
566+ }
567+
439568static struct bcmasp_hw_info v20_hw_info = {
440569 .rx_ctrl_flush = ASP_RX_CTRL_FLUSH ,
441570 .umac2fb = UMAC2FB_OFFSET ,
@@ -445,6 +574,9 @@ static struct bcmasp_hw_info v20_hw_info = {
445574};
446575
447576static const struct bcmasp_plat_data v20_plat_data = {
577+ .init_wol = bcmasp_init_wol_per_intf ,
578+ .enable_wol = bcmasp_enable_wol_per_intf ,
579+ .destroy_wol = bcmasp_wol_irq_destroy_per_intf ,
448580 .hw_info = & v20_hw_info ,
449581};
450582
@@ -458,6 +590,9 @@ static struct bcmasp_hw_info v21_hw_info = {
458590};
459591
460592static const struct bcmasp_plat_data v21_plat_data = {
593+ .init_wol = bcmasp_init_wol_shared ,
594+ .enable_wol = bcmasp_enable_wol_shared ,
595+ .destroy_wol = bcmasp_wol_irq_destroy_shared ,
461596 .hw_info = & v21_hw_info ,
462597};
463598
@@ -521,12 +656,16 @@ static int bcmasp_probe(struct platform_device *pdev)
521656 priv -> pdev = pdev ;
522657 spin_lock_init (& priv -> mda_lock );
523658 spin_lock_init (& priv -> clk_lock );
659+ mutex_init (& priv -> wol_lock );
524660 INIT_LIST_HEAD (& priv -> intfs );
525661
526662 pdata = device_get_match_data (& pdev -> dev );
527663 if (!pdata )
528664 return dev_err_probe (dev , - EINVAL , "unable to find platform data\n" );
529665
666+ priv -> init_wol = pdata -> init_wol ;
667+ priv -> enable_wol = pdata -> enable_wol ;
668+ priv -> destroy_wol = pdata -> destroy_wol ;
530669 priv -> hw_info = pdata -> hw_info ;
531670
532671 /* Enable all clocks to ensure successful probing */
@@ -570,6 +709,9 @@ static int bcmasp_probe(struct platform_device *pdev)
570709 i ++ ;
571710 }
572711
712+ /* Check and enable WoL */
713+ priv -> init_wol (priv );
714+
573715 /* Drop the clock reference count now and let ndo_open()/ndo_close()
574716 * manage it for us from now on.
575717 */
@@ -585,6 +727,7 @@ static int bcmasp_probe(struct platform_device *pdev)
585727 if (ret ) {
586728 netdev_err (intf -> ndev ,
587729 "failed to register net_device: %d\n" , ret );
730+ priv -> destroy_wol (priv );
588731 bcmasp_remove_intfs (priv );
589732 goto of_put_exit ;
590733 }
@@ -605,6 +748,7 @@ static int bcmasp_remove(struct platform_device *pdev)
605748 if (!priv )
606749 return 0 ;
607750
751+ priv -> destroy_wol (priv );
608752 bcmasp_remove_intfs (priv );
609753
610754 return 0 ;
0 commit comments