Commit 7fcb820c authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-microchip-common-spi-probe'

Arun Ramadoss says:

====================
net: dsa: microchip: common spi probe for the ksz series switches - part 2

This patch series aims to refactor the ksz_switch_register routine to have the
common flow for the ksz series switch. And this is the follow up patch series.

First, it tries moves the common implementation in the setup from individual
files to ksz_setup. Then implements the common dsa_switch_ops structure instead
of independent registration. And then moves the ksz_dev_ops to ksz_common.c,
it allows the dynamic detection of which ksz_dev_ops to be used based on
the switch detection function.

Finally, the patch updates the ksz_spi probe function to be same for all the
ksz_switches.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5d99ec3a 4658f2fe
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
config NET_DSA_MICROCHIP_KSZ_COMMON menuconfig NET_DSA_MICROCHIP_KSZ_COMMON
select NET_DSA_TAG_KSZ tristate "Microchip KSZ8795/KSZ9477 series switch support"
tristate
menuconfig NET_DSA_MICROCHIP_KSZ9477
tristate "Microchip KSZ9477 series switch support"
depends on NET_DSA depends on NET_DSA
select NET_DSA_MICROCHIP_KSZ_COMMON select NET_DSA_TAG_KSZ
help help
This driver adds support for Microchip KSZ9477 switch chips. This driver adds support for Microchip KSZ9477 series switch and
KSZ8795/KSZ88x3 switch chips.
config NET_DSA_MICROCHIP_KSZ9477_I2C config NET_DSA_MICROCHIP_KSZ9477_I2C
tristate "KSZ9477 series I2C connected switch driver" tristate "KSZ series I2C connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ9477 && I2C depends on NET_DSA_MICROCHIP_KSZ_COMMON && I2C
select REGMAP_I2C select REGMAP_I2C
help help
Select to enable support for registering switches configured through I2C. Select to enable support for registering switches configured through I2C.
config NET_DSA_MICROCHIP_KSZ9477_SPI config NET_DSA_MICROCHIP_KSZ_SPI
tristate "KSZ9477 series SPI connected switch driver" tristate "KSZ series SPI connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ9477 && SPI depends on NET_DSA_MICROCHIP_KSZ_COMMON && SPI
select REGMAP_SPI select REGMAP_SPI
help help
Select to enable support for registering switches configured through SPI. Select to enable support for registering switches configured through SPI.
menuconfig NET_DSA_MICROCHIP_KSZ8795
tristate "Microchip KSZ8795 series switch support"
depends on NET_DSA
select NET_DSA_MICROCHIP_KSZ_COMMON
help
This driver adds support for Microchip KSZ8795/KSZ88X3 switch chips.
config NET_DSA_MICROCHIP_KSZ8795_SPI
tristate "KSZ8795 series SPI connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ8795 && SPI
select REGMAP_SPI
help
This driver accesses KSZ8795 chip through SPI.
It is required to use the KSZ8795 switch driver as the only access
is through SPI.
config NET_DSA_MICROCHIP_KSZ8863_SMI config NET_DSA_MICROCHIP_KSZ8863_SMI
tristate "KSZ series SMI connected switch driver" tristate "KSZ series SMI connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ8795 depends on NET_DSA_MICROCHIP_KSZ_COMMON
select MDIO_BITBANG select MDIO_BITBANG
help help
Select to enable support for registering switches configured through Select to enable support for registering switches configured through
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_common.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_switch.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477) += ksz9477.o ksz_switch-objs := ksz_common.o
ksz_switch-objs += ksz9477.o
ksz_switch-objs += ksz8795.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o 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_KSZ_SPI) += ksz_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_SMI) += ksz8863_smi.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#define __KSZ8XXX_H #define __KSZ8XXX_H
#include <linux/types.h> #include <linux/types.h>
#include <net/dsa.h>
#include "ksz_common.h"
enum ksz_regs { enum ksz_regs {
REG_IND_CTRL_0, REG_IND_CTRL_0,
...@@ -68,4 +70,50 @@ struct ksz8 { ...@@ -68,4 +70,50 @@ struct ksz8 {
void *priv; void *priv;
}; };
int ksz8_setup(struct dsa_switch *ds);
u32 ksz8_get_port_addr(int port, int offset);
void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member);
void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port);
void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries);
int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
struct alu_struct *alu);
void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
struct alu_struct *alu);
void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);
void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt);
void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze);
void ksz8_port_init_cnt(struct ksz_device *dev, int port);
int ksz8_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int ksz8_mdb_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz8_mdb_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
struct netlink_ext_ack *extack);
int ksz8_port_vlan_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack);
int ksz8_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan);
int ksz8_port_mirror_add(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack);
void ksz8_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror);
int ksz8_get_stp_reg(void);
void ksz8_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
void ksz8_config_cpu_port(struct dsa_switch *ds);
int ksz8_enable_stp_addr(struct ksz_device *dev);
int ksz8_reset_switch(struct ksz_device *dev);
int ksz8_switch_detect(struct ksz_device *dev);
int ksz8_switch_init(struct ksz_device *dev);
void ksz8_switch_exit(struct ksz_device *dev);
#endif #endif
...@@ -162,7 +162,7 @@ static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data) ...@@ -162,7 +162,7 @@ static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
return ret; return ret;
} }
static int ksz8_reset_switch(struct ksz_device *dev) int ksz8_reset_switch(struct ksz_device *dev)
{ {
if (ksz_is_ksz88x3(dev)) { if (ksz_is_ksz88x3(dev)) {
/* reset switch */ /* reset switch */
...@@ -213,7 +213,7 @@ static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) ...@@ -213,7 +213,7 @@ static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue)
true); true);
} }
static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
const u32 *masks; const u32 *masks;
...@@ -334,8 +334,8 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, ...@@ -334,8 +334,8 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
} }
} }
static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt) u64 *dropped, u64 *cnt)
{ {
if (ksz_is_ksz88x3(dev)) if (ksz_is_ksz88x3(dev))
ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt); ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
...@@ -343,7 +343,7 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, ...@@ -343,7 +343,7 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt); ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
} }
static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
{ {
if (ksz_is_ksz88x3(dev)) if (ksz_is_ksz88x3(dev))
return; return;
...@@ -358,7 +358,7 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) ...@@ -358,7 +358,7 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
} }
static void ksz8_port_init_cnt(struct ksz_device *dev, int port) void ksz8_port_init_cnt(struct ksz_device *dev, int port)
{ {
struct ksz_port_mib *mib = &dev->ports[port].mib; struct ksz_port_mib *mib = &dev->ports[port].mib;
u64 *dropped; u64 *dropped;
...@@ -447,9 +447,8 @@ static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data) ...@@ -447,9 +447,8 @@ static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
return 0; return 0;
} }
static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
u8 *mac_addr, u8 *fid, u8 *src_port, u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries)
u8 *timestamp, u16 *entries)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo; u32 data_hi, data_lo;
...@@ -512,8 +511,8 @@ static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, ...@@ -512,8 +511,8 @@ static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
return rc; return rc;
} }
static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
struct alu_struct *alu) struct alu_struct *alu)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo; u32 data_hi, data_lo;
...@@ -551,8 +550,8 @@ static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, ...@@ -551,8 +550,8 @@ static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
return -ENXIO; return -ENXIO;
} }
static void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr, void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
struct alu_struct *alu) struct alu_struct *alu)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo; u32 data_hi, data_lo;
...@@ -663,7 +662,7 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) ...@@ -663,7 +662,7 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
ksz8_w_table(dev, TABLE_VLAN, addr, buf); ksz8_w_table(dev, TABLE_VLAN, addr, buf);
} }
static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
u8 restart, speed, ctrl, link; u8 restart, speed, ctrl, link;
...@@ -786,7 +785,7 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -786,7 +785,7 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
*val = data; *val = data;
} }
static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
u8 restart, speed, ctrl, data; u8 restart, speed, ctrl, data;
...@@ -898,7 +897,7 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -898,7 +897,7 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
} }
} }
static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
{ {
u8 data; u8 data;
...@@ -908,7 +907,7 @@ static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) ...@@ -908,7 +907,7 @@ static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
ksz_pwrite8(dev, port, P_MIRROR_CTRL, data); ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
} }
static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
{ {
u8 learn[DSA_MAX_PORTS]; u8 learn[DSA_MAX_PORTS];
int first, index, cnt; int first, index, cnt;
...@@ -941,8 +940,8 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) ...@@ -941,8 +940,8 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
} }
} }
static int ksz8_fdb_dump(struct ksz_device *dev, int port, int ksz8_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data) dsa_fdb_dump_cb_t *cb, void *data)
{ {
int ret = 0; int ret = 0;
u16 i = 0; u16 i = 0;
...@@ -969,9 +968,8 @@ static int ksz8_fdb_dump(struct ksz_device *dev, int port, ...@@ -969,9 +968,8 @@ static int ksz8_fdb_dump(struct ksz_device *dev, int port,
return ret; return ret;
} }
static int ksz8_mdb_add(struct ksz_device *dev, int port, int ksz8_mdb_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
struct dsa_db db)
{ {
struct alu_struct alu; struct alu_struct alu;
int index; int index;
...@@ -1013,9 +1011,8 @@ static int ksz8_mdb_add(struct ksz_device *dev, int port, ...@@ -1013,9 +1011,8 @@ static int ksz8_mdb_add(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz8_mdb_del(struct ksz_device *dev, int port, int ksz8_mdb_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
struct dsa_db db)
{ {
struct alu_struct alu; struct alu_struct alu;
int index; int index;
...@@ -1043,8 +1040,8 @@ static int ksz8_mdb_del(struct ksz_device *dev, int port, ...@@ -1043,8 +1040,8 @@ static int ksz8_mdb_del(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag, int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
if (ksz_is_ksz88x3(dev)) if (ksz_is_ksz88x3(dev))
return -ENOTSUPP; return -ENOTSUPP;
...@@ -1070,9 +1067,9 @@ static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state) ...@@ -1070,9 +1067,9 @@ static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state)
} }
} }
static int ksz8_port_vlan_add(struct ksz_device *dev, int port, int ksz8_port_vlan_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan, const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
struct ksz_port *p = &dev->ports[port]; struct ksz_port *p = &dev->ports[port];
...@@ -1142,8 +1139,8 @@ static int ksz8_port_vlan_add(struct ksz_device *dev, int port, ...@@ -1142,8 +1139,8 @@ static int ksz8_port_vlan_add(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz8_port_vlan_del(struct ksz_device *dev, int port, int ksz8_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan)
{ {
u16 data, pvid; u16 data, pvid;
u8 fid, member, valid; u8 fid, member, valid;
...@@ -1174,9 +1171,9 @@ static int ksz8_port_vlan_del(struct ksz_device *dev, int port, ...@@ -1174,9 +1171,9 @@ static int ksz8_port_vlan_del(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz8_port_mirror_add(struct ksz_device *dev, int port, int ksz8_port_mirror_add(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror, struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack) bool ingress, struct netlink_ext_ack *extack)
{ {
if (ingress) { if (ingress) {
ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
...@@ -1196,8 +1193,8 @@ static int ksz8_port_mirror_add(struct ksz_device *dev, int port, ...@@ -1196,8 +1193,8 @@ static int ksz8_port_mirror_add(struct ksz_device *dev, int port,
return 0; return 0;
} }
static void ksz8_port_mirror_del(struct ksz_device *dev, int port, void ksz8_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror) struct dsa_mall_mirror_tc_entry *mirror)
{ {
u8 data; u8 data;
...@@ -1264,7 +1261,7 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port) ...@@ -1264,7 +1261,7 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
p->phydev.duplex = 1; p->phydev.duplex = 1;
} }
static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{ {
struct dsa_switch *ds = dev->ds; struct dsa_switch *ds = dev->ds;
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
...@@ -1301,7 +1298,7 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1301,7 +1298,7 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz8_cfg_port_member(dev, port, member); ksz8_cfg_port_member(dev, port, member);
} }
static void ksz8_config_cpu_port(struct dsa_switch *ds) void ksz8_config_cpu_port(struct dsa_switch *ds)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
...@@ -1368,22 +1365,26 @@ static int ksz8_handle_global_errata(struct dsa_switch *ds) ...@@ -1368,22 +1365,26 @@ static int ksz8_handle_global_errata(struct dsa_switch *ds)
return ret; return ret;
} }
static int ksz8_setup(struct dsa_switch *ds) int ksz8_enable_stp_addr(struct ksz_device *dev)
{ {
struct ksz_device *dev = ds->priv;
struct alu_struct alu; struct alu_struct alu;
int i, ret = 0;
dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), /* Setup STP address for STP operation. */
dev->info->num_vlans, GFP_KERNEL); memset(&alu, 0, sizeof(alu));
if (!dev->vlan_cache) ether_addr_copy(alu.mac, eth_stp_addr);
return -ENOMEM; alu.is_static = true;
alu.is_override = true;
alu.port_forward = dev->info->cpu_ports;
ret = ksz8_reset_switch(dev); ksz8_w_sta_mac_table(dev, 0, &alu);
if (ret) {
dev_err(ds->dev, "failed to reset switch\n"); return 0;
return ret; }
}
int ksz8_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
int i;
ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true);
...@@ -1402,10 +1403,6 @@ static int ksz8_setup(struct dsa_switch *ds) ...@@ -1402,10 +1403,6 @@ static int ksz8_setup(struct dsa_switch *ds)
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP, UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP); UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
ksz8_config_cpu_port(ds);
ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false); ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false);
ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
...@@ -1413,33 +1410,14 @@ static int ksz8_setup(struct dsa_switch *ds) ...@@ -1413,33 +1410,14 @@ static int ksz8_setup(struct dsa_switch *ds)
if (!ksz_is_ksz88x3(dev)) if (!ksz_is_ksz88x3(dev))
ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true); ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
/* set broadcast storm protection 10% rate */
regmap_update_bits(dev->regmap[1], S_REPLACE_VID_CTRL,
BROADCAST_STORM_RATE,
(BROADCAST_STORM_VALUE *
BROADCAST_STORM_PROT_RATE) / 100);
for (i = 0; i < (dev->info->num_vlans / 4); i++) for (i = 0; i < (dev->info->num_vlans / 4); i++)
ksz8_r_vlan_entries(dev, i); ksz8_r_vlan_entries(dev, i);
/* Setup STP address for STP operation. */
memset(&alu, 0, sizeof(alu));
ether_addr_copy(alu.mac, eth_stp_addr);
alu.is_static = true;
alu.is_override = true;
alu.port_forward = dev->info->cpu_ports;
ksz8_w_sta_mac_table(dev, 0, &alu);
ksz_init_mib_timer(dev);
ds->configure_vlan_while_not_filtering = false;
return ksz8_handle_global_errata(ds); return ksz8_handle_global_errata(ds);
} }
static void ksz8_get_caps(struct ksz_device *dev, int port, void ksz8_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config) struct phylink_config *config)
{ {
config->mac_capabilities = MAC_10 | MAC_100; config->mac_capabilities = MAC_10 | MAC_100;
...@@ -1456,43 +1434,15 @@ static void ksz8_get_caps(struct ksz_device *dev, int port, ...@@ -1456,43 +1434,15 @@ static void ksz8_get_caps(struct ksz_device *dev, int port,
config->mac_capabilities |= MAC_ASYM_PAUSE; config->mac_capabilities |= MAC_ASYM_PAUSE;
} }
static const struct dsa_switch_ops ksz8_switch_ops = { u32 ksz8_get_port_addr(int port, int offset)
.get_tag_protocol = ksz_get_tag_protocol,
.get_phy_flags = ksz_get_phy_flags,
.setup = ksz8_setup,
.phy_read = ksz_phy_read16,
.phy_write = ksz_phy_write16,
.phylink_get_caps = ksz_phylink_get_caps,
.phylink_mac_link_down = ksz_mac_link_down,
.port_enable = ksz_enable_port,
.get_strings = ksz_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 = ksz_port_stp_state_set,
.port_fast_age = ksz_port_fast_age,
.port_vlan_filtering = ksz_port_vlan_filtering,
.port_vlan_add = ksz_port_vlan_add,
.port_vlan_del = ksz_port_vlan_del,
.port_fdb_dump = ksz_port_fdb_dump,
.port_mdb_add = ksz_port_mdb_add,
.port_mdb_del = ksz_port_mdb_del,
.port_mirror_add = ksz_port_mirror_add,
.port_mirror_del = ksz_port_mirror_del,
};
static u32 ksz8_get_port_addr(int port, int offset)
{ {
return PORT_CTRL_ADDR(port, offset); return PORT_CTRL_ADDR(port, offset);
} }
static int ksz8_switch_init(struct ksz_device *dev) int ksz8_switch_init(struct ksz_device *dev)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
dev->ds->ops = &ksz8_switch_ops;
dev->cpu_port = fls(dev->info->cpu_ports) - 1; dev->cpu_port = fls(dev->info->cpu_ports) - 1;
dev->phy_port_cnt = dev->info->port_cnt - 1; dev->phy_port_cnt = dev->info->port_cnt - 1;
dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports; dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports;
...@@ -1520,42 +1470,11 @@ static int ksz8_switch_init(struct ksz_device *dev) ...@@ -1520,42 +1470,11 @@ static int ksz8_switch_init(struct ksz_device *dev)
return 0; return 0;
} }
static void ksz8_switch_exit(struct ksz_device *dev) void ksz8_switch_exit(struct ksz_device *dev)
{ {
ksz8_reset_switch(dev); ksz8_reset_switch(dev);
} }
static const struct ksz_dev_ops ksz8_dev_ops = {
.get_port_addr = ksz8_get_port_addr,
.cfg_port_member = ksz8_cfg_port_member,
.flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
.port_setup = ksz8_port_setup,
.r_phy = ksz8_r_phy,
.w_phy = ksz8_w_phy,
.r_mib_cnt = ksz8_r_mib_cnt,
.r_mib_pkt = ksz8_r_mib_pkt,
.freeze_mib = ksz8_freeze_mib,
.port_init_cnt = ksz8_port_init_cnt,
.fdb_dump = ksz8_fdb_dump,
.mdb_add = ksz8_mdb_add,
.mdb_del = ksz8_mdb_del,
.vlan_filtering = ksz8_port_vlan_filtering,
.vlan_add = ksz8_port_vlan_add,
.vlan_del = ksz8_port_vlan_del,
.mirror_add = ksz8_port_mirror_add,
.mirror_del = ksz8_port_mirror_del,
.get_caps = ksz8_get_caps,
.shutdown = ksz8_reset_switch,
.init = ksz8_switch_init,
.exit = ksz8_switch_exit,
};
int ksz8_switch_register(struct ksz_device *dev)
{
return ksz_switch_register(dev, &ksz8_dev_ops);
}
EXPORT_SYMBOL(ksz8_switch_register);
MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver"); MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#define SW_REVISION_M 0x0E #define SW_REVISION_M 0x0E
#define SW_REVISION_S 1 #define SW_REVISION_S 1
#define SW_START 0x01
#define KSZ8863_REG_SW_RESET 0x43 #define KSZ8863_REG_SW_RESET 0x43
...@@ -44,7 +43,6 @@ ...@@ -44,7 +43,6 @@
#define REG_SW_CTRL_2 0x04 #define REG_SW_CTRL_2 0x04
#define UNICAST_VLAN_BOUNDARY BIT(7) #define UNICAST_VLAN_BOUNDARY BIT(7)
#define MULTICAST_STORM_DISABLE BIT(6)
#define SW_BACK_PRESSURE BIT(5) #define SW_BACK_PRESSURE BIT(5)
#define FAIR_FLOW_CTRL BIT(4) #define FAIR_FLOW_CTRL BIT(4)
#define NO_EXC_COLLISION_DROP BIT(3) #define NO_EXC_COLLISION_DROP BIT(3)
...@@ -64,13 +62,9 @@ ...@@ -64,13 +62,9 @@
#define SW_FLOW_CTRL BIT(5) #define SW_FLOW_CTRL BIT(5)
#define SW_10_MBIT BIT(4) #define SW_10_MBIT BIT(4)
#define SW_REPLACE_VID BIT(3) #define SW_REPLACE_VID BIT(3)
#define BROADCAST_STORM_RATE_HI 0x07
#define REG_SW_CTRL_5 0x07 #define REG_SW_CTRL_5 0x07
#define BROADCAST_STORM_RATE_LO 0xFF
#define BROADCAST_STORM_RATE 0x07FF
#define REG_SW_CTRL_6 0x08 #define REG_SW_CTRL_6 0x08
#define SW_MIB_COUNTER_FLUSH BIT(7) #define SW_MIB_COUNTER_FLUSH BIT(7)
...@@ -797,12 +791,6 @@ ...@@ -797,12 +791,6 @@
#define REG_IND_EEE_GLOB2_LO 0x34 #define REG_IND_EEE_GLOB2_LO 0x34
#define REG_IND_EEE_GLOB2_HI 0x35 #define REG_IND_EEE_GLOB2_HI 0x35
/* 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
/** /**
* MIB_COUNTER_VALUE 00-00000000-3FFFFFFF * MIB_COUNTER_VALUE 00-00000000-3FFFFFFF
* MIB_TOTAL_BYTES 00-0000000F-FFFFFFFF * MIB_TOTAL_BYTES 00-0000000F-FFFFFFFF
......
...@@ -174,7 +174,7 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev) ...@@ -174,7 +174,7 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev)
if (mdiodev->dev.platform_data) if (mdiodev->dev.platform_data)
dev->pdata = mdiodev->dev.platform_data; dev->pdata = mdiodev->dev.platform_data;
ret = ksz8_switch_register(dev); ret = ksz_switch_register(dev);
/* Main DSA driver may not be started yet. */ /* Main DSA driver may not be started yet. */
if (ret) if (ret)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ksz9477_reg.h" #include "ksz9477_reg.h"
#include "ksz_common.h" #include "ksz_common.h"
#include "ksz9477.h"
/* Used with variable features to indicate capabilities. */ /* Used with variable features to indicate capabilities. */
#define GBIT_SUPPORT BIT(0) #define GBIT_SUPPORT BIT(0)
...@@ -47,7 +48,7 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, ...@@ -47,7 +48,7 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset,
bits, set ? bits : 0); bits, set ? bits : 0);
} }
static int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu)
{ {
u16 frame_size, max_frame = 0; u16 frame_size, max_frame = 0;
int i; int i;
...@@ -64,7 +65,7 @@ static int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) ...@@ -64,7 +65,7 @@ static int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu)
REG_SW_MTU_MASK, max_frame); REG_SW_MTU_MASK, max_frame);
} }
static int ksz9477_max_mtu(struct ksz_device *dev, int port) int ksz9477_max_mtu(struct ksz_device *dev, int port)
{ {
return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
} }
...@@ -174,7 +175,7 @@ static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev) ...@@ -174,7 +175,7 @@ static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev)
10, 1000); 10, 1000);
} }
static int ksz9477_reset_switch(struct ksz_device *dev) int ksz9477_reset_switch(struct ksz_device *dev)
{ {
u8 data8; u8 data8;
u32 data32; u32 data32;
...@@ -197,12 +198,6 @@ static int ksz9477_reset_switch(struct ksz_device *dev) ...@@ -197,12 +198,6 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
/* set broadcast storm protection 10% rate */
regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2,
BROADCAST_STORM_RATE,
(BROADCAST_STORM_VALUE *
BROADCAST_STORM_PROT_RATE) / 100);
data8 = SW_ENABLE_REFCLKO; data8 = SW_ENABLE_REFCLKO;
if (dev->synclko_disable) if (dev->synclko_disable)
data8 = 0; data8 = 0;
...@@ -213,8 +208,7 @@ static int ksz9477_reset_switch(struct ksz_device *dev) ...@@ -213,8 +208,7 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
return 0; return 0;
} }
static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
u64 *cnt)
{ {
struct ksz_port *p = &dev->ports[port]; struct ksz_port *p = &dev->ports[port];
unsigned int val; unsigned int val;
...@@ -241,14 +235,14 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, ...@@ -241,14 +235,14 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
*cnt += data; *cnt += data;
} }
static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt) u64 *dropped, u64 *cnt)
{ {
addr = dev->info->mib_names[addr].index; addr = dev->info->mib_names[addr].index;
ksz9477_r_mib_cnt(dev, port, addr, cnt); ksz9477_r_mib_cnt(dev, port, addr, cnt);
} }
static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze) void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
{ {
u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
struct ksz_port *p = &dev->ports[port]; struct ksz_port *p = &dev->ports[port];
...@@ -262,7 +256,7 @@ static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze) ...@@ -262,7 +256,7 @@ static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
mutex_unlock(&p->mib.cnt_mutex); mutex_unlock(&p->mib.cnt_mutex);
} }
static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
{ {
struct ksz_port_mib *mib = &dev->ports[port].mib; struct ksz_port_mib *mib = &dev->ports[port].mib;
...@@ -275,7 +269,7 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) ...@@ -275,7 +269,7 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
mutex_unlock(&mib->cnt_mutex); mutex_unlock(&mib->cnt_mutex);
} }
static void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
{ {
u16 val = 0xffff; u16 val = 0xffff;
...@@ -324,7 +318,7 @@ static void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) ...@@ -324,7 +318,7 @@ static void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
*data = val; *data = val;
} }
static void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
{ {
/* No real PHY after this. */ /* No real PHY after this. */
if (addr >= dev->phy_port_cnt) if (addr >= dev->phy_port_cnt)
...@@ -337,13 +331,12 @@ static void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) ...@@ -337,13 +331,12 @@ static void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
} }
static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member)
u8 member)
{ {
ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
} }
static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
{ {
u8 data; u8 data;
...@@ -365,9 +358,8 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) ...@@ -365,9 +358,8 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
} }
} }
static int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port, int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
bool flag, bool flag, struct netlink_ext_ack *extack)
struct netlink_ext_ack *extack)
{ {
if (flag) { if (flag) {
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
...@@ -382,9 +374,9 @@ static int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port, ...@@ -382,9 +374,9 @@ static int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz9477_port_vlan_add(struct ksz_device *dev, int port, int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan, const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
u32 vlan_table[3]; u32 vlan_table[3];
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
...@@ -418,8 +410,8 @@ static int ksz9477_port_vlan_add(struct ksz_device *dev, int port, ...@@ -418,8 +410,8 @@ static int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz9477_port_vlan_del(struct ksz_device *dev, int port, int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan)
{ {
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
u32 vlan_table[3]; u32 vlan_table[3];
...@@ -451,9 +443,8 @@ static int ksz9477_port_vlan_del(struct ksz_device *dev, int port, ...@@ -451,9 +443,8 @@ static int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
return 0; return 0;
} }
static int ksz9477_fdb_add(struct ksz_device *dev, int port, int ksz9477_fdb_add(struct ksz_device *dev, int port,
const unsigned char *addr, u16 vid, const unsigned char *addr, u16 vid, struct dsa_db db)
struct dsa_db db)
{ {
u32 alu_table[4]; u32 alu_table[4];
u32 data; u32 data;
...@@ -508,9 +499,8 @@ static int ksz9477_fdb_add(struct ksz_device *dev, int port, ...@@ -508,9 +499,8 @@ static int ksz9477_fdb_add(struct ksz_device *dev, int port,
return ret; return ret;
} }
static int ksz9477_fdb_del(struct ksz_device *dev, int port, int ksz9477_fdb_del(struct ksz_device *dev, int port,
const unsigned char *addr, u16 vid, const unsigned char *addr, u16 vid, struct dsa_db db)
struct dsa_db db)
{ {
u32 alu_table[4]; u32 alu_table[4];
u32 data; u32 data;
...@@ -598,8 +588,8 @@ static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table) ...@@ -598,8 +588,8 @@ static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table)
alu->mac[5] = alu_table[3] & 0xFF; alu->mac[5] = alu_table[3] & 0xFF;
} }
static int ksz9477_fdb_dump(struct ksz_device *dev, int port, int ksz9477_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data) dsa_fdb_dump_cb_t *cb, void *data)
{ {
int ret = 0; int ret = 0;
u32 ksz_data; u32 ksz_data;
...@@ -649,9 +639,8 @@ static int ksz9477_fdb_dump(struct ksz_device *dev, int port, ...@@ -649,9 +639,8 @@ static int ksz9477_fdb_dump(struct ksz_device *dev, int port,
return ret; return ret;
} }
static int ksz9477_mdb_add(struct ksz_device *dev, int port, int ksz9477_mdb_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
struct dsa_db db)
{ {
u32 static_table[4]; u32 static_table[4];
u32 data; u32 data;
...@@ -724,9 +713,8 @@ static int ksz9477_mdb_add(struct ksz_device *dev, int port, ...@@ -724,9 +713,8 @@ static int ksz9477_mdb_add(struct ksz_device *dev, int port,
return err; return err;
} }
static int ksz9477_mdb_del(struct ksz_device *dev, int port, int ksz9477_mdb_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
struct dsa_db db)
{ {
u32 static_table[4]; u32 static_table[4];
u32 data; u32 data;
...@@ -799,9 +787,9 @@ static int ksz9477_mdb_del(struct ksz_device *dev, int port, ...@@ -799,9 +787,9 @@ static int ksz9477_mdb_del(struct ksz_device *dev, int port,
return ret; return ret;
} }
static int ksz9477_port_mirror_add(struct ksz_device *dev, int port, int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror, struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack) bool ingress, struct netlink_ext_ack *extack)
{ {
u8 data; u8 data;
int p; int p;
...@@ -838,8 +826,8 @@ static int ksz9477_port_mirror_add(struct ksz_device *dev, int port, ...@@ -838,8 +826,8 @@ static int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
return 0; return 0;
} }
static void ksz9477_port_mirror_del(struct ksz_device *dev, int port, void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror) struct dsa_mall_mirror_tc_entry *mirror)
{ {
bool in_use = false; bool in_use = false;
u8 data; u8 data;
...@@ -1062,14 +1050,17 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) ...@@ -1062,14 +1050,17 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee); ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee);
} }
static void ksz9477_get_caps(struct ksz_device *dev, int port, void ksz9477_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config) struct phylink_config *config)
{ {
config->mac_capabilities = MAC_10 | MAC_100 | MAC_1000FD | config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
MAC_ASYM_PAUSE | MAC_SYM_PAUSE; MAC_SYM_PAUSE;
if (dev->features & GBIT_SUPPORT)
config->mac_capabilities |= MAC_1000FD;
} }
static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{ {
struct ksz_port *p = &dev->ports[port]; struct ksz_port *p = &dev->ports[port];
struct dsa_switch *ds = dev->ds; struct dsa_switch *ds = dev->ds;
...@@ -1166,7 +1157,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1166,7 +1157,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
} }
static void ksz9477_config_cpu_port(struct dsa_switch *ds) void ksz9477_config_cpu_port(struct dsa_switch *ds)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
struct ksz_port *p; struct ksz_port *p;
...@@ -1236,22 +1227,41 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds) ...@@ -1236,22 +1227,41 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
} }
} }
static int ksz9477_setup(struct dsa_switch *ds) int ksz9477_enable_stp_addr(struct ksz_device *dev)
{ {
struct ksz_device *dev = ds->priv; u32 data;
int ret = 0; int ret;
dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), /* Enable Reserved multicast table */
dev->info->num_vlans, GFP_KERNEL); ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
if (!dev->vlan_cache)
return -ENOMEM;
ret = ksz9477_reset_switch(dev); /* Set the Override bit for forwarding BPDU packet to CPU */
if (ret) { ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
dev_err(ds->dev, "failed to reset switch\n"); ALU_V_OVERRIDE | BIT(dev->cpu_port));
if (ret < 0)
return ret;
data = ALU_STAT_START | ALU_RESV_MCAST_ADDR;
ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
if (ret < 0)
return ret;
/* wait to be finished */
ret = ksz9477_wait_alu_sta_ready(dev);
if (ret < 0) {
dev_err(dev->dev, "Failed to update Reserved Multicast table\n");
return ret; return ret;
} }
return 0;
}
int ksz9477_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
int ret = 0;
/* Required for port partitioning. */ /* Required for port partitioning. */
ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY,
true); true);
...@@ -1268,68 +1278,25 @@ static int ksz9477_setup(struct dsa_switch *ds) ...@@ -1268,68 +1278,25 @@ static int ksz9477_setup(struct dsa_switch *ds)
if (ret) if (ret)
return ret; return ret;
ksz9477_config_cpu_port(ds);
ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true);
/* queue based egress rate limit */ /* queue based egress rate limit */
ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
/* enable global MIB counter freeze function */ /* enable global MIB counter freeze function */
ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
/* start switch */
ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
ksz_init_mib_timer(dev);
ds->configure_vlan_while_not_filtering = false;
return 0; return 0;
} }
static const struct dsa_switch_ops ksz9477_switch_ops = { u32 ksz9477_get_port_addr(int port, int offset)
.get_tag_protocol = ksz_get_tag_protocol,
.setup = ksz9477_setup,
.phy_read = ksz_phy_read16,
.phy_write = ksz_phy_write16,
.phylink_mac_link_down = ksz_mac_link_down,
.phylink_get_caps = ksz_phylink_get_caps,
.port_enable = ksz_enable_port,
.get_strings = ksz_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 = ksz_port_stp_state_set,
.port_fast_age = ksz_port_fast_age,
.port_vlan_filtering = ksz_port_vlan_filtering,
.port_vlan_add = ksz_port_vlan_add,
.port_vlan_del = ksz_port_vlan_del,
.port_fdb_dump = ksz_port_fdb_dump,
.port_fdb_add = ksz_port_fdb_add,
.port_fdb_del = ksz_port_fdb_del,
.port_mdb_add = ksz_port_mdb_add,
.port_mdb_del = ksz_port_mdb_del,
.port_mirror_add = ksz_port_mirror_add,
.port_mirror_del = ksz_port_mirror_del,
.get_stats64 = ksz_get_stats64,
.port_change_mtu = ksz_change_mtu,
.port_max_mtu = ksz_max_mtu,
};
static u32 ksz9477_get_port_addr(int port, int offset)
{ {
return PORT_CTRL_ADDR(port, offset); return PORT_CTRL_ADDR(port, offset);
} }
static int ksz9477_switch_init(struct ksz_device *dev) int ksz9477_switch_init(struct ksz_device *dev)
{ {
u8 data8; u8 data8;
int ret; int ret;
dev->ds->ops = &ksz9477_switch_ops;
dev->port_mask = (1 << dev->info->port_cnt) - 1; dev->port_mask = (1 << dev->info->port_cnt) - 1;
/* turn off SPI DO Edge select */ /* turn off SPI DO Edge select */
...@@ -1367,72 +1334,15 @@ static int ksz9477_switch_init(struct ksz_device *dev) ...@@ -1367,72 +1334,15 @@ static int ksz9477_switch_init(struct ksz_device *dev)
if (!(data8 & SW_GIGABIT_ABLE)) if (!(data8 & SW_GIGABIT_ABLE))
dev->features &= ~GBIT_SUPPORT; dev->features &= ~GBIT_SUPPORT;
} }
return 0; return 0;
} }
static void ksz9477_switch_exit(struct ksz_device *dev) void ksz9477_switch_exit(struct ksz_device *dev)
{ {
ksz9477_reset_switch(dev); ksz9477_reset_switch(dev);
} }
static const struct ksz_dev_ops ksz9477_dev_ops = {
.get_port_addr = ksz9477_get_port_addr,
.cfg_port_member = ksz9477_cfg_port_member,
.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
.port_setup = ksz9477_port_setup,
.r_phy = ksz9477_r_phy,
.w_phy = ksz9477_w_phy,
.r_mib_cnt = ksz9477_r_mib_cnt,
.r_mib_pkt = ksz9477_r_mib_pkt,
.r_mib_stat64 = ksz_r_mib_stats64,
.freeze_mib = ksz9477_freeze_mib,
.port_init_cnt = ksz9477_port_init_cnt,
.vlan_filtering = ksz9477_port_vlan_filtering,
.vlan_add = ksz9477_port_vlan_add,
.vlan_del = ksz9477_port_vlan_del,
.mirror_add = ksz9477_port_mirror_add,
.mirror_del = ksz9477_port_mirror_del,
.get_caps = ksz9477_get_caps,
.fdb_dump = ksz9477_fdb_dump,
.fdb_add = ksz9477_fdb_add,
.fdb_del = ksz9477_fdb_del,
.mdb_add = ksz9477_mdb_add,
.mdb_del = ksz9477_mdb_del,
.change_mtu = ksz9477_change_mtu,
.max_mtu = ksz9477_max_mtu,
.shutdown = ksz9477_reset_switch,
.init = ksz9477_switch_init,
.exit = ksz9477_switch_exit,
};
int ksz9477_switch_register(struct ksz_device *dev)
{
int ret, i;
struct phy_device *phydev;
ret = ksz_switch_register(dev, &ksz9477_dev_ops);
if (ret)
return ret;
for (i = 0; i < dev->phy_port_cnt; ++i) {
if (!dsa_is_user_port(dev->ds, i))
continue;
phydev = dsa_to_port(dev->ds, i)->slave->phydev;
/* The MAC actually cannot run in 1000 half-duplex mode. */
phy_remove_link_mode(phydev,
ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
/* PHY does not support gigabit. */
if (!(dev->features & GBIT_SUPPORT))
phy_remove_link_mode(phydev,
ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
}
return ret;
}
EXPORT_SYMBOL(ksz9477_switch_register);
MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver"); MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Microchip KSZ9477 series Header file
*
* Copyright (C) 2017-2022 Microchip Technology Inc.
*/
#ifndef __KSZ9477_H
#define __KSZ9477_H
#include <net/dsa.h>
#include "ksz_common.h"
int ksz9477_setup(struct dsa_switch *ds);
u32 ksz9477_get_port_addr(int port, int offset);
void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member);
void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port);
void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);
void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt);
void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze);
void ksz9477_port_init_cnt(struct ksz_device *dev, int port);
int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
bool flag, struct netlink_ext_ack *extack);
int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack);
int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan);
int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack);
void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror);
int ksz9477_get_stp_reg(void);
void ksz9477_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
int ksz9477_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int ksz9477_fdb_add(struct ksz_device *dev, int port,
const unsigned char *addr, u16 vid, struct dsa_db db);
int ksz9477_fdb_del(struct ksz_device *dev, int port,
const unsigned char *addr, u16 vid, struct dsa_db db);
int ksz9477_mdb_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz9477_mdb_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu);
int ksz9477_max_mtu(struct ksz_device *dev, int port);
void ksz9477_config_cpu_port(struct dsa_switch *ds);
int ksz9477_enable_stp_addr(struct ksz_device *dev);
int ksz9477_reset_switch(struct ksz_device *dev);
int ksz9477_dsa_init(struct ksz_device *dev);
int ksz9477_switch_init(struct ksz_device *dev);
void ksz9477_switch_exit(struct ksz_device *dev);
#endif
...@@ -41,7 +41,7 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c, ...@@ -41,7 +41,7 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c,
if (i2c->dev.platform_data) if (i2c->dev.platform_data)
dev->pdata = i2c->dev.platform_data; dev->pdata = i2c->dev.platform_data;
ret = ksz9477_switch_register(dev); ret = ksz_switch_register(dev);
/* Main DSA driver may not be started yet. */ /* Main DSA driver may not be started yet. */
if (ret) if (ret)
...@@ -71,8 +71,8 @@ static void ksz9477_i2c_shutdown(struct i2c_client *i2c) ...@@ -71,8 +71,8 @@ static void ksz9477_i2c_shutdown(struct i2c_client *i2c)
if (!dev) if (!dev)
return; return;
if (dev->dev_ops->shutdown) if (dev->dev_ops->reset)
dev->dev_ops->shutdown(dev); dev->dev_ops->reset(dev);
dsa_switch_shutdown(dev->ds); dsa_switch_shutdown(dev->ds);
......
...@@ -165,7 +165,6 @@ ...@@ -165,7 +165,6 @@
#define SW_DOUBLE_TAG BIT(7) #define SW_DOUBLE_TAG BIT(7)
#define SW_RESET BIT(1) #define SW_RESET BIT(1)
#define SW_START BIT(0)
#define REG_SW_MAC_ADDR_0 0x0302 #define REG_SW_MAC_ADDR_0 0x0302
#define REG_SW_MAC_ADDR_1 0x0303 #define REG_SW_MAC_ADDR_1 0x0303
...@@ -265,7 +264,6 @@ ...@@ -265,7 +264,6 @@
#define REG_SW_MAC_CTRL_1 0x0331 #define REG_SW_MAC_CTRL_1 0x0331
#define MULTICAST_STORM_DISABLE BIT(6)
#define SW_BACK_PRESSURE BIT(5) #define SW_BACK_PRESSURE BIT(5)
#define FAIR_FLOW_CTRL BIT(4) #define FAIR_FLOW_CTRL BIT(4)
#define NO_EXC_COLLISION_DROP BIT(3) #define NO_EXC_COLLISION_DROP BIT(3)
...@@ -276,13 +274,9 @@ ...@@ -276,13 +274,9 @@
#define REG_SW_MAC_CTRL_2 0x0332 #define REG_SW_MAC_CTRL_2 0x0332
#define SW_REPLACE_VID BIT(3) #define SW_REPLACE_VID BIT(3)
#define BROADCAST_STORM_RATE_HI 0x07
#define REG_SW_MAC_CTRL_3 0x0333 #define REG_SW_MAC_CTRL_3 0x0333
#define BROADCAST_STORM_RATE_LO 0xFF
#define BROADCAST_STORM_RATE 0x07FF
#define REG_SW_MAC_CTRL_4 0x0334 #define REG_SW_MAC_CTRL_4 0x0334
#define SW_PASS_PAUSE BIT(3) #define SW_PASS_PAUSE BIT(3)
...@@ -1652,12 +1646,6 @@ ...@@ -1652,12 +1646,6 @@
#define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) #define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1)
#define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) #define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1)
/* 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 KSZ9477_MAX_FRAME_SIZE 9000 #define KSZ9477_MAX_FRAME_SIZE 9000
#endif /* KSZ9477_REGS_H */ #endif /* KSZ9477_REGS_H */
// SPDX-License-Identifier: GPL-2.0
/*
* Microchip KSZ9477 series register access through SPI
*
* Copyright (C) 2017-2019 Microchip Technology Inc.
*/
#include <asm/unaligned.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ksz_common.h"
#define SPI_ADDR_SHIFT 24
#define SPI_ADDR_ALIGN 3
#define SPI_TURNAROUND_SHIFT 5
KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT,
SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
static int ksz9477_spi_probe(struct spi_device *spi)
{
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;
dev = ksz_switch_alloc(&spi->dev, spi);
if (!dev)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
rc = ksz9477_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev,
"Failed to initialize regmap%i: %d\n",
ksz9477_regmap_config[i].val_bits, ret);
return ret;
}
}
if (spi->dev.platform_data)
dev->pdata = spi->dev.platform_data;
/* setup spi */
spi->mode = SPI_MODE_3;
ret = spi_setup(spi);
if (ret)
return ret;
ret = ksz9477_switch_register(dev);
/* Main DSA driver may not be started yet. */
if (ret)
return ret;
spi_set_drvdata(spi, dev);
return 0;
}
static void ksz9477_spi_remove(struct spi_device *spi)
{
struct ksz_device *dev = spi_get_drvdata(spi);
if (dev)
ksz_switch_remove(dev);
spi_set_drvdata(spi, NULL);
}
static void ksz9477_spi_shutdown(struct spi_device *spi)
{
struct ksz_device *dev = spi_get_drvdata(spi);
if (dev)
dsa_switch_shutdown(dev->ds);
spi_set_drvdata(spi, NULL);
}
static const struct of_device_id ksz9477_dt_ids[] = {
{
.compatible = "microchip,ksz9477",
.data = &ksz_switch_chips[KSZ9477]
},
{
.compatible = "microchip,ksz9897",
.data = &ksz_switch_chips[KSZ9897]
},
{
.compatible = "microchip,ksz9893",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz9563",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz8563",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz9567",
.data = &ksz_switch_chips[KSZ9567]
},
{},
};
MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
static const struct spi_device_id ksz9477_spi_ids[] = {
{ "ksz9477" },
{ "ksz9897" },
{ "ksz9893" },
{ "ksz9563" },
{ "ksz8563" },
{ "ksz9567" },
{ },
};
MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids);
static struct spi_driver ksz9477_spi_driver = {
.driver = {
.name = "ksz9477-switch",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(ksz9477_dt_ids),
},
.id_table = ksz9477_spi_ids,
.probe = ksz9477_spi_probe,
.remove = ksz9477_spi_remove,
.shutdown = ksz9477_spi_shutdown,
};
module_spi_driver(ksz9477_spi_driver);
MODULE_ALIAS("spi:ksz9477");
MODULE_ALIAS("spi:ksz9897");
MODULE_ALIAS("spi:ksz9893");
MODULE_ALIAS("spi:ksz9563");
MODULE_ALIAS("spi:ksz8563");
MODULE_ALIAS("spi:ksz9567");
MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch SPI access Driver");
MODULE_LICENSE("GPL");
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <net/switchdev.h> #include <net/switchdev.h>
#include "ksz_common.h" #include "ksz_common.h"
#include "ksz8.h"
#include "ksz9477.h"
#define MIB_COUNTER_NUM 0x20 #define MIB_COUNTER_NUM 0x20
...@@ -139,6 +141,66 @@ static const struct ksz_mib_names ksz9477_mib_names[] = { ...@@ -139,6 +141,66 @@ static const struct ksz_mib_names ksz9477_mib_names[] = {
{ 0x83, "tx_discards" }, { 0x83, "tx_discards" },
}; };
static const struct ksz_dev_ops ksz8_dev_ops = {
.setup = ksz8_setup,
.get_port_addr = ksz8_get_port_addr,
.cfg_port_member = ksz8_cfg_port_member,
.flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
.port_setup = ksz8_port_setup,
.r_phy = ksz8_r_phy,
.w_phy = ksz8_w_phy,
.r_mib_pkt = ksz8_r_mib_pkt,
.freeze_mib = ksz8_freeze_mib,
.port_init_cnt = ksz8_port_init_cnt,
.fdb_dump = ksz8_fdb_dump,
.mdb_add = ksz8_mdb_add,
.mdb_del = ksz8_mdb_del,
.vlan_filtering = ksz8_port_vlan_filtering,
.vlan_add = ksz8_port_vlan_add,
.vlan_del = ksz8_port_vlan_del,
.mirror_add = ksz8_port_mirror_add,
.mirror_del = ksz8_port_mirror_del,
.get_caps = ksz8_get_caps,
.config_cpu_port = ksz8_config_cpu_port,
.enable_stp_addr = ksz8_enable_stp_addr,
.reset = ksz8_reset_switch,
.init = ksz8_switch_init,
.exit = ksz8_switch_exit,
};
static const struct ksz_dev_ops ksz9477_dev_ops = {
.setup = ksz9477_setup,
.get_port_addr = ksz9477_get_port_addr,
.cfg_port_member = ksz9477_cfg_port_member,
.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
.port_setup = ksz9477_port_setup,
.r_phy = ksz9477_r_phy,
.w_phy = ksz9477_w_phy,
.r_mib_cnt = ksz9477_r_mib_cnt,
.r_mib_pkt = ksz9477_r_mib_pkt,
.r_mib_stat64 = ksz_r_mib_stats64,
.freeze_mib = ksz9477_freeze_mib,
.port_init_cnt = ksz9477_port_init_cnt,
.vlan_filtering = ksz9477_port_vlan_filtering,
.vlan_add = ksz9477_port_vlan_add,
.vlan_del = ksz9477_port_vlan_del,
.mirror_add = ksz9477_port_mirror_add,
.mirror_del = ksz9477_port_mirror_del,
.get_caps = ksz9477_get_caps,
.fdb_dump = ksz9477_fdb_dump,
.fdb_add = ksz9477_fdb_add,
.fdb_del = ksz9477_fdb_del,
.mdb_add = ksz9477_mdb_add,
.mdb_del = ksz9477_mdb_del,
.change_mtu = ksz9477_change_mtu,
.max_mtu = ksz9477_max_mtu,
.config_cpu_port = ksz9477_config_cpu_port,
.enable_stp_addr = ksz9477_enable_stp_addr,
.reset = ksz9477_reset_switch,
.init = ksz9477_switch_init,
.exit = ksz9477_switch_exit,
};
const struct ksz_chip_data ksz_switch_chips[] = { const struct ksz_chip_data ksz_switch_chips[] = {
[KSZ8795] = { [KSZ8795] = {
.chip_id = KSZ8795_CHIP_ID, .chip_id = KSZ8795_CHIP_ID,
...@@ -148,11 +210,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -148,11 +210,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 8, .num_statics = 8,
.cpu_ports = 0x10, /* can be configured as cpu port */ .cpu_ports = 0x10, /* can be configured as cpu port */
.port_cnt = 5, /* total cpu and user ports */ .port_cnt = 5, /* total cpu and user ports */
.ops = &ksz8_dev_ops,
.ksz87xx_eee_link_erratum = true, .ksz87xx_eee_link_erratum = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x02, .stp_ctrl_reg = 0x02,
.broadcast_ctrl_reg = 0x06,
.multicast_ctrl_reg = 0x04,
.start_ctrl_reg = 0x01,
.supports_mii = {false, false, false, false, true}, .supports_mii = {false, false, false, false, true},
.supports_rmii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true},
.supports_rgmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true},
...@@ -181,11 +247,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -181,11 +247,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 8, .num_statics = 8,
.cpu_ports = 0x10, /* can be configured as cpu port */ .cpu_ports = 0x10, /* can be configured as cpu port */
.port_cnt = 5, /* total cpu and user ports */ .port_cnt = 5, /* total cpu and user ports */
.ops = &ksz8_dev_ops,
.ksz87xx_eee_link_erratum = true, .ksz87xx_eee_link_erratum = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x02, .stp_ctrl_reg = 0x02,
.broadcast_ctrl_reg = 0x06,
.multicast_ctrl_reg = 0x04,
.start_ctrl_reg = 0x01,
.supports_mii = {false, false, false, false, true}, .supports_mii = {false, false, false, false, true},
.supports_rmii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true},
.supports_rgmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true},
...@@ -200,11 +270,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -200,11 +270,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 8, .num_statics = 8,
.cpu_ports = 0x10, /* can be configured as cpu port */ .cpu_ports = 0x10, /* can be configured as cpu port */
.port_cnt = 5, /* total cpu and user ports */ .port_cnt = 5, /* total cpu and user ports */
.ops = &ksz8_dev_ops,
.ksz87xx_eee_link_erratum = true, .ksz87xx_eee_link_erratum = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x02, .stp_ctrl_reg = 0x02,
.broadcast_ctrl_reg = 0x06,
.multicast_ctrl_reg = 0x04,
.start_ctrl_reg = 0x01,
.supports_mii = {false, false, false, false, true}, .supports_mii = {false, false, false, false, true},
.supports_rmii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true},
.supports_rgmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true},
...@@ -219,10 +293,14 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -219,10 +293,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 8, .num_statics = 8,
.cpu_ports = 0x4, /* can be configured as cpu port */ .cpu_ports = 0x4, /* can be configured as cpu port */
.port_cnt = 3, .port_cnt = 3,
.ops = &ksz8_dev_ops,
.mib_names = ksz88xx_mib_names, .mib_names = ksz88xx_mib_names,
.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names), .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x02, .stp_ctrl_reg = 0x02,
.broadcast_ctrl_reg = 0x06,
.multicast_ctrl_reg = 0x04,
.start_ctrl_reg = 0x01,
.supports_mii = {false, false, true}, .supports_mii = {false, false, true},
.supports_rmii = {false, false, true}, .supports_rmii = {false, false, true},
.internal_phy = {true, true, false}, .internal_phy = {true, true, false},
...@@ -236,11 +314,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -236,11 +314,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 16, .num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */ .cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */ .port_cnt = 7, /* total physical port count */
.ops = &ksz9477_dev_ops,
.phy_errata_9477 = true, .phy_errata_9477 = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
false, true, false}, false, true, false},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -259,11 +341,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -259,11 +341,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 16, .num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */ .cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */ .port_cnt = 7, /* total physical port count */
.ops = &ksz9477_dev_ops,
.phy_errata_9477 = true, .phy_errata_9477 = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
false, true, true}, false, true, true},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -282,10 +368,14 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -282,10 +368,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 16, .num_statics = 16,
.cpu_ports = 0x07, /* can be configured as cpu port */ .cpu_ports = 0x07, /* can be configured as cpu port */
.port_cnt = 3, /* total port count */ .port_cnt = 3, /* total port count */
.ops = &ksz9477_dev_ops,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, true}, .supports_mii = {false, false, true},
.supports_rmii = {false, false, true}, .supports_rmii = {false, false, true},
.supports_rgmii = {false, false, true}, .supports_rgmii = {false, false, true},
...@@ -300,11 +390,15 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -300,11 +390,15 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_statics = 16, .num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */ .cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */ .port_cnt = 7, /* total physical port count */
.ops = &ksz9477_dev_ops,
.phy_errata_9477 = true, .phy_errata_9477 = true,
.mib_names = ksz9477_mib_names, .mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
false, true, true}, false, true, true},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -327,6 +421,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -327,6 +421,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, true}, .supports_mii = {false, false, false, false, true},
.supports_rmii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true},
.supports_rgmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true},
...@@ -345,6 +442,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -345,6 +442,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, true, true}, .supports_mii = {false, false, false, false, true, true},
.supports_rmii = {false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, true, true},
.supports_rgmii = {false, false, false, false, true, true}, .supports_rgmii = {false, false, false, false, true, true},
...@@ -363,6 +463,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -363,6 +463,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
true, true, false, false}, true, true, false, false},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -385,6 +488,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -385,6 +488,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
true, true, false, false}, true, true, false, false},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -407,6 +513,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -407,6 +513,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM, .reg_mib_cnt = MIB_COUNTER_NUM,
.stp_ctrl_reg = 0x0B04, .stp_ctrl_reg = 0x0B04,
.broadcast_ctrl_reg = 0x0332,
.multicast_ctrl_reg = 0x0331,
.start_ctrl_reg = 0x0300,
.supports_mii = {false, false, false, false, .supports_mii = {false, false, false, false,
true, true, false, false}, true, true, false, false},
.supports_rmii = {false, false, false, false, .supports_rmii = {false, false, false, false,
...@@ -450,8 +559,8 @@ static int ksz_check_device_id(struct ksz_device *dev) ...@@ -450,8 +559,8 @@ static int ksz_check_device_id(struct ksz_device *dev)
return 0; return 0;
} }
void ksz_phylink_get_caps(struct dsa_switch *ds, int port, static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
struct phylink_config *config) struct phylink_config *config)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -474,7 +583,6 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port, ...@@ -474,7 +583,6 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
if (dev->dev_ops->get_caps) if (dev->dev_ops->get_caps)
dev->dev_ops->get_caps(dev, port, config); dev->dev_ops->get_caps(dev, port, config);
} }
EXPORT_SYMBOL_GPL(ksz_phylink_get_caps);
void ksz_r_mib_stats64(struct ksz_device *dev, int port) void ksz_r_mib_stats64(struct ksz_device *dev, int port)
{ {
...@@ -517,10 +625,9 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port) ...@@ -517,10 +625,9 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port)
spin_unlock(&mib->stats64_lock); spin_unlock(&mib->stats64_lock);
} }
EXPORT_SYMBOL_GPL(ksz_r_mib_stats64);
void ksz_get_stats64(struct dsa_switch *ds, int port, static void ksz_get_stats64(struct dsa_switch *ds, int port,
struct rtnl_link_stats64 *s) struct rtnl_link_stats64 *s)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
struct ksz_port_mib *mib; struct ksz_port_mib *mib;
...@@ -531,10 +638,9 @@ void ksz_get_stats64(struct dsa_switch *ds, int port, ...@@ -531,10 +638,9 @@ void ksz_get_stats64(struct dsa_switch *ds, int port,
memcpy(s, &mib->stats64, sizeof(*s)); memcpy(s, &mib->stats64, sizeof(*s));
spin_unlock(&mib->stats64_lock); spin_unlock(&mib->stats64_lock);
} }
EXPORT_SYMBOL_GPL(ksz_get_stats64);
void ksz_get_strings(struct dsa_switch *ds, int port, static void ksz_get_strings(struct dsa_switch *ds, int port,
u32 stringset, uint8_t *buf) u32 stringset, uint8_t *buf)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
int i; int i;
...@@ -547,7 +653,6 @@ void ksz_get_strings(struct dsa_switch *ds, int port, ...@@ -547,7 +653,6 @@ void ksz_get_strings(struct dsa_switch *ds, int port,
dev->info->mib_names[i].string, ETH_GSTRING_LEN); dev->info->mib_names[i].string, ETH_GSTRING_LEN);
} }
} }
EXPORT_SYMBOL_GPL(ksz_get_strings);
static void ksz_update_port_member(struct ksz_device *dev, int port) static void ksz_update_port_member(struct ksz_device *dev, int port)
{ {
...@@ -607,6 +712,52 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) ...@@ -607,6 +712,52 @@ static void ksz_update_port_member(struct ksz_device *dev, int port)
dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
} }
static int ksz_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
int ret;
dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
dev->info->num_vlans, GFP_KERNEL);
if (!dev->vlan_cache)
return -ENOMEM;
ret = dev->dev_ops->reset(dev);
if (ret) {
dev_err(ds->dev, "failed to reset switch\n");
return ret;
}
/* set broadcast storm protection 10% rate */
regmap_update_bits(dev->regmap[1], dev->info->broadcast_ctrl_reg,
BROADCAST_STORM_RATE,
(BROADCAST_STORM_VALUE *
BROADCAST_STORM_PROT_RATE) / 100);
dev->dev_ops->config_cpu_port(ds);
dev->dev_ops->enable_stp_addr(dev);
regmap_update_bits(dev->regmap[0], dev->info->multicast_ctrl_reg,
MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE);
ksz_init_mib_timer(dev);
ds->configure_vlan_while_not_filtering = false;
if (dev->dev_ops->setup) {
ret = dev->dev_ops->setup(ds);
if (ret)
return ret;
}
/* start switch */
regmap_update_bits(dev->regmap[0], dev->info->start_ctrl_reg,
SW_START, SW_START);
return 0;
}
static void port_r_cnt(struct ksz_device *dev, int port) static void port_r_cnt(struct ksz_device *dev, int port)
{ {
struct ksz_port_mib *mib = &dev->ports[port].mib; struct ksz_port_mib *mib = &dev->ports[port].mib;
...@@ -683,9 +834,8 @@ void ksz_init_mib_timer(struct ksz_device *dev) ...@@ -683,9 +834,8 @@ void ksz_init_mib_timer(struct ksz_device *dev)
memset(mib->counters, 0, dev->info->mib_cnt * sizeof(u64)); memset(mib->counters, 0, dev->info->mib_cnt * sizeof(u64));
} }
} }
EXPORT_SYMBOL_GPL(ksz_init_mib_timer);
int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
u16 val = 0xffff; u16 val = 0xffff;
...@@ -694,9 +844,8 @@ int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) ...@@ -694,9 +844,8 @@ int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
return val; return val;
} }
EXPORT_SYMBOL_GPL(ksz_phy_read16);
int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -704,9 +853,8 @@ int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) ...@@ -704,9 +853,8 @@ int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ksz_phy_write16);
u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -721,10 +869,9 @@ u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) ...@@ -721,10 +869,9 @@ u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ksz_get_phy_flags);
void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, static void ksz_mac_link_down(struct dsa_switch *ds, int port,
phy_interface_t interface) unsigned int mode, phy_interface_t interface)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
struct ksz_port *p = &dev->ports[port]; struct ksz_port *p = &dev->ports[port];
...@@ -735,9 +882,8 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, ...@@ -735,9 +882,8 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
if (dev->mib_read_interval) if (dev->mib_read_interval)
schedule_delayed_work(&dev->mib_read, 0); schedule_delayed_work(&dev->mib_read, 0);
} }
EXPORT_SYMBOL_GPL(ksz_mac_link_down);
int ksz_sset_count(struct dsa_switch *ds, int port, int sset) static int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -746,9 +892,9 @@ int ksz_sset_count(struct dsa_switch *ds, int port, int sset) ...@@ -746,9 +892,9 @@ int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
return dev->info->mib_cnt; return dev->info->mib_cnt;
} }
EXPORT_SYMBOL_GPL(ksz_sset_count);
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf) static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *buf)
{ {
const struct dsa_port *dp = dsa_to_port(ds, port); const struct dsa_port *dp = dsa_to_port(ds, port);
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -764,12 +910,11 @@ void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf) ...@@ -764,12 +910,11 @@ void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64)); memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64));
mutex_unlock(&mib->cnt_mutex); mutex_unlock(&mib->cnt_mutex);
} }
EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
int ksz_port_bridge_join(struct dsa_switch *ds, int port, static int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge, struct dsa_bridge bridge,
bool *tx_fwd_offload, bool *tx_fwd_offload,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
/* port_stp_state_set() will be called after to put the port in /* port_stp_state_set() will be called after to put the port in
* appropriate state so there is no need to do anything. * appropriate state so there is no need to do anything.
...@@ -777,27 +922,25 @@ int ksz_port_bridge_join(struct dsa_switch *ds, int port, ...@@ -777,27 +922,25 @@ int ksz_port_bridge_join(struct dsa_switch *ds, int port,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
void ksz_port_bridge_leave(struct dsa_switch *ds, int port, static void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge) struct dsa_bridge bridge)
{ {
/* port_stp_state_set() will be called after to put the port in /* port_stp_state_set() will be called after to put the port in
* forwarding state so there is no need to do anything. * forwarding state so there is no need to do anything.
*/ */
} }
EXPORT_SYMBOL_GPL(ksz_port_bridge_leave);
void ksz_port_fast_age(struct dsa_switch *ds, int port) static void ksz_port_fast_age(struct dsa_switch *ds, int port)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
dev->dev_ops->flush_dyn_mac_table(dev, port); dev->dev_ops->flush_dyn_mac_table(dev, port);
} }
EXPORT_SYMBOL_GPL(ksz_port_fast_age);
int ksz_port_fdb_add(struct dsa_switch *ds, int port, static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, struct dsa_db db) const unsigned char *addr, u16 vid,
struct dsa_db db)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -806,10 +949,10 @@ int ksz_port_fdb_add(struct dsa_switch *ds, int port, ...@@ -806,10 +949,10 @@ int ksz_port_fdb_add(struct dsa_switch *ds, int port,
return dev->dev_ops->fdb_add(dev, port, addr, vid, db); return dev->dev_ops->fdb_add(dev, port, addr, vid, db);
} }
EXPORT_SYMBOL_GPL(ksz_port_fdb_add);
int ksz_port_fdb_del(struct dsa_switch *ds, int port, static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, struct dsa_db db) const unsigned char *addr,
u16 vid, struct dsa_db db)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -818,10 +961,9 @@ int ksz_port_fdb_del(struct dsa_switch *ds, int port, ...@@ -818,10 +961,9 @@ int ksz_port_fdb_del(struct dsa_switch *ds, int port,
return dev->dev_ops->fdb_del(dev, port, addr, vid, db); return dev->dev_ops->fdb_del(dev, port, addr, vid, db);
} }
EXPORT_SYMBOL_GPL(ksz_port_fdb_del);
int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
void *data) dsa_fdb_dump_cb_t *cb, void *data)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -830,11 +972,10 @@ int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, ...@@ -830,11 +972,10 @@ int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
return dev->dev_ops->fdb_dump(dev, port, cb, data); return dev->dev_ops->fdb_dump(dev, port, cb, data);
} }
EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
int ksz_port_mdb_add(struct dsa_switch *ds, int port, static int ksz_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db) struct dsa_db db)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -843,11 +984,10 @@ int ksz_port_mdb_add(struct dsa_switch *ds, int port, ...@@ -843,11 +984,10 @@ int ksz_port_mdb_add(struct dsa_switch *ds, int port,
return dev->dev_ops->mdb_add(dev, port, mdb, db); return dev->dev_ops->mdb_add(dev, port, mdb, db);
} }
EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
int ksz_port_mdb_del(struct dsa_switch *ds, int port, static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db) struct dsa_db db)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -856,9 +996,9 @@ int ksz_port_mdb_del(struct dsa_switch *ds, int port, ...@@ -856,9 +996,9 @@ int ksz_port_mdb_del(struct dsa_switch *ds, int port,
return dev->dev_ops->mdb_del(dev, port, mdb, db); return dev->dev_ops->mdb_del(dev, port, mdb, db);
} }
EXPORT_SYMBOL_GPL(ksz_port_mdb_del);
int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) static int ksz_enable_port(struct dsa_switch *ds, int port,
struct phy_device *phy)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -874,7 +1014,6 @@ int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) ...@@ -874,7 +1014,6 @@ int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ksz_enable_port);
void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{ {
...@@ -916,10 +1055,10 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ...@@ -916,10 +1055,10 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
ksz_update_port_member(dev, port); ksz_update_port_member(dev, port);
} }
EXPORT_SYMBOL_GPL(ksz_port_stp_state_set);
enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
int port, enum dsa_tag_protocol mp) int port,
enum dsa_tag_protocol mp)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE; enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE;
...@@ -940,10 +1079,9 @@ enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, ...@@ -940,10 +1079,9 @@ enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
return proto; return proto;
} }
EXPORT_SYMBOL_GPL(ksz_get_tag_protocol);
int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
bool flag, struct netlink_ext_ack *extack) bool flag, struct netlink_ext_ack *extack)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -952,11 +1090,10 @@ int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, ...@@ -952,11 +1090,10 @@ int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
return dev->dev_ops->vlan_filtering(dev, port, flag, extack); return dev->dev_ops->vlan_filtering(dev, port, flag, extack);
} }
EXPORT_SYMBOL_GPL(ksz_port_vlan_filtering);
int ksz_port_vlan_add(struct dsa_switch *ds, int port, static int ksz_port_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan, const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -965,10 +1102,9 @@ int ksz_port_vlan_add(struct dsa_switch *ds, int port, ...@@ -965,10 +1102,9 @@ int ksz_port_vlan_add(struct dsa_switch *ds, int port,
return dev->dev_ops->vlan_add(dev, port, vlan, extack); return dev->dev_ops->vlan_add(dev, port, vlan, extack);
} }
EXPORT_SYMBOL_GPL(ksz_port_vlan_add);
int ksz_port_vlan_del(struct dsa_switch *ds, int port, static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -977,11 +1113,10 @@ int ksz_port_vlan_del(struct dsa_switch *ds, int port, ...@@ -977,11 +1113,10 @@ int ksz_port_vlan_del(struct dsa_switch *ds, int port,
return dev->dev_ops->vlan_del(dev, port, vlan); return dev->dev_ops->vlan_del(dev, port, vlan);
} }
EXPORT_SYMBOL_GPL(ksz_port_vlan_del);
int ksz_port_mirror_add(struct dsa_switch *ds, int port, static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror, struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack) bool ingress, struct netlink_ext_ack *extack)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -990,19 +1125,17 @@ int ksz_port_mirror_add(struct dsa_switch *ds, int port, ...@@ -990,19 +1125,17 @@ int ksz_port_mirror_add(struct dsa_switch *ds, int port,
return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack); return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack);
} }
EXPORT_SYMBOL_GPL(ksz_port_mirror_add);
void ksz_port_mirror_del(struct dsa_switch *ds, int port, static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror) struct dsa_mall_mirror_tc_entry *mirror)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
if (dev->dev_ops->mirror_del) if (dev->dev_ops->mirror_del)
dev->dev_ops->mirror_del(dev, port, mirror); dev->dev_ops->mirror_del(dev, port, mirror);
} }
EXPORT_SYMBOL_GPL(ksz_port_mirror_del);
int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu) static int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -1011,9 +1144,8 @@ int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu) ...@@ -1011,9 +1144,8 @@ int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
return dev->dev_ops->change_mtu(dev, port, mtu); return dev->dev_ops->change_mtu(dev, port, mtu);
} }
EXPORT_SYMBOL_GPL(ksz_change_mtu);
int ksz_max_mtu(struct dsa_switch *ds, int port) static int ksz_max_mtu(struct dsa_switch *ds, int port)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
...@@ -1022,7 +1154,6 @@ int ksz_max_mtu(struct dsa_switch *ds, int port) ...@@ -1022,7 +1154,6 @@ int ksz_max_mtu(struct dsa_switch *ds, int port)
return dev->dev_ops->max_mtu(dev, port); return dev->dev_ops->max_mtu(dev, port);
} }
EXPORT_SYMBOL_GPL(ksz_max_mtu);
static int ksz_switch_detect(struct ksz_device *dev) static int ksz_switch_detect(struct ksz_device *dev)
{ {
...@@ -1090,6 +1221,37 @@ static int ksz_switch_detect(struct ksz_device *dev) ...@@ -1090,6 +1221,37 @@ static int ksz_switch_detect(struct ksz_device *dev)
return 0; return 0;
} }
static const struct dsa_switch_ops ksz_switch_ops = {
.get_tag_protocol = ksz_get_tag_protocol,
.get_phy_flags = ksz_get_phy_flags,
.setup = ksz_setup,
.phy_read = ksz_phy_read16,
.phy_write = ksz_phy_write16,
.phylink_get_caps = ksz_phylink_get_caps,
.phylink_mac_link_down = ksz_mac_link_down,
.port_enable = ksz_enable_port,
.get_strings = ksz_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 = ksz_port_stp_state_set,
.port_fast_age = ksz_port_fast_age,
.port_vlan_filtering = ksz_port_vlan_filtering,
.port_vlan_add = ksz_port_vlan_add,
.port_vlan_del = ksz_port_vlan_del,
.port_fdb_dump = ksz_port_fdb_dump,
.port_fdb_add = ksz_port_fdb_add,
.port_fdb_del = ksz_port_fdb_del,
.port_mdb_add = ksz_port_mdb_add,
.port_mdb_del = ksz_port_mdb_del,
.port_mirror_add = ksz_port_mirror_add,
.port_mirror_del = ksz_port_mirror_del,
.get_stats64 = ksz_get_stats64,
.port_change_mtu = ksz_change_mtu,
.port_max_mtu = ksz_max_mtu,
};
struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
{ {
struct dsa_switch *ds; struct dsa_switch *ds;
...@@ -1101,6 +1263,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) ...@@ -1101,6 +1263,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
ds->dev = base; ds->dev = base;
ds->num_ports = DSA_MAX_PORTS; ds->num_ports = DSA_MAX_PORTS;
ds->ops = &ksz_switch_ops;
swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
if (!swdev) if (!swdev)
...@@ -1116,8 +1279,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) ...@@ -1116,8 +1279,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
} }
EXPORT_SYMBOL(ksz_switch_alloc); EXPORT_SYMBOL(ksz_switch_alloc);
int ksz_switch_register(struct ksz_device *dev, int ksz_switch_register(struct ksz_device *dev)
const struct ksz_dev_ops *ops)
{ {
const struct ksz_chip_data *info; const struct ksz_chip_data *info;
struct device_node *port, *ports; struct device_node *port, *ports;
...@@ -1164,7 +1326,7 @@ int ksz_switch_register(struct ksz_device *dev, ...@@ -1164,7 +1326,7 @@ int ksz_switch_register(struct ksz_device *dev,
if (ret) if (ret)
return ret; return ret;
dev->dev_ops = ops; dev->dev_ops = dev->info->ops;
ret = dev->dev_ops->init(dev); ret = dev->dev_ops->init(dev);
if (ret) if (ret)
...@@ -1236,7 +1398,7 @@ int ksz_switch_register(struct ksz_device *dev, ...@@ -1236,7 +1398,7 @@ int ksz_switch_register(struct ksz_device *dev,
/* Start the MIB timer. */ /* Start the MIB timer. */
schedule_delayed_work(&dev->mib_read, 0); schedule_delayed_work(&dev->mib_read, 0);
return 0; return ret;
} }
EXPORT_SYMBOL(ksz_switch_register); EXPORT_SYMBOL(ksz_switch_register);
......
...@@ -41,12 +41,16 @@ struct ksz_chip_data { ...@@ -41,12 +41,16 @@ struct ksz_chip_data {
int num_statics; int num_statics;
int cpu_ports; int cpu_ports;
int port_cnt; int port_cnt;
const struct ksz_dev_ops *ops;
bool phy_errata_9477; bool phy_errata_9477;
bool ksz87xx_eee_link_erratum; bool ksz87xx_eee_link_erratum;
const struct ksz_mib_names *mib_names; const struct ksz_mib_names *mib_names;
int mib_cnt; int mib_cnt;
u8 reg_mib_cnt; u8 reg_mib_cnt;
int stp_ctrl_reg; int stp_ctrl_reg;
int broadcast_ctrl_reg;
int multicast_ctrl_reg;
int start_ctrl_reg;
bool supports_mii[KSZ_MAX_NUM_PORTS]; bool supports_mii[KSZ_MAX_NUM_PORTS];
bool supports_rmii[KSZ_MAX_NUM_PORTS]; bool supports_rmii[KSZ_MAX_NUM_PORTS];
bool supports_rgmii[KSZ_MAX_NUM_PORTS]; bool supports_rgmii[KSZ_MAX_NUM_PORTS];
...@@ -162,6 +166,7 @@ struct alu_struct { ...@@ -162,6 +166,7 @@ struct alu_struct {
}; };
struct ksz_dev_ops { struct ksz_dev_ops {
int (*setup)(struct dsa_switch *ds);
u32 (*get_port_addr)(int port, int offset); u32 (*get_port_addr)(int port, int offset);
void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member); void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member);
void (*flush_dyn_mac_table)(struct ksz_device *dev, int port); void (*flush_dyn_mac_table)(struct ksz_device *dev, int port);
...@@ -204,74 +209,21 @@ struct ksz_dev_ops { ...@@ -204,74 +209,21 @@ struct ksz_dev_ops {
int (*max_mtu)(struct ksz_device *dev, int port); int (*max_mtu)(struct ksz_device *dev, int port);
void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze);
void (*port_init_cnt)(struct ksz_device *dev, int port); void (*port_init_cnt)(struct ksz_device *dev, int port);
int (*shutdown)(struct ksz_device *dev); void (*config_cpu_port)(struct dsa_switch *ds);
int (*enable_stp_addr)(struct ksz_device *dev);
int (*reset)(struct ksz_device *dev);
int (*init)(struct ksz_device *dev); int (*init)(struct ksz_device *dev);
void (*exit)(struct ksz_device *dev); void (*exit)(struct ksz_device *dev);
}; };
struct ksz_device *ksz_switch_alloc(struct device *base, void *priv); struct ksz_device *ksz_switch_alloc(struct device *base, void *priv);
int ksz_switch_register(struct ksz_device *dev, int ksz_switch_register(struct ksz_device *dev);
const struct ksz_dev_ops *ops);
void ksz_switch_remove(struct ksz_device *dev); void ksz_switch_remove(struct ksz_device *dev);
int ksz8_switch_register(struct ksz_device *dev);
int ksz9477_switch_register(struct ksz_device *dev);
void ksz_init_mib_timer(struct ksz_device *dev); void ksz_init_mib_timer(struct ksz_device *dev);
void ksz_r_mib_stats64(struct ksz_device *dev, int port); void ksz_r_mib_stats64(struct ksz_device *dev, int port);
void ksz_get_stats64(struct dsa_switch *ds, int port,
struct rtnl_link_stats64 *s);
void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
struct phylink_config *config);
extern const struct ksz_chip_data ksz_switch_chips[];
/* Common DSA access functions */
int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg);
int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val);
u32 ksz_get_phy_flags(struct dsa_switch *ds, int port);
void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface);
int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge, bool *tx_fwd_offload,
struct netlink_ext_ack *extack);
void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
void ksz_port_fast_age(struct dsa_switch *ds, int port); extern const struct ksz_chip_data ksz_switch_chips[];
int ksz_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, struct dsa_db db);
int ksz_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, struct dsa_db db);
int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
void *data);
int ksz_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int ksz_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
void ksz_get_strings(struct dsa_switch *ds, int port,
u32 stringset, uint8_t *buf);
enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
int port, enum dsa_tag_protocol mp);
int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
bool flag, struct netlink_ext_ack *extack);
int ksz_port_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack);
int ksz_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
int ksz_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack);
void ksz_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror);
int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu);
int ksz_max_mtu(struct dsa_switch *ds, int port);
/* Common register access functions */ /* Common register access functions */
...@@ -411,6 +363,20 @@ static inline void ksz_regmap_unlock(void *__mtx) ...@@ -411,6 +363,20 @@ static inline void ksz_regmap_unlock(void *__mtx)
#define SW_REV_ID_M GENMASK(7, 4) #define SW_REV_ID_M GENMASK(7, 4)
/* 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 BROADCAST_STORM_RATE_HI 0x07
#define BROADCAST_STORM_RATE_LO 0xFF
#define BROADCAST_STORM_RATE 0x07FF
#define MULTICAST_STORM_DISABLE BIT(6)
#define SW_START 0x01
/* Regmap tables generation */ /* Regmap tables generation */
#define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_RD 3
#define KSZ_SPI_OP_WR 2 #define KSZ_SPI_OP_WR 2
......
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Microchip KSZ8795 series register access through SPI * Microchip ksz series register access through SPI
* *
* Copyright (C) 2017 Microchip Technology Inc. * Copyright (C) 2017 Microchip Technology Inc.
* Tristram Ha <Tristram.Ha@microchip.com> * Tristram Ha <Tristram.Ha@microchip.com>
...@@ -25,13 +25,20 @@ ...@@ -25,13 +25,20 @@
#define KSZ8863_SPI_ADDR_ALIGN 8 #define KSZ8863_SPI_ADDR_ALIGN 8
#define KSZ8863_SPI_TURNAROUND_SHIFT 0 #define KSZ8863_SPI_TURNAROUND_SHIFT 0
#define KSZ9477_SPI_ADDR_SHIFT 24
#define KSZ9477_SPI_ADDR_ALIGN 3
#define KSZ9477_SPI_TURNAROUND_SHIFT 5
KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT, KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN); KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT, KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN); KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
static int ksz8795_spi_probe(struct spi_device *spi) KSZ_REGMAP_TABLE(ksz9477, 32, KSZ9477_SPI_ADDR_SHIFT,
KSZ9477_SPI_TURNAROUND_SHIFT, KSZ9477_SPI_ADDR_ALIGN);
static int ksz_spi_probe(struct spi_device *spi)
{ {
const struct regmap_config *regmap_config; const struct regmap_config *regmap_config;
const struct ksz_chip_data *chip; const struct ksz_chip_data *chip;
...@@ -57,8 +64,12 @@ static int ksz8795_spi_probe(struct spi_device *spi) ...@@ -57,8 +64,12 @@ static int ksz8795_spi_probe(struct spi_device *spi)
if (chip->chip_id == KSZ8830_CHIP_ID) if (chip->chip_id == KSZ8830_CHIP_ID)
regmap_config = ksz8863_regmap_config; regmap_config = ksz8863_regmap_config;
else else if (chip->chip_id == KSZ8795_CHIP_ID ||
chip->chip_id == KSZ8794_CHIP_ID ||
chip->chip_id == KSZ8765_CHIP_ID)
regmap_config = ksz8795_regmap_config; regmap_config = ksz8795_regmap_config;
else
regmap_config = ksz9477_regmap_config;
for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
rc = regmap_config[i]; rc = regmap_config[i];
...@@ -82,7 +93,7 @@ static int ksz8795_spi_probe(struct spi_device *spi) ...@@ -82,7 +93,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
if (ret) if (ret)
return ret; return ret;
ret = ksz8_switch_register(dev); ret = ksz_switch_register(dev);
/* Main DSA driver may not be started yet. */ /* Main DSA driver may not be started yet. */
if (ret) if (ret)
...@@ -93,7 +104,7 @@ static int ksz8795_spi_probe(struct spi_device *spi) ...@@ -93,7 +104,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
return 0; return 0;
} }
static void ksz8795_spi_remove(struct spi_device *spi) static void ksz_spi_remove(struct spi_device *spi)
{ {
struct ksz_device *dev = spi_get_drvdata(spi); struct ksz_device *dev = spi_get_drvdata(spi);
...@@ -103,22 +114,22 @@ static void ksz8795_spi_remove(struct spi_device *spi) ...@@ -103,22 +114,22 @@ static void ksz8795_spi_remove(struct spi_device *spi)
spi_set_drvdata(spi, NULL); spi_set_drvdata(spi, NULL);
} }
static void ksz8795_spi_shutdown(struct spi_device *spi) static void ksz_spi_shutdown(struct spi_device *spi)
{ {
struct ksz_device *dev = spi_get_drvdata(spi); struct ksz_device *dev = spi_get_drvdata(spi);
if (!dev) if (!dev)
return; return;
if (dev->dev_ops->shutdown) if (dev->dev_ops->reset)
dev->dev_ops->shutdown(dev); dev->dev_ops->reset(dev);
dsa_switch_shutdown(dev->ds); dsa_switch_shutdown(dev->ds);
spi_set_drvdata(spi, NULL); spi_set_drvdata(spi, NULL);
} }
static const struct of_device_id ksz8795_dt_ids[] = { static const struct of_device_id ksz_dt_ids[] = {
{ {
.compatible = "microchip,ksz8765", .compatible = "microchip,ksz8765",
.data = &ksz_switch_chips[KSZ8765] .data = &ksz_switch_chips[KSZ8765]
...@@ -139,34 +150,70 @@ static const struct of_device_id ksz8795_dt_ids[] = { ...@@ -139,34 +150,70 @@ static const struct of_device_id ksz8795_dt_ids[] = {
.compatible = "microchip,ksz8873", .compatible = "microchip,ksz8873",
.data = &ksz_switch_chips[KSZ8830] .data = &ksz_switch_chips[KSZ8830]
}, },
{
.compatible = "microchip,ksz9477",
.data = &ksz_switch_chips[KSZ9477]
},
{
.compatible = "microchip,ksz9897",
.data = &ksz_switch_chips[KSZ9897]
},
{
.compatible = "microchip,ksz9893",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz9563",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz8563",
.data = &ksz_switch_chips[KSZ9893]
},
{
.compatible = "microchip,ksz9567",
.data = &ksz_switch_chips[KSZ9567]
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); MODULE_DEVICE_TABLE(of, ksz_dt_ids);
static const struct spi_device_id ksz8795_spi_ids[] = { static const struct spi_device_id ksz_spi_ids[] = {
{ "ksz8765" }, { "ksz8765" },
{ "ksz8794" }, { "ksz8794" },
{ "ksz8795" }, { "ksz8795" },
{ "ksz8863" }, { "ksz8863" },
{ "ksz8873" }, { "ksz8873" },
{ "ksz9477" },
{ "ksz9897" },
{ "ksz9893" },
{ "ksz9563" },
{ "ksz8563" },
{ "ksz9567" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); MODULE_DEVICE_TABLE(spi, ksz_spi_ids);
static struct spi_driver ksz8795_spi_driver = { static struct spi_driver ksz_spi_driver = {
.driver = { .driver = {
.name = "ksz8795-switch", .name = "ksz-switch",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(ksz8795_dt_ids), .of_match_table = of_match_ptr(ksz_dt_ids),
}, },
.id_table = ksz8795_spi_ids, .id_table = ksz_spi_ids,
.probe = ksz8795_spi_probe, .probe = ksz_spi_probe,
.remove = ksz8795_spi_remove, .remove = ksz_spi_remove,
.shutdown = ksz8795_spi_shutdown, .shutdown = ksz_spi_shutdown,
}; };
module_spi_driver(ksz8795_spi_driver); module_spi_driver(ksz_spi_driver);
MODULE_ALIAS("spi:ksz9477");
MODULE_ALIAS("spi:ksz9897");
MODULE_ALIAS("spi:ksz9893");
MODULE_ALIAS("spi:ksz9563");
MODULE_ALIAS("spi:ksz8563");
MODULE_ALIAS("spi:ksz9567");
MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch SPI Driver"); MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment