Skip to content

Commit 6e571e6

Browse files
committed
net: mtk: eth-mux: fix rcu_lock in mux
rcu lock caused by phy not ready yet when phylink_start is called for it switch to sfp works too but switch back causes deadlock (no rcu-stall)
1 parent bc4bad5 commit 6e571e6

1 file changed

Lines changed: 72 additions & 7 deletions

File tree

drivers/net/ethernet/mediatek/mtk_eth_soc.c

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4919,6 +4919,37 @@ static const struct net_device_ops mtk_netdev_ops = {
49194919
.ndo_select_queue = mtk_select_queue,
49204920
};
49214921

4922+
static struct phylink *mtk_mux_create_phylink(struct mtk_mux *mux, unsigned int channel)
4923+
{
4924+
struct mtk_mux_data *data = mux->data[channel];
4925+
struct mtk_mac *mac = mux->mac;
4926+
struct mtk_eth *eth = mac->hw;
4927+
phy_interface_t phy_mode;
4928+
struct phylink *pl;
4929+
int err;
4930+
4931+
if (!data || !data->of_node)
4932+
return ERR_PTR(-EINVAL);
4933+
4934+
err = of_get_phy_mode(data->of_node, &phy_mode);
4935+
if (err) {
4936+
dev_err(eth->dev, "invalid phy-mode for mux channel %u\n", channel);
4937+
return ERR_PTR(err);
4938+
}
4939+
4940+
pl = phylink_create(&mac->phylink_config,
4941+
of_fwnode_handle(data->of_node),
4942+
phy_mode, &mtk_phylink_ops);
4943+
if (IS_ERR(pl)) {
4944+
dev_err(eth->dev, "failed to create phylink for channel %u\n", channel);
4945+
return pl;
4946+
}
4947+
4948+
dev_info(eth->dev, "Created phylink for channel %u\n", channel);
4949+
data->phylink = pl;
4950+
return pl;
4951+
}
4952+
49224953
static void mux_poll(struct work_struct *work)
49234954
{
49244955
struct mtk_mux *mux = container_of(work, struct mtk_mux, poll.work);
@@ -4928,6 +4959,7 @@ static void mux_poll(struct work_struct *work)
49284959
unsigned int new_channel;
49294960
int sfp_present;
49304961

4962+
//dev_info(eth->dev, "ethernet mux: %s:%d\n",__func__,__LINE__);
49314963
if (IS_ERR(mux->mod_def0_gpio) || IS_ERR(mux->chan_sel_gpio))
49324964
goto reschedule;
49334965

@@ -4937,23 +4969,51 @@ static void mux_poll(struct work_struct *work)
49374969
if (mux->channel == new_channel || !netif_running(dev))
49384970
goto reschedule;
49394971

4940-
rtnl_lock();
4972+
dev_info(eth->dev, "ethernet mux: line:%d new channel:%d,sfp:%d\n",__LINE__, new_channel,sfp_present);
49414973

4974+
rtnl_lock();
49424975
mtk_stop(dev);
49434976

4944-
mac->of_node = mux->data[new_channel]->of_node;
4945-
mac->phylink = mux->data[new_channel]->phylink;
4977+
/* Destroy old phylink if it exists */
4978+
if (mux->data[mux->channel] && mux->data[mux->channel]->phylink) {
4979+
dev_info(eth->dev, "Destroying phylink for channel %u\n", mux->channel);
4980+
phylink_destroy(mux->data[mux->channel]->phylink);
4981+
phylink_stop(mux->data[mux->channel]->phylink);
4982+
phylink_disconnect_phy(mux->data[mux->channel]->phylink);
4983+
phylink_destroy(mux->data[mux->channel]->phylink);
4984+
mux->data[mux->channel]->phylink = NULL;
4985+
}
4986+
rtnl_unlock();
49464987

49474988
dev_info(eth->dev, "ethernet mux: switch to channel%d\n", new_channel);
49484989

49494990
gpiod_set_value_cansleep(mux->chan_sel_gpio, new_channel);
49504991

4992+
usleep_range(100000,200000);
4993+
4994+
/* Create new phylink if not yet present */
4995+
if (!mux->data[new_channel]->phylink) {
4996+
mux->data[new_channel]->phylink = mtk_mux_create_phylink(mux, new_channel);
4997+
if (IS_ERR(mux->data[new_channel]->phylink)) {
4998+
dev_err(eth->dev, "Failed to create new phylink\n");
4999+
mux->data[new_channel]->phylink=NULL;
5000+
goto out_unlock;
5001+
}
5002+
}
5003+
5004+
mac->of_node = mux->data[new_channel]->of_node;
5005+
mac->phylink = mux->data[new_channel]->phylink;
5006+
5007+
rtnl_lock();
49515008
mtk_open(dev);
49525009

49535010
rtnl_unlock();
49545011

49555012
mux->channel = new_channel;
5013+
goto reschedule;
49565014

5015+
out_unlock:
5016+
rtnl_unlock();
49575017
reschedule:
49585018
mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(100));
49595019
}
@@ -4991,17 +5051,18 @@ static int mtk_add_mux_channel(struct mtk_mux *mux, struct device_node *np)
49915051
goto err_free_data;
49925052
}
49935053

4994-
phylink = phylink_create(&mux->mac->phylink_config,
5054+
/*phylink = phylink_create(&mux->mac->phylink_config,
49955055
of_fwnode_handle(np),
49965056
phy_mode, &mtk_phylink_ops);
49975057
if (IS_ERR(phylink)) {
49985058
dev_err(eth->dev, "failed to create phylink structure\n");
49995059
err = PTR_ERR(phylink);
50005060
goto err_free_data;
5001-
}
5061+
}*/
50025062

5063+
dev_info(eth->dev, "ethernet mux: line:%d added new channel:%d\n",__LINE__,id);
50035064
data->of_node = np;
5004-
data->phylink = phylink;
5065+
data->phylink = NULL;//phylink;
50055066
mux->data[id] = data;
50065067

50075068
return 0;
@@ -5072,7 +5133,7 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
50725133

50735134
eth->mux[id] = mux;
50745135
mux->mac = eth->mac[id];
5075-
mux->channel = 0;
5136+
mux->channel = 0;//more than channels, just to make current channel invalid for switching the first time the gpio is read
50765137

50775138
mux->mod_def0_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np),
50785139
"mod-def0", 0, GPIOD_IN |
@@ -5103,8 +5164,12 @@ static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
51035164
of_node_put(child);
51045165
goto err_put_chan_sel;
51055166
}
5167+
//should set initial mux->channel be set if ! mux->sfp_present_channel?
51065168
}
51075169

5170+
gpiod_set_value_cansleep(mux->chan_sel_gpio, mux->sfp_present_channel ? 0 : 1);
5171+
5172+
dev_info(eth->dev, "ethernet mux: line:%d added new mux\n",__LINE__);
51085173
INIT_DELAYED_WORK(&mux->poll, mux_poll);
51095174
mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(3000));
51105175

0 commit comments

Comments
 (0)