From: Marek Behún <kabel@kernel.org> Date: 2021-01-11 05:01:50
Hello,
this is v4 of series adding support for RollBall/Hilink SFP modules.
Checked with:
checkpatch.pl --max-line-length=80
Changes from v3:
- RollBall mdio-i2c driver now sets/restores SFP_PAGE for every MDIO
access.
I first wanted to achieve this operation (setting
SFP_PAGE/doing MDIO/restoring SFP_PAGE) via one call do i2c_transfer,
by constructing msgs array in such a way, but it turned out that this
doesn't work on RollBall SFPs, because changed SFP_PAGE takes into
account only after i2c_transfer ends.
So instead I use i2c_lock_bus/serveral __i2c_transfers/i2c_unlock_bus.
- I have removed the patch which changes MACTYPE in the marvell10g
driver, since Russell has in his net-queue a better solution. I still
think that my patch would have sufficed temporarily (and would not
cause regressions), but nobody wanted to review it. If you think that
I should sent this series again with that patch, please let me know.
Changes from v2:
- added comment into the patch adding support for RollBall I2C MDIO
protocol, saying that we expect the SFP_PAGE not to be changed by
the SFP code, as requested by Russell. If, in the future, SFP code
starts modifying SFP_PAGE, we will have to handle it in mdio-i2c
somehow
- destruction of I2C MDIO bus in patch 3/5 now depends on whether the
MDIO bus is not NULL, instead of whether PHY exists, as suggested by
Russell
- changed waiting time for RollBall module to initialize from 30 seconds
to 25 seconds. Testing shows that it is never longer than 21-22
seconds, so waiting 25 seconds instead of 30 is IMO safe enough
- added Russell's Reviewed-by tags where relevant
Changes from v1:
- wrapped to 80 columns as per Russell's request
- initialization of RollBall MDIO I2C protocol moved from sfp.c to
mdio-i2c.c as per Russell's request
- second patch removes the 802.3z check also from phylink_sfp_config
as suggested by Russell
- creation/destruction of mdiobus for SFP now occurs before probing
for PHY/after releasing PHY (as suggested by Russell)
- the last patch became a little simpler after the above was done
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
Marek Behún (4):
net: phy: mdio-i2c: support I2C MDIO protocol for RollBall SFP modules
net: phylink: allow attaching phy for SFP modules on 802.3z mode
net: sfp: create/destroy I2C mdiobus before PHY probe/after PHY
release
net: sfp: add support for multigig RollBall transceivers
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/phylink.c | 5 +-
drivers/net/phy/sfp.c | 66 +++++--
include/linux/mdio/mdio-i2c.h | 8 +-
4 files changed, 378 insertions(+), 20 deletions(-)
base-commit: 73b7a6047971aa6ce4a70fc4901964d14f077171
--
2.26.2
From: Marek Behún <kabel@kernel.org> Date: 2021-01-11 05:01:50
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id)returnphy_id+0x40;}-staticinti2c_mii_read(structmii_bus*bus,intphy_id,intreg)+staticinti2c_mii_read_default(structmii_bus*bus,intphy_id,intreg){structi2c_adapter*i2c=bus->priv;structi2c_msgmsgs[2];
@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)returndata[0]<<8|data[1];}-staticinti2c_mii_write(structmii_bus*bus,intphy_id,intreg,u16val)+staticinti2c_mii_write_default(structmii_bus*bus,intphy_id,intreg,+u16val){structi2c_adapter*i2c=bus->priv;structi2c_msgmsg;
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)returnret<0?ret:0;}-structmii_bus*mdio_i2c_alloc(structdevice*parent,structi2c_adapter*i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+*insteadviaaddress0x51,whenSFPpageissetto0x03andpasswordto+*0xffffffff.+*SincecurrentSFPcodedoesnotmodifySFP_PAGE,wesetitto0x03onlyat+*buscreationtime,andexpectittoremainsetto0x03throughoutthe+*lifetimeofthemodulepluggedintothesystem.IftheSFPcodestarts+*modifyingSFP_PAGEinthefuture,thiscodewillneedtochange.+*+*addresssizecontentsdescription+*------------------------------+*0x801CMD0x01/0x02/0x04forwrite/read/done+*0x811DEVClause45device+*0x822REGClause45register+*0x842VALRegistervalue+*/+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b++#define ROLLBALL_CMD_ADDR 0x80+#define ROLLBALL_DATA_ADDR 0x81++#define ROLLBALL_CMD_WRITE 0x01+#define ROLLBALL_CMD_READ 0x02+#define ROLLBALL_CMD_DONE 0x04++#define SFP_PAGE_ROLLBALL_MDIO 3++staticint__i2c_transfer_err(structi2c_adapter*i2c,structi2c_msg*msgs,+intnum)+{+intret;++ret=__i2c_transfer(i2c,msgs,num);+if(ret<0)+returnret;+elseif(ret!=num)+return-EIO;+else+return0;+}++staticint__i2c_rollball_get_page(structi2c_adapter*i2c,intbus_addr,+u8*page)+{+structi2c_msgmsgs[2];+u8addr=SFP_PAGE;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=1;+msgs[0].buf=&addr;++msgs[1].addr=bus_addr;+msgs[1].flags=I2C_M_RD;+msgs[1].len=1;+msgs[1].buf=page;++return__i2c_transfer_err(i2c,msgs,2);+}++staticint__i2c_rollball_set_page(structi2c_adapter*i2c,intbus_addr,+u8page)+{+structi2c_msgmsg;+u8buf[2];++buf[0]=SFP_PAGE;+buf[1]=page;++msg.addr=bus_addr;+msg.flags=0;+msg.len=2;+msg.buf=buf;++return__i2c_transfer_err(i2c,&msg,1);+}++/* In order to not interfere with other SFP code (which possibly may manipulate+*SFP_PAGE),foreverytransferwedothis:+*1.lockthebus+*2.savecontentofSFP_PAGE+*3.setSFP_PAGEto3+*4.dothetransfer+*5.restoreoriginalSFP_PAGE+*6.unlockthebus+*Notethatonemightthinkthatsteps2to5couldbetheoreticallydoneall+*inonecalltoi2c_transfer(byconstructingmsgsarrayinsuchaway),but+*unfortunatelytestsshowthatthisdoesnotwork:-(ChangedSFP_PAGEdoes+*nottakeintoaccountuntili2c_transfer()isdone.+*/+staticinti2c_transfer_rollball(structi2c_adapter*i2c,+structi2c_msg*msgs,intnum)+{+u8saved_page;+intret;++i2c_lock_bus(i2c,I2C_LOCK_SEGMENT);++/* save original page */+ret=__i2c_rollball_get_page(i2c,msgs->addr,&saved_page);+if(ret)+gotounlock;++/* change to RollBall MDIO page */+ret=__i2c_rollball_set_page(i2c,msgs->addr,SFP_PAGE_ROLLBALL_MDIO);+if(ret)+gotounlock;++/* do the transfer */+ret=__i2c_transfer_err(i2c,msgs,num);+if(ret)+gotounlock;++/* restore original page */+ret=__i2c_rollball_set_page(i2c,msgs->addr,saved_page);++unlock:+i2c_unlock_bus(i2c,I2C_LOCK_SEGMENT);++returnret;+}++staticinti2c_rollball_mii_poll(structmii_bus*bus,intbus_addr,u8*buf,+size_tlen)+{+structi2c_adapter*i2c=bus->priv;+structi2c_msgmsgs[2];+u8cmd_addr,tmp,*res;+inti,ret;++cmd_addr=ROLLBALL_CMD_ADDR;++res=buf?buf:&tmp;+len=buf?len:1;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=1;+msgs[0].buf=&cmd_addr;++msgs[1].addr=bus_addr;+msgs[1].flags=I2C_M_RD;+msgs[1].len=len;+msgs[1].buf=res;++/* By experiment it takes up to 70 ms to access a register for these+*SFPs.Sleep20msbetweeniteratiosandtry10times.+*/+i=10;+do{+msleep(20);++ret=i2c_transfer_rollball(i2c,msgs,ARRAY_SIZE(msgs));+if(ret)+returnret;++if(*res==ROLLBALL_CMD_DONE)+return0;+}while(i-->0);++dev_dbg(&bus->dev,"poll timed out\n");++return-ETIMEDOUT;+}++staticinti2c_rollball_mii_cmd(structmii_bus*bus,intbus_addr,u8cmd,+u8*data,size_tlen)+{+structi2c_adapter*i2c=bus->priv;+structi2c_msgmsgs[2];+u8cmdbuf[2];++cmdbuf[0]=ROLLBALL_CMD_ADDR;+cmdbuf[1]=cmd;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=len;+msgs[0].buf=data;++msgs[1].addr=bus_addr;+msgs[1].flags=0;+msgs[1].len=sizeof(cmdbuf);+msgs[1].buf=cmdbuf;++returni2c_transfer_rollball(i2c,msgs,ARRAY_SIZE(msgs));+}++staticinti2c_mii_read_rollball(structmii_bus*bus,intphy_id,intreg)+{+u8buf[4],res[6];+intbus_addr,ret;+u16val;++if(!(reg&MII_ADDR_C45))+return-EOPNOTSUPP;++bus_addr=i2c_mii_phy_addr(phy_id);+if(bus_addr!=ROLLBALL_PHY_I2C_ADDR)+return0xffff;++buf[0]=ROLLBALL_DATA_ADDR;+buf[1]=(reg>>16)&0x1f;+buf[2]=(reg>>8)&0xff;+buf[3]=reg&0xff;++ret=i2c_rollball_mii_cmd(bus,bus_addr,ROLLBALL_CMD_READ,buf,+sizeof(buf));+if(ret<0)+returnret;++ret=i2c_rollball_mii_poll(bus,bus_addr,res,sizeof(res));+if(ret==-ETIMEDOUT)+return0xffff;+elseif(ret<0)+returnret;++val=res[4]<<8|res[5];++dev_dbg(&bus->dev,"read reg %02x:%04x = %04x\n",(reg>>16)&0x1f,+reg&0xffff,val);++returnval;+}++staticinti2c_mii_write_rollball(structmii_bus*bus,intphy_id,intreg,+u16val)+{+intbus_addr,ret;+u8buf[6];++if(!(reg&MII_ADDR_C45))+return-EOPNOTSUPP;++bus_addr=i2c_mii_phy_addr(phy_id);+if(bus_addr!=ROLLBALL_PHY_I2C_ADDR)+return0;++buf[0]=ROLLBALL_DATA_ADDR;+buf[1]=(reg>>16)&0x1f;+buf[2]=(reg>>8)&0xff;+buf[3]=reg&0xff;+buf[4]=val>>8;+buf[5]=val&0xff;++ret=i2c_rollball_mii_cmd(bus,bus_addr,ROLLBALL_CMD_WRITE,buf,+sizeof(buf));+if(ret<0)+returnret;++ret=i2c_rollball_mii_poll(bus,bus_addr,NULL,0);+if(ret<0)+returnret;++dev_dbg(&bus->dev,"write reg %02x:%04x = %04x\n",(reg>>16)&0x1f,+reg&0xffff,val);++return0;+}++staticinti2c_mii_init_rollball(structi2c_adapter*i2c)+{+structi2c_msgmsg;+u8pw[5];+intret;++pw[0]=ROLLBALL_SFP_PASSWORD_ADDR;+pw[1]=0xff;+pw[2]=0xff;+pw[3]=0xff;+pw[4]=0xff;++msg.addr=ROLLBALL_PHY_I2C_ADDR;+msg.flags=0;+msg.len=sizeof(pw);+msg.buf=pw;++ret=i2c_transfer(i2c,&msg,1);+if(ret<0)+returnret;+elseif(ret!=1)+return-EIO;+else+return0;+}++structmii_bus*mdio_i2c_alloc(structdevice*parent,structi2c_adapter*i2c,+enummdio_i2c_protoprotocol){structmii_bus*mii;+intret;if(!i2c_check_functionality(i2c,I2C_FUNC_I2C))returnERR_PTR(-EINVAL);
From: Marek Behún <kabel@kernel.org> Date: 2021-01-11 05:01:50
This adds support for multigig copper SFP modules from RollBall/Hilink.
These modules have a specific way to access clause 45 registers of the
internal PHY.
We also need to wait at least 22 seconds after deasserting TX disable
before accessing the PHY. The code waits for 25 seconds just to be sure.
Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Russell King <redacted>
Cc: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)
@@ -1835,6 +1841,23 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)sfp->mdio_protocol=MDIO_I2C_DEFAULT;+sfp->phy_addr=SFP_PHY_ADDR;+sfp->module_t_wait=T_WAIT;++if(((!memcmp(id.base.vendor_name,"OEM ",16)||+!memcmp(id.base.vendor_name,"Turris ",16))&&+(!memcmp(id.base.vendor_pn,"SFP-10G-T ",16)||+!memcmp(id.base.vendor_pn,"RTSFP-10",8)))){+sfp->mdio_protocol=MDIO_I2C_ROLLBALL;+sfp->phy_addr=SFP_PHY_ADDR_ROLLBALL;+sfp->module_t_wait=T_WAIT_ROLLBALL;++/* RollBall SFPs may have wrong (zero) extended compliacne code+*burnedinEEPROM.ForPHYprobingweneedthecorrectone.+*/+id.base.extended_cc=SFF8024_ECC_10GBASE_T_SFI;+}+return0;}
@@ -2030,9 +2053,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)/* We need to check the TX_FAULT state, which is not defined*whileTX_DISABLEisasserted.Theearliestwewanttodo-*anything(suchasprobeforaPHY)is50ms.+*anything(suchasprobeforaPHY)is50ms.(ormoreon+*specificmodules).*/-sfp_sm_next(sfp,SFP_S_WAIT,T_WAIT);+sfp_sm_next(sfp,SFP_S_WAIT,sfp->module_t_wait);break;caseSFP_S_WAIT:
From: Marek Behún <kabel@kernel.org> Date: 2021-01-11 05:01:50
Some SFPs may contain an internal PHY which may in some cases want to
connect with the host interface in 1000base-x/2500base-x mode.
Do not fail if such PHY is being attached in one of these PHY interface
modes.
Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Russell King <redacted>
Cc: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/phylink.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
From: Marek Behún <kabel@kernel.org> Date: 2021-01-11 05:01:50
Instead of configuring the I2C mdiobus when SFP driver is probed,
create/destroy the mdiobus before the PHY is probed for/after it is
released.
This way we can tell the mdio-i2c code which protocol to use for each
SFP transceiver.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/phy/sfp.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
quoted hunk
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id)returnphy_id+0x40;}-staticinti2c_mii_read(structmii_bus*bus,intphy_id,intreg)+staticinti2c_mii_read_default(structmii_bus*bus,intphy_id,intreg){structi2c_adapter*i2c=bus->priv;structi2c_msgmsgs[2];
@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)returndata[0]<<8|data[1];}-staticinti2c_mii_write(structmii_bus*bus,intphy_id,intreg,u16val)+staticinti2c_mii_write_default(structmii_bus*bus,intphy_id,intreg,+u16val){structi2c_adapter*i2c=bus->priv;structi2c_msgmsg;
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)returnret<0?ret:0;}-structmii_bus*mdio_i2c_alloc(structdevice*parent,structi2c_adapter*i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+*insteadviaaddress0x51,whenSFPpageissetto0x03andpasswordto+*0xffffffff.+*SincecurrentSFPcodedoesnotmodifySFP_PAGE,wesetitto0x03onlyat+*buscreationtime,andexpectittoremainsetto0x03throughoutthe+*lifetimeofthemodulepluggedintothesystem.IftheSFPcodestarts+*modifyingSFP_PAGEinthefuture,thiscodewillneedtochange.+*+*addresssizecontentsdescription+*------------------------------+*0x801CMD0x01/0x02/0x04forwrite/read/done+*0x811DEVClause45device+*0x822REGClause45register+*0x842VALRegistervalue+*/+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b++#define ROLLBALL_CMD_ADDR 0x80+#define ROLLBALL_DATA_ADDR 0x81++#define ROLLBALL_CMD_WRITE 0x01+#define ROLLBALL_CMD_READ 0x02+#define ROLLBALL_CMD_DONE 0x04++#define SFP_PAGE_ROLLBALL_MDIO 3++staticint__i2c_transfer_err(structi2c_adapter*i2c,structi2c_msg*msgs,+intnum)+{+intret;++ret=__i2c_transfer(i2c,msgs,num);+if(ret<0)+returnret;+elseif(ret!=num)+return-EIO;+else+return0;+}++staticint__i2c_rollball_get_page(structi2c_adapter*i2c,intbus_addr,+u8*page)+{+structi2c_msgmsgs[2];+u8addr=SFP_PAGE;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=1;+msgs[0].buf=&addr;++msgs[1].addr=bus_addr;+msgs[1].flags=I2C_M_RD;+msgs[1].len=1;+msgs[1].buf=page;++return__i2c_transfer_err(i2c,msgs,2);+}++staticint__i2c_rollball_set_page(structi2c_adapter*i2c,intbus_addr,+u8page)+{+structi2c_msgmsg;+u8buf[2];++buf[0]=SFP_PAGE;+buf[1]=page;++msg.addr=bus_addr;+msg.flags=0;+msg.len=2;+msg.buf=buf;++return__i2c_transfer_err(i2c,&msg,1);+}++/* In order to not interfere with other SFP code (which possibly may manipulate+*SFP_PAGE),foreverytransferwedothis:+*1.lockthebus+*2.savecontentofSFP_PAGE+*3.setSFP_PAGEto3+*4.dothetransfer+*5.restoreoriginalSFP_PAGE+*6.unlockthebus+*Notethatonemightthinkthatsteps2to5couldbetheoreticallydoneall+*inonecalltoi2c_transfer(byconstructingmsgsarrayinsuchaway),but+*unfortunatelytestsshowthatthisdoesnotwork:-(ChangedSFP_PAGEdoes+*nottakeintoaccountuntili2c_transfer()isdone.+*/+staticinti2c_transfer_rollball(structi2c_adapter*i2c,+structi2c_msg*msgs,intnum)+{+u8saved_page;+intret;++i2c_lock_bus(i2c,I2C_LOCK_SEGMENT);++/* save original page */+ret=__i2c_rollball_get_page(i2c,msgs->addr,&saved_page);+if(ret)+gotounlock;++/* change to RollBall MDIO page */+ret=__i2c_rollball_set_page(i2c,msgs->addr,SFP_PAGE_ROLLBALL_MDIO);+if(ret)+gotounlock;++/* do the transfer */+ret=__i2c_transfer_err(i2c,msgs,num);+if(ret)+gotounlock;++/* restore original page */+ret=__i2c_rollball_set_page(i2c,msgs->addr,saved_page);++unlock:+i2c_unlock_bus(i2c,I2C_LOCK_SEGMENT);++returnret;+}++staticinti2c_rollball_mii_poll(structmii_bus*bus,intbus_addr,u8*buf,+size_tlen)+{+structi2c_adapter*i2c=bus->priv;+structi2c_msgmsgs[2];+u8cmd_addr,tmp,*res;+inti,ret;++cmd_addr=ROLLBALL_CMD_ADDR;++res=buf?buf:&tmp;+len=buf?len:1;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=1;+msgs[0].buf=&cmd_addr;++msgs[1].addr=bus_addr;+msgs[1].flags=I2C_M_RD;+msgs[1].len=len;+msgs[1].buf=res;++/* By experiment it takes up to 70 ms to access a register for these+*SFPs.Sleep20msbetweeniteratiosandtry10times.+*/+i=10;+do{+msleep(20);++ret=i2c_transfer_rollball(i2c,msgs,ARRAY_SIZE(msgs));+if(ret)+returnret;++if(*res==ROLLBALL_CMD_DONE)+return0;+}while(i-->0);++dev_dbg(&bus->dev,"poll timed out\n");++return-ETIMEDOUT;+}++staticinti2c_rollball_mii_cmd(structmii_bus*bus,intbus_addr,u8cmd,+u8*data,size_tlen)+{+structi2c_adapter*i2c=bus->priv;+structi2c_msgmsgs[2];+u8cmdbuf[2];++cmdbuf[0]=ROLLBALL_CMD_ADDR;+cmdbuf[1]=cmd;++msgs[0].addr=bus_addr;+msgs[0].flags=0;+msgs[0].len=len;+msgs[0].buf=data;++msgs[1].addr=bus_addr;+msgs[1].flags=0;+msgs[1].len=sizeof(cmdbuf);+msgs[1].buf=cmdbuf;++returni2c_transfer_rollball(i2c,msgs,ARRAY_SIZE(msgs));+}++staticinti2c_mii_read_rollball(structmii_bus*bus,intphy_id,intreg)+{+u8buf[4],res[6];+intbus_addr,ret;+u16val;++if(!(reg&MII_ADDR_C45))+return-EOPNOTSUPP;++bus_addr=i2c_mii_phy_addr(phy_id);+if(bus_addr!=ROLLBALL_PHY_I2C_ADDR)+return0xffff;++buf[0]=ROLLBALL_DATA_ADDR;+buf[1]=(reg>>16)&0x1f;+buf[2]=(reg>>8)&0xff;+buf[3]=reg&0xff;++ret=i2c_rollball_mii_cmd(bus,bus_addr,ROLLBALL_CMD_READ,buf,+sizeof(buf));+if(ret<0)+returnret;++ret=i2c_rollball_mii_poll(bus,bus_addr,res,sizeof(res));+if(ret==-ETIMEDOUT)+return0xffff;+elseif(ret<0)+returnret;++val=res[4]<<8|res[5];++dev_dbg(&bus->dev,"read reg %02x:%04x = %04x\n",(reg>>16)&0x1f,+reg&0xffff,val);++returnval;+}++staticinti2c_mii_write_rollball(structmii_bus*bus,intphy_id,intreg,+u16val)+{+intbus_addr,ret;+u8buf[6];++if(!(reg&MII_ADDR_C45))+return-EOPNOTSUPP;++bus_addr=i2c_mii_phy_addr(phy_id);+if(bus_addr!=ROLLBALL_PHY_I2C_ADDR)+return0;++buf[0]=ROLLBALL_DATA_ADDR;+buf[1]=(reg>>16)&0x1f;+buf[2]=(reg>>8)&0xff;+buf[3]=reg&0xff;+buf[4]=val>>8;+buf[5]=val&0xff;++ret=i2c_rollball_mii_cmd(bus,bus_addr,ROLLBALL_CMD_WRITE,buf,+sizeof(buf));+if(ret<0)+returnret;++ret=i2c_rollball_mii_poll(bus,bus_addr,NULL,0);+if(ret<0)+returnret;++dev_dbg(&bus->dev,"write reg %02x:%04x = %04x\n",(reg>>16)&0x1f,+reg&0xffff,val);++return0;+}++staticinti2c_mii_init_rollball(structi2c_adapter*i2c)+{+structi2c_msgmsg;+u8pw[5];+intret;++pw[0]=ROLLBALL_SFP_PASSWORD_ADDR;+pw[1]=0xff;+pw[2]=0xff;+pw[3]=0xff;+pw[4]=0xff;++msg.addr=ROLLBALL_PHY_I2C_ADDR;+msg.flags=0;+msg.len=sizeof(pw);+msg.buf=pw;++ret=i2c_transfer(i2c,&msg,1);+if(ret<0)+returnret;+elseif(ret!=1)+return-EIO;+else+return0;+}++structmii_bus*mdio_i2c_alloc(structdevice*parent,structi2c_adapter*i2c,+enummdio_i2c_protoprotocol){structmii_bus*mii;+intret;if(!i2c_check_functionality(i2c,I2C_FUNC_I2C))returnERR_PTR(-EINVAL);
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-01-12 14:03:33
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
Hi Heiner
There is no standardised way to access MDIO over i2c. So the existing
code is vendor code, even if it is used by a few different vendors.
Andrew
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
Hi Heiner
There is no standardised way to access MDIO over i2c. So the existing
code is vendor code, even if it is used by a few different vendors.
Andrew
From: Marek Behún <kabel@kernel.org> Date: 2021-01-12 17:50:39
On Tue, 12 Jan 2021 15:02:49 +0100
Andrew Lunn [off-list ref] wrote:
quoted
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
Hi Heiner
There is no standardised way to access MDIO over i2c. So the existing
code is vendor code, even if it is used by a few different vendors.
Andrew
Andrew, if you could find the time, could you please review these
patches? Patches 2 and 4 already have reviewed-by Russell, but 1 and 3
still need some review.
Marek
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-01-12 19:24:25
On Tue, Jan 12, 2021 at 09:42:56AM +0100, Heiner Kallweit wrote:
On 11.01.2021 06:00, Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
There is nothing in the SFP MSAs about how to access an on-board PHY
on a SFP. This is something that vendors choose to do (or in some
cases, not do.)
mdio-i2c currently implements the access protocol for Marvell 88E1111
PHYs which have an I2C mode. It was extended to support the DM7052
module which has a Broadcom Clause 45 PHY and either a microcontroller
or FPGA to convert I2C cycles to MDIO cycles - and sensibly performs
clock stretching.
There are modules that the clause 45 PHY is accessible via exactly the
same I2C address, using exactly the same data accesses, but do not
do the clock stretching thing, instead telling you that you must wait
N microseconds between the bus transactions. We don't yet support
these.
Then there is Marek's module, where the PHY is accessible via a page
in the diagnostic address - which is another entirely reasonable
implementation. The solution we have here is one that I've worked with
Marek for a few months now.
I don't think we should grow lots of separate mdio-i2c-vendorfoo.c
drivers - at least not yet. Maybe if we get lots of different access
methods, it may make sense in the future.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-01-12 21:38:37
On Tue, Jan 12, 2021 at 09:54:24PM +0100, Andrew Lunn wrote:
quoted
+static int i2c_transfer_rollball(struct i2c_adapter *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ u8 saved_page;
+ int ret;
+
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
+
+ /* save original page */
+ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
+ if (ret)
+ goto unlock;
+
+ /* change to RollBall MDIO page */
+ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
+ if (ret)
+ goto unlock;
+
+ /* do the transfer */
+ ret = __i2c_transfer_err(i2c, msgs, num);
+ if (ret)
+ goto unlock;
If get page and set page worked, and you get an error in during the
actual data transfer, i wonder if you should try restoring the page
before returning with the error?
That's what we do with paged PHYs - if the access encounters an error,
we still attempt to restore the page and propagate the _original_ error.
We would only propagate the error from the page restore if it was the
only error. See the logic and comments for phy_restore_page().
Note that phy_(save|select)_page()..phy_restore_page() deal with the
locking, which is why they always have to be paired (also means that
the user doesn't have to think too hard about error handling.)
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Marek Behún <kabel@kernel.org> Date: 2021-01-12 21:40:39
On Tue, 12 Jan 2021 21:54:24 +0100
Andrew Lunn [off-list ref] wrote:
quoted
+static int i2c_transfer_rollball(struct i2c_adapter *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ u8 saved_page;
+ int ret;
+
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
+
+ /* save original page */
+ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
+ if (ret)
+ goto unlock;
+
+ /* change to RollBall MDIO page */
+ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
+ if (ret)
+ goto unlock;
+
+ /* do the transfer */
+ ret = __i2c_transfer_err(i2c, msgs, num);
+ if (ret)
+ goto unlock;
If get page and set page worked, and you get an error in during the
actual data transfer, i wonder if you should try restoring the page
before returning with the error?
I don't know. Can i2c trasfer fail and the next one succeed?
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-01-12 21:41:58
+static int i2c_transfer_rollball(struct i2c_adapter *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ u8 saved_page;
+ int ret;
+
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
+
+ /* save original page */
+ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
+ if (ret)
+ goto unlock;
+
+ /* change to RollBall MDIO page */
+ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
+ if (ret)
+ goto unlock;
+
+ /* do the transfer */
+ ret = __i2c_transfer_err(i2c, msgs, num);
+ if (ret)
+ goto unlock;
If get page and set page worked, and you get an error in during the
actual data transfer, i wonder if you should try restoring the page
before returning with the error?
From: Marek Behún <kabel@kernel.org> Date: 2021-01-12 21:41:59
On Tue, 12 Jan 2021 21:43:29 +0100
Andrew Lunn [off-list ref] wrote:
quoted
+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
+ * instead via address 0x51, when SFP page is set to 0x03 and password to
+ * 0xffffffff.
+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at
+ * bus creation time, and expect it to remain set to 0x03 throughout the
+ * lifetime of the module plugged into the system. If the SFP code starts
+ * modifying SFP_PAGE in the future, this code will need to change.
...
quoted
+/* In order to not interfere with other SFP code (which possibly may manipulate
+ * SFP_PAGE), for every transfer we do this:
+ * 1. lock the bus
+ * 2. save content of SFP_PAGE
+ * 3. set SFP_PAGE to 3
+ * 4. do the transfer
+ * 5. restore original SFP_PAGE
+ * 6. unlock the bus
These two comments seem to contradict each other?
I forgot about the first comment. I will rewrite it and send again.
quoted
+static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
+ size_t len)
+{
+ struct i2c_adapter *i2c = bus->priv;
+ struct i2c_msg msgs[2];
+ u8 cmd_addr, tmp, *res;
+ int i, ret;
+
+ cmd_addr = ROLLBALL_CMD_ADDR;
+
+ res = buf ? buf : &tmp;
+ len = buf ? len : 1;
+
+ msgs[0].addr = bus_addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 1;
+ msgs[0].buf = &cmd_addr;
+
+ msgs[1].addr = bus_addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = res;
+
+ /* By experiment it takes up to 70 ms to access a register for these
+ * SFPs. Sleep 20ms between iteratios and try 10 times.
+ */
This looks odd. There are only 32 registers for C22 transactions, so
it fits in one byte. You can set buf[1] and buf[2] to zero.
C22 is not supported by this protocol. A few line above there is
if (!(reg & MII_ADDR_C45))
return -EOPNOTSUPP;
C45 transactions allow for 65536 registers, and has the devtype field,
so would need 3 bytes. Which suggests that C45 might actually be
supported? At least by the protocol, if not the device.
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-01-12 21:41:59
+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
+ * instead via address 0x51, when SFP page is set to 0x03 and password to
+ * 0xffffffff.
+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at
+ * bus creation time, and expect it to remain set to 0x03 throughout the
+ * lifetime of the module plugged into the system. If the SFP code starts
+ * modifying SFP_PAGE in the future, this code will need to change.
...
+/* In order to not interfere with other SFP code (which possibly may manipulate
+ * SFP_PAGE), for every transfer we do this:
+ * 1. lock the bus
+ * 2. save content of SFP_PAGE
+ * 3. set SFP_PAGE to 3
+ * 4. do the transfer
+ * 5. restore original SFP_PAGE
+ * 6. unlock the bus
These two comments seem to contradict each other?
+static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
+ size_t len)
+{
+ struct i2c_adapter *i2c = bus->priv;
+ struct i2c_msg msgs[2];
+ u8 cmd_addr, tmp, *res;
+ int i, ret;
+
+ cmd_addr = ROLLBALL_CMD_ADDR;
+
+ res = buf ? buf : &tmp;
+ len = buf ? len : 1;
+
+ msgs[0].addr = bus_addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 1;
+ msgs[0].buf = &cmd_addr;
+
+ msgs[1].addr = bus_addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = res;
+
+ /* By experiment it takes up to 70 ms to access a register for these
+ * SFPs. Sleep 20ms between iteratios and try 10 times.
+ */
This looks odd. There are only 32 registers for C22 transactions, so
it fits in one byte. You can set buf[1] and buf[2] to zero.
C45 transactions allow for 65536 registers, and has the devtype field,
so would need 3 bytes. Which suggests that C45 might actually be
supported? At least by the protocol, if not the device.
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-01-12 21:47:11
-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
+ * instead via address 0x51, when SFP page is set to 0x03 and password to
+ * 0xffffffff.
+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at
+ * bus creation time, and expect it to remain set to 0x03 throughout the
+ * lifetime of the module plugged into the system. If the SFP code starts
+ * modifying SFP_PAGE in the future, this code will need to change.
Just an FYI: This is likely to change. NVIDIA are working on
generalizing the API ethtool -m uses. The new API should allow access
to pages and banks. I've already said i will implement the API in the
generic phylink SFP code. But no need to address this now.
Andrew
On Monday 11 January 2021 06:00:42 Marek Behún wrote:
Some SFPs may contain an internal PHY which may in some cases want to
connect with the host interface in 1000base-x/2500base-x mode.
Do not fail if such PHY is being attached in one of these PHY interface
modes.
Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Russell King <redacted>
Cc: Andrew Lunn <andrew@lunn.ch>
On Monday 11 January 2021 06:00:43 Marek Behún wrote:
Instead of configuring the I2C mdiobus when SFP driver is probed,
create/destroy the mdiobus before the PHY is probed for/after it is
released.
This way we can tell the mdio-i2c code which protocol to use for each
SFP transceiver.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
Hello! (See comment below)
On Monday 11 January 2021 06:00:44 Marek Behún wrote:
quoted hunk
This adds support for multigig copper SFP modules from RollBall/Hilink.
These modules have a specific way to access clause 45 registers of the
internal PHY.
We also need to wait at least 22 seconds after deasserting TX disable
before accessing the PHY. The code waits for 25 seconds just to be sure.
Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Russell King <redacted>
Cc: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)
@@ -1835,6 +1841,23 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)sfp->mdio_protocol=MDIO_I2C_DEFAULT;+sfp->phy_addr=SFP_PHY_ADDR;+sfp->module_t_wait=T_WAIT;++if(((!memcmp(id.base.vendor_name,"OEM ",16)||+!memcmp(id.base.vendor_name,"Turris ",16))&&+(!memcmp(id.base.vendor_pn,"SFP-10G-T ",16)||+!memcmp(id.base.vendor_pn,"RTSFP-10",8)))){+sfp->mdio_protocol=MDIO_I2C_ROLLBALL;+sfp->phy_addr=SFP_PHY_ADDR_ROLLBALL;+sfp->module_t_wait=T_WAIT_ROLLBALL;++/* RollBall SFPs may have wrong (zero) extended compliacne code+*burnedinEEPROM.ForPHYprobingweneedthecorrectone.+*/+id.base.extended_cc=SFF8024_ECC_10GBASE_T_SFI;
Should not we rather in sfp_sm_probe_for_phy() function in "default"
section try to probe also for clause 45 PHY when clause 22 fails?
quoted hunk
+ }
+
return 0;
}
@@ -2030,9 +2053,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) /* We need to check the TX_FAULT state, which is not defined * while TX_DISABLE is asserted. The earliest we want to do- * anything (such as probe for a PHY) is 50ms.+ * anything (such as probe for a PHY) is 50ms. (or more on+ * specific modules). */- sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);+ sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); break; case SFP_S_WAIT:
On Tuesday 12 January 2021 22:01:14 Marek Behún wrote:
On Tue, 12 Jan 2021 21:54:24 +0100
Andrew Lunn [off-list ref] wrote:
quoted
quoted
+static int i2c_transfer_rollball(struct i2c_adapter *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ u8 saved_page;
+ int ret;
+
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
+
+ /* save original page */
+ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
+ if (ret)
+ goto unlock;
+
+ /* change to RollBall MDIO page */
+ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
+ if (ret)
+ goto unlock;
+
+ /* do the transfer */
+ ret = __i2c_transfer_err(i2c, msgs, num);
+ if (ret)
+ goto unlock;
If get page and set page worked, and you get an error in during the
actual data transfer, i wonder if you should try restoring the page
before returning with the error?
I don't know. Can i2c trasfer fail and the next one succeed?
I guess it can depend also on i2c driver. I'm for trying to restore
previous i2c page on failure. In the worst case also restoring fails...
+ * burned in EEPROM. For PHY probing we need the correct one.
+ */
+ id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI;
Should not we rather in sfp_sm_probe_for_phy() function in "default"
section try to probe also for clause 45 PHY when clause 22 fails?
Why? That's opening the possibilities for more problems - remember,
the access method is vendor defined, and we already have the situation
where I2C address 0x56 is used in two different styles that are
indistinguishable:
- Clause 22 write:
Write register address, value high, value low.
- Clause 22 read:
Write register address.
Read value high, low.
- Clause 45 write:
Write devad, register address high, register address low,
value high, value low.
- Clause 45 read:
Write devad, register address high, register address low.
Read value high, low.
Look closely at the similarities of Clause 22 write and Clause 45
read, you'll see that if you issue a clause 45 read to a SFP module
that implements Clause 22, you actually end up issuing a write to it.
Sending random MDIO cycles to a SFP is a really bad idea.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
Hello! See my comments below.
On Monday 11 January 2021 06:00:41 Marek Behún wrote:
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Maybe it could be interesting to test if clause 22 access via i2c
address 0x56 can work also in write mode after setting rollball
password...
quoted hunk
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) return ret < 0 ? ret : 0; }-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+ * instead via address 0x51, when SFP page is set to 0x03 and password to+ * 0xffffffff.+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at+ * bus creation time, and expect it to remain set to 0x03 throughout the+ * lifetime of the module plugged into the system. If the SFP code starts+ * modifying SFP_PAGE in the future, this code will need to change.+ *+ * address size contents description+ * ------- ---- -------- -----------+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done+ * 0x81 1 DEV Clause 45 device+ * 0x82 2 REG Clause 45 register+ * 0x84 2 VAL Register value+ */+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b
It looks like that this password entry is standard field described in
QSFP+ specifications SFF-8436 and SFF-8636. Should not it be rather
named vendor-neutral (as it is not Rollball specific)? And maybe defined
in include/linux/sfp.h file where also also other standard macros, like
SFP_PAGE macro?
Russel wrote that current mdio i2c (default) access method is also
vendor specific for Marvell chips. Should not we rather call it
MDIO_I2C_MARVELL if both methods are vendor/chip specific?
+ * burned in EEPROM. For PHY probing we need the correct one.
+ */
+ id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI;
Should not we rather in sfp_sm_probe_for_phy() function in "default"
section try to probe also for clause 45 PHY when clause 22 fails?
Why? That's opening the possibilities for more problems - remember,
the access method is vendor defined, and we already have the situation
where I2C address 0x56 is used in two different styles that are
indistinguishable:
- Clause 22 write:
Write register address, value high, value low.
- Clause 22 read:
Write register address.
Read value high, low.
- Clause 45 write:
Write devad, register address high, register address low,
value high, value low.
- Clause 45 read:
Write devad, register address high, register address low.
Read value high, low.
Look closely at the similarities of Clause 22 write and Clause 45
read, you'll see that if you issue a clause 45 read to a SFP module
that implements Clause 22, you actually end up issuing a write to it.
Sending random MDIO cycles to a SFP is a really bad idea.
I see, thank you for explanation. Incorrect data in SFP EEPROM may cause
lot of other issues :-(
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-01-13 13:56:58
On Wed, Jan 13, 2021 at 12:22:04PM +0100, Pali Rohár wrote:
Hello! See my comments below.
On Monday 11 January 2021 06:00:41 Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Maybe it could be interesting to test if clause 22 access via i2c
address 0x56 can work also in write mode after setting rollball
password...
quoted
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) return ret < 0 ? ret : 0; }-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+ * instead via address 0x51, when SFP page is set to 0x03 and password to+ * 0xffffffff.+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at+ * bus creation time, and expect it to remain set to 0x03 throughout the+ * lifetime of the module plugged into the system. If the SFP code starts+ * modifying SFP_PAGE in the future, this code will need to change.+ *+ * address size contents description+ * ------- ---- -------- -----------+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done+ * 0x81 1 DEV Clause 45 device+ * 0x82 2 REG Clause 45 register+ * 0x84 2 VAL Register value+ */+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b
It looks like that this password entry is standard field described in
QSFP+ specifications SFF-8436 and SFF-8636. Should not it be rather
named vendor-neutral (as it is not Rollball specific)? And maybe defined
in include/linux/sfp.h file where also also other standard macros, like
SFP_PAGE macro?
If it is generic, the functions themselves should probably move into
sfp.c. Being able to swap pages is something needed for accessing the
diagnostic registers under some conditions. Because we don't have
support for changing the page, the HWMON support is disabled in this
condition.
Andrew
On Wednesday 13 January 2021 14:56:13 Andrew Lunn wrote:
On Wed, Jan 13, 2021 at 12:22:04PM +0100, Pali Rohár wrote:
quoted
Hello! See my comments below.
On Monday 11 January 2021 06:00:41 Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Maybe it could be interesting to test if clause 22 access via i2c
address 0x56 can work also in write mode after setting rollball
password...
quoted
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) return ret < 0 ? ret : 0; }-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+ * instead via address 0x51, when SFP page is set to 0x03 and password to+ * 0xffffffff.+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at+ * bus creation time, and expect it to remain set to 0x03 throughout the+ * lifetime of the module plugged into the system. If the SFP code starts+ * modifying SFP_PAGE in the future, this code will need to change.+ *+ * address size contents description+ * ------- ---- -------- -----------+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done+ * 0x81 1 DEV Clause 45 device+ * 0x82 2 REG Clause 45 register+ * 0x84 2 VAL Register value+ */+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b
It looks like that this password entry is standard field described in
QSFP+ specifications SFF-8436 and SFF-8636. Should not it be rather
named vendor-neutral (as it is not Rollball specific)? And maybe defined
in include/linux/sfp.h file where also also other standard macros, like
SFP_PAGE macro?
If it is generic, the functions themselves should probably move into
sfp.c. Being able to swap pages is something needed for accessing the
diagnostic registers under some conditions. Because we don't have
support for changing the page, the HWMON support is disabled in this
condition.
Only password is described in SFF-8436 and SFF-8636, nothing more.
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-01-13 16:15:53
On Wed, Jan 13, 2021 at 02:56:13PM +0100, Andrew Lunn wrote:
On Wed, Jan 13, 2021 at 12:22:04PM +0100, Pali Rohár wrote:
quoted
Hello! See my comments below.
On Monday 11 January 2021 06:00:41 Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Maybe it could be interesting to test if clause 22 access via i2c
address 0x56 can work also in write mode after setting rollball
password...
quoted
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
Signed-off-by: Marek Behún <kabel@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Russell King <redacted>
---
drivers/net/mdio/mdio-i2c.c | 319 +++++++++++++++++++++++++++++++++-
drivers/net/phy/sfp.c | 2 +-
include/linux/mdio/mdio-i2c.h | 8 +-
3 files changed, 322 insertions(+), 7 deletions(-)
@@ -91,9 +94,297 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) return ret < 0 ? ret : 0; }-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)+/* RollBall SFPs do not access internal PHY via I2C address 0x56, but+ * instead via address 0x51, when SFP page is set to 0x03 and password to+ * 0xffffffff.+ * Since current SFP code does not modify SFP_PAGE, we set it to 0x03 only at+ * bus creation time, and expect it to remain set to 0x03 throughout the+ * lifetime of the module plugged into the system. If the SFP code starts+ * modifying SFP_PAGE in the future, this code will need to change.+ *+ * address size contents description+ * ------- ---- -------- -----------+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done+ * 0x81 1 DEV Clause 45 device+ * 0x82 2 REG Clause 45 register+ * 0x84 2 VAL Register value+ */+#define ROLLBALL_PHY_I2C_ADDR 0x51+#define ROLLBALL_SFP_PASSWORD_ADDR 0x7b
It looks like that this password entry is standard field described in
QSFP+ specifications SFF-8436 and SFF-8636. Should not it be rather
named vendor-neutral (as it is not Rollball specific)? And maybe defined
in include/linux/sfp.h file where also also other standard macros, like
SFP_PAGE macro?
If it is generic, the functions themselves should probably move into
sfp.c. Being able to swap pages is something needed for accessing the
diagnostic registers under some conditions. Because we don't have
support for changing the page, the HWMON support is disabled in this
condition.
QSFPs are quite different from SFPs.
- the data structures in the "I2C device" are quite different.
- they don't have as many controls signals either - signals such as
RX_LOS, TX_DISABLE etc are handled per channel and are only exposed
via the I2C bus.
I've some rudimentary code for QSFP support in my CEX7 branch, which is
currently entirely separate from the SFP code. I haven't done much on
that for quite some time due to the historical difficulties of working
with NXP, but I have over the course of the last week updated my branch
to 5.10 and have patches to move SFP support forward. However, I expect
further difficulties interacting with NXP and fully expect to be
blocked from being able to achieve anything useful.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
On Tuesday 12 January 2021 19:22:33 Russell King - ARM Linux admin wrote:
On Tue, Jan 12, 2021 at 09:42:56AM +0100, Heiner Kallweit wrote:
quoted
On 11.01.2021 06:00, Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
There is nothing in the SFP MSAs about how to access an on-board PHY
on a SFP. This is something that vendors choose to do (or in some
cases, not do.)
mdio-i2c currently implements the access protocol for Marvell 88E1111
PHYs which have an I2C mode. It was extended to support the DM7052
module which has a Broadcom Clause 45 PHY and either a microcontroller
or FPGA to convert I2C cycles to MDIO cycles - and sensibly performs
clock stretching.
There are modules that the clause 45 PHY is accessible via exactly the
same I2C address, using exactly the same data accesses, but do not
do the clock stretching thing, instead telling you that you must wait
N microseconds between the bus transactions. We don't yet support
these.
Then there is Marek's module, where the PHY is accessible via a page
in the diagnostic address - which is another entirely reasonable
implementation. The solution we have here is one that I've worked with
Marek for a few months now.
I don't think we should grow lots of separate mdio-i2c-vendorfoo.c
drivers - at least not yet. Maybe if we get lots of different access
methods, it may make sense in the future.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Russell King - ARM Linux admin <linux@armlinux.org.uk> Date: 2021-01-18 15:49:14
On Mon, Jan 18, 2021 at 01:13:38PM +0100, Pali Rohár wrote:
On Tuesday 12 January 2021 19:22:33 Russell King - ARM Linux admin wrote:
quoted
On Tue, Jan 12, 2021 at 09:42:56AM +0100, Heiner Kallweit wrote:
quoted
On 11.01.2021 06:00, Marek Behún wrote:
quoted
Some multigig SFPs from RollBall and Hilink do not expose functional
MDIO access to the internal PHY of the SFP via I2C address 0x56
(although there seems to be read-only clause 22 access on this address).
Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
selected to 3 and the password must be filled with 0xff bytes for this
PHY communication to work.
This extends the mdio-i2c driver to support this protocol by adding a
special parameter to mdio_i2c_alloc function via which this RollBall
protocol can be selected.
I'd think that mdio-i2c.c is for generic code. When adding a
vendor-specific protocol, wouldn't it make sense to use a dedicated
source file for it?
There is nothing in the SFP MSAs about how to access an on-board PHY
on a SFP. This is something that vendors choose to do (or in some
cases, not do.)
mdio-i2c currently implements the access protocol for Marvell 88E1111
PHYs which have an I2C mode. It was extended to support the DM7052
module which has a Broadcom Clause 45 PHY and either a microcontroller
or FPGA to convert I2C cycles to MDIO cycles - and sensibly performs
clock stretching.
Only if the Clause 45 PHY supports the Clause 22 interface. Not all do.
However, which access method really only depends on the SFP module,
and how they interface the PHY to the I2C bus. As I've previously
mentioned, using a wrong access method will be misinterpreted by
the SFP.
Even if the PHY supports both Clause 22 and Clause 45 accesses,
if the I2C-to-MDIO layer in the SFP only supports Clause 45, then
Clause 22 accesses will not work. As I've previously said, a
Clause 45 read access is indistinguishable from a Clause 22 write
access on the I2C bus.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!