* [PATCH v1 0/4] microchip: add support for ksz88x3 driver family @ 2019-11-07 11:00 Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik ` (4 more replies) 0 siblings, 5 replies; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw) To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel This series adds support for the ksz88x3 driver family to the dsa based ksz drivers. For now the ksz8863 and ksz8873 are compatible. The driver is based on the ksz8895 RFC patch from Tristam Ha: https://patchwork.ozlabs.org/patch/822712/ And the latest version of the ksz8863.h from Microchip: https://raw.githubusercontent.com/Microchip-Ethernet/UNG8071_old_1.10/master/KSZ/linux-drivers/ksz8863/linux-3.14/drivers/net/ethernet/micrel/ksz8863.h Michael Grzeschik (4): mdio-bitbang: add SMI0 mode support net: tag: ksz: Add KSZ8863 tag code ksz: Add Microchip KSZ8863 SMI-DSA driver dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch .../devicetree/bindings/net/dsa/ksz.txt | 2 + drivers/net/dsa/microchip/Kconfig | 16 + drivers/net/dsa/microchip/Makefile | 2 + drivers/net/dsa/microchip/ksz8863.c | 1038 +++++++++++++++++ drivers/net/dsa/microchip/ksz8863_reg.h | 605 ++++++++++ drivers/net/dsa/microchip/ksz8863_smi.c | 166 +++ drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/phy/mdio-bitbang.c | 21 + include/linux/phy.h | 2 + include/net/dsa.h | 2 + net/dsa/tag_ksz.c | 60 + 11 files changed, 1915 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8863.c create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c -- 2.24.0.rc1 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik @ 2019-11-07 11:00 ` Michael Grzeschik 2019-11-07 15:42 ` Andrew Lunn 2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik ` (3 subsequent siblings) 4 siblings, 1 reply; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw) To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel Some microchip phys support the Serial Management Interface Protocol (SMI) for the configuration of the extended register set. We add MII_ADDR_SMI0 as an available interface to the mdiobb write and read functions, as this interface can be easy realized using the bitbang mdio driver. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> --- RFC -> v1: - moved the Protocol description to mdio-bitbang - renamed the protocol to SMI_KSZ88X3... drivers/net/phy/mdio-bitbang.c | 21 +++++++++++++++++++++ include/linux/phy.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 5136275c8e739..9f6fb84f92f60 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -22,6 +22,21 @@ #define MDIO_READ 2 #define MDIO_WRITE 1 +/* KSZ8863 Serial Management Interface (SMI) uses the following frame format: + * + * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle + * |frame| OP code |address |address| | | + * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z + * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z + * + * The register number is encoded with the 5 least significant bits in REG + * and the 3 most significant bits in PHY + */ + +#define SMI_KSZ88X3_RW_OPCODE 0 +#define SMI_KSZ88X3_READ_PHY (1 << 4) +#define SMI_KSZ88X3_WRITE_PHY (0 << 4) + #define MDIO_C45 (1<<15) #define MDIO_C45_ADDR (MDIO_C45 | 0) #define MDIO_C45_READ (MDIO_C45 | 3) @@ -157,6 +172,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg) if (reg & MII_ADDR_C45) { reg = mdiobb_cmd_addr(ctrl, phy, reg); mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); + } else if (reg & MII_ADDR_SMI_KSZ88X3) { + mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE, + (reg & 0xE0) >> 5 | SMI_KSZ88X3_READ_PHY, reg); } else mdiobb_cmd(ctrl, MDIO_READ, phy, reg); @@ -188,6 +206,9 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) if (reg & MII_ADDR_C45) { reg = mdiobb_cmd_addr(ctrl, phy, reg); mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); + } else if (reg & MII_ADDR_SMI_KSZ88X3) { + mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE, + (reg & 0xE0) >> 5 | SMI_KSZ88X3_WRITE_PHY, reg); } else mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); diff --git a/include/linux/phy.h b/include/linux/phy.h index 78436d58ce7ce..e569aa92ac6c8 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -201,6 +201,8 @@ static inline const char *phy_modes(phy_interface_t interface) #define MII_DEVADDR_C45_SHIFT 16 #define MII_REGADDR_C45_MASK GENMASK(15, 0) +#define MII_ADDR_SMI_KSZ88X3 (1<<31) + struct device; struct phylink; struct sk_buff; -- 2.24.0.rc1 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support 2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik @ 2019-11-07 15:42 ` Andrew Lunn 2019-12-18 16:29 ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik 0 siblings, 1 reply; 20+ messages in thread From: Andrew Lunn @ 2019-11-07 15:42 UTC (permalink / raw) To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel On Thu, Nov 07, 2019 at 12:00:27PM +0100, Michael Grzeschik wrote: > Some microchip phys support the Serial Management Interface Protocol > (SMI) for the configuration of the extended register set. We add > MII_ADDR_SMI0 as an available interface to the mdiobb write and read > functions, as this interface can be easy realized using the bitbang mdio > driver. > > Signed-off-by: Sam Ravnborg <sam@ravnborg.org> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Hi Michael I don't like adding vendor proprietary stuff to generic code like this. Please could you see if you can make use of mdiobb_ops in some way? Move all this junk out into a mdio-kzs88x3.c? Thanks Andrew ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-11-07 15:42 ` Andrew Lunn @ 2019-12-18 16:29 ` Michael Grzeschik 2019-12-19 20:39 ` Andrew Lunn ` (2 more replies) 0 siblings, 3 replies; 20+ messages in thread From: Michael Grzeschik @ 2019-12-18 16:29 UTC (permalink / raw) To: andrew; +Cc: f.fainelli, netdev, davem, kernel Some phys support special opcode handling when communicating via mdio. This patch introduces mdio_ll_read/write which makes it possible to set the opcode. It implements these functions in the gpio-bitbang driver, which is capable of setting the opcode on read and write. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> --- Hi Andrew, I worked on your suggestion moving the proprietary call to mdio-ksz88x3.c which does not seem to work out very well. I still end up having an MII_ADDR_SMI???? define in linux/phy.h. Instead of having to support this special case in one extra file what do you think of adding mdiobus_lowlevel_write/read to mdio_bus. This way it would be possible to add the opcode directly as user. Other controllers which have the possibility to set the op code in hardware will also profit from that and can implement these functions. Regards, Michael drivers/net/phy/mdio-bitbang.c | 41 +++++++++--- drivers/net/phy/mdio_bus.c | 110 +++++++++++++++++++++++++++++++++ include/linux/mdio.h | 6 ++ include/linux/phy.h | 3 + 4 files changed, 150 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 5136275c8e739..77fbc7eaadf51 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -149,16 +149,12 @@ static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) return dev_addr; } -static int mdiobb_read(struct mii_bus *bus, int phy, int reg) +static int mdiobb_ll_read(struct mii_bus *bus, int op, int phy, int reg) { struct mdiobb_ctrl *ctrl = bus->priv; int ret, i; - if (reg & MII_ADDR_C45) { - reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); - } else - mdiobb_cmd(ctrl, MDIO_READ, phy, reg); + mdiobb_cmd(ctrl, op, phy, reg); ctrl->ops->set_mdio_dir(ctrl, 0); @@ -181,15 +177,25 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg) return ret; } -static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +static int mdiobb_read(struct mii_bus *bus, int phy, int reg) { struct mdiobb_ctrl *ctrl = bus->priv; + int op = MDIO_READ; if (reg & MII_ADDR_C45) { reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); - } else - mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); + op = MDIO_C45_READ; + } + + return mdiobb_ll_read(bus, op, phy, reg); +} + +static int mdiobb_ll_write(struct mii_bus *bus, int op, int phy, + int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd(ctrl, op, phy, reg); /* send the turnaround (10) */ mdiobb_send_bit(ctrl, 1); @@ -202,6 +208,19 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) return 0; } +static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + int op = MDIO_WRITE; + + if (reg & MII_ADDR_C45) { + reg = mdiobb_cmd_addr(ctrl, phy, reg); + op = MDIO_C45_WRITE; + } + + return mdiobb_ll_write(bus, op, phy, reg, val); +} + struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) { struct mii_bus *bus; @@ -213,7 +232,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) __module_get(ctrl->ops->owner); bus->read = mdiobb_read; + bus->ll_read = mdiobb_ll_read; bus->write = mdiobb_write; + bus->ll_write = mdiobb_ll_write; bus->priv = ctrl; return bus; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 229e480179ff1..57f4b7b9ce39a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -560,6 +560,34 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) } EXPORT_SYMBOL(__mdiobus_read); +/** + * __mdiobus_ll_read - Unlocked version of the mdiobus_read function + * @bus: the mii_bus struct + * @op: opcode to use on transfer + * @addr: the phy address + * @regnum: register number to read + * + * Read a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum) +{ + int retval; + + if (!bus->ll_write) + return -ENODEV; + + WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); + + retval = bus->ll_read(bus, op, addr, regnum); + + trace_mdio_access(bus, 1, addr, regnum, retval, retval); + + return retval; +} +EXPORT_SYMBOL(__mdiobus_ll_read); + /** * __mdiobus_write - Unlocked version of the mdiobus_write function * @bus: the mii_bus struct @@ -585,6 +613,36 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) } EXPORT_SYMBOL(__mdiobus_write); +/** + * __mdiobus_ll_write - Unlocked version of the mdiobus_write function + * @bus: the mii_bus struct + * @op: opcode to use on transfer + * @addr: the phy address + * @regnum: register number to write + * @val: value to write to @regnum + * + * Write a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_ll_write(struct mii_bus *bus, int op, int addr, + u32 regnum, u16 val) +{ + int err; + + if (!bus->ll_write) + return -ENODEV; + + WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); + + err = bus->ll_write(bus, op, addr, regnum, val); + + trace_mdio_access(bus, 0, addr, regnum, val, err); + + return err; +} +EXPORT_SYMBOL(__mdiobus_ll_write); + /** * mdiobus_read_nested - Nested version of the mdiobus_read function * @bus: the mii_bus struct @@ -636,6 +694,31 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) } EXPORT_SYMBOL(mdiobus_read); +/** + * mdiobus_ll_read - Convenience function for reading a given MII mgmt register + * @bus: the mii_bus struct + * @op: opcode to use on transfer + * @addr: the phy address + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum) +{ + int retval; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + retval = __mdiobus_ll_read(bus, op, addr, regnum); + mutex_unlock(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(mdiobus_ll_read); + /** * mdiobus_write_nested - Nested version of the mdiobus_write function * @bus: the mii_bus struct @@ -689,6 +772,33 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) } EXPORT_SYMBOL(mdiobus_write); +/** + * mdiobus_ll_write - Convenience function for writing a given MII mgmt register + * @bus: the mii_bus struct + * @op: opcode to use on transfer + * @addr: the phy address + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_ll_write(struct mii_bus *bus, int op, int addr, + u32 regnum, u16 val) +{ + int err; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + err = __mdiobus_ll_write(bus, op, addr, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(mdiobus_ll_write); + /** * mdio_bus_match - determine if given MDIO driver supports the given * MDIO device diff --git a/include/linux/mdio.h b/include/linux/mdio.h index a7604248777b7..aafd24eb6d393 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -315,11 +315,17 @@ static inline void mii_10gbt_stat_mod_linkmode_lpa_t(unsigned long *advertising, } int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); +int __mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum); int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); +int __mdiobus_ll_write(struct mii_bus *bus, int op, int addr, + u32 regnum, u16 val); int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); +int mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum); int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum); int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); +int mdiobus_ll_write(struct mii_bus *bus, int op, int addr, + u32 regnum, u16 val); int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val); int mdiobus_register_device(struct mdio_device *mdiodev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 5032d453ac66a..3bb802cb03a8a 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -218,6 +218,9 @@ struct mii_bus { void *priv; int (*read)(struct mii_bus *bus, int addr, int regnum); int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val); + int (*ll_read)(struct mii_bus *bus, int op, int addr, int regnum); + int (*ll_write)(struct mii_bus *bus, int op, int addr, + int regnum, u16 val); int (*reset)(struct mii_bus *bus); /* -- 2.24.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-12-18 16:29 ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik @ 2019-12-19 20:39 ` Andrew Lunn 2019-12-19 22:01 ` Michael Grzeschik 2019-12-19 22:05 ` Florian Fainelli 2019-12-21 16:41 ` Andrew Lunn 2 siblings, 1 reply; 20+ messages in thread From: Andrew Lunn @ 2019-12-19 20:39 UTC (permalink / raw) To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel On Wed, Dec 18, 2019 at 05:29:19PM +0100, Michael Grzeschik wrote: > Some phys support special opcode handling when communicating via mdio. > This patch introduces mdio_ll_read/write which makes it possible to set > the opcode. It implements these functions in the gpio-bitbang driver, > which is capable of setting the opcode on read and write. > > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Hi Michael It is normal to post the user of a new API at the same time as a new API. I'm having trouble working out how this is supposed to be used. Andrew ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-12-19 20:39 ` Andrew Lunn @ 2019-12-19 22:01 ` Michael Grzeschik 0 siblings, 0 replies; 20+ messages in thread From: Michael Grzeschik @ 2019-12-19 22:01 UTC (permalink / raw) To: Andrew Lunn, g; +Cc: f.fainelli, netdev, davem, kernel [-- Attachment #1: Type: text/plain, Size: 1201 bytes --] On Thu, Dec 19, 2019 at 09:39:31PM +0100, Andrew Lunn wrote: > On Wed, Dec 18, 2019 at 05:29:19PM +0100, Michael Grzeschik wrote: > > Some phys support special opcode handling when communicating via mdio. > > This patch introduces mdio_ll_read/write which makes it possible to set > > the opcode. It implements these functions in the gpio-bitbang driver, > > which is capable of setting the opcode on read and write. > > > > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> > > Hi Michael > > It is normal to post the user of a new API at the same time as a new > API. I'm having trouble working out how this is supposed to be used. Hi Andrew, so this patch should have been in the series with the ksz8863 driver, which is using the API. I will send the series again as v3 including this patch, so it will be clear how this is ment. Thanks, Michael -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-12-18 16:29 ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik 2019-12-19 20:39 ` Andrew Lunn @ 2019-12-19 22:05 ` Florian Fainelli 2019-12-21 16:41 ` Andrew Lunn 2 siblings, 0 replies; 20+ messages in thread From: Florian Fainelli @ 2019-12-19 22:05 UTC (permalink / raw) To: Michael Grzeschik, andrew; +Cc: netdev, davem, kernel On 12/18/19 8:29 AM, Michael Grzeschik wrote: > Some phys support special opcode handling when communicating via mdio. > This patch introduces mdio_ll_read/write which makes it possible to set > the opcode. It implements these functions in the gpio-bitbang driver, > which is capable of setting the opcode on read and write. > > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> > --- > Hi Andrew, > > I worked on your suggestion moving the proprietary call to > mdio-ksz88x3.c which does not seem to work out very well. > I still end up having an MII_ADDR_SMI???? define in linux/phy.h. > > Instead of having to support this special case in one extra file > what do you think of adding mdiobus_lowlevel_write/read to mdio_bus. > This way it would be possible to add the opcode directly as user. > > Other controllers which have the possibility to set the op code in hardware > will also profit from that and can implement these functions. I am not sure it makes sense for the entire struct mii_bus to gain two new pointers, when you could just exported the mdiobb_ll_read() and mdiobb_ll_write() to the kernel modules that needs those, and wrap them however you need them to implement the mdiobus->read() and mdiobus->write() operations? -- Florian ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-12-18 16:29 ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik 2019-12-19 20:39 ` Andrew Lunn 2019-12-19 22:05 ` Florian Fainelli @ 2019-12-21 16:41 ` Andrew Lunn 2020-01-29 15:42 ` Michael Grzeschik 2 siblings, 1 reply; 20+ messages in thread From: Andrew Lunn @ 2019-12-21 16:41 UTC (permalink / raw) To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel Hi Michael In your V1 patch, you had this diagram. +/* Serial Management Interface (SMI) uses the following frame format: + * + * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle + * |frame| OP code |address |address| | | + * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z + * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z + * + */ I just compared this to plain MDIO: + * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle + * |frame| OP code |address |address| | | + * read | 32x1´s | 01 | 10 | AAAA | RRRRR |Z0| DDDDDDDDDDDDDDDD | Z + * write| 32x1´s | 01 | 01 | AAAA | RRRRR |10| DDDDDDDDDDDDDDDD | Z So the only real issue here is the OP code? The rest you can do with a layer on top of the standard API. How about something like this. Totally untested, probably does not even compile..... Andrew From 6051479b218fd19942d702e3e051c6355fe2a11f Mon Sep 17 00:00:00 2001 From: Andrew Lunn <andrew@lunn.ch> Date: Sat, 21 Dec 2019 10:31:19 -0600 Subject: [PATCH] net: phy: Add support for microchip SMI0 MDIO bus. SMI0 is a mangled version of MDIO. The main low level difference is the MDIO C22 OP code is always 0, not 0x2 or 0x1 for Read/Write. The read/write information is instead encoded in the PHY address. Extend the bit-bang code to allow the op code to be overridden, but default to normal C22 values. Add an extra compatible to the mdio-gpio driver, and when this compatible is present, set the op codes to 0. A higher level driver, sitting on top of the basic MDIO bus driver can then implement the rest of the microchip SMI0 odderties. Signed-off-by: Andrew Lunn <andrew@lunn.ch> --- drivers/net/phy/mdio-bitbang.c | 7 +++++-- drivers/net/phy/mdio-gpio.c | 7 +++++++ include/linux/mdio-bitbang.h | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 5136275c8e73..01f620889c78 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -158,7 +158,7 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg) reg = mdiobb_cmd_addr(ctrl, phy, reg); mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); } else - mdiobb_cmd(ctrl, MDIO_READ, phy, reg); + mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg); ctrl->ops->set_mdio_dir(ctrl, 0); @@ -189,7 +189,7 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) reg = mdiobb_cmd_addr(ctrl, phy, reg); mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); } else - mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); + mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg); /* send the turnaround (10) */ mdiobb_send_bit(ctrl, 1); @@ -216,6 +216,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) bus->write = mdiobb_write; bus->priv = ctrl; + ctrl->op_c22_read = MDIO_READ; + ctrl->op_c22_write = MDIO_WRITE; + return bus; } EXPORT_SYMBOL(alloc_mdio_bitbang); diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 1b00235d7dc5..282bc38331d7 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -132,6 +132,12 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; } + if (dev->of_node && + of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) { + bitbang->ctrl->op_c22_read = 0; + bitbang->ctrl->op_c22_write = 0; + } + dev_set_drvdata(dev, new_bus); return new_bus; @@ -196,6 +202,7 @@ static int mdio_gpio_remove(struct platform_device *pdev) static const struct of_device_id mdio_gpio_of_match[] = { { .compatible = "virtual,mdio-gpio", }, + { .compatible = "microchip,mdio-smi0" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h index 5d71e8a8500f..8ae0b3835233 100644 --- a/include/linux/mdio-bitbang.h +++ b/include/linux/mdio-bitbang.h @@ -33,6 +33,8 @@ struct mdiobb_ops { struct mdiobb_ctrl { const struct mdiobb_ops *ops; + u8 op_c22_read; + u8 op_c22_write; }; /* The returned bus is not yet registered with the phy layer. */ -- 2.24.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2019-12-21 16:41 ` Andrew Lunn @ 2020-01-29 15:42 ` Michael Grzeschik 2020-01-29 15:53 ` Andrew Lunn 0 siblings, 1 reply; 20+ messages in thread From: Michael Grzeschik @ 2020-01-29 15:42 UTC (permalink / raw) To: Andrew Lunn; +Cc: f.fainelli, netdev, davem, kernel [-- Attachment #1: Type: text/plain, Size: 5663 bytes --] Hi Andrew! I tested your patch. But it works only partially. For the case that the upper driver is directly communicating in SMI mode with the phy, this works fine. But the regular MDIO connection does not work anymore afterwards. The normals MDIO communication still needs to work, as mdio-gpio is calling of_mdiobus_register that on the other end calls get_phy_device and tries to communicate via regular MDIO to the device. Fixing the whole bus to the SMI opcode breaks the regular commands. Do you have any ideas how to fix that? Regards, Michael On Sat, Dec 21, 2019 at 05:41:10PM +0100, Andrew Lunn wrote: > Hi Michael > > In your V1 patch, you had this diagram. > > +/* Serial Management Interface (SMI) uses the following frame format: > + * > + * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle > + * |frame| OP code |address |address| | | > + * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z > + * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z > + * > + */ > > I just compared this to plain MDIO: > > + * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle > + * |frame| OP code |address |address| | | > + * read | 32x1´s | 01 | 10 | AAAA | RRRRR |Z0| DDDDDDDDDDDDDDDD | Z > + * write| 32x1´s | 01 | 01 | AAAA | RRRRR |10| DDDDDDDDDDDDDDDD | Z > > So the only real issue here is the OP code? The rest you can do with a > layer on top of the standard API. > > How about something like this. Totally untested, probably does not > even compile..... > > Andrew > > From 6051479b218fd19942d702e3e051c6355fe2a11f Mon Sep 17 00:00:00 2001 > From: Andrew Lunn <andrew@lunn.ch> > Date: Sat, 21 Dec 2019 10:31:19 -0600 > Subject: [PATCH] net: phy: Add support for microchip SMI0 MDIO bus. > > SMI0 is a mangled version of MDIO. The main low level difference is > the MDIO C22 OP code is always 0, not 0x2 or 0x1 for Read/Write. The > read/write information is instead encoded in the PHY address. > > Extend the bit-bang code to allow the op code to be overridden, but > default to normal C22 values. Add an extra compatible to the mdio-gpio > driver, and when this compatible is present, set the op codes to 0. > > A higher level driver, sitting on top of the basic MDIO bus driver can > then implement the rest of the microchip SMI0 odderties. > > Signed-off-by: Andrew Lunn <andrew@lunn.ch> > --- > drivers/net/phy/mdio-bitbang.c | 7 +++++-- > drivers/net/phy/mdio-gpio.c | 7 +++++++ > include/linux/mdio-bitbang.h | 2 ++ > 3 files changed, 14 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c > index 5136275c8e73..01f620889c78 100644 > --- a/drivers/net/phy/mdio-bitbang.c > +++ b/drivers/net/phy/mdio-bitbang.c > @@ -158,7 +158,7 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg) > reg = mdiobb_cmd_addr(ctrl, phy, reg); > mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); > } else > - mdiobb_cmd(ctrl, MDIO_READ, phy, reg); > + mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg); > > ctrl->ops->set_mdio_dir(ctrl, 0); > > @@ -189,7 +189,7 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) > reg = mdiobb_cmd_addr(ctrl, phy, reg); > mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); > } else > - mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); > + mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg); > > /* send the turnaround (10) */ > mdiobb_send_bit(ctrl, 1); > @@ -216,6 +216,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) > bus->write = mdiobb_write; > bus->priv = ctrl; > > + ctrl->op_c22_read = MDIO_READ; > + ctrl->op_c22_write = MDIO_WRITE; > + > return bus; > } > EXPORT_SYMBOL(alloc_mdio_bitbang); > diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c > index 1b00235d7dc5..282bc38331d7 100644 > --- a/drivers/net/phy/mdio-gpio.c > +++ b/drivers/net/phy/mdio-gpio.c > @@ -132,6 +132,12 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, > new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; > } > > + if (dev->of_node && > + of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) { > + bitbang->ctrl->op_c22_read = 0; > + bitbang->ctrl->op_c22_write = 0; > + } > + > dev_set_drvdata(dev, new_bus); > > return new_bus; > @@ -196,6 +202,7 @@ static int mdio_gpio_remove(struct platform_device *pdev) > > static const struct of_device_id mdio_gpio_of_match[] = { > { .compatible = "virtual,mdio-gpio", }, > + { .compatible = "microchip,mdio-smi0" }, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); > diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h > index 5d71e8a8500f..8ae0b3835233 100644 > --- a/include/linux/mdio-bitbang.h > +++ b/include/linux/mdio-bitbang.h > @@ -33,6 +33,8 @@ struct mdiobb_ops { > > struct mdiobb_ctrl { > const struct mdiobb_ops *ops; > + u8 op_c22_read; > + u8 op_c22_write; > }; > > /* The returned bus is not yet registered with the phy layer. */ > -- > 2.24.0 > > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2020-01-29 15:42 ` Michael Grzeschik @ 2020-01-29 15:53 ` Andrew Lunn 2020-01-29 21:48 ` Michael Grzeschik 0 siblings, 1 reply; 20+ messages in thread From: Andrew Lunn @ 2020-01-29 15:53 UTC (permalink / raw) To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote: > Hi Andrew! > > I tested your patch. But it works only partially. For the case that > the upper driver is directly communicating in SMI mode with the phy, > this works fine. But the regular MDIO connection does not work anymore > afterwards. > > The normals MDIO communication still needs to work, as mdio-gpio is > calling of_mdiobus_register that on the other end calls get_phy_device > and tries to communicate via regular MDIO to the device. Do you mean you have a mix of devices on the bus, some standards comformant, and others using this hacked up SMI0 mode? You need to specify per device if SMI0 should be used? Andrew ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2020-01-29 15:53 ` Andrew Lunn @ 2020-01-29 21:48 ` Michael Grzeschik 2020-04-21 14:31 ` Michael Grzeschik 0 siblings, 1 reply; 20+ messages in thread From: Michael Grzeschik @ 2020-01-29 21:48 UTC (permalink / raw) To: Andrew Lunn; +Cc: f.fainelli, netdev, davem, kernel [-- Attachment #1: Type: text/plain, Size: 1434 bytes --] On Wed, Jan 29, 2020 at 04:53:46PM +0100, Andrew Lunn wrote: > On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote: > > Hi Andrew! > > > > I tested your patch. But it works only partially. For the case that > > the upper driver is directly communicating in SMI mode with the phy, > > this works fine. But the regular MDIO connection does not work anymore > > afterwards. > > > > The normals MDIO communication still needs to work, as mdio-gpio is > > calling of_mdiobus_register that on the other end calls get_phy_device > > and tries to communicate via regular MDIO to the device. > > Do you mean you have a mix of devices on the bus, some standards > comformant, and others using this hacked up SMI0 mode? Actually it is the same device used in both modes. The SMI0 mode is used by the switch driver to address the extended switch functions. But on the same bus we have the fec connected to the cpu bound fixed-phy (microchip,ks8863) via MDIO. > You need to specify per device if SMI0 should be used? Yes, we have to use the same bus fot both modes SMI0 and MDIO. Michael -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write 2020-01-29 21:48 ` Michael Grzeschik @ 2020-04-21 14:31 ` Michael Grzeschik 0 siblings, 0 replies; 20+ messages in thread From: Michael Grzeschik @ 2020-04-21 14:31 UTC (permalink / raw) To: Andrew Lunn; +Cc: netdev, f.fainelli, davem, kernel [-- Attachment #1: Type: text/plain, Size: 1964 bytes --] Hi Andrew, I want to refresh this thread. On Wed, Jan 29, 2020 at 10:48:05PM +0100, Michael Grzeschik wrote: >On Wed, Jan 29, 2020 at 04:53:46PM +0100, Andrew Lunn wrote: >> On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote: >> > Hi Andrew! >> > >> > I tested your patch. But it works only partially. For the case that >> > the upper driver is directly communicating in SMI mode with the phy, >> > this works fine. But the regular MDIO connection does not work anymore >> > afterwards. >> > >> > The normals MDIO communication still needs to work, as mdio-gpio is >> > calling of_mdiobus_register that on the other end calls get_phy_device >> > and tries to communicate via regular MDIO to the device. >> >> Do you mean you have a mix of devices on the bus, some standards >> comformant, and others using this hacked up SMI0 mode? > >Actually it is the same device used in both modes. The SMI0 >mode is used by the switch driver to address the extended switch >functions. But on the same bus we have the fec connected to >the cpu bound fixed-phy (microchip,ks8863) via MDIO. > >> You need to specify per device if SMI0 should be used? > >Yes, we have to use the same bus fot both modes SMI0 and MDIO. In fact I for now used the cpu bound port with phy-handle to the fec. This way it still used mdio for the initial probe. But it should also work to use fixed-phy for it don't run into mdio communication on the same bus. This way your patch should work. In case you did not think of anything else, I will send the series including your patch after I tested it with master. Regards, Michael -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik @ 2019-11-07 11:00 ` Michael Grzeschik 2019-11-07 15:44 ` Andrew Lunn 2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik ` (2 subsequent siblings) 4 siblings, 1 reply; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw) To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel Add DSA tag code for the Microchip KSZ8863 switch. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> --- include/net/dsa.h | 2 ++ net/dsa/tag_ksz.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 9507611a41f07..911f07ec40e3a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -42,6 +42,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_8021Q_VALUE 12 #define DSA_TAG_PROTO_SJA1105_VALUE 13 #define DSA_TAG_PROTO_KSZ8795_VALUE 14 +#define DSA_TAG_PROTO_KSZ8863_VALUE 15 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -59,6 +60,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, + DSA_TAG_PROTO_KSZ8863 = DSA_TAG_PROTO_KSZ8863_VALUE, }; struct packet_type; diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 73605bcbb3851..08ea996af3c34 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -243,8 +243,68 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); +/* For ingress (Host -> KSZ8863), 1 byte is added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0[1,0] : represents port + * (e.g. 0b00=addr-lookup 0b01=port1, 0b10=port2, 0b11=port1+port2) + * tag0[3,2] : bits two and three represent prioritization + * (e.g. 0b00xx=prio0, 0b01xx=prio1, 0b10xx=prio2, 0b11xx=prio3) + * + * For egress (KSZ8873 -> Host), 1 byte is added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0[0] : zero-based value represents port + * (eg, 0b0=port1, 0b1=port2) + */ + +static struct sk_buff *ksz8863_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct sk_buff *nskb; + u16 *tag; + + nskb = ksz_common_xmit(skb, dev, KSZ_INGRESS_TAG_LEN); + if (!nskb) + return NULL; + + /* Tag encoding */ + tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN); + + *tag = 1 << (dp->index); /* destination port */ + *tag = cpu_to_be16(*tag); + + return nskb; +} + +static struct sk_buff *ksz8863_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + /* Tag decoding */ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + unsigned int port = tag[0] & 1; + unsigned int len = KSZ_EGRESS_TAG_LEN; + + return ksz_common_rcv(skb, dev, port, len); +} + +static const struct dsa_device_ops ksz8863_netdev_ops = { + .name = "ksz8863", + .proto = DSA_TAG_PROTO_KSZ8863, + .xmit = ksz8863_xmit, + .rcv = ksz8863_rcv, + .overhead = KSZ_INGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(ksz8863_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8863); + static struct dsa_tag_driver *dsa_tag_driver_array[] = { &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), + &DSA_TAG_DRIVER_NAME(ksz8863_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), }; -- 2.24.0.rc1 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code 2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik @ 2019-11-07 15:44 ` Andrew Lunn 0 siblings, 0 replies; 20+ messages in thread From: Andrew Lunn @ 2019-11-07 15:44 UTC (permalink / raw) To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel On Thu, Nov 07, 2019 at 12:00:28PM +0100, Michael Grzeschik wrote: > Add DSA tag code for the Microchip KSZ8863 switch. > > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Andrew ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik @ 2019-11-07 11:00 ` Michael Grzeschik 2019-11-07 15:56 ` Andrew Lunn 2019-11-09 8:08 ` kbuild test robot 2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik 2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik 4 siblings, 2 replies; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw) To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel Add KSZ88X3 driver support. The code ksz8863.c and ksz8863_smi.c add support for the three port switches ksz8863 and ksz8873 using the Microchip SMI Interface. They are currently only supported using the MDIO-Bitbang Interface. Cc: Tristram.Ha@microchip.com Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> --- RFC -> v1: - added Microchip SMI to description - added select MDIO_BITBANG - added return error code handling in mdiobus_read/write - fixed the stp state handling - moved tag handling code to seperate patch drivers/net/dsa/microchip/Kconfig | 16 + drivers/net/dsa/microchip/Makefile | 2 + drivers/net/dsa/microchip/ksz8863.c | 1038 +++++++++++++++++++++++ drivers/net/dsa/microchip/ksz8863_reg.h | 605 +++++++++++++ drivers/net/dsa/microchip/ksz8863_smi.c | 166 ++++ drivers/net/dsa/microchip/ksz_common.h | 1 + 6 files changed, 1828 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8863.c create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 1d7870c6df3ce..5bd5d4a8d875e 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -39,3 +39,19 @@ config NET_DSA_MICROCHIP_KSZ8795_SPI It is required to use the KSZ8795 switch driver as the only access is through SPI. + +menuconfig NET_DSA_MICROCHIP_KSZ8863 + tristate "Microchip KSZ8863 series switch support" + depends on NET_DSA + select NET_DSA_MICROCHIP_KSZ_COMMON + help + This driver adds support for Microchip KSZ8863 switch chips. + +config NET_DSA_MICROCHIP_KSZ8863_SMI + tristate "KSZ series SMI connected switch driver" + depends on NET_DSA_MICROCHIP_KSZ8863 + select MDIO_BITBANG + default y + help + Select to enable support for registering switches configured through + Microchip SMI. It Supports the KSZ8863 and KSZ8873 Switch. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 929caa81e782e..694c2e2eea228 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI) += ksz9477_spi.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795) += ksz8795.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI) += ksz8795_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863) += ksz8863.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o diff --git a/drivers/net/dsa/microchip/ksz8863.c b/drivers/net/dsa/microchip/ksz8863.c new file mode 100644 index 0000000000000..c299a3f41eef7 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8863.c @@ -0,0 +1,1038 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8863 switch driver main logic + * + * Copyright (C) 2017-2019 Microchip Technology Inc. + * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de> + */ + +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_data/microchip-ksz.h> +#include <linux/phy.h> +#include <linux/etherdevice.h> +#include <linux/if_bridge.h> +#include <net/dsa.h> +#include <net/switchdev.h> + +#include "ksz_common.h" +#include "ksz8863_reg.h" + +static const struct { + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { "rx" }, + { "rx_hi" }, + { "rx_undersize" }, + { "rx_fragments" }, + { "rx_oversize" }, + { "rx_jabbers" }, + { "rx_symbol_err" }, + { "rx_crc_err" }, + { "rx_align_err" }, + { "rx_mac_ctrl" }, + { "rx_pause" }, + { "rx_bcast" }, + { "rx_mcast" }, + { "rx_ucast" }, + { "rx_64_or_less" }, + { "rx_65_127" }, + { "rx_128_255" }, + { "rx_256_511" }, + { "rx_512_1023" }, + { "rx_1024_1522" }, + { "tx" }, + { "tx_hi" }, + { "tx_late_col" }, + { "tx_pause" }, + { "tx_bcast" }, + { "tx_mcast" }, + { "tx_ucast" }, + { "tx_deferred" }, + { "tx_total_col" }, + { "tx_exc_col" }, + { "tx_single_col" }, + { "tx_mult_col" }, + { "rx_discards" }, + { "tx_discards" }, +}; + +static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, + bool set) +{ + regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); +} + +static int ksz8863_reset_switch(struct ksz_device *dev) +{ + /* reset switch */ + ksz_cfg(dev, REG_SWITCH_RESET, GLOBAL_SOFTWARE_RESET | PCS_RESET, true); + + ksz_cfg(dev, REG_POWER_MANAGEMENT, SWITCH_SOFTWARE_POWER_DOWN, true); + ksz_cfg(dev, REG_POWER_MANAGEMENT, SWITCH_SOFTWARE_POWER_DOWN, false); + + return 0; +} + +static void ksz8863_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, + u64 *cnt) +{ + u32 data; + u16 ctrl_addr; + u8 check; + int loop; + + ctrl_addr = addr + SWITCH_COUNTER_NUM * port; + ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); + + mutex_lock(&dev->alu_mutex); + ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); + + /* It is almost guaranteed to always read the valid bit because of + * slow SPI speed. + */ + for (loop = 2; loop > 0; loop--) { + ksz_read8(dev, REG_IND_MIB_CHECK, &check); + + if (check & MIB_COUNTER_VALID) { + ksz_read32(dev, REG_IND_DATA_LO, &data); + if (check & MIB_COUNTER_OVERFLOW) + *cnt += MIB_COUNTER_VALUE + 1; + *cnt += data & MIB_COUNTER_VALUE; + break; + } + } + mutex_unlock(&dev->alu_mutex); +} + +static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, + u64 *dropped, u64 *cnt) +{ + u32 cur; + u32 data; + u16 ctrl_addr; + u32 *last = (u32 *)dropped; + + addr -= SWITCH_COUNTER_NUM; + ctrl_addr = addr ? KS_MIB_PACKET_DROPPED_TX_0 : + KS_MIB_PACKET_DROPPED_RX_0; + ctrl_addr += port; + ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); + + mutex_lock(&dev->alu_mutex); + ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); + ksz_read32(dev, REG_IND_DATA_LO, &data); + mutex_unlock(&dev->alu_mutex); + + data &= MIB_PACKET_DROPPED; + cur = last[addr]; + if (data != cur) { + last[addr] = data; + if (data < cur) + data += MIB_PACKET_DROPPED + 1; + data -= cur; + *cnt += data; + } +} + +static void ksz8863_port_init_cnt(struct ksz_device *dev, int port) +{ + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *dropped; + + mib->cnt_ptr = 0; + + /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */ + while (mib->cnt_ptr < dev->reg_mib_cnt) { + dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr, + &mib->counters[mib->cnt_ptr]); + ++mib->cnt_ptr; + } + + /* last one in storage */ + dropped = &mib->counters[dev->mib_cnt]; + + /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ + while (mib->cnt_ptr < dev->mib_cnt) { + dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr, + dropped, &mib->counters[mib->cnt_ptr]); + ++mib->cnt_ptr; + } + mib->cnt_ptr = 0; + memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); +} + +static void ksz8863_r_table(struct ksz_device *dev, int table, u16 addr, + u64 *data) +{ + u16 ctrl_addr; + + ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr; + + mutex_lock(&dev->alu_mutex); + ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); + ksz_read64(dev, REG_IND_DATA_HI, data); + mutex_unlock(&dev->alu_mutex); + *data = be64_to_cpu(*data); +} + +static void ksz8863_w_table(struct ksz_device *dev, int table, u16 addr, + u64 data) +{ + u16 ctrl_addr; + + ctrl_addr = IND_ACC_TABLE(table) | addr; + data = cpu_to_be64(data); + + mutex_lock(&dev->alu_mutex); + ksz_write64(dev, REG_IND_DATA_HI, data); + ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); + mutex_unlock(&dev->alu_mutex); +} + +static int ksz8863_valid_dyn_entry(struct ksz_device *dev, u8 *data) +{ + int timeout = 100; + + do { + ksz_read8(dev, REG_IND_DATA_CHECK, data); + timeout--; + } while ((*data & DYNAMIC_MAC_TABLE_NOT_READY) && timeout); + + /* Entry is not ready for accessing. */ + if (*data & DYNAMIC_MAC_TABLE_NOT_READY) { + return -EAGAIN; + /* Entry is ready for accessing. */ + } else { + ksz_read8(dev, REG_IND_DATA_8, data); + + /* There is no valid entry in the table. */ + if (*data & DYNAMIC_MAC_TABLE_MAC_EMPTY) + return -ENXIO; + } + return 0; +} + +static int ksz8863_r_dyn_mac_table(struct ksz_device *dev, u16 addr, + u8 *mac_addr, u8 *fid, u8 *src_port, + u8 *timestamp, u16 *entries) +{ + u32 data_hi; + u32 data_lo; + u16 ctrl_addr; + int rc; + u8 data; + + ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr; + + mutex_lock(&dev->alu_mutex); + ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); + + rc = ksz8863_valid_dyn_entry(dev, &data); + if (rc == -EAGAIN) { + if (addr == 0) + *entries = 0; + } else if (rc == -ENXIO) { + *entries = 0; + /* At least one valid entry in the table. */ + } else { + u64 buf; + int cnt; + + regmap_bulk_read(dev->regmap[0], REG_IND_DATA_HI, + &buf, sizeof(buf)); + buf = be64_to_cpu(buf); + data_hi = (u32)(buf >> 32); + data_lo = (u32)buf; + + /* Check out how many valid entry in the table. */ + cnt = data & DYNAMIC_MAC_TABLE_ENTRIES_H; + cnt <<= DYNAMIC_MAC_ENTRIES_H_S; + cnt |= (data_hi & DYNAMIC_MAC_TABLE_ENTRIES) >> + DYNAMIC_MAC_ENTRIES_S; + *entries = cnt + 1; + + *fid = (data_hi & DYNAMIC_MAC_TABLE_FID) >> + DYNAMIC_MAC_FID_S; + *src_port = (data_hi & DYNAMIC_MAC_TABLE_SRC_PORT) >> + DYNAMIC_MAC_SRC_PORT_S; + *timestamp = (data_hi & DYNAMIC_MAC_TABLE_TIMESTAMP) >> + DYNAMIC_MAC_TIMESTAMP_S; + + mac_addr[5] = (u8)data_lo; + mac_addr[4] = (u8)(data_lo >> 8); + mac_addr[3] = (u8)(data_lo >> 16); + mac_addr[2] = (u8)(data_lo >> 24); + + mac_addr[1] = (u8)data_hi; + mac_addr[0] = (u8)(data_hi >> 8); + rc = 0; + } + mutex_unlock(&dev->alu_mutex); + + return rc; +} + +static int ksz8863_r_sta_mac_table(struct ksz_device *dev, u16 addr, + struct alu_struct *alu) +{ + u64 data; + u32 data_hi; + u32 data_lo; + + ksz8863_r_table(dev, TABLE_STATIC_MAC, addr, &data); + + data_hi = data >> 32; + data_lo = (u32)data; + + if (data_hi & (STATIC_MAC_TABLE_VALID | STATIC_MAC_TABLE_OVERRIDE)) { + alu->mac[5] = (u8)data_lo; + alu->mac[4] = (u8)(data_lo >> 8); + alu->mac[3] = (u8)(data_lo >> 16); + alu->mac[2] = (u8)(data_lo >> 24); + alu->mac[1] = (u8)data_hi; + alu->mac[0] = (u8)(data_hi >> 8); + alu->port_forward = (data_hi & STATIC_MAC_TABLE_FWD_PORTS) >> + STATIC_MAC_FWD_PORTS_S; + alu->is_override = + (data_hi & STATIC_MAC_TABLE_OVERRIDE) ? 1 : 0; + data_hi >>= 1; + alu->is_static = true; + alu->is_use_fid = (data_hi & STATIC_MAC_TABLE_USE_FID) ? 1 : 0; + alu->fid = (data_hi & STATIC_MAC_TABLE_FID) >> + STATIC_MAC_FID_S; + + return 0; + } + + return -ENXIO; +} + +static void ksz8863_w_sta_mac_table(struct ksz_device *dev, u16 addr, + struct alu_struct *alu) +{ + u64 data; + u32 data_hi; + u32 data_lo; + + data_lo = ((u32)alu->mac[2] << 24) | + ((u32)alu->mac[3] << 16) | + ((u32)alu->mac[4] << 8) | alu->mac[5]; + data_hi = ((u32)alu->mac[0] << 8) | alu->mac[1]; + data_hi |= (u32)alu->port_forward << STATIC_MAC_FWD_PORTS_S; + + if (alu->is_override) + data_hi |= STATIC_MAC_TABLE_OVERRIDE; + + if (alu->is_use_fid) { + data_hi |= STATIC_MAC_TABLE_USE_FID; + data_hi |= (u32)alu->fid << STATIC_MAC_FID_S; + } + + if (alu->is_static) + data_hi |= STATIC_MAC_TABLE_VALID; + else + data_hi &= ~STATIC_MAC_TABLE_OVERRIDE; + + data = (u64)data_hi << 32 | data_lo; + ksz8863_w_table(dev, TABLE_STATIC_MAC, addr, data); +} + +static inline void ksz8863_from_vlan(u16 vlan, u8 *fid, u8 *member, u8 *valid) +{ + *fid = vlan & VLAN_TABLE_FID; + *member = (vlan & VLAN_TABLE_MEMBERSHIP) >> VLAN_TABLE_MEMBERSHIP_S; + *valid = !!(vlan & VLAN_TABLE_VALID); +} + +static inline void ksz8863_to_vlan(u8 fid, u8 member, u8 valid, u16 *vlan) +{ + *vlan = fid; + *vlan |= (u16)member << VLAN_TABLE_MEMBERSHIP_S; + if (valid) + *vlan |= VLAN_TABLE_VALID; +} + +static void ksz8863_r_vlan_entries(struct ksz_device *dev, u16 addr) +{ + u64 data; + int i; + + ksz8863_r_table(dev, TABLE_VLAN, addr, &data); + addr *= 2; + for (i = 0; i < 2; i++) { + dev->vlan_cache[addr + i].table[0] = data & VLAN_TABLE_M; + data >>= VLAN_TABLE_S; + } +} + +static void ksz8863_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan) +{ + u64 buf; + u16 addr; + int index; + + addr = vid / 2; + index = vid & 3; + ksz8863_r_table(dev, TABLE_VLAN, addr, &buf); + buf >>= VLAN_TABLE_S * index; + *vlan = buf & VLAN_TABLE_M; +} + +static void ksz8863_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) +{ + u64 buf; + u16 addr; + int index; + + addr = vid / 2; + index = vid & 3; + ksz8863_r_table(dev, TABLE_VLAN, addr, &buf); + index *= VLAN_TABLE_S; + buf &= ~(VLAN_TABLE_M << index); + buf |= (u64)vlan << index; + dev->vlan_cache[vid].table[0] = vlan; + ksz8863_w_table(dev, TABLE_VLAN, addr, buf); +} + +static enum dsa_tag_protocol ksz8863_get_tag_protocol(struct dsa_switch *ds, + int port) +{ + /* Use KSZ8795 tail tagging code. */ + return DSA_TAG_PROTO_KSZ8863; +} + +static void ksz8863_get_strings(struct dsa_switch *ds, int port, + u32 stringset, uint8_t *buf) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { + memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, + ETH_GSTRING_LEN); + } + break; + } +} + +static const u8 stp_multicast_addr[] = { + 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 +}; + +static void ksz8863_cfg_port_member(struct ksz_device *dev, int port, + u8 member) +{ + u8 data; + + ksz_pread8(dev, port, P_MIRROR_CTRL, &data); + data &= ~PORT_VLAN_MEMBERSHIP; + data |= (member & dev->port_mask); + ksz_pwrite8(dev, port, P_MIRROR_CTRL, data); + dev->ports[port].member = member; +} + +static void ksz8863_port_stp_state_set(struct dsa_switch *ds, int port, + u8 state) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *p = &dev->ports[port]; + u8 data; + int member = -1; + + ksz_pread8(dev, port, P_STP_CTRL, &data); + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); + + switch (state) { + case BR_STATE_DISABLED: + data |= PORT_LEARN_DISABLE; + if (port < SWITCH_PORT_NUM) + member = 0; + break; + case BR_STATE_LISTENING: + data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); + if (port < SWITCH_PORT_NUM && + p->stp_state == BR_STATE_DISABLED) + member = dev->host_mask | p->vid_member; + break; + case BR_STATE_LEARNING: + data |= PORT_RX_ENABLE; + break; + case BR_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + + /* This function is also used internally. */ + if (port == dev->cpu_port) + break; + + /* Port is a member of a bridge. */ + if (dev->br_member & (1 << port)) { + dev->member |= (1 << port); + member = dev->member; + } else { + member = dev->host_mask | p->vid_member; + } + break; + case BR_STATE_BLOCKING: + data |= PORT_LEARN_DISABLE; + if (port < SWITCH_PORT_NUM && + p->stp_state == BR_STATE_DISABLED) + member = dev->host_mask | p->vid_member; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + ksz_pwrite8(dev, port, P_STP_CTRL, data); + p->stp_state = state; + if (data & PORT_RX_ENABLE) + dev->rx_ports |= (1 << port); + else + dev->rx_ports &= ~(1 << port); + if (data & PORT_TX_ENABLE) + dev->tx_ports |= (1 << port); + else + dev->tx_ports &= ~(1 << port); + + /* Port membership may share register with STP state. */ + if (member >= 0 && member != p->member) + ksz8863_cfg_port_member(dev, port, (u8)member); + + /* Check if forwarding needs to be updated. */ + if (state != BR_STATE_FORWARDING) { + if (dev->br_member & (1 << port)) + dev->member &= ~(1 << port); + } + + /* When topology has changed the function ksz_update_port_member + * should be called to modify port forwarding behavior. However + * as the offload_fwd_mark indication cannot be reported here + * the switch forwarding function is not enabled. + */ +} + +static void ksz8863_flush_dyn_mac_table(struct ksz_device *dev, int port) +{ + int cnt; + int first; + int index; + u8 learn[TOTAL_PORT_NUM]; + + if ((uint)port < TOTAL_PORT_NUM) { + first = port; + cnt = port + 1; + } else { + /* Flush all ports. */ + first = 0; + cnt = dev->mib_port_cnt; + } + for (index = first; index < cnt; index++) { + ksz_pread8(dev, index, P_STP_CTRL, &learn[index]); + if (!(learn[index] & PORT_LEARN_DISABLE)) + ksz_pwrite8(dev, index, P_STP_CTRL, + learn[index] | PORT_LEARN_DISABLE); + } + ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SWITCH_FLUSH_DYN_MAC_TABLE, true); + for (index = first; index < cnt; index++) { + if (!(learn[index] & PORT_LEARN_DISABLE)) + ksz_pwrite8(dev, index, P_STP_CTRL, learn[index]); + } +} + +static int ksz8863_port_vlan_filtering(struct dsa_switch *ds, int port, + bool flag) +{ + struct ksz_device *dev = ds->priv; + + ksz_cfg(dev, S_MIRROR_CTRL, SWITCH_VLAN_ENABLE, flag); + + return 0; +} + +static void ksz8863_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + u16 data; + u16 vid; + u8 fid; + u8 member; + u8 valid; + u16 new_pvid = 0; + + mutex_lock(&dev->vlan_mutex); + + ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + ksz8863_r_vlan_table(dev, vid, &data); + ksz8863_from_vlan(data, &fid, &member, &valid); + + /* First time to setup the VLAN entry. */ + if (!valid) { + /* Need to find a way to map VID to FID. */ + fid = 1; + valid = 1; + } + member |= BIT(port); + + ksz8863_to_vlan(fid, member, valid, &data); + ksz8863_w_vlan_table(dev, vid, data); + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + new_pvid = vid; + } + + if (new_pvid) { + ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid); + vid &= 0xfff; + vid |= new_pvid; + ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid); + } + + mutex_unlock(&dev->vlan_mutex); +} + +static int ksz8863_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + u16 data; + u16 vid; + u16 pvid; + u8 fid; + u8 member; + u8 valid; + u16 new_pvid = 0; + + mutex_lock(&dev->vlan_mutex); + + ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid); + pvid = pvid & 0xFFF; + + ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + ksz8863_r_vlan_table(dev, vid, &data); + ksz8863_from_vlan(data, &fid, &member, &valid); + + member &= ~BIT(port); + + /* Invalidate the entry if no more member. */ + if (!member) { + fid = 0; + valid = 0; + } + + if (pvid == vid) + new_pvid = 1; + + ksz8863_to_vlan(fid, member, valid, &data); + ksz8863_w_vlan_table(dev, vid, data); + } + + if (new_pvid != pvid) + ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, pvid); + + mutex_unlock(&dev->vlan_mutex); + + return 0; +} + +static int ksz8863_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct ksz_device *dev = ds->priv; + + if (ingress) { + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); + dev->mirror_rx |= (1 << port); + } else { + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); + dev->mirror_tx |= (1 << port); + } + + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); + + /* configure mirror port */ + if (dev->mirror_rx || dev->mirror_tx) + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, true); + + return 0; +} + +static void ksz8863_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + if (mirror->ingress) { + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); + dev->mirror_rx &= ~(1 << port); + } else { + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); + dev->mirror_tx &= ~(1 << port); + } + + ksz_pread8(dev, port, P_MIRROR_CTRL, &data); + + if (!dev->mirror_rx && !dev->mirror_tx) + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, false); +} + +static void ksz8863_phy_setup(struct ksz_device *dev, int port, + struct phy_device *phy) +{ + /* SUPPORTED_Pause can be removed to disable flow control when + * rate limiting is used. + */ + linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phy->supported); + linkmode_copy(phy->advertising, phy->supported); +} + +static void ksz8863_port_setup(struct ksz_device *dev, int port, bool cpu_port) +{ + u8 member; + struct ksz_port *p = &dev->ports[port]; + + /* enable broadcast storm limit */ + ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); + + /* disable DiffServ priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false); + + /* replace priority */ + ksz_port_cfg(dev, port, P_802_1P_CTRL, PORT_802_1P_REMAPPING, false); + + /* enable 802.1p priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true); + + if (cpu_port) { + member = dev->port_mask; + dev->on_ports = dev->host_mask; + dev->live_ports = dev->host_mask; + } else { + member = dev->host_mask | p->vid_member; + dev->on_ports |= (1 << port); + + /* Link was detected before port is enabled. */ + if (p->phydev.link) + dev->live_ports |= (1 << port); + } + ksz8863_cfg_port_member(dev, port, member); +} + +static void ksz8863_config_cpu_port(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *p; + int i; + + ds->num_ports = dev->port_cnt + 1; + + ksz_cfg(dev, S_TAIL_TAG_CTRL, SWITCH_TAIL_TAG_ENABLE, true); + + p = &dev->ports[dev->cpu_port]; + p->vid_member = dev->port_mask; + p->on = 1; + + ksz8863_port_setup(dev, dev->cpu_port, true); + dev->member = dev->host_mask; + + for (i = 0; i < SWITCH_PORT_NUM; i++) { + p = &dev->ports[i]; + + /* Initialize to non-zero so that ksz_cfg_port_member() will + * be called. + */ + p->vid_member = (1 << i); + p->member = dev->port_mask; + ksz8863_port_stp_state_set(ds, i, BR_STATE_DISABLED); + + p->on = 1; + p->phy = 1; + } + + for (i = 0; i < dev->phy_port_cnt; i++) { + p = &dev->ports[i]; + if (!p->on) + continue; + ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL, + false); + } +} + +static int ksz8863_setup(struct dsa_switch *ds) +{ + u8 data8; + u16 data16; + u32 value; + int i; + struct alu_struct alu; + struct ksz_device *dev = ds->priv; + int ret = 0; + + dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), + dev->num_vlans, GFP_KERNEL); + if (!dev->vlan_cache) + return -ENOMEM; + + ret = ksz8863_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + ksz_cfg(dev, S_REPLACE_VID_CTRL, SWITCH_FLOW_CTRL, true); + + /* Enable automatic fast aging when link changed detected. */ + ksz_cfg(dev, S_LINK_AGING_CTRL, SWITCH_LINK_AUTO_AGING, true); + + ksz_read8(dev, REG_SWITCH_CTRL_1, &data8); + + /* Enable aggressive back off algorithm in half duplex mode. */ + data8 |= SWITCH_AGGR_BACKOFF; + ksz_write8(dev, REG_SWITCH_CTRL_1, data8); + + ksz_read8(dev, REG_SWITCH_CTRL_2, &data8); + + /* Make sure unicast VLAN boundary is set as default. */ + data8 |= UNICAST_VLAN_BOUNDARY; + + /* Enable no excessive collision drop. */ + data8 |= NO_EXC_COLLISION_DROP; + ksz_write8(dev, REG_SWITCH_CTRL_2, data8); + + ksz8863_config_cpu_port(ds); + + ksz_cfg(dev, REG_SWITCH_CTRL_2, MULTICAST_STORM_DISABLE, true); + + ksz_cfg(dev, S_REPLACE_VID_CTRL, SWITCH_REPLACE_VID, false); + + ksz_cfg(dev, S_MIRROR_CTRL, SWITCH_MIRROR_RX_TX, false); + + /* set broadcast storm protection 10% rate */ + data8 = BROADCAST_STORM_PROT_RATE; + value = ((u32)BROADCAST_STORM_VALUE * data8) / 100; + if (value > BROADCAST_STORM_RATE) + value = BROADCAST_STORM_RATE; + ksz_read16(dev, S_REPLACE_VID_CTRL, &data16); + data16 &= ~BROADCAST_STORM_RATE; + data16 |= value; + ksz_write16(dev, S_REPLACE_VID_CTRL, data16); + + for (i = 0; i < VLAN_TABLE_ENTRIES; i++) + ksz8863_r_vlan_entries(dev, i); + + /* Setup STP address for STP operation. */ + memset(&alu, 0, sizeof(alu)); + memcpy(alu.mac, stp_multicast_addr, ETH_ALEN); + alu.is_static = true; + alu.is_override = true; + alu.port_forward = dev->host_mask; + + ksz8863_w_sta_mac_table(dev, 0, &alu); + + ksz_write8(dev, REG_CHIP_ID1, SWITCH_START); + + ksz_init_mib_timer(dev); + + return 0; +} + +static const struct dsa_switch_ops ksz8863_switch_ops = { + .get_tag_protocol = ksz8863_get_tag_protocol, + .setup = ksz8863_setup, + .adjust_link = ksz_adjust_link, + .port_enable = ksz_enable_port, + .port_disable = ksz_disable_port, + .get_strings = ksz8863_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, + .port_bridge_join = ksz_port_bridge_join, + .port_bridge_leave = ksz_port_bridge_leave, + .port_stp_state_set = ksz8863_port_stp_state_set, + .port_fast_age = ksz_port_fast_age, + .port_vlan_filtering = ksz8863_port_vlan_filtering, + .port_vlan_prepare = ksz_port_vlan_prepare, + .port_vlan_add = ksz8863_port_vlan_add, + .port_vlan_del = ksz8863_port_vlan_del, + .port_fdb_dump = ksz_port_fdb_dump, + .port_mdb_prepare = ksz_port_mdb_prepare, + .port_mdb_add = ksz_port_mdb_add, + .port_mdb_del = ksz_port_mdb_del, + .port_mirror_add = ksz8863_port_mirror_add, + .port_mirror_del = ksz8863_port_mirror_del, +}; + +static u32 ksz8863_get_port_addr(int port, int reg) +{ + int offset; + + PORT_CTRL_ADDR(port, offset); + + return reg + offset; +} + +static int ksz8863_switch_detect(struct ksz_device *dev) +{ + u16 id16; + u8 id1; + u8 id2; + int ret; + + /* read chip id */ + ret = ksz_read16(dev, REG_CHIP_ID0, &id16); + if (ret) + return ret; + + id1 = id16 >> 8; + id2 = id16 & SW_CHIP_ID_M; + if (id1 != FAMILY_ID || + id2 != CHIP_ID_63) + return -ENODEV; + + dev->mib_port_cnt = TOTAL_PORT_NUM; + dev->phy_port_cnt = SWITCH_PORT_NUM; + + id16 = 0x8800; + id16 |= 0x73; + dev->chip_id = id16; + + dev->cpu_port = dev->mib_port_cnt - 1; + dev->host_mask = (1 << dev->cpu_port); + + return 0; +} + +struct ksz_chip_data { + u16 chip_id; + const char *dev_name; + int num_vlans; + int num_alus; + int num_statics; + int cpu_ports; + int port_cnt; +}; + +static const struct ksz_chip_data ksz8863_switch_chips[] = { + { + .chip_id = 0x8863, + .dev_name = "KSZ8863", + .num_vlans = 16, + .num_alus = 0, + .num_statics = 8, + .cpu_ports = 0x4, /* can be configured as cpu port */ + .port_cnt = 2, /* total physical port count */ + }, + { + .chip_id = 0x8873, + .dev_name = "KSZ8873", + .num_vlans = 16, + .num_alus = 0, + .num_statics = 8, + .cpu_ports = 0x4, /* can be configured as cpu port */ + .port_cnt = 2, /* total physical port count */ + }, +}; + +static int ksz8863_switch_init(struct ksz_device *dev) +{ + int i; + + dev->ds->ops = &ksz8863_switch_ops; + + for (i = 0; i < ARRAY_SIZE(ksz8863_switch_chips); i++) { + const struct ksz_chip_data *chip = &ksz8863_switch_chips[i]; + + if (dev->chip_id == chip->chip_id) { + dev->name = chip->dev_name; + dev->num_vlans = chip->num_vlans; + dev->num_alus = chip->num_alus; + dev->num_statics = chip->num_statics; + dev->port_cnt = chip->port_cnt; + dev->cpu_ports = chip->cpu_ports; + + break; + } + } + + /* no switch found */ + if (!dev->cpu_ports) + return -ENODEV; + + dev->port_mask = (1 << dev->port_cnt) - 1; + dev->port_mask |= dev->host_mask; + + dev->reg_mib_cnt = SWITCH_COUNTER_NUM; + dev->mib_cnt = TOTAL_SWITCH_COUNTER_NUM; + + i = dev->mib_port_cnt; + dev->ports = devm_kzalloc(dev->dev, sizeof(struct ksz_port) * i, + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + for (i = 0; i < dev->mib_port_cnt; i++) { + mutex_init(&dev->ports[i].mib.cnt_mutex); + dev->ports[i].mib.counters = + devm_kzalloc(dev->dev, + sizeof(u64) * + (TOTAL_SWITCH_COUNTER_NUM + 1), + GFP_KERNEL); + if (!dev->ports[i].mib.counters) + return -ENOMEM; + } + + return 0; +} + +static void ksz8863_switch_exit(struct ksz_device *dev) +{ + ksz8863_reset_switch(dev); + ksz_write8(dev, REG_CHIP_ID1, SWITCH_START); +} + +static const struct ksz_dev_ops ksz8863_dev_ops = { + .get_port_addr = ksz8863_get_port_addr, + .cfg_port_member = ksz8863_cfg_port_member, + .flush_dyn_mac_table = ksz8863_flush_dyn_mac_table, + .phy_setup = ksz8863_phy_setup, + .port_setup = ksz8863_port_setup, + .r_dyn_mac_table = ksz8863_r_dyn_mac_table, + .r_sta_mac_table = ksz8863_r_sta_mac_table, + .w_sta_mac_table = ksz8863_w_sta_mac_table, + .r_mib_cnt = ksz8863_r_mib_cnt, + .r_mib_pkt = ksz8863_r_mib_pkt, + .port_init_cnt = ksz8863_port_init_cnt, + .shutdown = ksz8863_reset_switch, + .detect = ksz8863_switch_detect, + .init = ksz8863_switch_init, + .exit = ksz8863_switch_exit, +}; + +int ksz8863_switch_register(struct ksz_device *dev) +{ + return ksz_switch_register(dev, &ksz8863_dev_ops); +} +EXPORT_SYMBOL(ksz8863_switch_register); + +MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); +MODULE_DESCRIPTION("Micrel KSZ8863 SMI Switch driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/dsa/microchip/ksz8863_reg.h b/drivers/net/dsa/microchip/ksz8863_reg.h new file mode 100644 index 0000000000000..6921890ae5509 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8863_reg.h @@ -0,0 +1,605 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Microchip KSZ8863 definition file + * + * Copyright (c) 2015-2016 Microchip Technology Inc. + */ + +#ifndef __KSZ8863_REGS_H +#define __KSZ8863_REGS_H + +#define REG_CHIP_ID0 0x00 + +#define FAMILY_ID 0x88 + +#define REG_CHIP_ID1 0x01 +#define SW_CHIP_ID_M 0xF0 + +#define SWITCH_CHIP_ID_MASK 0xF0 +#define SWITCH_CHIP_ID_SHIFT 4 +#define SWITCH_REVISION_MASK 0x0E +#define SWITCH_REVISION_SHIFT 1 +#define SWITCH_START 0x01 + +#define CHIP_ID_63 0x30 + +#define REG_SWITCH_CTRL_0 0x02 + +#define SWITCH_NEW_BACKOFF BIT(7) +#define SWITCH_FLUSH_DYN_MAC_TABLE BIT(5) +#define SWITCH_FLUSH_STA_MAC_TABLE BIT(4) +#define SWITCH_PASS_PAUSE BIT(3) +#define SWITCH_LINK_AUTO_AGING BIT(0) + +#define REG_SWITCH_CTRL_1 0x03 + +#define SWITCH_PASS_ALL BIT(7) +#define SWITCH_TAIL_TAG_ENABLE BIT(6) +#define SWITCH_TX_FLOW_CTRL BIT(5) +#define SWITCH_RX_FLOW_CTRL BIT(4) +#define SWITCH_CHECK_LENGTH BIT(3) +#define SWITCH_AGING_ENABLE BIT(2) +#define SWITCH_FAST_AGING BIT(1) +#define SWITCH_AGGR_BACKOFF BIT(0) + +#define REG_SWITCH_CTRL_2 0x04 + +#define UNICAST_VLAN_BOUNDARY BIT(7) +#define MULTICAST_STORM_DISABLE BIT(6) +#define SWITCH_BACK_PRESSURE BIT(5) +#define FAIR_FLOW_CTRL BIT(4) +#define NO_EXC_COLLISION_DROP BIT(3) +#define SWITCH_HUGE_PACKET BIT(2) +#define SWITCH_LEGAL_PACKET BIT(1) + +#define REG_SWITCH_CTRL_3 0x05 + +#define SWITCH_VLAN_ENABLE BIT(7) +#define SWITCH_IGMP_SNOOP BIT(6) +#define WEIGHTED_FAIR_QUEUE_ENABLE BIT(3) +#define SWITCH_MIRROR_RX_TX BIT(0) + +#define REG_SWITCH_CTRL_4 0x06 + +#define SWITCH_HALF_DUPLEX BIT(6) +#define SWITCH_FLOW_CTRL BIT(5) +#define SWITCH_10_MBIT BIT(4) +#define SWITCH_REPLACE_VID BIT(3) +#define BROADCAST_STORM_RATE_HI 0x07 + +#define REG_SWITCH_CTRL_5 0x07 + +#define BROADCAST_STORM_RATE_LO 0xFF +#define BROADCAST_STORM_RATE 0x07FF + +#define REG_SWITCH_CTRL_9 0x0B + +#define SPI_CLK_125_MHZ 0x80 +#define SPI_CLK_62_5_MHZ 0x40 +#define SPI_CLK_31_25_MHZ 0x00 + +#define REG_SWITCH_CTRL_10 0x0C +#define REG_SWITCH_CTRL_11 0x0D + +#define SWITCH_802_1P_MASK 3 +#define SWITCH_802_1P_BASE 3 +#define SWITCH_802_1P_SHIFT 2 + +#define SWITCH_802_1P_MAP_MASK 3 +#define SWITCH_802_1P_MAP_SHIFT 2 + +#define REG_SWITCH_CTRL_12 0x0E + +#define SWITCH_UNKNOWN_DA_ENABLE BIT(7) +#define SWITCH_DRIVER_16MA BIT(6) +#define SWITCH_UNKNOWN_DA_2_PORT3 BIT(2) +#define SWITCH_UNKNOWN_DA_2_PORT2 BIT(1) +#define SWITCH_UNKNOWN_DA_2_PORT1 BIT(0) + +#define REG_SWITCH_CTRL_13 0x0F + +#define SWITCH_PORT_PHY_ADDR_MASK 0x1F +#define SWITCH_PORT_PHY_ADDR_SHIFT 3 + +#define REG_PORT_1_CTRL_0 0x10 +#define REG_PORT_2_CTRL_0 0x20 +#define REG_PORT_3_CTRL_0 0x30 + +#define PORT_BROADCAST_STORM BIT(7) +#define PORT_DIFFSERV_ENABLE BIT(6) +#define PORT_802_1P_ENABLE BIT(5) +#define PORT_BASED_PRIORITY_MASK 0x18 +#define PORT_BASED_PRIORITY_BASE 0x03 +#define PORT_BASED_PRIORITY_SHIFT 3 +#define PORT_PORT_PRIO_0 0x00 +#define PORT_PORT_PRIO_1 0x08 +#define PORT_PORT_PRIO_2 0x10 +#define PORT_PORT_PRIO_3 0x18 +#define PORT_INSERT_TAG BIT(2) +#define PORT_REMOVE_TAG BIT(1) +#define PORT_4_QUEUES_ENABLE BIT(0) + +#define REG_PORT_1_CTRL_1 0x11 +#define REG_PORT_2_CTRL_1 0x21 +#define REG_PORT_3_CTRL_1 0x31 + +#define PORT_MIRROR_SNIFFER BIT(7) +#define PORT_MIRROR_RX BIT(6) +#define PORT_MIRROR_TX BIT(5) +#define PORT_DOUBLE_TAG BIT(4) +#define PORT_802_1P_REMAPPING BIT(3) +#define PORT_VLAN_MEMBERSHIP 0x07 + +#define REG_PORT_1_CTRL_2 0x12 +#define REG_PORT_2_CTRL_2 0x22 +#define REG_PORT_3_CTRL_2 0x32 + +#define PORT_2_QUEUES_ENABLE BIT(7) +#define PORT_INGRESS_FILTER BIT(6) +#define PORT_DISCARD_NON_VID BIT(5) +#define PORT_FORCE_FLOW_CTRL BIT(4) +#define PORT_BACK_PRESSURE BIT(3) +#define PORT_TX_ENABLE BIT(2) +#define PORT_RX_ENABLE BIT(1) +#define PORT_LEARN_DISABLE BIT(0) + +#define REG_PORT_1_CTRL_3 0x13 +#define REG_PORT_2_CTRL_3 0x23 +#define REG_PORT_3_CTRL_3 0x33 +#define REG_PORT_1_CTRL_4 0x14 +#define REG_PORT_2_CTRL_4 0x24 +#define REG_PORT_3_CTRL_4 0x34 + +#define PORT_DEFAULT_VID 0x0001 + +#define REG_PORT_1_CTRL_5 0x15 +#define REG_PORT_2_CTRL_5 0x25 +#define REG_PORT_3_CTRL_5 0x35 + +#define PORT_3_MII_MAC_MODE BIT(7) +#define PORT_SA_MAC2 BIT(6) +#define PORT_SA_MAC1 BIT(5) +#define PORT_DROP_TAG BIT(4) +#define PORT_INGRESS_LIMIT_MODE 0x0C +#define PORT_INGRESS_ALL 0x00 +#define PORT_INGRESS_UNICAST 0x04 +#define PORT_INGRESS_MULTICAST 0x08 +#define PORT_INGRESS_BROADCAST 0x0C +#define PORT_COUNT_IFG BIT(1) +#define PORT_COUNT_PREAMBLE BIT(0) + +#define REG_PORT_1_IN_RATE_0 0x16 +#define REG_PORT_2_IN_RATE_0 0x26 +#define REG_PORT_3_IN_RATE_0 0x36 + +#define PORT_3_INVERTED_REFCLK BIT(7) + +#define REG_PORT_1_IN_RATE_1 0x17 +#define REG_PORT_2_IN_RATE_1 0x27 +#define REG_PORT_3_IN_RATE_1 0x37 +#define REG_PORT_1_IN_RATE_2 0x18 +#define REG_PORT_2_IN_RATE_2 0x28 +#define REG_PORT_3_IN_RATE_2 0x38 +#define REG_PORT_1_IN_RATE_3 0x19 +#define REG_PORT_2_IN_RATE_3 0x29 +#define REG_PORT_3_IN_RATE_3 0x39 + +#define PORT_PRIO_RATE 0x0F +#define PORT_PRIO_RATE_SHIFT 4 + +#define REG_PORT_1_LINK_MD_CTRL 0x1A +#define REG_PORT_2_LINK_MD_CTRL 0x2A + +#define PORT_CABLE_10M_SHORT BIT(7) +#define PORT_CABLE_DIAG_RESULT 0x60 +#define PORT_CABLE_STAT_NORMAL 0x00 +#define PORT_CABLE_STAT_OPEN 0x20 +#define PORT_CABLE_STAT_SHORT 0x40 +#define PORT_CABLE_STAT_FAILED 0x60 +#define PORT_START_CABLE_DIAG BIT(4) +#define PORT_FORCE_LINK BIT(3) +#define PORT_POWER_SAVING 0x04 +#define PORT_PHY_REMOTE_LOOPBACK BIT(1) +#define PORT_CABLE_FAULT_COUNTER_H 0x01 + +#define REG_PORT_1_LINK_MD_RESULT 0x1B +#define REG_PORT_2_LINK_MD_RESULT 0x2B + +#define PORT_CABLE_FAULT_COUNTER_L 0xFF +#define PORT_CABLE_FAULT_COUNTER 0x1FF + +#define REG_PORT_1_CTRL_12 0x1C +#define REG_PORT_2_CTRL_12 0x2C + +#define PORT_AUTO_NEG_ENABLE BIT(7) +#define PORT_FORCE_100_MBIT BIT(6) +#define PORT_FORCE_FULL_DUPLEX BIT(5) +#define PORT_AUTO_NEG_SYM_PAUSE BIT(4) +#define PORT_AUTO_NEG_100BTX_FD BIT(3) +#define PORT_AUTO_NEG_100BTX BIT(2) +#define PORT_AUTO_NEG_10BT_FD BIT(1) +#define PORT_AUTO_NEG_10BT BIT(0) + +#define REG_PORT_1_CTRL_13 0x1D +#define REG_PORT_2_CTRL_13 0x2D + +#define PORT_LED_OFF BIT(7) +#define PORT_TX_DISABLE BIT(6) +#define PORT_AUTO_NEG_RESTART BIT(5) +#define PORT_REMOTE_FAULT_DISABLE BIT(4) +#define PORT_POWER_DOWN BIT(3) +#define PORT_AUTO_MDIX_DISABLE BIT(2) +#define PORT_FORCE_MDIX BIT(1) +#define PORT_LOOPBACK BIT(0) + +#define REG_PORT_1_STATUS_0 0x1E +#define REG_PORT_2_STATUS_0 0x2E + +#define PORT_MDIX_STATUS BIT(7) +#define PORT_AUTO_NEG_COMPLETE BIT(6) +#define PORT_STATUS_LINK_GOOD BIT(5) +#define PORT_REMOTE_SYM_PAUSE BIT(4) +#define PORT_REMOTE_100BTX_FD BIT(3) +#define PORT_REMOTE_100BTX BIT(2) +#define PORT_REMOTE_10BT_FD BIT(1) +#define PORT_REMOTE_10BT BIT(0) + +#define REG_PORT_1_STATUS_1 0x1F +#define REG_PORT_2_STATUS_1 0x2F +#define REG_PORT_3_STATUS_1 0x3F + +#define PORT_HP_MDIX BIT(7) +#define PORT_REVERSED_POLARITY BIT(5) +#define PORT_TX_FLOW_CTRL BIT(4) +#define PORT_RX_FLOW_CTRL BIT(3) +#define PORT_STAT_SPEED_100MBIT BIT(2) +#define PORT_STAT_FULL_DUPLEX BIT(1) +#define PORT_REMOTE_FAULT BIT(0) + +#define REG_PORT_CTRL_0 0x00 +#define REG_PORT_CTRL_1 0x01 +#define REG_PORT_CTRL_2 0x02 +#define REG_PORT_CTRL_VID 0x03 +#define REG_PORT_CTRL_5 0x05 +#define REG_PORT_IN_RATE_0 0x06 +#define REG_PORT_IN_RATE_1 0x07 +#define REG_PORT_IN_RATE_2 0x08 +#define REG_PORT_IN_RATE_3 0x09 +#define REG_PORT_LINK_MD_CTRL 0x0A +#define REG_PORT_LINK_MD_RESULT 0x0B +#define REG_PORT_CTRL_12 0x0C +#define REG_PORT_CTRL_13 0x0D +#define REG_PORT_STATUS_0 0x0E +#define REG_PORT_STATUS_1 0x0F + +#define PORT_CTRL_ADDR(port, addr) \ + (addr = REG_PORT_1_CTRL_0 + (port) * \ + (REG_PORT_2_CTRL_0 - REG_PORT_1_CTRL_0)) + +#define REG_SWITCH_RESET 0x43 + +#define GLOBAL_SOFTWARE_RESET BIT(4) +#define PCS_RESET BIT(0) + +#define REG_TOS_PRIO_CTRL_0 0x60 +#define REG_TOS_PRIO_CTRL_1 0x61 +#define REG_TOS_PRIO_CTRL_2 0x62 +#define REG_TOS_PRIO_CTRL_3 0x63 +#define REG_TOS_PRIO_CTRL_4 0x64 +#define REG_TOS_PRIO_CTRL_5 0x65 +#define REG_TOS_PRIO_CTRL_6 0x66 +#define REG_TOS_PRIO_CTRL_7 0x67 +#define REG_TOS_PRIO_CTRL_8 0x68 +#define REG_TOS_PRIO_CTRL_9 0x69 +#define REG_TOS_PRIO_CTRL_10 0x6A +#define REG_TOS_PRIO_CTRL_11 0x6B +#define REG_TOS_PRIO_CTRL_12 0x6C +#define REG_TOS_PRIO_CTRL_13 0x6D +#define REG_TOS_PRIO_CTRL_14 0x6E +#define REG_TOS_PRIO_CTRL_15 0x6F + +#define TOS_PRIO_M 3 +#define TOS_PRIO_S 2 + +#define REG_SWITCH_MAC_ADDR_0 0x70 +#define REG_SWITCH_MAC_ADDR_1 0x71 +#define REG_SWITCH_MAC_ADDR_2 0x72 +#define REG_SWITCH_MAC_ADDR_3 0x73 +#define REG_SWITCH_MAC_ADDR_4 0x74 +#define REG_SWITCH_MAC_ADDR_5 0x75 + +#define REG_USER_DEFINED_1 0x76 +#define REG_USER_DEFINED_2 0x77 +#define REG_USER_DEFINED_3 0x78 + +#define REG_IND_CTRL_0 0x79 + +#define TABLE_READ BIT(4) +#define TABLE_STATIC_MAC BIT(2) +#define TABLE_VLAN BIT(2) +#define TABLE_DYNAMIC_MAC BIT(2) +#define TABLE_MIB BIT(2) + +#define REG_IND_CTRL_1 0x7A + +#define TABLE_ENTRY_MASK 0x03FF + +#define REG_IND_DATA_8 0x7B +#define REG_IND_DATA_7 0x7C +#define REG_IND_DATA_6 0x7D +#define REG_IND_DATA_5 0x7E +#define REG_IND_DATA_4 0x7F +#define REG_IND_DATA_3 0x80 +#define REG_IND_DATA_2 0x81 +#define REG_IND_DATA_1 0x82 +#define REG_IND_DATA_0 0x83 + +#define REG_IND_DATA_CHECK REG_IND_DATA_8 +#define REG_IND_MIB_CHECK REG_IND_DATA_3 +#define REG_IND_DATA_HI REG_IND_DATA_7 +#define REG_IND_DATA_LO REG_IND_DATA_3 + +#define REG_PORT_0_MAC_ADDR_0 0x8E +#define REG_PORT_0_MAC_ADDR_1 0x8F +#define REG_PORT_0_MAC_ADDR_2 0x90 +#define REG_PORT_0_MAC_ADDR_3 0x91 +#define REG_PORT_0_MAC_ADDR_4 0x92 +#define REG_PORT_0_MAC_ADDR_5 0x93 +#define REG_PORT_1_MAC_ADDR_0 0x94 +#define REG_PORT_1_MAC_ADDR_1 0x95 +#define REG_PORT_1_MAC_ADDR_2 0x96 +#define REG_PORT_1_MAC_ADDR_3 0x97 +#define REG_PORT_1_MAC_ADDR_4 0x98 +#define REG_PORT_1_MAC_ADDR_5 0x99 + +#define REG_PORT_1_OUT_RATE_0 0x9A +#define REG_PORT_2_OUT_RATE_0 0x9E +#define REG_PORT_3_OUT_RATE_0 0xA2 + +#define SWITCH_OUT_RATE_ENABLE BIT(7) + +#define REG_PORT_1_OUT_RATE_1 0x9B +#define REG_PORT_2_OUT_RATE_1 0x9F +#define REG_PORT_3_OUT_RATE_1 0xA3 +#define REG_PORT_1_OUT_RATE_2 0x9C +#define REG_PORT_2_OUT_RATE_2 0xA0 +#define REG_PORT_3_OUT_RATE_2 0xA4 +#define REG_PORT_1_OUT_RATE_3 0x9D +#define REG_PORT_2_OUT_RATE_3 0xA1 +#define REG_PORT_3_OUT_RATE_3 0xA5 + +#define REG_PORT_OUT_RATE_0 0x00 +#define REG_PORT_OUT_RATE_1 0x01 +#define REG_PORT_OUT_RATE_2 0x02 +#define REG_PORT_OUT_RATE_3 0x03 + +#define REG_MODE_INDICATOR 0xA6 + +#define MODE_2_MII BIT(7) +#define MODE_2_PHY BIT(6) +#define PORT_1_RMII BIT(5) +#define PORT_3_RMII BIT(4) +#define PORT_1_MAC_MII BIT(3) +#define PORT_3_MAC_MII BIT(2) +#define PORT_1_FIBER BIT(1) +#define PORT_2_FIBER BIT(0) + +#define MODE_MLL 0x03 +#define MODE_RLL 0x13 +#define MODE_FLL 0x01 + +#define REG_BUF_RESERVED_Q3 0xA7 +#define REG_BUF_RESERVED_Q2 0xA8 +#define REG_BUF_RESERVED_Q1 0xA9 +#define REG_BUF_RESERVED_Q0 0xAA +#define REG_PM_FLOW_CTRL_SELECT_1 0xAB +#define REG_PM_FLOW_CTRL_SELECT_2 0xAC +#define REG_PM_FLOW_CTRL_SELECT_3 0xAD +#define REG_PM_FLOW_CTRL_SELECT_4 0xAE + +#define REG_PORT1_TXQ3_RATE_CTRL 0xAF +#define REG_PORT1_TXQ2_RATE_CTRL 0xB0 +#define REG_PORT1_TXQ1_RATE_CTRL 0xB1 +#define REG_PORT1_TXQ0_RATE_CTRL 0xB2 +#define REG_PORT2_TXQ3_RATE_CTRL 0xB3 +#define REG_PORT2_TXQ2_RATE_CTRL 0xB4 +#define REG_PORT2_TXQ1_RATE_CTRL 0xB5 +#define REG_PORT2_TXQ0_RATE_CTRL 0xB6 +#define REG_PORT3_TXQ3_RATE_CTRL 0xB7 +#define REG_PORT3_TXQ2_RATE_CTRL 0xB8 +#define REG_PORT3_TXQ1_RATE_CTRL 0xB9 +#define REG_PORT3_TXQ0_RATE_CTRL 0xBA + +#define RATE_CTRL_ENABLE BIT(7) + +#define REG_INT_ENABLE 0xBB + +#define REG_INT_STATUS 0xBC + +#define INT_PORT_1_2_LINK_CHANGE BIT(7) +#define INT_PORT_3_LINK_CHANGE BIT(2) +#define INT_PORT_2_LINK_CHANGE BIT(1) +#define INT_PORT_1_LINK_CHANGE BIT(0) + +#define REG_PAUSE_ITERATION_LIMIT 0xBD + +#define REG_INSERT_SRC_PVID 0xC2 + +#define SWITCH_INS_TAG_1_PORT_2 BIT(5) +#define SWITCH_INS_TAG_1_PORT_3 BIT(4) +#define SWITCH_INS_TAG_2_PORT_1 BIT(3) +#define SWITCH_INS_TAG_2_PORT_3 BIT(2) +#define SWITCH_INS_TAG_3_PORT_1 BIT(1) +#define SWITCH_INS_TAG_3_PORT_2 BIT(0) + +#define REG_POWER_MANAGEMENT 0xC3 + +#define SWITCH_CPU_CLK_POWER_DOWN BIT(7) +#define SWITCH_CLK_POWER_DOWN BIT(6) +#define SWITCH_LED_SELECTION 0x30 +#define SWITCH_LED_LINK_ACT_SPEED 0x00 +#define SWITCH_LED_LINK_ACT 0x20 +#define SWITCH_LED_LINK_ACT_DUPLEX 0x10 +#define SWITCH_LED_LINK_DUPLEX 0x30 +#define SWITCH_LED_OUTPUT_MODE BIT(3) +#define SWITCH_PLL_POWER_DOWN BIT(2) +#define SWITCH_POWER_MANAGEMENT_MODE 0x03 +#define SWITCH_NORMAL 0x00 +#define SWITCH_ENERGY_DETECTION 0x01 +#define SWITCH_SOFTWARE_POWER_DOWN 0x02 +#define SWITCH_POWER_SAVING 0x03 + +#define REG_FORWARD_INVALID_VID 0xC6 + +#define SWITCH_FORWARD_INVALID_PORTS 0x70 +#define FORWARD_INVALID_PORT_SHIFT 4 +#define PORT_3_RMII_CLOCK_SELECTION BIT(3) +#define PORT_1_RMII_CLOCK_SELECTION BIT(2) +#define SWITCH_HOST_INTERFACE_MODE 0x03 +#define SWITCH_I2C_MASTER 0x00 +#define SWITCH_I2C_SLAVE 0x01 +#define SWITCH_SPI_SLAVE 0x02 +#define SWITCH_SMII 0x03 + +#define KSZ8863_ID_HI 0x0022 +#define KSZ8863_ID_LO 0x1430 + +#define PHY_REG_LINK_MD 29 + +#define PHY_START_CABLE_DIAG BIT(15) +#define PHY_CABLE_DIAG_RESULT 0x6000 +#define PHY_CABLE_STAT_NORMAL 0x0000 +#define PHY_CABLE_STAT_OPEN 0x2000 +#define PHY_CABLE_STAT_SHORT 0x4000 +#define PHY_CABLE_STAT_FAILED 0x6000 +#define PHY_CABLE_10M_SHORT BIT(12) +#define PHY_CABLE_FAULT_COUNTER 0x01FF + +#define PHY_REG_PHY_CTRL 30 + +#define PHY_STAT_REVERSED_POLARITY BIT(5) +#define PHY_STAT_MDIX BIT(4) +#define PHY_FORCE_LINK BIT(3) +#define PHY_POWER_SAVING_DISABLE BIT(2) +#define PHY_REMOTE_LOOPBACK BIT(1) + +/* Default values are used in ksz_sw.h if these are not defined. */ +#define PRIO_QUEUES 4 + +#define KS_PRIO_IN_REG 4 + +#define TOTAL_PORT_NUM 3 + +/* Host port can only be last of them. */ +#define SWITCH_PORT_NUM (TOTAL_PORT_NUM - 1) + +#define KSZ8863_COUNTER_NUM 0x20 +#define TOTAL_KSZ8863_COUNTER_NUM (KSZ8863_COUNTER_NUM + 2) + +#define SWITCH_COUNTER_NUM KSZ8863_COUNTER_NUM +#define TOTAL_SWITCH_COUNTER_NUM TOTAL_KSZ8863_COUNTER_NUM + +#define P_802_1P_CTRL REG_PORT_CTRL_2 +#define P_LOCAL_CTRL REG_PORT_CTRL_5 +#define P_REMOTE_STATUS REG_PORT_STATUS_1 +#define P_INS_SRC_PVID_CTRL REG_PORT_CTRL_8 +#define P_DROP_TAG_CTRL REG_PORT_CTRL_9 + +#define S_HUGE_PACKET_CTRL REG_SW_CTRL_2 +#define S_PASS_PAUSE_CTRL REG_SW_CTRL_10 +#define S_IPV6_MLD_CTRL REG_SW_CTRL_21 + +#define P_BCAST_STORM_CTRL REG_PORT_CTRL_0 +#define P_PRIO_CTRL REG_PORT_CTRL_0 +#define P_TAG_CTRL REG_PORT_CTRL_0 +#define P_MIRROR_CTRL REG_PORT_CTRL_1 +#define P_STP_CTRL REG_PORT_CTRL_2 +#define P_PHY_CTRL REG_PORT_CTRL_12 +#define P_FORCE_CTRL REG_PORT_CTRL_12 +#define P_NEG_RESTART_CTRL REG_PORT_CTRL_13 +#define P_LINK_STATUS REG_PORT_STATUS_0 +#define P_SPEED_STATUS REG_PORT_STATUS_1 +#define P_RATE_LIMIT_CTRL REG_PORT_CTRL_5 +#define P_SA_MAC_CTRL REG_PORT_CTRL_5 +#define P_4_QUEUE_CTRL REG_PORT_CTRL_0 +#define P_2_QUEUE_CTRL REG_PORT_CTRL_2 + +#define S_LINK_AGING_CTRL REG_SWITCH_CTRL_0 +#define S_MIRROR_CTRL REG_SWITCH_CTRL_3 +#define S_REPLACE_VID_CTRL REG_SWITCH_CTRL_4 +#define S_802_1P_PRIO_CTRL REG_SWITCH_CTRL_10 +#define S_UNKNOWN_DA_CTRL REG_SWITCH_CTRL_12 +#define S_TOS_PRIO_CTRL REG_TOS_PRIO_CTRL_0 +#define S_FLUSH_TABLE_CTRL REG_SWITCH_CTRL_0 +#define S_TAIL_TAG_CTRL REG_SWITCH_CTRL_1 +#define S_FORWARD_INVALID_VID_CTRL REG_FORWARD_INVALID_VID +#define S_INS_SRC_PVID_CTRL REG_INSERT_SRC_PVID + +#define IND_ACC_TABLE(table) ((table) << 8) + +/* Driver set switch broadcast storm protection at 10% rate. */ +#define BROADCAST_STORM_PROT_RATE 10 + +/* 148,800 frames * 67 ms / 100 */ +#define BROADCAST_STORM_VALUE 9969 + +#define STATIC_MAC_TABLE_ADDR 0x0000FFFF +#define STATIC_MAC_TABLE_FWD_PORTS 0x001F0000 +#define STATIC_MAC_TABLE_VALID 0x00200000 +#define STATIC_MAC_TABLE_OVERRIDE 0x00400000 +#define STATIC_MAC_TABLE_USE_FID 0x00800000 +#define STATIC_MAC_TABLE_FID 0x7F000000 + +#define STATIC_MAC_FWD_PORTS_S 16 +#define STATIC_MAC_FID_S 24 + +#define VLAN_TABLE_FID 0x007F +#define VLAN_TABLE_MEMBERSHIP 0x0F80 +#define VLAN_TABLE_VALID 0x1000 + +#define VLAN_TABLE_MEMBERSHIP_S 7 +#define VLAN_TABLE_S 13 +#define VLAN_TABLE_M (BIT(VLAN_TABLE_S) - 1) + +#define DYNAMIC_MAC_TABLE_ADDR 0x0000FFFF +#define DYNAMIC_MAC_TABLE_FID 0x007F0000 +#define DYNAMIC_MAC_TABLE_SRC_PORT 0x07000000 +#define DYNAMIC_MAC_TABLE_TIMESTAMP 0x18000000 +#define DYNAMIC_MAC_TABLE_ENTRIES 0xE0000000 + +#define DYNAMIC_MAC_TABLE_NOT_READY 0x80 + +#define DYNAMIC_MAC_TABLE_ENTRIES_H 0x7F +#define DYNAMIC_MAC_TABLE_MAC_EMPTY 0x80 + +#define DYNAMIC_MAC_FID_S 16 +#define DYNAMIC_MAC_SRC_PORT_S 24 +#define DYNAMIC_MAC_TIMESTAMP_S 27 +#define DYNAMIC_MAC_ENTRIES_S 29 +#define DYNAMIC_MAC_ENTRIES_H_S 3 + +#define MIB_COUNTER_OVERFLOW BIT(7) +#define MIB_COUNTER_VALID BIT(6) + +#define MIB_COUNTER_VALUE 0x3FFFFFFF + +#define KS_MIB_PACKET_DROPPED_TX_0 0x100 +#define KS_MIB_PACKET_DROPPED_TX_1 0x101 +#define KS_MIB_PACKET_DROPPED_TX_2 0x102 +#define KS_MIB_PACKET_DROPPED_TX_3 0x103 +#define KS_MIB_PACKET_DROPPED_TX_4 0x104 +#define KS_MIB_PACKET_DROPPED_RX_0 0x105 +#define KS_MIB_PACKET_DROPPED_RX_1 0x106 +#define KS_MIB_PACKET_DROPPED_RX_2 0x107 +#define KS_MIB_PACKET_DROPPED_RX_3 0x108 +#define KS_MIB_PACKET_DROPPED_RX_4 0x109 + +#define MIB_PACKET_DROPPED 0x0000FFFF + +#define TAIL_TAG_OVERRIDE BIT(6) +#define TAIL_TAG_LOOKUP BIT(7) + +#define VLAN_TABLE_ENTRIES (16 / 2) +#define FID_ENTRIES 16 + +#endif diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c new file mode 100644 index 0000000000000..742955c85d859 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8863 series register access through SMI + * + * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de> + */ + +#include "ksz_common.h" + +static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len, + void *val_buf, size_t val_len) +{ + struct ksz_device *dev = (struct ksz_device *)ctx; + struct mdio_device *mdev = (struct mdio_device *)dev->priv; + u8 reg = *(u8 *)reg_buf; + u8 *val = val_buf; + int ret; + int i; + + for (i = 0; i < val_len; i++) { + ret = mdiobus_read(mdev->bus, 0, (reg + i) | + MII_ADDR_SMI_KSZ88X3); + if (ret < 0) + return ret; + + val[i] = ret; + } + + return 0; +} + +static int ksz8863_mdio_write(void *ctx, const void *data, size_t count) +{ + struct ksz_device *dev = (struct ksz_device *)ctx; + struct mdio_device *mdev = (struct mdio_device *)dev->priv; + u32 reg = *(u32 *)data; + u8 *val = (u8 *)(data + 4); + int ret; + int i; + + for (i = 0; i < (count - 4); i++) { + ret = mdiobus_write(mdev->bus, 0, (reg + i) | + MII_ADDR_SMI_KSZ88X3, val[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct regmap_bus regmap_smi[] = { + { + .read = ksz8863_mdio_read, + .write = ksz8863_mdio_write, + .max_raw_read = 1, + .max_raw_write = 1, + }, + { + .read = ksz8863_mdio_read, + .write = ksz8863_mdio_write, + .val_format_endian_default = REGMAP_ENDIAN_BIG, + .max_raw_read = 2, + .max_raw_write = 2, + }, + { + .read = ksz8863_mdio_read, + .write = ksz8863_mdio_write, + .val_format_endian_default = REGMAP_ENDIAN_BIG, + .max_raw_read = 4, + .max_raw_write = 4, + } +}; + +static const struct regmap_config ksz8863_regmap_config[] = { + { + .name = "#8", + .reg_bits = 8, + .pad_bits = 24, + .val_bits = 8, + .cache_type = REGCACHE_NONE, + .use_single_read = 1, + }, + { + .name = "#16", + .reg_bits = 8, + .pad_bits = 24, + .val_bits = 16, + .cache_type = REGCACHE_NONE, + .use_single_read = 1, + }, + { + .name = "#32", + .reg_bits = 8, + .pad_bits = 24, + .val_bits = 32, + .cache_type = REGCACHE_NONE, + .use_single_read = 1, + } +}; + +static int ksz8863_smi_probe(struct mdio_device *mdiodev) +{ + struct ksz_device *dev; + int ret; + int i; + + dev = ksz_switch_alloc(&mdiodev->dev, mdiodev); + if (!dev) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ksz8863_regmap_config); i++) { + dev->regmap[i] = devm_regmap_init(&mdiodev->dev, + ®map_smi[i], dev, + &ksz8863_regmap_config[i]); + if (IS_ERR(dev->regmap[i])) { + ret = PTR_ERR(dev->regmap[i]); + dev_err(&mdiodev->dev, + "Failed to initialize regmap%i: %d\n", + ksz8863_regmap_config[i].val_bits, ret); + return ret; + } + } + + if (mdiodev->dev.platform_data) + dev->pdata = mdiodev->dev.platform_data; + + ret = ksz8863_switch_register(dev); + + /* Main DSA driver may not be started yet. */ + if (ret) + return ret; + + dev_set_drvdata(&mdiodev->dev, dev); + + return 0; +} + +static void ksz8863_smi_remove(struct mdio_device *mdiodev) +{ + struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev); + + if (dev) + ksz_switch_remove(dev); +} + +static const struct of_device_id ksz8863_dt_ids[] = { + { .compatible = "microchip,ksz8863" }, + { .compatible = "microchip,ksz8873" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ksz8863_dt_ids); + +static struct mdio_driver ksz8863_driver = { + .probe = ksz8863_smi_probe, + .remove = ksz8863_smi_remove, + .mdiodrv.driver = { + .name = "ksz8863-switch", + .of_match_table = ksz8863_dt_ids, + }, +}; + +mdio_module_driver(ksz8863_driver); + +MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); +MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index a20ebb749377c..dd2bd645a3125 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -151,6 +151,7 @@ int ksz_switch_register(struct ksz_device *dev, void ksz_switch_remove(struct ksz_device *dev); int ksz8795_switch_register(struct ksz_device *dev); +int ksz8863_switch_register(struct ksz_device *dev); int ksz9477_switch_register(struct ksz_device *dev); void ksz_update_port_member(struct ksz_device *dev, int port); -- 2.24.0.rc1 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver 2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik @ 2019-11-07 15:56 ` Andrew Lunn 2019-11-09 8:08 ` kbuild test robot 1 sibling, 0 replies; 20+ messages in thread From: Andrew Lunn @ 2019-11-07 15:56 UTC (permalink / raw) To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel > +static const u8 stp_multicast_addr[] = { > + 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 > +}; This probably exists already. Please go looking in include/linux and include/net. > +static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len, > + void *val_buf, size_t val_len) > +{ > + struct ksz_device *dev = (struct ksz_device *)ctx; ctx is a void *, so you don't need the cast. > + struct mdio_device *mdev = (struct mdio_device *)dev->priv; and priv is also probably a void *. And please fix the reverse christmas tree. Thanks Andrew ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver 2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik 2019-11-07 15:56 ` Andrew Lunn @ 2019-11-09 8:08 ` kbuild test robot 1 sibling, 0 replies; 20+ messages in thread From: kbuild test robot @ 2019-11-09 8:08 UTC (permalink / raw) To: Michael Grzeschik; +Cc: kbuild-all, netdev, Tristram.Ha, UNGLinuxDriver, kernel Hi Michael, I love your patch! Perhaps something to improve: [auto build test WARNING on net/master] [also build test WARNING on v5.4-rc6 next-20191108] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Michael-Grzeschik/microchip-add-support-for-ksz88x3-driver-family/20191109-122140 base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git a2582cdc32f071422e0197a6c59bd1235b426ce2 reproduce: # apt-get install sparse # sparse version: v0.6.1-21-gb31adac-dirty make ARCH=x86_64 allmodconfig make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' If you fix the issue, kindly add following tag Reported-by: kbuild test robot <lkp@intel.com> sparse warnings: (new ones prefixed by >>) >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64 >> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned long long [usertype] data @@ got nsigned long long [usertype] data @@ >> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse: expected unsigned long long [usertype] data >> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse: got restricted __be64 [usertype] drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64 vim +184 drivers/net/dsa/microchip/ksz8863.c 172 173 static void ksz8863_r_table(struct ksz_device *dev, int table, u16 addr, 174 u64 *data) 175 { 176 u16 ctrl_addr; 177 178 ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr; 179 180 mutex_lock(&dev->alu_mutex); 181 ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); 182 ksz_read64(dev, REG_IND_DATA_HI, data); 183 mutex_unlock(&dev->alu_mutex); > 184 *data = be64_to_cpu(*data); 185 } 186 187 static void ksz8863_w_table(struct ksz_device *dev, int table, u16 addr, 188 u64 data) 189 { 190 u16 ctrl_addr; 191 192 ctrl_addr = IND_ACC_TABLE(table) | addr; > 193 data = cpu_to_be64(data); 194 195 mutex_lock(&dev->alu_mutex); 196 ksz_write64(dev, REG_IND_DATA_HI, data); 197 ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); 198 mutex_unlock(&dev->alu_mutex); 199 } 200 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik ` (2 preceding siblings ...) 2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik @ 2019-11-07 11:00 ` Michael Grzeschik 2019-11-13 13:34 ` Rob Herring 2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik 4 siblings, 1 reply; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw) To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel, devicetree It is a 3-Port 10/100 Ethernet Switch. One CPU-Port and two Switch-Ports. Cc: devicetree@vger.kernel.org Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> --- Documentation/devicetree/bindings/net/dsa/ksz.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 95e91e84151c3..a5d71862f53cb 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -8,6 +8,8 @@ Required properties: - "microchip,ksz8765" - "microchip,ksz8794" - "microchip,ksz8795" + - "microchip,ksz8863" + - "microchip,ksz8873" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" -- 2.24.0.rc1 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch 2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik @ 2019-11-13 13:34 ` Rob Herring 0 siblings, 0 replies; 20+ messages in thread From: Rob Herring @ 2019-11-13 13:34 UTC (permalink / raw) To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel, devicetree On Thu, 7 Nov 2019 12:00:30 +0100, Michael Grzeschik wrote: > It is a 3-Port 10/100 Ethernet Switch. One CPU-Port and two > Switch-Ports. > > Cc: devicetree@vger.kernel.org > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> > --- > Documentation/devicetree/bindings/net/dsa/ksz.txt | 2 ++ > 1 file changed, 2 insertions(+) > Acked-by: Rob Herring <robh@kernel.org> ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 0/4] microchip: add support for ksz88x3 driver family 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik ` (3 preceding siblings ...) 2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik @ 2019-11-07 15:36 ` Michael Grzeschik 4 siblings, 0 replies; 20+ messages in thread From: Michael Grzeschik @ 2019-11-07 15:36 UTC (permalink / raw) To: netdev; +Cc: UNGLinuxDriver, kernel, Tristram.Ha [-- Attachment #1: Type: text/plain, Size: 2275 bytes --] On Thu, Nov 07, 2019 at 12:00:26PM +0100, Michael Grzeschik wrote: > This series adds support for the ksz88x3 driver family to the > dsa based ksz drivers. For now the ksz8863 and ksz8873 are compatible. > > The driver is based on the ksz8895 RFC patch from Tristam Ha: > > https://patchwork.ozlabs.org/patch/822712/ > > And the latest version of the ksz8863.h from Microchip: > > https://raw.githubusercontent.com/Microchip-Ethernet/UNG8071_old_1.10/master/KSZ/linux-drivers/ksz8863/linux-3.14/drivers/net/ethernet/micrel/ksz8863.h After reviewing the code with my colleague, we found out this core is not very different to the already mainlined ksz8795. So it will be easier to port the ksz8863 specific changes into that driver. I will give it a try. > Michael Grzeschik (4): > mdio-bitbang: add SMI0 mode support > net: tag: ksz: Add KSZ8863 tag code > ksz: Add Microchip KSZ8863 SMI-DSA driver > dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 > switch > > .../devicetree/bindings/net/dsa/ksz.txt | 2 + > drivers/net/dsa/microchip/Kconfig | 16 + > drivers/net/dsa/microchip/Makefile | 2 + > drivers/net/dsa/microchip/ksz8863.c | 1038 +++++++++++++++++ > drivers/net/dsa/microchip/ksz8863_reg.h | 605 ++++++++++ > drivers/net/dsa/microchip/ksz8863_smi.c | 166 +++ > drivers/net/dsa/microchip/ksz_common.h | 1 + > drivers/net/phy/mdio-bitbang.c | 21 + > include/linux/phy.h | 2 + > include/net/dsa.h | 2 + > net/dsa/tag_ksz.c | 60 + > 11 files changed, 1915 insertions(+) > create mode 100644 drivers/net/dsa/microchip/ksz8863.c > create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h > create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c > > -- > 2.24.0.rc1 > > > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2020-04-21 14:32 UTC | newest] Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik 2019-11-07 15:42 ` Andrew Lunn 2019-12-18 16:29 ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik 2019-12-19 20:39 ` Andrew Lunn 2019-12-19 22:01 ` Michael Grzeschik 2019-12-19 22:05 ` Florian Fainelli 2019-12-21 16:41 ` Andrew Lunn 2020-01-29 15:42 ` Michael Grzeschik 2020-01-29 15:53 ` Andrew Lunn 2020-01-29 21:48 ` Michael Grzeschik 2020-04-21 14:31 ` Michael Grzeschik 2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik 2019-11-07 15:44 ` Andrew Lunn 2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik 2019-11-07 15:56 ` Andrew Lunn 2019-11-09 8:08 ` kbuild test robot 2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik 2019-11-13 13:34 ` Rob Herring 2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).