From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:39
mdio drivers should not use REGCHACHE. Also disable locking since it's
handled by the mdio users and regmap is always accessed atomically.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/mdio/mdio-ipq8064.c | 34 +++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
@@ -97,14 +96,34 @@ ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)returnipq8064_mdio_wait_busy(priv);}+staticconststructregmap_configipq8064_mdio_regmap_config={+.reg_bits=32,+.reg_stride=4,+.val_bits=32,+.can_multi_write=false,+/* the mdio lock is used by any user of this mdio driver */+.disable_locking=true,++.cache_type=REGCACHE_NONE,+};+staticintipq8064_mdio_probe(structplatform_device*pdev){structdevice_node*np=pdev->dev.of_node;structipq8064_mdio*priv;+structresourceres;structmii_bus*bus;+void__iomem*base;intret;+if(of_address_to_resource(np,0,&res))+return-ENOMEM;++base=ioremap(res.start,resource_size(&res));+if(!base)+return-ENOMEM;+bus=devm_mdiobus_alloc_size(&pdev->dev,sizeof(*priv));if(!bus)return-ENOMEM;
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:41
qca8k_read can fail. Rework any user to handle error values and
correctly return.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 90 +++++++++++++++++++++++++++++++----------
1 file changed, 69 insertions(+), 21 deletions(-)
@@ -280,15 +285,17 @@ static intqca8k_busy_wait(structqca8k_priv*priv,u32reg,u32mask){unsignedlongtimeout;+u32val;timeout=jiffies+msecs_to_jiffies(20);/* loop until the busy flag has cleared */do{-u32val=qca8k_read(priv,reg);-intbusy=val&mask;+val=qca8k_read(priv,reg);+if(val<0)+continue;-if(!busy)+if(!(val&mask))break;cond_resched();}while(!time_after_eq(jiffies,timeout));
@@ -296,15 +303,20 @@ qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)returntime_after_eq(jiffies,timeout);}-staticvoid+staticintqca8k_fdb_read(structqca8k_priv*priv,structqca8k_fdb*fdb){-u32reg[4];+u32reg[4],val;inti;/* load the ARL table into an array */-for(i=0;i<4;i++)-reg[i]=qca8k_read(priv,QCA8K_REG_ATU_DATA0+(i*4));+for(i=0;i<4;i++){+val=qca8k_read(priv,QCA8K_REG_ATU_DATA0+(i*4));+if(val<0)+returnval;++reg[i]=val;+}/* vid - 83:72 */fdb->vid=(reg[2]>>QCA8K_ATU_VID_S)&QCA8K_ATU_VID_M;
@@ -370,6 +384,8 @@ qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)/* Check for table full violation when adding an entry */if(cmd==QCA8K_FDB_LOAD){reg=qca8k_read(priv,QCA8K_REG_ATU_FUNC);+if(reg<0)+returnreg;if(reg&QCA8K_ATU_FUNC_FULL)return-1;}
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:44
With the use of the qca8k dsa driver, some problem arised related to
port status detection. With a load on a specific port (for example a
simple speed test), the driver starts to behave in a strange way and
garbage data is produced. To address this, enlarge the sleep delay and
address a bug for the reg offset 31 that require additional delay for
this specific reg.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/mdio/mdio-ipq8064.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
@@ -65,7 +65,7 @@ ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset)((reg_offset<<MII_REG_SHIFT)&MII_REG_MASK);regmap_write(priv->base,MII_ADDR_REG_ADDR,miiaddr);-usleep_range(8,10);+usleep_range(10,13);err=ipq8064_mdio_wait_busy(priv);if(err)
@@ -91,7 +91,14 @@ ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)((reg_offset<<MII_REG_SHIFT)&MII_REG_MASK);regmap_write(priv->base,MII_ADDR_REG_ADDR,miiaddr);-usleep_range(8,10);++/* For the specific reg 31 extra time is needed or the next+*readwillproducegarbagedata.+*/+if(reg_offset==31)+usleep_range(30,43);+else+usleep_range(10,13);returnipq8064_mdio_wait_busy(priv);}
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:47
With a remote possibility, the set_page function can fail. Since this is
a critical part of the write/read qca8k regs, propagate the error and
terminate any read/write operation.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:49
qca8k_write can fail. Rework any user to handle error values and
correctly return.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 112 +++++++++++++++++++++++++++-------------
1 file changed, 75 insertions(+), 37 deletions(-)
@@ -365,6 +365,7 @@ static intqca8k_fdb_access(structqca8k_priv*priv,enumqca8k_fdb_cmdcmd,intport){u32reg;+intret;/* Set the command and FDB index */reg=QCA8K_ATU_FUNC_BUSY;
@@ -375,7 +376,9 @@ qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)}/* Write the function register triggering the table access */-qca8k_write(priv,QCA8K_REG_ATU_FUNC,reg);+ret=qca8k_write(priv,QCA8K_REG_ATU_FUNC,reg);+if(ret)+returnret;/* wait for completion */if(qca8k_busy_wait(priv,QCA8K_REG_ATU_FUNC,QCA8K_ATU_FUNC_BUSY))
@@ -448,6 +451,7 @@ static intqca8k_vlan_access(structqca8k_priv*priv,enumqca8k_vlan_cmdcmd,u16vid){u32reg;+intret;/* Set the command and VLAN index */reg=QCA8K_VTU_FUNC1_BUSY;
@@ -455,7 +459,9 @@ qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)reg|=vid<<QCA8K_VTU_FUNC1_VID_S;/* Write the function register triggering the table access */-qca8k_write(priv,QCA8K_REG_VTU_FUNC1,reg);+ret=qca8k_write(priv,QCA8K_REG_VTU_FUNC1,reg);+if(ret)+returnret;/* wait for completion */if(qca8k_busy_wait(priv,QCA8K_REG_VTU_FUNC1,QCA8K_VTU_FUNC1_BUSY))
@@ -767,12 +793,18 @@ qca8k_setup(struct dsa_switch *ds)QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);/* Enable MIB counters */-qca8k_mib_init(priv);+ret=qca8k_mib_init(priv);+if(ret)+pr_warn("mib init failed");/* Enable QCA header mode on the cpu port */-qca8k_write(priv,QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),-QCA8K_PORT_HDR_CTRL_ALL<<QCA8K_PORT_HDR_CTRL_TX_S|-QCA8K_PORT_HDR_CTRL_ALL<<QCA8K_PORT_HDR_CTRL_RX_S);+ret=qca8k_write(priv,QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),+QCA8K_PORT_HDR_CTRL_ALL<<QCA8K_PORT_HDR_CTRL_TX_S|+QCA8K_PORT_HDR_CTRL_ALL<<QCA8K_PORT_HDR_CTRL_RX_S);+if(ret){+pr_err("failed enabling QCA header mode");+returnret;+}/* Disable forwarding by default on all ports */for(i=0;i<QCA8K_NUM_PORTS;i++)
@@ -784,11 +816,13 @@ qca8k_setup(struct dsa_switch *ds)qca8k_port_set_status(priv,i,0);/* Forward all unknown frames to CPU port for Linux processing */-qca8k_write(priv,QCA8K_REG_GLOBAL_FW_CTRL1,-BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S|-BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_BC_DP_S|-BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_MC_DP_S|-BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);+ret=qca8k_write(priv,QCA8K_REG_GLOBAL_FW_CTRL1,+BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S|+BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_BC_DP_S|+BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_MC_DP_S|+BIT(0)<<QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);+if(ret)+returnret;/* Setup connection between CPU port & user ports */for(i=0;i<QCA8K_NUM_PORTS;i++){
@@ -816,16 +850,20 @@ qca8k_setup(struct dsa_switch *ds)qca8k_rmw(priv,QCA8K_EGRESS_VLAN(i),0xfff<<shift,QCA8K_PORT_VID_DEF<<shift);-qca8k_write(priv,QCA8K_REG_PORT_VLAN_CTRL0(i),-QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF)|-QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));+ret=qca8k_write(priv,QCA8K_REG_PORT_VLAN_CTRL0(i),+QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF)|+QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));+if(ret)+returnret;}}/* Setup our port MTUs to match power on defaults */for(i=0;i<QCA8K_NUM_PORTS;i++)priv->port_mtu[i]=ETH_FRAME_LEN+ETH_FCS_LEN;-qca8k_write(priv,QCA8K_MAX_FRAME_SIZE,ETH_FRAME_LEN+ETH_FCS_LEN);+ret=qca8k_write(priv,QCA8K_MAX_FRAME_SIZE,ETH_FRAME_LEN+ETH_FCS_LEN);+if(ret)+pr_warn("failed setting MTU settings");/* Flush the FDB table */qca8k_fdb_flush(priv);
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:52
qca8k_rmw can fail. Rework any user to handle error values and
correctly return.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 130 +++++++++++++++++++++++++---------------
1 file changed, 83 insertions(+), 47 deletions(-)
@@ -789,8 +804,12 @@ qca8k_setup(struct dsa_switch *ds)returnret;/* Enable CPU Port */-qca8k_reg_set(priv,QCA8K_REG_GLOBAL_FW_CTRL0,-QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);+ret=qca8k_reg_set(priv,QCA8K_REG_GLOBAL_FW_CTRL0,+QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);+if(ret){+pr_err("failed enabling CPU port");+returnret;+}/* Enable MIB counters */ret=qca8k_mib_init(priv);
@@ -807,9 +826,12 @@ qca8k_setup(struct dsa_switch *ds)}/* Disable forwarding by default on all ports */-for(i=0;i<QCA8K_NUM_PORTS;i++)-qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(i),-QCA8K_PORT_LOOKUP_MEMBER,0);+for(i=0;i<QCA8K_NUM_PORTS;i++){+ret=qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(i),+QCA8K_PORT_LOOKUP_MEMBER,0);+if(ret<0)+returnret;+}/* Disable MAC by default on all ports */for(i=1;i<QCA8K_NUM_PORTS;i++)
@@ -828,28 +850,37 @@ qca8k_setup(struct dsa_switch *ds)for(i=0;i<QCA8K_NUM_PORTS;i++){/* CPU port gets connected to all user ports of the switch */if(dsa_is_cpu_port(ds,i)){-qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),-QCA8K_PORT_LOOKUP_MEMBER,dsa_user_ports(ds));+ret=qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),+QCA8K_PORT_LOOKUP_MEMBER,dsa_user_ports(ds));+if(ret<0)+returnret;}/* Individual user ports get connected to CPU port only */if(dsa_is_user_port(ds,i)){intshift=16*(i%2);-qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(i),-QCA8K_PORT_LOOKUP_MEMBER,-BIT(QCA8K_CPU_PORT));+ret=qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(i),+QCA8K_PORT_LOOKUP_MEMBER,+BIT(QCA8K_CPU_PORT));+if(ret<0)+returnret;/* Enable ARP Auto-learning by default */-qca8k_reg_set(priv,QCA8K_PORT_LOOKUP_CTRL(i),-QCA8K_PORT_LOOKUP_LEARN);+ret=qca8k_reg_set(priv,QCA8K_PORT_LOOKUP_CTRL(i),+QCA8K_PORT_LOOKUP_LEARN);+if(ret)+returnret;/* For port based vlans to work we need to set the*defaultegressvid*/-qca8k_rmw(priv,QCA8K_EGRESS_VLAN(i),-0xfff<<shift,-QCA8K_PORT_VID_DEF<<shift);+ret=qca8k_rmw(priv,QCA8K_EGRESS_VLAN(i),+0xfff<<shift,+QCA8K_PORT_VID_DEF<<shift);+if(ret<0)+returnret;+ret=qca8k_write(priv,QCA8K_REG_PORT_VLAN_CTRL0(i),QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF)|QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
@@ -1249,17 +1280,20 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)/* Add this port to the portvlan mask of the other ports*inthebridge*/-qca8k_reg_set(priv,-QCA8K_PORT_LOOKUP_CTRL(i),-BIT(port));+ret=qca8k_reg_set(priv,+QCA8K_PORT_LOOKUP_CTRL(i),+BIT(port));+if(ret)+returnret;if(i!=port)port_mask|=BIT(i);}+/* Add all other ports to this ports portvlan mask */-qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(port),-QCA8K_PORT_LOOKUP_MEMBER,port_mask);+ret=qca8k_rmw(priv,QCA8K_PORT_LOOKUP_CTRL(port),+QCA8K_PORT_LOOKUP_MEMBER,port_mask);-return0;+returnret<0?ret:0;}staticvoid
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:29:56
qca8327 switch is a low tier version of the more recent qca8337.
It does share the same regs used by the qca8k driver and can be
supported with minimal change.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 23 ++++++++++++++++++++---
drivers/net/dsa/qca8k.h | 6 ++++++
2 files changed, 26 insertions(+), 3 deletions(-)
@@ -1556,6 +1557,11 @@ qca8k_sw_probe(struct mdio_device *mdiodev)gpiod_set_value_cansleep(priv->reset_gpio,0);}+/* get the switches ID from the compatible */+data=of_device_get_match_data(&mdiodev->dev);+if(!data)+return-ENODEV;+/* read the switches ID register */id=qca8k_read(priv,QCA8K_REG_MASK_CTRL);if(id<0)
@@ -1563,8 +1569,10 @@ qca8k_sw_probe(struct mdio_device *mdiodev)id>>=QCA8K_MASK_CTRL_ID_S;id&=QCA8K_MASK_CTRL_ID_M;-if(id!=QCA8K_ID_QCA8337)+if(id!=data->id){+dev_err(&mdiodev->dev,"Switch id detected %x but expected %x",id,data->id);return-ENODEV;+}priv->ds=devm_kzalloc(&mdiodev->dev,sizeof(*priv->ds),GFP_KERNEL);if(!priv->ds)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:02
Add support for qca8327 in the compatible list.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 1 +
1 file changed, 1 insertion(+)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:04
The port 5 of the ar8337 have some problem in flood condition. The
original legacy driver had some specific buffer and priority settings
for the different port suggested by the QCA switch team. Add this
missing settings to improve switch stability under load condition.
The packet priority tweak and the rx delay is specific to qca8337.
Limit this changes to qca8337 as now we also support 8327 switch.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 54 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 24 ++++++++++++++++++
2 files changed, 76 insertions(+), 2 deletions(-)
@@ -783,7 +783,12 @@ static intqca8k_setup(structdsa_switch*ds){structqca8k_priv*priv=(structqca8k_priv*)ds->priv;+conststructqca8k_match_data*data;intret,i;+u32mask;++/* get the switches ID from the compatible */+data=of_device_get_match_data(priv->dev);/* Make sure that port 0 is the cpu port */if(!dsa_is_cpu_port(ds,0)){
@@ -889,6 +894,45 @@ qca8k_setup(struct dsa_switch *ds)}}+if(data->id==QCA8K_ID_QCA8337){+for(i=0;i<QCA8K_NUM_PORTS;i++){+switch(i){+/* The 2 CPU port and port 5 requires some different+*prioritythananyotherports.+*/+case0:+case5:+case6:+mask=QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3)|+QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6)|+QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8)|+QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);+break;+default:+mask=QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3)|+QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6)|+QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8)|+QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);+}+qca8k_write(priv,QCA8K_REG_PORT_HOL_CTRL0(i),mask);++mask=QCA8K_PORT_HOL_CTRL1_ING(0x6)|+QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN|+QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN|+QCA8K_PORT_HOL_CTRL1_WRED_EN;+qca8k_rmw(priv,QCA8K_REG_PORT_HOL_CTRL1(i),+QCA8K_PORT_HOL_CTRL1_ING_BUF|+QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN|+QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN|+QCA8K_PORT_HOL_CTRL1_WRED_EN,+mask);+}+}+/* Setup our port MTUs to match power on defaults */for(i=0;i<QCA8K_NUM_PORTS;i++)priv->port_mtu[i]=ETH_FRAME_LEN+ETH_FCS_LEN;
@@ -909,9 +953,13 @@ static voidqca8k_phylink_mac_config(structdsa_switch*ds,intport,unsignedintmode,conststructphylink_link_state*state){+conststructqca8k_match_data*data;structqca8k_priv*priv=ds->priv;u32reg,val;+/* get the switches ID from the compatible */+data=of_device_get_match_data(priv->dev);+switch(port){case0:/* 1st CPU port */if(state->interface!=PHY_INTERFACE_MODE_RGMII&&
@@ -962,8 +1010,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,QCA8K_PORT_PAD_RGMII_EN|QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY)|QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));-qca8k_write(priv,QCA8K_REG_PORT5_PAD_CTRL,-QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);+/* QCA8337 requires to set rgmii rx delay */+if(data->id==QCA8K_ID_QCA8337)+qca8k_write(priv,QCA8K_REG_PORT5_PAD_CTRL,+QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);break;casePHY_INTERFACE_MODE_SGMII:casePHY_INTERFACE_MODE_1000BASEX:
@@ -933,6 +933,16 @@ qca8k_setup(struct dsa_switch *ds)}}+/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */+if(data->id==QCA8K_ID_QCA8327){+mask=QCA8K_GLOBAL_FC_GOL_XON_THRES(288)|+QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);+qca8k_rmw(priv,QCA8K_REG_GLOBAL_FC_THRESH,+QCA8K_GLOBAL_FC_GOL_XON_THRES_S|+QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S,+mask);+}+/* Setup our port MTUs to match power on defaults */for(i=0;i<QCA8K_NUM_PORTS;i++)priv->port_mtu[i]=ETH_FRAME_LEN+ETH_FCS_LEN;
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:23
qca8k internal phy driver require some special debug value to be set
based on the switch revision. Rework the switch id read function to
also read the chip revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 50 ++++++++++++++++++++++++++---------------
drivers/net/dsa/qca8k.h | 6 +++--
2 files changed, 36 insertions(+), 20 deletions(-)
@@ -1586,12 +1586,38 @@ static const struct dsa_switch_ops qca8k_switch_ops = {.phylink_mac_link_up=qca8k_phylink_mac_link_up,};+staticintqca8k_read_switch_id(structqca8k_priv*priv)+{+conststructqca8k_match_data*data;+u32val;+u8id;++/* get the switches ID from the compatible */+data=of_device_get_match_data(priv->dev);+if(!data)+return-ENODEV;++val=qca8k_read(priv,QCA8K_REG_MASK_CTRL);+if(val<0)+return-ENODEV;++id=QCA8K_MASK_CTRL_DEVICE_ID(val&QCA8K_MASK_CTRL_DEVICE_ID_MASK);+if(id!=data->id){+dev_err(priv->dev,"Switch id detected %x but expected %x",id,data->id);+return-ENODEV;+}++/* Save revision to communicate to the internal PHY driver */+priv->switch_revision=(val&QCA8K_MASK_CTRL_REV_ID_MASK);++return0;+}+staticintqca8k_sw_probe(structmdio_device*mdiodev){-conststructqca8k_match_data*data;structqca8k_priv*priv;-u32id;+intret;/* allocate the private data struct so that we can probe the switches*IDregister
@@ -1617,22 +1643,10 @@ qca8k_sw_probe(struct mdio_device *mdiodev)gpiod_set_value_cansleep(priv->reset_gpio,0);}-/* get the switches ID from the compatible */-data=of_device_get_match_data(&mdiodev->dev);-if(!data)-return-ENODEV;--/* read the switches ID register */-id=qca8k_read(priv,QCA8K_REG_MASK_CTRL);-if(id<0)-returnid;--id>>=QCA8K_MASK_CTRL_ID_S;-id&=QCA8K_MASK_CTRL_ID_M;-if(id!=data->id){-dev_err(&mdiodev->dev,"Switch id detected %x but expected %x",id,data->id);-return-ENODEV;-}+/* Check the detected switch id */+ret=qca8k_read_switch_id(priv);+if(ret)+returnret;priv->ds=devm_kzalloc(&mdiodev->dev,sizeof(*priv->ds),GFP_KERNEL);if(!priv->ds)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:26
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
@@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)return0;}+staticint+qca8k_setup_of_rgmii_delay(structqca8k_priv*priv)+{+structdevice_node*ports,*port;+u32val;++ports=of_get_child_by_name(priv->dev->of_node,"ports");+if(!ports)+return-EINVAL;++/* Assume only one port with rgmii-id mode */+for_each_available_child_of_node(ports,port){+if(!of_property_match_string(port,"phy-mode","rgmii-id"))+continue;++if(of_property_read_u32(port,"rx-internal-delay-ps",&val))+val=2;++if(val>QCA8K_MAX_DELAY){+dev_err(priv->dev,"rgmii rx delay is limited to more than 3ps, setting to the max value");+priv->rgmii_rx_delay=3;+}else{+priv->rgmii_rx_delay=val;+}++if(of_property_read_u32(port,"rx-internal-delay-ps",&val))+val=1;++if(val>QCA8K_MAX_DELAY){+dev_err(priv->dev,"rgmii tx delay is limited to more than 3ps, setting to the max value");+priv->rgmii_tx_delay=3;+}else{+priv->rgmii_rx_delay=val;+}+}++of_node_put(ports);++return0;+}+staticintqca8k_setup(structdsa_switch*ds){
@@ -808,6 +849,10 @@ qca8k_setup(struct dsa_switch *ds)if(ret)returnret;+ret=qca8k_setup_of_rgmii_delay(priv);+if(ret)+returnret;+/* Enable CPU Port */ret=qca8k_reg_set(priv,QCA8K_REG_GLOBAL_FW_CTRL0,QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
@@ -1018,8 +1063,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,*/qca8k_write(priv,reg,QCA8K_PORT_PAD_RGMII_EN|-QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY)|-QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));+QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay)|+QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay)|+QCA8K_PORT_PAD_RGMII_TX_DELAY_EN|+QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);/* QCA8337 requires to set rgmii rx delay */if(data->id==QCA8K_ID_QCA8337)qca8k_write(priv,QCA8K_REG_PORT5_PAD_CTRL,
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:48
Clear MDIO_MASTER_EN bit from MDIO_MASTER_CTRL after read/write
operation. The MDIO_MASTER_EN bit is not reset after read/write
operation and the next operation can be wrongly interpreted by the
switch as a mdio operation. This cause a production of wrong/garbage
data from the switch and underfined bheavior. (random port drop,
unplugged port flagged with link up, wrong port speed)
Also on driver remove the MASTER_CTRL can be left set and cause the
malfunction of any next driver using the mdio device.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
@@ -655,8 +655,14 @@ qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)if(ret)returnret;-returnqca8k_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,-QCA8K_MDIO_MASTER_BUSY);+ret=qca8k_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,+QCA8K_MDIO_MASTER_BUSY);++/* even if the busy_wait timeouts try to clear the MASTER_EN */+qca8k_reg_clear(priv,QCA8K_MDIO_MASTER_CTRL,+QCA8K_MDIO_MASTER_EN);++returnret;}staticint
@@ -690,6 +696,10 @@ qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)val&=QCA8K_MDIO_MASTER_DATA_MASK;+/* even if the busy_wait timeouts try to clear the MASTER_EN */+qca8k_reg_clear(priv,QCA8K_MDIO_MASTER_CTRL,+QCA8K_MDIO_MASTER_EN);+returnval;}
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:30:56
MDIO_MASTER operation have a dedicated busy wait that is not protected
by the mdio mutex. This can cause situation where the MASTER operation
is done and a normal operation is executed between the MASTER read/write
and the MASTER busy_wait. Rework the qca8k_mdio_read/write function to
address this issue by binding the lock for the whole MASTER operation
and not only the mdio read/write common operation.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 69 ++++++++++++++++++++++++++++++++++-------
1 file changed, 57 insertions(+), 12 deletions(-)
@@ -633,9 +633,33 @@ qca8k_port_to_phy(int port)returnport-1;}+staticint+qca8k_mdio_busy_wait(structqca8k_priv*priv,u32reg,u32mask)+{+unsignedlongtimeout;+u16r1,r2,page;++qca8k_split_addr(reg,&r1,&r2,&page);++timeout=jiffies+msecs_to_jiffies(20);++/* loop until the busy flag has cleared */+do{+u32val=qca8k_mii_read32(priv->bus,0x10|r2,r1);+intbusy=val&mask;++if(!busy)+break;+cond_resched();+}while(!time_after_eq(jiffies,timeout));++returntime_after_eq(jiffies,timeout);+}+staticintqca8k_mdio_write(structqca8k_priv*priv,intport,u32regnum,u16data){+u16r1,r2,page;u32phy,val;intret;
@@ -651,12 +675,22 @@ qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)QCA8K_MDIO_MASTER_REG_ADDR(regnum)|QCA8K_MDIO_MASTER_DATA(data);-ret=qca8k_write(priv,QCA8K_MDIO_MASTER_CTRL,val);+qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL,&r1,&r2,&page);++mutex_lock_nested(&priv->bus->mdio_lock,MDIO_MUTEX_NESTED);++ret=qca8k_set_page(priv->bus,page);if(ret)-returnret;+gotoexit;-ret=qca8k_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,-QCA8K_MDIO_MASTER_BUSY);+qca8k_mii_write32(priv->bus,0x10|r2,r1,val);++if(qca8k_mdio_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,+QCA8K_MDIO_MASTER_BUSY))+ret=-ETIMEDOUT;++exit:+mutex_unlock(&priv->bus->mdio_lock);/* even if the busy_wait timeouts try to clear the MASTER_EN */qca8k_reg_clear(priv,QCA8K_MDIO_MASTER_CTRL,
@@ -682,20 +717,30 @@ qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)QCA8K_MDIO_MASTER_READ|QCA8K_MDIO_MASTER_PHY_ADDR(phy)|QCA8K_MDIO_MASTER_REG_ADDR(regnum);-ret=qca8k_write(priv,QCA8K_MDIO_MASTER_CTRL,val);+qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL,&r1,&r2,&page);++mutex_lock_nested(&priv->bus->mdio_lock,MDIO_MUTEX_NESTED);++ret=qca8k_set_page(priv->bus,page);if(ret)-returnret;+gotoexit;-if(qca8k_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,-QCA8K_MDIO_MASTER_BUSY))-return-ETIMEDOUT;+qca8k_mii_write32(priv->bus,0x10|r2,r1,val);-val=qca8k_read(priv,QCA8K_MDIO_MASTER_CTRL);-if(val<0)-returnval;+if(qca8k_mdio_busy_wait(priv,QCA8K_MDIO_MASTER_CTRL,+QCA8K_MDIO_MASTER_BUSY))+val=-ETIMEDOUT;+else+val=qca8k_mii_read32(priv->bus,0x10|r2,r1);val&=QCA8K_MDIO_MASTER_DATA_MASK;+exit:+mutex_unlock(&priv->bus->mdio_lock);++if(val>=0)+val&=QCA8K_MDIO_MASTER_DATA_MASK;+/* even if the busy_wait timeouts try to clear the MASTER_EN */qca8k_reg_clear(priv,QCA8K_MDIO_MASTER_CTRL,QCA8K_MDIO_MASTER_EN);
@@ -641,7 +642,7 @@ qca8k_mdio_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)qca8k_split_addr(reg,&r1,&r2,&page);-timeout=jiffies+msecs_to_jiffies(20);+timeout=jiffies+msecs_to_jiffies(2000);/* loop until the busy flag has cleared */do{
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:31:18
Add support for phylink_connect_phy to pass dev_flags to the PHY driver.
Change any user of phylink_connect_phy to pass 0 as dev_flags by
default.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/ethernet/cadence/macb_main.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
drivers/net/phy/phylink.c | 12 +++++++-----
include/linux/phylink.h | 2 +-
net/dsa/slave.c | 2 +-
5 files changed, 11 insertions(+), 9 deletions(-)
@@ -834,7 +834,7 @@ static int macb_phylink_connect(struct macb *bp)}/* attach the mac to the phy */-ret=phylink_connect_phy(bp->phylink,phydev);+ret=phylink_connect_phy(bp->phylink,phydev,0);}if(ret){
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:31:20
Add support to dsa_slave_phy_connect to properly pass dev_flags if
defined by the dsa driver.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
net/dsa/slave.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
@@ -1718,7 +1718,7 @@ static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr)return-ENODEV;}-returnphylink_connect_phy(dp->pl,slave_dev->phydev,0);+returnphylink_connect_phy(dp->pl,slave_dev->phydev,flags);}staticintdsa_slave_phy_setup(structnet_device*slave_dev)
@@ -1762,7 +1762,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)/* We could not connect to a designated PHY or SFP, so try to*usetheswitchinternalMDIObusinstead*/-ret=dsa_slave_phy_connect(slave_dev,dp->index);+ret=dsa_slave_phy_connect(slave_dev,dp->index,phy_flags);if(ret){netdev_err(slave_dev,"failed to connect to port %d: %d\n",
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:31:24
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);++/* Communicate to the phy internal driver the switch revision.+*Basedontheswitchrevisiondifferentvaluesneedstobe+*settothedbgandmmdregonthephy.+*Thefirst2bitareusedtocommunicatetheswitchrevision+*tothephydriver.+*/+if(port>0&&port<6)+returnpriv->switch_revision;++return0;+}+staticenumdsa_tag_protocolqca8k_get_tag_protocol(structdsa_switch*ds,intport,enumdsa_tag_protocolmp)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:32:09
Add initial support for qca8k internal PHYs. The internal PHYs requires
special mmd and debug values to be set based on the switch revision
passwd using the dev_flags. Supports output of idle, receive and eee_wake
errors stats.
Some debug values sets can't be translated as the documentation lacks any
reference about them.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/phy/Kconfig | 7 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/qca8k.c | 174 +++++++++++++++++++++++++++++++++++++++
3 files changed, 182 insertions(+)
create mode 100644 drivers/net/phy/qca8k.c
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-04 22:32:14
Currently qca8337 switch are widely used on ipq8064 based router.
On these particular router it was notice a very unstable switch with
port not link detected as link with unknown speed, port dropping
randomly and general unreliability. Lots of testing and comparison
between this dsa driver and the original qsdk driver showed lack of some
additional delay and values. A main difference arised from the original
driver and the dsa one. The original driver didn't use MASTER regs to
read phy status and the dedicated mdio driver worked correctly. Now that
the dsa driver actually use these regs, it was found that these special
read/write operation required mutual exclusion to normal
qca8k_read/write operation. The add of mutex for these operation fixed
the random port dropping and now only the actual linked port randomly
dropped. Adding additional delay for set_page operation and fixing a bug
in the mdio dedicated driver fixed also this problem. The current driver
requires also more time to apply vlan switch. All of these changes and
tweak permit a now very stable and reliable dsa driver and 0 port
dropping. This series is currently tested by at least 5 user with
different routers and all reports positive results and no problems.
Changes v3:
- Revert mdio writel changes (use regmap with REGCACHE disabled)
- Split propagate error patch to 4 different patch
Changes v2:
- Implemented phy driver for internal PHYs
I'm testing cable test functions as I found some documentation that
actually declare regs about it. Problem is that it doesn't actually
work. It seems that the value set are ignored by the phy.
- Made the rgmii delay configurable
- Reordered patch
- Split mdio patches to more specific ones
- Reworked mdio driver to use readl/writel instead of regmap
- Reworked the entire driver to make it aware of any read/write error.
- Added phy generic patch to pass flags with phylink_connect_phy
function
A decision about the extra mdio delay is still to be taken but I
preferred to push a v2 since there is a new driver and more changes than
v0.
Ansuel Smith (20):
net: mdio: ipq8064: clean whitespaces in define
net: mdio: ipq8064: add regmap config to disable REGCACHE
net: mdio: ipq8064: enlarge sleep after read/write operation
net: dsa: qca8k: handle qca8k_set_page errors
net: dsa: qca8k: handle error with qca8k_read operation
net: dsa: qca8k: handle error with qca8k_write operation
net: dsa: qca8k: handle error with qca8k_rmw operation
net: dsa: qca8k: add support for qca8327 switch
devicetree: net: dsa: qca8k: Document new compatible qca8327
net: dsa: qca8k: add priority tweak to qca8337 switch
net: dsa: qca8k: add GLOBAL_FC settings needed for qca8327
net: dsa: qca8k: add support for switch rev
net: dsa: qca8k: make rgmii delay configurable
net: dsa: qca8k: clear MASTER_EN after phy read/write
net: dsa: qca8k: dsa: qca8k: protect MASTER busy_wait with mdio mutex
net: dsa: qca8k: enlarge mdio delay and timeout
net: phy: phylink: permit to pass dev_flags to phylink_connect_phy
net: dsa: slave: pass dev_flags also to internal PHY
net: dsa: qca8k: pass switch_revision info to phy dev_flags
net: phy: add qca8k driver for qca8k switch internal PHY
.../devicetree/bindings/net/dsa/qca8k.txt | 1 +
drivers/net/dsa/qca8k.c | 602 ++++++++++++++----
drivers/net/dsa/qca8k.h | 54 +-
drivers/net/ethernet/cadence/macb_main.c | 2 +-
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
drivers/net/mdio/mdio-ipq8064.c | 58 +-
drivers/net/phy/Kconfig | 7 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/phylink.c | 12 +-
drivers/net/phy/qca8k.c | 174 +++++
include/linux/phylink.h | 2 +-
net/dsa/slave.c | 6 +-
12 files changed, 756 insertions(+), 165 deletions(-)
create mode 100644 drivers/net/phy/qca8k.c
--
2.30.2
Add support for phylink_connect_phy to pass dev_flags to the PHY driver.
Change any user of phylink_connect_phy to pass 0 as dev_flags by
default.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
I do not think that this patch and the next one are necessary at all,
because phylink_of_phy_connect() already supports passing a dev_flags.
That means that you should be representing the switch's internal MDIO
bus in the Device Tree and then describe how each port of the switch
connects to the internal PHY on that same bus. Once you do that the
logic in net/dsa/slave.c will call phylink_of_phy_connect() and all you
will have to do is implement dsa_switch_ops::get_phy_flags. Can you try
that?
--
Florian
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-05 00:35:37
On Tue, May 04, 2021 at 03:33:36PM -0700, Florian Fainelli wrote:
On 5/4/21 3:29 PM, Ansuel Smith wrote:
quoted
Add support for phylink_connect_phy to pass dev_flags to the PHY driver.
Change any user of phylink_connect_phy to pass 0 as dev_flags by
default.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
I do not think that this patch and the next one are necessary at all,
because phylink_of_phy_connect() already supports passing a dev_flags.
That means that you should be representing the switch's internal MDIO
bus in the Device Tree and then describe how each port of the switch
connects to the internal PHY on that same bus. Once you do that the
logic in net/dsa/slave.c will call phylink_of_phy_connect() and all you
will have to do is implement dsa_switch_ops::get_phy_flags. Can you try
that?
I did some testing. Just to make sure I'm correctly implementing this I'm
using the phy-handle binding and the phy-mode set to internal. It does
work with a quick test but I think with this implementation we would be
back to this problem [0].
(I'm declaring the phy_port to the top mdio driver like it was done
before [0])
I was thinking if a good solution would be to register a internal mdio driver
in the qca8k code so that it can use the MASTER reg.
(it's late here so I could be very confused about this)
I think that using this solution we would be able to better describe the phy
by declaring them INSIDE the switch node instead of declaring them
outside in the top mdio node. The internal mdio driver would register
with this new mdio node inside the switch node and use the custom mdio
read/write that use the MASTER reg.
[0] http://patchwork.ozlabs.org/project/netdev/patch/20190319195419.12746-3-chunkeey@gmail.com/
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 00:36:23
On Wed, May 05, 2021 at 12:28:59AM +0200, Ansuel Smith wrote:
quoted hunk
qca8k_read can fail. Rework any user to handle error values and
correctly return.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 90 +++++++++++++++++++++++++++++++----------
1 file changed, 69 insertions(+), 21 deletions(-)
@@ -280,15 +285,17 @@ static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) { unsigned long timeout;+ u32 val; timeout = jiffies + msecs_to_jiffies(20); /* loop until the busy flag has cleared */ do {- u32 val = qca8k_read(priv, reg);- int busy = val & mask;+ val = qca8k_read(priv, reg);+ if (val < 0)+ continue;- if (!busy)+ if (!(val & mask)) break; cond_resched();
Maybe there is a patch doing this already, but it would be good to
make use of include/linux/iopoll.h
qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
{
- int ret;
+ int ret, ret_read;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
- if (ret >= 0)
- qca8k_fdb_read(priv, fdb);
+ if (ret >= 0) {
+ ret_read = qca8k_fdb_read(priv, fdb);
+ if (ret_read < 0)
+ return ret_read;
+ }
return ret;
}
This is oddly structured. Why not:
qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
{
int ret;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
if (ret < 0)
return ret;
return qca8k_fdb_read(priv, fdb);
}
Andrew
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-05 00:45:07
On Wed, May 05, 2021 at 02:36:15AM +0200, Andrew Lunn wrote:
On Wed, May 05, 2021 at 12:28:59AM +0200, Ansuel Smith wrote:
quoted
qca8k_read can fail. Rework any user to handle error values and
correctly return.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 90 +++++++++++++++++++++++++++++++----------
1 file changed, 69 insertions(+), 21 deletions(-)
@@ -280,15 +285,17 @@ static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) { unsigned long timeout;+ u32 val; timeout = jiffies + msecs_to_jiffies(20); /* loop until the busy flag has cleared */ do {- u32 val = qca8k_read(priv, reg);- int busy = val & mask;+ val = qca8k_read(priv, reg);+ if (val < 0)+ continue;- if (!busy)+ if (!(val & mask)) break; cond_resched();
Maybe there is a patch doing this already, but it would be good to
make use of include/linux/iopoll.h
Will check if I can find something to replace this.
quoted
qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
{
- int ret;
+ int ret, ret_read;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
- if (ret >= 0)
- qca8k_fdb_read(priv, fdb);
+ if (ret >= 0) {
+ ret_read = qca8k_fdb_read(priv, fdb);
+ if (ret_read < 0)
+ return ret_read;
+ }
return ret;
}
This is oddly structured. Why not:
qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
{
int ret;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
if (ret < 0)
return ret;
return qca8k_fdb_read(priv, fdb);
}
It's late here and I could be wrong...
Doesn't your suggested code change the original function return value?
In the original function we returned qca8k_fdb_access, isn't wrong to
return qca8k_fdb_read on success? Or the function was wrong from the
start?
@@ -1249,17 +1280,20 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) /* Add this port to the portvlan mask of the other ports * in the bridge */- qca8k_reg_set(priv,- QCA8K_PORT_LOOKUP_CTRL(i),- BIT(port));+ ret = qca8k_reg_set(priv,+ QCA8K_PORT_LOOKUP_CTRL(i),+ BIT(port));+ if (ret)+ return ret; if (i != port) port_mask |= BIT(i); }+ /* Add all other ports to this ports portvlan mask */- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_MEMBER, port_mask);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);- return 0;+ return ret < 0 ? ret : 0;
Can this is simplified to
return = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_MEMBER, port_mask);
quoted hunk
@@ -1396,18 +1430,19 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) { struct qca8k_priv *priv = ds->priv;+ int ret; if (vlan_filtering) {- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_VLAN_MODE,- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_VLAN_MODE,+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); } else {- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_VLAN_MODE,- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_VLAN_MODE,+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); }- return 0;+ return ret < 0 ? ret : 0;
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 00:48:11
On Wed, May 05, 2021 at 12:29:02AM +0200, Ansuel Smith wrote:
qca8327 switch is a low tier version of the more recent qca8337.
It does share the same regs used by the qca8k driver and can be
supported with minimal change.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
@@ -1249,17 +1280,20 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) /* Add this port to the portvlan mask of the other ports * in the bridge */- qca8k_reg_set(priv,- QCA8K_PORT_LOOKUP_CTRL(i),- BIT(port));+ ret = qca8k_reg_set(priv,+ QCA8K_PORT_LOOKUP_CTRL(i),+ BIT(port));+ if (ret)+ return ret; if (i != port) port_mask |= BIT(i); }+ /* Add all other ports to this ports portvlan mask */- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_MEMBER, port_mask);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);- return 0;+ return ret < 0 ? ret : 0;
Can this is simplified to
return = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_MEMBER, port_mask);
quoted
@@ -1396,18 +1430,19 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) { struct qca8k_priv *priv = ds->priv;+ int ret; if (vlan_filtering) {- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_VLAN_MODE,- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_VLAN_MODE,+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); } else {- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),- QCA8K_PORT_LOOKUP_VLAN_MODE,- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),+ QCA8K_PORT_LOOKUP_VLAN_MODE,+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); }- return 0;+ return ret < 0 ? ret : 0;
What does qca8k_rmw() actually return?
Andrew
qca8k_rmw in the original code returns the value read from the reg and
modified. So this is why all the strange checks. The idea is to not
change the original return values of the users so I check if every return
value is negative and return 0 in all the other cases.
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 00:53:09
On Wed, May 05, 2021 at 12:29:04AM +0200, Ansuel Smith wrote:
quoted hunk
The port 5 of the ar8337 have some problem in flood condition. The
original legacy driver had some specific buffer and priority settings
for the different port suggested by the QCA switch team. Add this
missing settings to improve switch stability under load condition.
The packet priority tweak and the rx delay is specific to qca8337.
Limit this changes to qca8337 as now we also support 8327 switch.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 54 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 24 ++++++++++++++++++
2 files changed, 76 insertions(+), 2 deletions(-)
@@ -783,7 +783,12 @@ static intqca8k_setup(structdsa_switch*ds){structqca8k_priv*priv=(structqca8k_priv*)ds->priv;+conststructqca8k_match_data*data;intret,i;+u32mask;++/* get the switches ID from the compatible */+data=of_device_get_match_data(priv->dev);
You have already done this once in probe. Either store data in qca8k_priv,
or add the id to qca8K_priv.
Andrew
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 01:00:52
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
quoted hunk
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
@@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)return0;}+staticint+qca8k_setup_of_rgmii_delay(structqca8k_priv*priv)+{+structdevice_node*ports,*port;+u32val;++ports=of_get_child_by_name(priv->dev->of_node,"ports");+if(!ports)+return-EINVAL;++/* Assume only one port with rgmii-id mode */+for_each_available_child_of_node(ports,port){
Are delays global? Or per port? They really should be per port. If it
is global, one value that applies to all ports, i would not use
it. Have the PHY apply the delay, not the MAC.
Andrew
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 01:04:53
On Wed, May 05, 2021 at 12:29:09AM +0200, Ansuel Smith wrote:
quoted hunk
MDIO_MASTER operation have a dedicated busy wait that is not protected
by the mdio mutex. This can cause situation where the MASTER operation
is done and a normal operation is executed between the MASTER read/write
and the MASTER busy_wait. Rework the qca8k_mdio_read/write function to
address this issue by binding the lock for the whole MASTER operation
and not only the mdio read/write common operation.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 69 ++++++++++++++++++++++++++++++++++-------
1 file changed, 57 insertions(+), 12 deletions(-)
@@ -633,9 +633,33 @@ qca8k_port_to_phy(int port)returnport-1;}+staticint+qca8k_mdio_busy_wait(structqca8k_priv*priv,u32reg,u32mask)+{+unsignedlongtimeout;+u16r1,r2,page;++qca8k_split_addr(reg,&r1,&r2,&page);++timeout=jiffies+msecs_to_jiffies(20);++/* loop until the busy flag has cleared */+do{+u32val=qca8k_mii_read32(priv->bus,0x10|r2,r1);+intbusy=val&mask;++if(!busy)+break;+cond_resched();+}while(!time_after_eq(jiffies,timeout));
include/linux/iopoll.h
quoted hunk
+
+ return time_after_eq(jiffies, timeout);
+}
+
static int
qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
{
+ u16 r1, r2, page;
u32 phy, val;
int ret;
@@ -651,12 +675,22 @@ qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data) QCA8K_MDIO_MASTER_REG_ADDR(regnum) | QCA8K_MDIO_MASTER_DATA(data);- ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);++ ret = qca8k_set_page(priv->bus, page); if (ret)- return ret;+ goto exit;- ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,- QCA8K_MDIO_MASTER_BUSY);+ qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);++ if (qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,+ QCA8K_MDIO_MASTER_BUSY))+ ret = -ETIMEDOUT;
qca8k_mdio_busy_wait() should be returning -EIMEDOUT.
Andrew
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-05 01:07:18
On Wed, May 05, 2021 at 03:00:45AM +0200, Andrew Lunn wrote:
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
quoted
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
@@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)return0;}+staticint+qca8k_setup_of_rgmii_delay(structqca8k_priv*priv)+{+structdevice_node*ports,*port;+u32val;++ports=of_get_child_by_name(priv->dev->of_node,"ports");+if(!ports)+return-EINVAL;++/* Assume only one port with rgmii-id mode */+for_each_available_child_of_node(ports,port){
Are delays global? Or per port? They really should be per port. If it
is global, one value that applies to all ports, i would not use
it. Have the PHY apply the delay, not the MAC.
Andrew
It's expected to set the delay in the port node. But yes the value is
global and assigned to every port (in reality this is only assigned to
the unique rgmii cpu port). The switch has only one rgmii port
and one sgmii, that's why I skipped any logic about handling more than
one case with internal delay. If you want I can try to add some logic to
handle this value per port. But again on the switch there is only one
reg to set the delay and the qca8k_phylink_mac_config function use this
only for the rgmii cpu port.
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-05 12:06:54
On Wed, May 05, 2021 at 03:17:20AM +0200, Ansuel Smith wrote:
On Wed, May 05, 2021 at 03:11:36AM +0200, Andrew Lunn wrote:
quoted
quoted
+/* QCA specific MII registers access function */
+static void qca8k_phy_dbg_write(struct mii_bus *bus, int phy_addr, u16 dbg_addr, u16 dbg_data)
+{
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+ bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
+ bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data);
+ mutex_unlock(&bus->mdio_lock);
+}
What are you locking against here?
Andrew
Added the locking if in the future it will be used outside the
config_init function but since it's used only there, yes, I can drop the
useless lock.
The PHY core will take the phydev->lock whenever it calls the PHY
driver functions. The only exception to this is suspend/resume. So
long as you only access the devices own addresses on the MDIO bus, you
don't need any additional locks.
Andrew
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-06 11:10:42
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
quoted hunk
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
Consider falling back to searching for the "ethernet-ports" name too,
DSA should now support both.
+ if (!ports)
+ return -EINVAL;
+
+ /* Assume only one port with rgmii-id mode */
+ for_each_available_child_of_node(ports, port) {
+ if (!of_property_match_string(port, "phy-mode", "rgmii-id"))
+ continue;
+
+ if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+ val = 2;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii rx delay is limited to more than 3ps, setting to the max value");
+ priv->rgmii_rx_delay = 3;
?!
3 picoseconds is not a lot of clock skew for a 125/25/2.5 MHz clock. 3 nanoseconds maybe?
quoted hunk
+ } else {
+ priv->rgmii_rx_delay = val;
+ }
+
+ if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+ val = 1;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii tx delay is limited to more than 3ps, setting to the max value");
+ priv->rgmii_tx_delay = 3;
+ } else {
+ priv->rgmii_rx_delay = val;
+ }
+ }
+
+ of_node_put(ports);
+
+ return 0;
+}
+
static int
qca8k_setup(struct dsa_switch *ds)
{
@@ -808,6 +849,10 @@ qca8k_setup(struct dsa_switch *ds) if (ret) return ret;+ ret = qca8k_setup_of_rgmii_delay(priv);+ if (ret)+ return ret;+ /* Enable CPU Port */ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
@@ -1018,8 +1063,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, */ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN |- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); /* QCA8337 requires to set rgmii rx delay */ if (data->id == QCA8K_ID_QCA8337) qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-06 11:16:27
On Wed, May 05, 2021 at 12:29:04AM +0200, Ansuel Smith wrote:
quoted hunk
The port 5 of the ar8337 have some problem in flood condition. The
original legacy driver had some specific buffer and priority settings
for the different port suggested by the QCA switch team. Add this
missing settings to improve switch stability under load condition.
The packet priority tweak and the rx delay is specific to qca8337.
Limit this changes to qca8337 as now we also support 8327 switch.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 54 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 24 ++++++++++++++++++
2 files changed, 76 insertions(+), 2 deletions(-)
@@ -783,7 +783,12 @@ static intqca8k_setup(structdsa_switch*ds){structqca8k_priv*priv=(structqca8k_priv*)ds->priv;+conststructqca8k_match_data*data;intret,i;+u32mask;++/* get the switches ID from the compatible */+data=of_device_get_match_data(priv->dev);/* Make sure that port 0 is the cpu port */if(!dsa_is_cpu_port(ds,0)){
@@ -889,6 +894,45 @@ qca8k_setup(struct dsa_switch *ds)}}+if(data->id==QCA8K_ID_QCA8337){+for(i=0;i<QCA8K_NUM_PORTS;i++){+switch(i){+/* The 2 CPU port and port 5 requires some different+*prioritythananyotherports.+*/+case0:+case5:+case6:+mask=QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3)|+QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6)|+QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8)|+QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);+break;+default:+mask=QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3)|+QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4)|+QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6)|+QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8)|+QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);+}+qca8k_write(priv,QCA8K_REG_PORT_HOL_CTRL0(i),mask);++mask=QCA8K_PORT_HOL_CTRL1_ING(0x6)|+QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN|+QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN|+QCA8K_PORT_HOL_CTRL1_WRED_EN;+qca8k_rmw(priv,QCA8K_REG_PORT_HOL_CTRL1(i),+QCA8K_PORT_HOL_CTRL1_ING_BUF|+QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN|+QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN|+QCA8K_PORT_HOL_CTRL1_WRED_EN,+mask);+}
What is this actually doing and why is it needed?
quoted hunk
+ }
+
/* Setup our port MTUs to match power on defaults */
for (i = 0; i < QCA8K_NUM_PORTS; i++)
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
@@ -909,9 +953,13 @@ static void qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) {+ const struct qca8k_match_data *data; struct qca8k_priv *priv = ds->priv; u32 reg, val;+ /* get the switches ID from the compatible */+ data = of_device_get_match_data(priv->dev);+ switch (port) { case 0: /* 1st CPU port */ if (state->interface != PHY_INTERFACE_MODE_RGMII &&
@@ -962,8 +1010,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, QCA8K_PORT_PAD_RGMII_EN | QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) | QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);+ /* QCA8337 requires to set rgmii rx delay */+ if (data->id == QCA8K_ID_QCA8337)+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
Why are we looking at an RGMII delay change in a patch about "priority
tweaks"? This patch is very confusing.
quoted hunk
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-06 11:20:59
On Wed, May 05, 2021 at 12:29:02AM +0200, Ansuel Smith wrote:
qca8327 switch is a low tier version of the more recent qca8337.
It does share the same regs used by the qca8k driver and can be
supported with minimal change.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-06 11:25:05
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted hunk
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted hunk
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
From: Rob Herring <robh@kernel.org> Date: 2021-05-06 21:07:22
On Wed, 05 May 2021 00:29:03 +0200, Ansuel Smith wrote:
Add support for qca8327 in the compatible list.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 1 +
1 file changed, 1 insertion(+)
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-06 21:53:42
On Thu, May 06, 2021 at 02:10:33PM +0300, Vladimir Oltean wrote:
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
quoted
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
Consider falling back to searching for the "ethernet-ports" name too,
DSA should now support both.
The function qca8k_setup_mdio_bus also checks for ports node. Should I
also there the fallback correct?
quoted
+ if (!ports)
+ return -EINVAL;
+
+ /* Assume only one port with rgmii-id mode */
+ for_each_available_child_of_node(ports, port) {
+ if (!of_property_match_string(port, "phy-mode", "rgmii-id"))
+ continue;
+
+ if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+ val = 2;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii rx delay is limited to more than 3ps, setting to the max value");
+ priv->rgmii_rx_delay = 3;
?!
3 picoseconds is not a lot of clock skew for a 125/25/2.5 MHz clock. 3 nanoseconds maybe?
quoted
+ } else {
+ priv->rgmii_rx_delay = val;
+ }
+
+ if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+ val = 1;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii tx delay is limited to more than 3ps, setting to the max value");
+ priv->rgmii_tx_delay = 3;
+ } else {
+ priv->rgmii_rx_delay = val;
+ }
+ }
+
+ of_node_put(ports);
+
+ return 0;
+}
+
static int
qca8k_setup(struct dsa_switch *ds)
{
@@ -808,6 +849,10 @@ qca8k_setup(struct dsa_switch *ds) if (ret) return ret;+ ret = qca8k_setup_of_rgmii_delay(priv);+ if (ret)+ return ret;+ /* Enable CPU Port */ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
@@ -1018,8 +1063,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, */ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN |- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); /* QCA8337 requires to set rgmii rx delay */ if (data->id == QCA8K_ID_QCA8337) qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-07 08:51:22
On Thu, May 06, 2021 at 11:53:36PM +0200, Ansuel Smith wrote:
On Thu, May 06, 2021 at 02:10:33PM +0300, Vladimir Oltean wrote:
quoted
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
quoted
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
drivers/net/dsa/qca8k.h | 11 +++++----
2 files changed, 55 insertions(+), 7 deletions(-)
+
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
We had some discussion back in February about the PHY flags argument
("Rework of phydev->dev_flags") as there is a need to generically
identify whether a PHY is on a SFP module or not. This discussion
hasn't progressed to any changes (yet) but some of the points remain
valid: if we do go down the route of needing to have generic PHY flags
in dev_flags, then we need vendor specific stuff to avoid those bits.
So, rather than introduce a new case of passing some undefined data
through the flags argument, can we come up with some sort of proposal
for this.
It may also be a good idea if we document it. Maybe something like
"low 16 bits are free for driver use, upper 16 bits are reserved
for generic use"?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-07 23:26:05
On Thu, May 06, 2021 at 02:24:58PM +0300, Vladimir Oltean wrote:
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
Just to make sure. This is the SWITCH revision not the PHY revision. It
was pointed out in old version that I should get this value from the PHY
regs but they are different values. This is why the dsa driver needs to
use the dev_flags to pass the SWITCH revision to the phy driver. Am I
implementing this in the wrong way and I should declare something to
pass this value in a more standard way? (anyway i'm pushing v4 so i
don't know if we should continue that there)
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-05-07 23:35:30
On Sat, May 08, 2021 at 01:26:02AM +0200, Ansuel Smith wrote:
On Thu, May 06, 2021 at 02:24:58PM +0300, Vladimir Oltean wrote:
quoted
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
Just to make sure. This is the SWITCH revision not the PHY revision. It
was pointed out in old version that I should get this value from the PHY
regs but they are different values. This is why the dsa driver needs to
use the dev_flags to pass the SWITCH revision to the phy driver. Am I
implementing this in the wrong way and I should declare something to
pass this value in a more standard way? (anyway i'm pushing v4 so i
don't know if we should continue that there)
Vladimir is confused - it is not PHY revision at all, but the PHY
identifiers.
What was actually suggested was checking the PHY identifiers before
passing PHY-driver specific flags, so that we didn't end up setting
driver private flags that are intending for one driver, but end up
actually binding a different driver, and mis-interpreting the flags.
This is one of the problems of the current scheme: it's just a
meaningless opaque u32 variable with no defined structure to it that
the various PHY drivers themselves use in whatever way they see fit.
That is only fine to use _if_ you know for certain which driver is
going to bind ahead of time.
As I mentioned in direct reply to your patch, there was discussions
about this back in February, but they seem to have stalled.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Ansuel Smith <ansuelsmth@gmail.com> Date: 2021-05-07 23:51:36
On Sat, May 08, 2021 at 12:33:53AM +0100, Russell King - ARM Linux admin wrote:
On Sat, May 08, 2021 at 01:26:02AM +0200, Ansuel Smith wrote:
quoted
On Thu, May 06, 2021 at 02:24:58PM +0300, Vladimir Oltean wrote:
quoted
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
Just to make sure. This is the SWITCH revision not the PHY revision. It
was pointed out in old version that I should get this value from the PHY
regs but they are different values. This is why the dsa driver needs to
use the dev_flags to pass the SWITCH revision to the phy driver. Am I
implementing this in the wrong way and I should declare something to
pass this value in a more standard way? (anyway i'm pushing v4 so i
don't know if we should continue that there)
Vladimir is confused - it is not PHY revision at all, but the PHY
identifiers.
What was actually suggested was checking the PHY identifiers before
passing PHY-driver specific flags, so that we didn't end up setting
driver private flags that are intending for one driver, but end up
actually binding a different driver, and mis-interpreting the flags.
This is one of the problems of the current scheme: it's just a
meaningless opaque u32 variable with no defined structure to it that
the various PHY drivers themselves use in whatever way they see fit.
That is only fine to use _if_ you know for certain which driver is
going to bind ahead of time.
The problem here was find a way to pass data from the dsa driver to the
phy driver. In this specific case the phy driver is an internal phy
present in the switch so it won't appear on anything else. Aside from
this I agree that it seems wrong that random values are used without
some type of rules or definition but I think that try to address this
problem is too much for this already large series. In theory this should
be safe to use as this driver would only be used by qca8k dsa driver.
As I mentioned in direct reply to your patch, there was discussions
about this back in February, but they seem to have stalled.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-08 17:31:58
The problem here was find a way to pass data from the dsa driver to the
phy driver. In this specific case the phy driver is an internal phy
present in the switch so it won't appear on anything else.
For internal PHYs, you are safe. But please keep in mind any RGMII
ports which the switch might have. Somebody could attach an external
PHY on such a port. So you should not return any flags for such ports.
Andrew
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-05-08 18:26:28
On Sat, May 08, 2021 at 12:33:53AM +0100, Russell King - ARM Linux admin wrote:
On Sat, May 08, 2021 at 01:26:02AM +0200, Ansuel Smith wrote:
quoted
On Thu, May 06, 2021 at 02:24:58PM +0300, Vladimir Oltean wrote:
quoted
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
Just to make sure. This is the SWITCH revision not the PHY revision. It
was pointed out in old version that I should get this value from the PHY
regs but they are different values. This is why the dsa driver needs to
use the dev_flags to pass the SWITCH revision to the phy driver. Am I
implementing this in the wrong way and I should declare something to
pass this value in a more standard way? (anyway i'm pushing v4 so i
don't know if we should continue that there)
Vladimir is confused - it is not PHY revision at all, but the PHY
identifiers.
What was actually suggested was checking the PHY identifiers before
passing PHY-driver specific flags, so that we didn't end up setting
driver private flags that are intending for one driver, but end up
actually binding a different driver, and mis-interpreting the flags.
This is one of the problems of the current scheme: it's just a
meaningless opaque u32 variable with no defined structure to it that
the various PHY drivers themselves use in whatever way they see fit.
That is only fine to use _if_ you know for certain which driver is
going to bind ahead of time.
As I mentioned in direct reply to your patch, there was discussions
about this back in February, but they seem to have stalled.
Yes, I was indeed confused. My problem was mixing up the PHY OUI/device ID
and revision concepts in one big fuzzy notion. I remembered Heiner's
suggestion to do something similar to mv88e6xxx_mdio_read from here:
https://patchwork.kernel.org/project/netdevbpf/patch/20210423014741.11858-12-ansuelsmth@gmail.com/
(where the problem is that some internal PHYs are lacking a device
identifier) and thought that the problem here is the same.
Nonetheless, now it is clear to me that with care (don't set dev_flags
except for internal PHYs which are statically known), it is possible for
the PHY driver to have a larger identifier (PHY ID concatenated with
switch revision passed through dev_flags) based on which it can
configure the hardware.
Sorry.
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-05-08 19:39:23
On Sat, May 08, 2021 at 09:26:20PM +0300, Vladimir Oltean wrote:
On Sat, May 08, 2021 at 12:33:53AM +0100, Russell King - ARM Linux admin wrote:
quoted
On Sat, May 08, 2021 at 01:26:02AM +0200, Ansuel Smith wrote:
quoted
On Thu, May 06, 2021 at 02:24:58PM +0300, Vladimir Oltean wrote:
quoted
On Wed, May 05, 2021 at 12:29:13AM +0200, Ansuel Smith wrote:
quoted
Define get_phy_flags to pass switch_Revision needed to tweak the
internal PHY with debug values based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
@@ -1654,6 +1654,24 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,returnret;}+staticu32qca8k_get_phy_flags(structdsa_switch*ds,intport)+{+structqca8k_priv*priv=ds->priv;++pr_info("revision from phy %d",priv->switch_revision);
Log spam.
quoted
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
Florian, I think at one point you said that a correct user of
phydev->dev_flags should first check the PHY revision and not apply
dev_flags in blind, since they are namespaced to each PHY driver?
It sounds a bit circular to pass the PHY revision to the PHY through
phydev->dev_flags, either that or I'm missing some piece.
Just to make sure. This is the SWITCH revision not the PHY revision. It
was pointed out in old version that I should get this value from the PHY
regs but they are different values. This is why the dsa driver needs to
use the dev_flags to pass the SWITCH revision to the phy driver. Am I
implementing this in the wrong way and I should declare something to
pass this value in a more standard way? (anyway i'm pushing v4 so i
don't know if we should continue that there)
Vladimir is confused - it is not PHY revision at all, but the PHY
identifiers.
What was actually suggested was checking the PHY identifiers before
passing PHY-driver specific flags, so that we didn't end up setting
driver private flags that are intending for one driver, but end up
actually binding a different driver, and mis-interpreting the flags.
This is one of the problems of the current scheme: it's just a
meaningless opaque u32 variable with no defined structure to it that
the various PHY drivers themselves use in whatever way they see fit.
That is only fine to use _if_ you know for certain which driver is
going to bind ahead of time.
As I mentioned in direct reply to your patch, there was discussions
about this back in February, but they seem to have stalled.
Yes, I was indeed confused. My problem was mixing up the PHY OUI/device ID
and revision concepts in one big fuzzy notion. I remembered Heiner's
suggestion to do something similar to mv88e6xxx_mdio_read from here:
https://patchwork.kernel.org/project/netdevbpf/patch/20210423014741.11858-12-ansuelsmth@gmail.com/
(where the problem is that some internal PHYs are lacking a device
identifier) and thought that the problem here is the same.
Nonetheless, now it is clear to me that with care (don't set dev_flags
except for internal PHYs which are statically known), it is possible for
the PHY driver to have a larger identifier (PHY ID concatenated with
switch revision passed through dev_flags) based on which it can
configure the hardware.
We do have the problem with Marvell DSA vs Marvell PHY setup in that
the Marvell DSA driver assumes that all integrated PHYs that do not
have an ID are all the same. They are most definitely not, and this
shows itself up when we register the hwmon stuff inappropriately, or
access the wrong registers to report hwmon values.
We really need to solve this problem properly rather than bodging
around it with driver specific usage of dev_flags.
We already have the ability for drivers to have custom match functions
(match_phy_device) that do not depend on the probed ID - maybe we
should have an additional u32 member in struct phy_device for the
switch_id that the PHY is a part of that PHY drivers can check in their
match_phy_device method if necessary, or otherwise use that to parse
the switch revision from. Or something like that?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-05-08 20:56:06
We do have the problem with Marvell DSA vs Marvell PHY setup in that
the Marvell DSA driver assumes that all integrated PHYs that do not
have an ID are all the same. They are most definitely not, and this
shows itself up when we register the hwmon stuff inappropriately, or
access the wrong registers to report hwmon values.
Hi Russell
This was to some degree fixed recently. Rather than always use the
6390 ID for everything, the family ID is now used. This should avoid
the issue with the SERDES being incorrectly considered a PHY, since
that particular family ID is not listed in the PHY driver.
Andrew