@@ -5360,65 +5360,77 @@ static void mux_poll(struct work_struct *work)
53605360 struct mtk_eth * eth = mac -> hw ;
53615361 struct net_device * dev = eth -> netdev [mac -> id ];
53625362 unsigned int new_channel ;
5363- struct phylink * tmp_pl ;
5363+ struct phylink * old_pl ;
53645364 int sfp_present ;
5365+ int err ;
5366+ bool running ;
5367+ bool transitional_old_pl ;
53655368
53665369 //dev_info(eth->dev, "ethernet mux: %s:%d\n",__func__,__LINE__);
53675370 if (IS_ERR (mux -> mod_def0_gpio ) || IS_ERR (mux -> chan_sel_gpio ))
53685371 goto reschedule ;
53695372
53705373 sfp_present = gpiod_get_value_cansleep (mux -> mod_def0_gpio );
5374+ if (sfp_present < 0 )
5375+ goto reschedule ;
53715376 new_channel = sfp_present ? mux -> sfp_present_channel : !mux -> sfp_present_channel ;
53725377
5373- if (mux -> channel == new_channel || ! netif_running ( dev ) )
5378+ if (mux -> channel == new_channel )
53745379 goto reschedule ;
53755380
5381+ running = netif_running (dev );
5382+
53765383 dev_info (eth -> dev , "ethernet mux: line:%d new channel:%d,sfp:%d\n" ,__LINE__ , new_channel ,sfp_present );
53775384
5385+ if (mux -> data [mux -> channel ] && mux -> data [mux -> channel ]-> phylink )
5386+ old_pl = mux -> data [mux -> channel ]-> phylink ;
5387+ else
5388+ old_pl = mac -> phylink ;
5389+ transitional_old_pl = old_pl && old_pl == mux -> initial_phylink ;
5390+
53785391 rtnl_lock ();
5379- mtk_stop (dev );
5392+ if (running )
5393+ mtk_stop (dev );
53805394 rtnl_unlock ();
53815395
5382- /* Destroy old phylink if it exists */
5383- if (mux -> data [mux -> channel ] && mux -> data [mux -> channel ]-> phylink ) {
5384- tmp_pl = mux -> data [mux -> channel ]-> phylink ;
5396+ if (old_pl ) {
53855397 dev_info (eth -> dev , "Destroying phylink for channel %u\n" , mux -> channel );
5386- } else {
5387- /* phylink was created by mtk_add_mac,
5388- we need to release the reference to available PCS from phylink config
5389- */
5390- tmp_pl = mac -> phylink ;
5398+ if (mux -> data [mux -> channel ] &&
5399+ mux -> data [mux -> channel ]-> phylink == old_pl )
5400+ mux -> data [mux -> channel ]-> phylink = NULL ;
5401+ phylink_destroy (old_pl );
5402+ if (transitional_old_pl )
5403+ mux -> initial_phylink = NULL ;
53915404 }
5392- if (tmp_pl ) {
5393- phylink_destroy (tmp_pl );
5394- mux -> data [mux -> channel ]-> phylink = NULL ;
5395- }
5396-
5397- dev_info (eth -> dev , "ethernet mux: switch to channel%d\n" , new_channel );
53985405
5399- /* Create new phylink if not yet present */
5406+ /* Build target phylink after tearing down the old one, since both
5407+ * instances share the same PCS objects in mac->available_pcs.
5408+ */
54005409 if (!mux -> data [new_channel ]-> phylink ) {
54015410 mux -> data [new_channel ]-> phylink = mtk_mux_create_phylink (mux , new_channel );
54025411 if (IS_ERR (mux -> data [new_channel ]-> phylink )) {
54035412 dev_err (eth -> dev , "Failed to create new phylink\n" );
5404- mux -> data [new_channel ]-> phylink = NULL ;
5405- goto out_unlock ;
5413+ mux -> data [new_channel ]-> phylink = NULL ;
5414+ goto reschedule ;
54065415 }
54075416 }
54085417
5418+ rtnl_lock ();
5419+ dev_info (eth -> dev , "ethernet mux: switch to channel%d\n" , new_channel );
54095420 mac -> of_node = mux -> data [new_channel ]-> of_node ;
54105421 mac -> phylink = mux -> data [new_channel ]-> phylink ;
54115422
5412- rtnl_lock ();
5413- mtk_open (dev );
5414- rtnl_unlock ();
5423+ if (running ) {
5424+ err = mtk_open (dev );
5425+ if (err )
5426+ dev_err (eth -> dev , "ethernet mux: failed to open dev on channel %u: %d\n" ,
5427+ new_channel , err );
5428+ }
54155429
54165430 gpiod_set_value_cansleep (mux -> chan_sel_gpio , new_channel );
54175431 mux -> channel = new_channel ;
5418- goto reschedule ;
5419-
5420- out_unlock :
54215432 rtnl_unlock ();
5433+
54225434reschedule :
54235435 mod_delayed_work (system_wq , & mux -> poll , msecs_to_jiffies (100 ));
54245436}
@@ -5499,6 +5511,13 @@ static void mtk_release_mux(struct mtk_eth *eth, int id)
54995511 kfree (mux -> data [i ]);
55005512 }
55015513 }
5514+
5515+ /* Destroy transitional phylink created by mtk_add_mac() when it was
5516+ * never promoted into a mux channel instance.
5517+ */
5518+ if (mux -> initial_phylink )
5519+ phylink_destroy (mux -> initial_phylink );
5520+
55025521 kfree (mux );
55035522 eth -> mux [id ] = NULL ;
55045523}
@@ -5516,7 +5535,8 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
55165535 struct device_node * child ;
55175536 struct mtk_mux * mux ;
55185537 unsigned int id ;
5519- int err ;
5538+ unsigned int initial_channel ;
5539+ int err , sfp_present ;
55205540
55215541 if (!_id ) {
55225542 dev_err (eth -> dev , "missing attach mac id\n" );
@@ -5529,15 +5549,15 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
55295549 return - EINVAL ;
55305550 }
55315551
5532- mux = kmalloc (sizeof (struct mtk_mux ), GFP_KERNEL );
5552+ mux = kzalloc (sizeof (struct mtk_mux ), GFP_KERNEL );
55335553 if (unlikely (!mux )) {
55345554 dev_err (eth -> dev , "failed to create mux structure\n" );
55355555 return - ENOMEM ;
55365556 }
55375557
55385558 eth -> mux [id ] = mux ;
55395559 mux -> mac = eth -> mac [id ];
5540- mux -> channel = 0 ; //more than channels, just to make current channel invalid for switching the first time the gpio is read
5560+ mux -> initial_phylink = mux -> mac ? mux -> mac -> phylink : NULL ;
55415561
55425562 mux -> mod_def0_gpio = fwnode_gpiod_get_index (of_fwnode_handle (np ),
55435563 "mod-def0" , 0 , GPIOD_IN |
@@ -5558,8 +5578,11 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
55585578 goto err_put_mod_def0 ;
55595579 }
55605580
5561- of_property_read_u32 (np , "sfp-present-channel" ,
5562- & mux -> sfp_present_channel );
5581+ if (of_property_read_u32 (np , "sfp-present-channel" ,
5582+ & mux -> sfp_present_channel ))
5583+ mux -> sfp_present_channel = 0 ;
5584+ else if (mux -> sfp_present_channel > 1 )
5585+ mux -> sfp_present_channel = 1 ;
55635586
55645587 for_each_child_of_node (np , child ) {
55655588 err = mtk_add_mux_channel (mux , child );
@@ -5571,7 +5594,18 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
55715594 //should set initial mux->channel be set if ! mux->sfp_present_channel?
55725595 }
55735596
5574- gpiod_set_value_cansleep (mux -> chan_sel_gpio , mux -> sfp_present_channel ? 0 : 1 );
5597+ /* Configure initial mux channel based on current module presence. */
5598+ sfp_present = gpiod_get_value_cansleep (mux -> mod_def0_gpio );
5599+ if (sfp_present < 0 ) {
5600+ dev_warn (eth -> dev , "failed to read mod-def0 gpio, defaulting to non-SFP channel\n" );
5601+ initial_channel = !mux -> sfp_present_channel ;
5602+ } else {
5603+ initial_channel = sfp_present ? mux -> sfp_present_channel :
5604+ !mux -> sfp_present_channel ;
5605+ }
5606+ gpiod_set_value_cansleep (mux -> chan_sel_gpio , initial_channel );
5607+ /* Force first poll pass to (re)build phylink for selected channel. */
5608+ mux -> channel = !initial_channel ;
55755609
55765610 dev_info (eth -> dev , "ethernet mux: line:%d added new mux\n" ,__LINE__ );
55775611 INIT_DELAYED_WORK (& mux -> poll , mux_poll );
0 commit comments