Skip to content

Commit 2e72221

Browse files
committed
net: dsa: mxl862xx: add ds-mux (WIP)
https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/7ba42053fbd98a162f847cad2578dcf7ad30d347%5E%21/ and fix build-error (slave => user) ported to upstream dsa driver
1 parent 03e214d commit 2e72221

2 files changed

Lines changed: 253 additions & 1 deletion

File tree

drivers/net/dsa/mxl862xx/mxl862xx.c

Lines changed: 235 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <linux/phylink.h>
2121
#include <linux/dsa/8021q.h>
2222
#include <net/dsa.h>
23+
#include <linux/stddef.h>
24+
#include <linux/gpio/consumer.h>
25+
#include <linux/of_net.h>
2326

2427
#include "mxl862xx.h"
2528
#include "mxl862xx-api.h"
@@ -4516,10 +4519,219 @@ static const struct dsa_switch_ops mxl862xx_switch_ops = {
45164519
.devlink_flash_update = mxl862xx_devlink_flash_update,
45174520
};
45184521

4522+
static void sfp_monitor_work_func(struct work_struct *work)
4523+
{
4524+
struct combo_port_mux *mux = container_of(work, struct combo_port_mux, sfp_monitor_work.work);
4525+
struct dsa_switch *ds = mux->dp->ds;
4526+
struct dsa_port *dp = mux->dp;
4527+
struct net_device *dev = mux->dp->user;
4528+
unsigned int new_channel;
4529+
int sfp_present;
4530+
4531+
if (IS_ERR(mux->mod_def0_gpio) || IS_ERR(mux->chan_sel_gpio))
4532+
goto reschedule;
4533+
4534+
if (!netif_running(dev))
4535+
goto reschedule;
4536+
4537+
sfp_present = gpiod_get_value_cansleep(mux->mod_def0_gpio);
4538+
new_channel = sfp_present ? mux->sfp_present_channel : !mux->sfp_present_channel;
4539+
4540+
if (mux->initialized && mux->channel == new_channel)
4541+
goto reschedule;
4542+
4543+
rtnl_lock();
4544+
4545+
phylink_stop(dp->pl);
4546+
phylink_disconnect_phy(dp->pl);
4547+
4548+
dp->dn = mux->data[new_channel]->of_node;
4549+
dp->pl = mux->data[new_channel]->phylink;
4550+
4551+
phylink_of_phy_connect(dp->pl, dp->dn, 0);
4552+
phylink_start(dp->pl);
4553+
4554+
dev_info(ds->dev, "dsa mux: switch to channel%d\n", new_channel);
4555+
4556+
gpiod_set_value_cansleep(mux->chan_sel_gpio, new_channel);
4557+
4558+
rtnl_unlock();
4559+
4560+
mux->channel = new_channel;
4561+
mux->initialized = true;
4562+
4563+
reschedule:
4564+
mod_delayed_work(system_wq, &mux->sfp_monitor_work, msecs_to_jiffies(100));
4565+
}
4566+
4567+
static int ds_add_mux_channel(struct combo_port_mux *mux, struct device_node *np)
4568+
{
4569+
const __be32 *_id = of_get_property(np, "reg", NULL);
4570+
struct dsa_switch *ds = mux->dp->ds;
4571+
struct dp_mux_data *data;
4572+
struct phylink *phylink;
4573+
phy_interface_t phy_mode;
4574+
int id, err;
4575+
4576+
if (!_id) {
4577+
dev_err(ds->dev, "missing mux channel id\n");
4578+
return -EINVAL;
4579+
}
4580+
4581+
id = be32_to_cpup(_id);
4582+
if (id < 0 || id > 1) {
4583+
dev_err(ds->dev, "%d is not a valid mux channel id\n", id);
4584+
return -EINVAL;
4585+
}
4586+
4587+
data = kmalloc(sizeof(*data), GFP_KERNEL);
4588+
if (unlikely(!data)) {
4589+
dev_err(ds->dev, "failed to create mux data structure\n");
4590+
return -ENOMEM;
4591+
}
4592+
4593+
err = of_get_phy_mode(np, &phy_mode);
4594+
if (err) {
4595+
dev_err(ds->dev, "incorrect phy-mode\n");
4596+
goto err_free_data;
4597+
}
4598+
4599+
phylink = phylink_create(&mux->dp->pl_config,
4600+
of_fwnode_handle(np),
4601+
phy_mode, ds->phylink_mac_ops);
4602+
if (IS_ERR(phylink)) {
4603+
dev_err(ds->dev, "failed to create phylink structure\n");
4604+
err = PTR_ERR(phylink);
4605+
goto err_free_data;
4606+
}
4607+
4608+
data->of_node = np;
4609+
data->phylink = phylink;
4610+
mux->data[id] = data;
4611+
4612+
return 0;
4613+
4614+
err_free_data:
4615+
kfree(data);
4616+
return err;
4617+
}
4618+
4619+
static int ds_add_mux(struct mxl862xx_priv *priv, struct device_node *np)
4620+
{
4621+
const __be32 *_id = of_get_property(np, "reg", NULL);
4622+
struct device_node *child;
4623+
struct combo_port_mux *mux;
4624+
unsigned int id;
4625+
int err;
4626+
4627+
if (!_id) {
4628+
dev_err(priv->ds->dev, "missing attach dp id\n");
4629+
return -EINVAL;
4630+
}
4631+
4632+
id = be32_to_cpup(_id);
4633+
if (id < 0 || id >= MXL862XX_MAX_PORTS) {
4634+
dev_err(priv->ds->dev, "%d is not a valid attach dp id\n", id);
4635+
return -EINVAL;
4636+
}
4637+
4638+
mux = kmalloc(sizeof(struct combo_port_mux), GFP_KERNEL);
4639+
if (unlikely(!mux)) {
4640+
dev_err(priv->ds->dev, "failed to create mux structure\n");
4641+
return -ENOMEM;
4642+
}
4643+
4644+
mux->mod_def0_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np),
4645+
"mod-def0", 0, GPIOD_IN |
4646+
GPIOD_FLAGS_BIT_NONEXCLUSIVE, "?");
4647+
4648+
if (IS_ERR(mux->mod_def0_gpio)) {
4649+
dev_err(priv->ds->dev, "failed to requset gpio for mod-def0\n");
4650+
err = PTR_ERR(mux->mod_def0_gpio);
4651+
goto err_free_mux;
4652+
}
4653+
4654+
mux->chan_sel_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np),
4655+
"chan-sel", 0, GPIOD_OUT_LOW, "?");
4656+
4657+
if (IS_ERR(mux->chan_sel_gpio)) {
4658+
dev_err(priv->ds->dev, "failed to requset gpio for chan-sel\n");
4659+
err = PTR_ERR(mux->chan_sel_gpio);
4660+
goto err_put_mod_def0;
4661+
}
4662+
4663+
of_property_read_u32(np, "sfp-present-channel",
4664+
&mux->sfp_present_channel);
4665+
4666+
priv->ds_mux[id] = mux;
4667+
mux->dp = dsa_to_port(priv->ds, id);
4668+
/* configure default channel to 10G PHY */
4669+
mux->channel = !mux->sfp_present_channel;
4670+
mux->initialized = false;
4671+
4672+
for_each_child_of_node(np, child) {
4673+
err = ds_add_mux_channel(mux, child);
4674+
if (err) {
4675+
dev_err(priv->ds->dev, "failed to add ds_mux\n");
4676+
of_node_put(child);
4677+
goto err_put_chan_sel;
4678+
}
4679+
}
4680+
4681+
INIT_DELAYED_WORK(&mux->sfp_monitor_work, sfp_monitor_work_func);
4682+
mod_delayed_work(system_wq, &mux->sfp_monitor_work, msecs_to_jiffies(3000));
4683+
4684+
return 0;
4685+
4686+
err_put_chan_sel:
4687+
gpiod_put(mux->chan_sel_gpio);
4688+
err_put_mod_def0:
4689+
gpiod_put(mux->mod_def0_gpio);
4690+
err_free_mux:
4691+
kfree(mux);
4692+
priv->ds_mux[id] = NULL;
4693+
return err;
4694+
}
4695+
4696+
static void mxl862xx_release_mux(struct mxl862xx_priv *priv, int id)
4697+
{
4698+
struct combo_port_mux *mux = priv->ds_mux[id];
4699+
int i;
4700+
4701+
if (!mux)
4702+
return;
4703+
4704+
cancel_delayed_work_sync(&mux->sfp_monitor_work);
4705+
4706+
if (!IS_ERR_OR_NULL(mux->mod_def0_gpio))
4707+
gpiod_put(mux->mod_def0_gpio);
4708+
4709+
if (!IS_ERR_OR_NULL(mux->chan_sel_gpio))
4710+
gpiod_put(mux->chan_sel_gpio);
4711+
4712+
for (i = 0; i < 2; i++) {
4713+
if (mux->data[i]) {
4714+
if (mux->data[i]->phylink)
4715+
phylink_destroy(mux->data[i]->phylink);
4716+
kfree(mux->data[i]);
4717+
}
4718+
}
4719+
kfree(mux);
4720+
priv->ds_mux[id] = NULL;
4721+
}
4722+
4723+
static void mxl862xx_release_all_muxes(struct mxl862xx_priv *priv)
4724+
{
4725+
int i;
4726+
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
4727+
mxl862xx_release_mux(priv, i);
4728+
}
4729+
45194730
static int mxl862xx_probe(struct mdio_device *mdiodev)
45204731
{
45214732
struct device *dev = &mdiodev->dev;
45224733
struct mxl862xx_priv *priv;
4734+
struct device_node *mux_np;
45234735
struct dsa_switch *ds;
45244736
int err, i;
45254737

@@ -4565,9 +4777,30 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
45654777
mxl862xx_host_shutdown(priv);
45664778
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
45674779
cancel_work_sync(&priv->ports[i].host_flood_work);
4780+
return err;
45684781
}
45694782

4570-
return err;
4783+
mux_np = of_get_child_by_name(priv->ds->dev->of_node, "ds-mux-bus");
4784+
if (mux_np) {
4785+
struct device_node *child;
4786+
4787+
for_each_available_child_of_node(mux_np, child) {
4788+
if (!of_device_is_compatible(child,
4789+
"mxl862xx,ds-mux"))
4790+
continue;
4791+
4792+
if (!of_device_is_available(child))
4793+
continue;
4794+
4795+
err = ds_add_mux(priv, child);
4796+
if (err)
4797+
dev_err(dev, "failed to add mux\n");
4798+
4799+
of_node_put(mux_np);
4800+
};
4801+
}
4802+
4803+
return 0;
45714804
}
45724805

45734806
static void mxl862xx_remove(struct mdio_device *mdiodev)
@@ -4597,6 +4830,7 @@ static void mxl862xx_remove(struct mdio_device *mdiodev)
45974830
rtnl_unlock();
45984831
}
45994832

4833+
mxl862xx_release_all_muxes(ds->priv);
46004834
dsa_unregister_switch(ds);
46014835

46024836
mxl862xx_host_shutdown(priv);

drivers/net/dsa/mxl862xx/mxl862xx.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,23 @@ struct mxl862xx_fw_version {
340340
#define MXL862XX_FLAG_CRC_ERR 0
341341
#define MXL862XX_FLAG_WORK_STOPPED 1
342342

343+
344+
struct dp_mux_data {
345+
struct device_node *of_node;
346+
struct phylink *phylink;
347+
};
348+
349+
struct combo_port_mux {
350+
struct dsa_port *dp;
351+
struct gpio_desc *mod_def0_gpio;
352+
struct gpio_desc *chan_sel_gpio;
353+
struct dp_mux_data *data[2];
354+
unsigned int channel;
355+
unsigned int sfp_present_channel;
356+
struct delayed_work sfp_monitor_work;
357+
bool initialized;
358+
};
359+
343360
/**
344361
* struct mxl862xx_priv - driver private data for an MxL862xx switch
345362
* @ds: pointer to the DSA switch instance
@@ -445,6 +462,7 @@ struct mxl862xx_priv {
445462
u8 trunk_hash;
446463
int mirror_dest;
447464
struct delayed_work stats_work;
465+
struct combo_port_mux *ds_mux[MXL862XX_MAX_PORTS];
448466
};
449467

450468
/* Stop the background workers. The flag is set under heal_lock, which the

0 commit comments

Comments
 (0)