Skip to content

Commit 0e807dd

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
1 parent dc5f57b commit 0e807dd

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

drivers/net/ethernet/mediatek/mtk_eth_soc.c

Lines changed: 54 additions & 3 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);
@@ -4943,6 +4974,23 @@ static void mux_poll(struct work_struct *work)
49434974

49444975
mtk_stop(dev);
49454976

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+
mux->data[mux->channel]->phylink = NULL;
4982+
}
4983+
4984+
/* Create new phylink if not yet present */
4985+
if (!mux->data[new_channel]->phylink) {
4986+
mux->data[new_channel]->phylink = mtk_mux_create_phylink(mux, new_channel);
4987+
if (IS_ERR(mux->data[new_channel]->phylink)) {
4988+
dev_err(eth->dev, "Failed to create new phylink\n");
4989+
mux->data[new_channel]->phylink=NULL;
4990+
goto out_unlock;
4991+
}
4992+
}
4993+
49464994
mac->of_node = mux->data[new_channel]->of_node;
49474995
mac->phylink = mux->data[new_channel]->phylink;
49484996

@@ -4957,7 +5005,10 @@ static void mux_poll(struct work_struct *work)
49575005
rtnl_unlock();
49585006

49595007
mux->channel = new_channel;
5008+
goto reschedule;
49605009

5010+
out_unlock:
5011+
rtnl_unlock();
49615012
reschedule:
49625013
mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(100));
49635014
}
@@ -4995,18 +5046,18 @@ static int mtk_add_mux_channel(struct mtk_mux *mux, struct device_node *np)
49955046
goto err_free_data;
49965047
}
49975048

4998-
phylink = phylink_create(&mux->mac->phylink_config,
5049+
/*phylink = phylink_create(&mux->mac->phylink_config,
49995050
of_fwnode_handle(np),
50005051
phy_mode, &mtk_phylink_ops);
50015052
if (IS_ERR(phylink)) {
50025053
dev_err(eth->dev, "failed to create phylink structure\n");
50035054
err = PTR_ERR(phylink);
50045055
goto err_free_data;
5005-
}
5056+
}*/
50065057

50075058
dev_info(eth->dev, "ethernet mux: line:%d added new channel:%d\n",__LINE__,id);
50085059
data->of_node = np;
5009-
data->phylink = phylink;
5060+
data->phylink = NULL;//phylink;
50105061
mux->data[id] = data;
50115062

50125063
return 0;

0 commit comments

Comments
 (0)