@@ -127,6 +127,10 @@ struct lynx_28g_lane {
127127struct lynx_28g_priv {
128128 void __iomem * base ;
129129 struct device * dev ;
130+ /* Serialize concurrent access to registers shared between lanes,
131+ * like PCCn
132+ */
133+ spinlock_t pcc_lock ;
130134 struct lynx_28g_pll pll [LYNX_28G_NUM_PLL ];
131135 struct lynx_28g_lane lane [LYNX_28G_NUM_LANE ];
132136
@@ -397,6 +401,8 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
397401 if (powered_up )
398402 lynx_28g_power_off (phy );
399403
404+ spin_lock (& priv -> pcc_lock );
405+
400406 switch (submode ) {
401407 case PHY_INTERFACE_MODE_SGMII :
402408 case PHY_INTERFACE_MODE_1000BASEX :
@@ -413,6 +419,8 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
413419 lane -> interface = submode ;
414420
415421out :
422+ spin_unlock (& priv -> pcc_lock );
423+
416424 /* Power up the lane if necessary */
417425 if (powered_up )
418426 lynx_28g_power_on (phy );
@@ -508,11 +516,12 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
508516 for (i = 0 ; i < LYNX_28G_NUM_LANE ; i ++ ) {
509517 lane = & priv -> lane [i ];
510518
511- if (!lane -> init )
512- continue ;
519+ mutex_lock (& lane -> phy -> mutex );
513520
514- if (!lane -> powered_up )
521+ if (!lane -> init || !lane -> powered_up ) {
522+ mutex_unlock (& lane -> phy -> mutex );
515523 continue ;
524+ }
516525
517526 rrstctl = lynx_28g_lane_read (lane , LNaRRSTCTL );
518527 if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK )) {
@@ -521,6 +530,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
521530 rrstctl = lynx_28g_lane_read (lane , LNaRRSTCTL );
522531 } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE ));
523532 }
533+
534+ mutex_unlock (& lane -> phy -> mutex );
524535 }
525536 queue_delayed_work (system_power_efficient_wq , & priv -> cdr_check ,
526537 msecs_to_jiffies (1000 ));
@@ -593,6 +604,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
593604
594605 dev_set_drvdata (dev , priv );
595606
607+ spin_lock_init (& priv -> pcc_lock );
596608 INIT_DELAYED_WORK (& priv -> cdr_check , lynx_28g_cdr_lock_check );
597609
598610 queue_delayed_work (system_power_efficient_wq , & priv -> cdr_check ,
@@ -604,6 +616,14 @@ static int lynx_28g_probe(struct platform_device *pdev)
604616 return PTR_ERR_OR_ZERO (provider );
605617}
606618
619+ static void lynx_28g_remove (struct platform_device * pdev )
620+ {
621+ struct device * dev = & pdev -> dev ;
622+ struct lynx_28g_priv * priv = dev_get_drvdata (dev );
623+
624+ cancel_delayed_work_sync (& priv -> cdr_check );
625+ }
626+
607627static const struct of_device_id lynx_28g_of_match_table [] = {
608628 { .compatible = "fsl,lynx-28g" },
609629 { },
@@ -612,6 +632,7 @@ MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
612632
613633static struct platform_driver lynx_28g_driver = {
614634 .probe = lynx_28g_probe ,
635+ .remove_new = lynx_28g_remove ,
615636 .driver = {
616637 .name = "lynx-28g" ,
617638 .of_match_table = lynx_28g_of_match_table ,
0 commit comments