diff options
author | Paolo Abeni | 2022-06-21 15:26:47 +0200 |
---|---|---|
committer | Paolo Abeni | 2022-06-21 15:26:48 +0200 |
commit | 8720bd951b8e8515ffd995c7631790fdabaa9265 (patch) | |
tree | d11e5c4f72ca0e1ff679c1391eafa0f1649066d4 | |
parent | 00bb2920cf6a6ed14100822f0e7feaf5e53a9795 (diff) | |
parent | 1fe94f542e66b5de526233762ed528e7d3b66ff9 (diff) |
Merge branch 'net-dsa-microchip-common-spi-probe-for-the-ksz-series-switches-part-1'
Arun Ramadoss says:
====================
net: dsa: microchip: common spi probe for the ksz series switches - part 1
This patch series aims to refactor the ksz_switch_register routine to have the
common flow for the ksz series switch. At present ksz8795.c & ksz9477.c have
its own dsa_switch_ops and switch detect functionality.
In ksz_switch_register, ksz_dev_ops is assigned based on the function parameter
passed by the individual ksz8/ksz9477 switch register function. And then switch
detect is performed based on the ksz_dev_ops.detect hook. This patch modifies
the ksz_switch_register such a way that switch detect is performed first, based
on the chip ksz_dev_ops is assigned to ksz_device structure. It ensures the
common flow for the existing as well as LAN937x switches.
In the next series of patch, it will move ksz_dsa_ops and dsa_switch_ops
from ksz8795.c and ksz9477.c to ksz_common.c and have the common spi
probe all the ksz based switches.
Changes in v1
- Splitted the patch series into two.
- Replaced all occurrence of REG_PORT_STATUS_0 and PORT_FIBER_MODE to
KSZ8_PORT_STATUS_0 and KSZ8_PORT_FIBER_MODE.
- Separated the tag protocol and phy read/write patch into two.
- Assigned the DSA_TAG_PROTO_NONE as the default value for get_tag_protocol hook.
- Reduced the indentation level by using the if(!dev->dev_ops->mirror_add).
- Added the stp_ctrl_reg as a member in ksz_chip_data and removed the member
in ksz_dev_ops.
- Removed the r_dyn_mac_table, r_sta_mac_table and w_sta_mac_table from the
ksz_dev_ops since it is used only in the ksz8795.c.
Changes in RFC v2
- Fixed the compilation issue.
- Reduced the patch set to 15.
====================
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://lore.kernel.org/r/20220617084255.19376-1-arun.ramadoss@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r-- | drivers/net/dsa/microchip/ksz8795.c | 233 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz8795_reg.h | 16 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz9477.c | 181 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz9477_reg.h | 1 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz_common.c | 342 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz_common.h | 80 |
6 files changed, 517 insertions, 336 deletions
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 12a599d5e61a..23ed05f4efcc 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -898,29 +898,6 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) } } -static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds, - int port, - enum dsa_tag_protocol mp) -{ - struct ksz_device *dev = ds->priv; - - /* ksz88x3 uses the same tag schema as KSZ9893 */ - return ksz_is_ksz88x3(dev) ? - DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795; -} - -static u32 ksz8_sw_get_phy_flags(struct dsa_switch *ds, int port) -{ - /* Silicon Errata Sheet (DS80000830A): - * Port 1 does not work with LinkMD Cable-Testing. - * Port 1 does not respond to received PAUSE control frames. - */ - if (!port) - return MICREL_KSZ8_P1_ERRATA; - - return 0; -} - static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) { u8 data; @@ -931,11 +908,6 @@ static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) ksz_pwrite8(dev, port, P_MIRROR_CTRL, data); } -static void ksz8_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -{ - ksz_port_stp_state_set(ds, port, state, P_STP_CTRL); -} - static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) { u8 learn[DSA_MAX_PORTS]; @@ -969,11 +941,111 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) } } -static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, - struct netlink_ext_ack *extack) +static int ksz8_fdb_dump(struct ksz_device *dev, int port, + dsa_fdb_dump_cb_t *cb, void *data) { - struct ksz_device *dev = ds->priv; + int ret = 0; + u16 i = 0; + u16 entries = 0; + u8 timestamp = 0; + u8 fid; + u8 member; + struct alu_struct alu; + + do { + alu.is_static = false; + ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member, + ×tamp, &entries); + if (!ret && (member & BIT(port))) { + ret = cb(alu.mac, alu.fid, alu.is_static, data); + if (ret) + break; + } + i++; + } while (i < entries); + if (i >= entries) + ret = 0; + + return ret; +} + +static int ksz8_mdb_add(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) +{ + struct alu_struct alu; + int index; + int empty = 0; + + alu.port_forward = 0; + for (index = 0; index < dev->info->num_statics; index++) { + if (!ksz8_r_sta_mac_table(dev, index, &alu)) { + /* Found one already in static MAC table. */ + if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && + alu.fid == mdb->vid) + break; + /* Remember the first empty entry. */ + } else if (!empty) { + empty = index + 1; + } + } + + /* no available entry */ + if (index == dev->info->num_statics && !empty) + return -ENOSPC; + + /* add entry */ + if (index == dev->info->num_statics) { + index = empty - 1; + memset(&alu, 0, sizeof(alu)); + memcpy(alu.mac, mdb->addr, ETH_ALEN); + alu.is_static = true; + } + alu.port_forward |= BIT(port); + if (mdb->vid) { + alu.is_use_fid = true; + + /* Need a way to map VID to FID. */ + alu.fid = mdb->vid; + } + ksz8_w_sta_mac_table(dev, index, &alu); + + return 0; +} + +static int ksz8_mdb_del(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) +{ + struct alu_struct alu; + int index; + + for (index = 0; index < dev->info->num_statics; index++) { + if (!ksz8_r_sta_mac_table(dev, index, &alu)) { + /* Found one already in static MAC table. */ + if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && + alu.fid == mdb->vid) + break; + } + } + + /* no available entry */ + if (index == dev->info->num_statics) + goto exit; + + /* clear port */ + alu.port_forward &= ~BIT(port); + if (!alu.port_forward) + alu.is_static = false; + ksz8_w_sta_mac_table(dev, index, &alu); +exit: + return 0; +} + +static int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag, + struct netlink_ext_ack *extack) +{ if (ksz_is_ksz88x3(dev)) return -ENOTSUPP; @@ -998,12 +1070,11 @@ static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state) } } -static int ksz8_port_vlan_add(struct dsa_switch *ds, int port, +static int ksz8_port_vlan_add(struct ksz_device *dev, int port, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) { bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; - struct ksz_device *dev = ds->priv; struct ksz_port *p = &dev->ports[port]; u16 data, new_pvid = 0; u8 fid, member, valid; @@ -1071,10 +1142,9 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port, return 0; } -static int ksz8_port_vlan_del(struct dsa_switch *ds, int port, +static int ksz8_port_vlan_del(struct ksz_device *dev, int port, const struct switchdev_obj_port_vlan *vlan) { - struct ksz_device *dev = ds->priv; u16 data, pvid; u8 fid, member, valid; @@ -1104,12 +1174,10 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port, return 0; } -static int ksz8_port_mirror_add(struct dsa_switch *ds, int port, +static 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) { - struct ksz_device *dev = ds->priv; - if (ingress) { ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); dev->mirror_rx |= BIT(port); @@ -1128,10 +1196,9 @@ static int ksz8_port_mirror_add(struct dsa_switch *ds, int port, return 0; } -static void ksz8_port_mirror_del(struct dsa_switch *ds, int port, +static void ksz8_port_mirror_del(struct ksz_device *dev, int port, struct dsa_mall_mirror_tc_entry *mirror) { - struct ksz_device *dev = ds->priv; u8 data; if (mirror->ingress) { @@ -1258,7 +1325,7 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds) for (i = 0; i < dev->phy_port_cnt; i++) { p = &dev->ports[i]; - ksz8_port_stp_state_set(ds, i, BR_STATE_DISABLED); + ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); /* Last port may be disabled. */ if (i == dev->phy_port_cnt) @@ -1272,7 +1339,7 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds) continue; if (!ksz_is_ksz88x3(dev)) { ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); - if (remote & PORT_FIBER_MODE) + if (remote & KSZ8_PORT_FIBER_MODE) p->fiber = 1; } if (p->fiber) @@ -1371,13 +1438,9 @@ static int ksz8_setup(struct dsa_switch *ds) return ksz8_handle_global_errata(ds); } -static void ksz8_get_caps(struct dsa_switch *ds, int port, +static void ksz8_get_caps(struct ksz_device *dev, int port, struct phylink_config *config) { - struct ksz_device *dev = ds->priv; - - ksz_phylink_get_caps(ds, port, config); - config->mac_capabilities = MAC_10 | MAC_100; /* Silicon Errata Sheet (DS80000830A): @@ -1394,12 +1457,12 @@ static void ksz8_get_caps(struct dsa_switch *ds, int port, } static const struct dsa_switch_ops ksz8_switch_ops = { - .get_tag_protocol = ksz8_get_tag_protocol, - .get_phy_flags = ksz8_sw_get_phy_flags, + .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 = ksz8_get_caps, + .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, @@ -1407,16 +1470,16 @@ static const struct dsa_switch_ops ksz8_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_stp_state_set = ksz8_port_stp_state_set, + .port_stp_state_set = ksz_port_stp_state_set, .port_fast_age = ksz_port_fast_age, - .port_vlan_filtering = ksz8_port_vlan_filtering, - .port_vlan_add = ksz8_port_vlan_add, - .port_vlan_del = ksz8_port_vlan_del, + .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 = ksz8_port_mirror_add, - .port_mirror_del = ksz8_port_mirror_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) @@ -1424,51 +1487,6 @@ static u32 ksz8_get_port_addr(int port, int offset) return PORT_CTRL_ADDR(port, offset); } -static int ksz8_switch_detect(struct ksz_device *dev) -{ - u8 id1, id2; - u16 id16; - int ret; - - /* read chip id */ - ret = ksz_read16(dev, REG_CHIP_ID0, &id16); - if (ret) - return ret; - - id1 = id16 >> 8; - id2 = id16 & SW_CHIP_ID_M; - - switch (id1) { - case KSZ87_FAMILY_ID: - if ((id2 != CHIP_ID_94 && id2 != CHIP_ID_95)) - return -ENODEV; - - if (id2 == CHIP_ID_95) { - u8 val; - - id2 = 0x95; - ksz_read8(dev, REG_PORT_STATUS_0, &val); - if (val & PORT_FIBER_MODE) - id2 = 0x65; - } else if (id2 == CHIP_ID_94) { - id2 = 0x94; - } - break; - case KSZ88_FAMILY_ID: - if (id2 != CHIP_ID_63) - return -ENODEV; - break; - default: - dev_err(dev->dev, "invalid family id: %d\n", id1); - return -ENODEV; - } - id16 &= ~0xff; - id16 |= id2; - dev->chip_id = id16; - - return 0; -} - static int ksz8_switch_init(struct ksz_device *dev) { struct ksz8 *ksz8 = dev->priv; @@ -1514,15 +1532,20 @@ static const struct ksz_dev_ops ksz8_dev_ops = { .port_setup = ksz8_port_setup, .r_phy = ksz8_r_phy, .w_phy = ksz8_w_phy, - .r_dyn_mac_table = ksz8_r_dyn_mac_table, - .r_sta_mac_table = ksz8_r_sta_mac_table, - .w_sta_mac_table = ksz8_w_sta_mac_table, .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, - .detect = ksz8_switch_detect, .init = ksz8_switch_init, .exit = ksz8_switch_exit, }; diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index 4109433b6b6c..b8f6ad7581bc 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -14,23 +14,10 @@ #define KS_PRIO_M 0x3 #define KS_PRIO_S 2 -#define REG_CHIP_ID0 0x00 - -#define KSZ87_FAMILY_ID 0x87 -#define KSZ88_FAMILY_ID 0x88 - -#define REG_CHIP_ID1 0x01 - -#define SW_CHIP_ID_M 0xF0 -#define SW_CHIP_ID_S 4 #define SW_REVISION_M 0x0E #define SW_REVISION_S 1 #define SW_START 0x01 -#define CHIP_ID_94 0x60 -#define CHIP_ID_95 0x90 -#define CHIP_ID_63 0x30 - #define KSZ8863_REG_SW_RESET 0x43 #define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4) @@ -217,8 +204,6 @@ #define REG_PORT_4_STATUS_0 0x48 /* For KSZ8765. */ -#define PORT_FIBER_MODE BIT(7) - #define PORT_REMOTE_ASYM_PAUSE BIT(5) #define PORT_REMOTE_SYM_PAUSE BIT(4) #define PORT_REMOTE_100BTX_FD BIT(3) @@ -322,7 +307,6 @@ #define REG_PORT_CTRL_5 0x05 -#define REG_PORT_STATUS_0 0x08 #define REG_PORT_STATUS_1 0x09 #define REG_PORT_LINK_MD_CTRL 0x0A #define REG_PORT_LINK_MD_RESULT 0x0B diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index ab40b700cf1a..5b4fc16e1692 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -47,9 +47,8 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, bits, set ? bits : 0); } -static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu) +static int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) { - struct ksz_device *dev = ds->priv; u16 frame_size, max_frame = 0; int i; @@ -65,7 +64,7 @@ static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu) REG_SW_MTU_MASK, max_frame); } -static int ksz9477_max_mtu(struct dsa_switch *ds, int port) +static int ksz9477_max_mtu(struct ksz_device *dev, int port) { return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; } @@ -276,21 +275,8 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) mutex_unlock(&mib->cnt_mutex); } -static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds, - int port, - enum dsa_tag_protocol mp) -{ - enum dsa_tag_protocol proto = DSA_TAG_PROTO_KSZ9477; - struct ksz_device *dev = ds->priv; - - if (dev->features & IS_9893) - proto = DSA_TAG_PROTO_KSZ9893; - return proto; -} - -static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg) +static void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) { - struct ksz_device *dev = ds->priv; u16 val = 0xffff; /* No real PHY after this. Simulate the PHY. @@ -335,24 +321,20 @@ static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg) ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); } - return val; + *data = val; } -static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg, - u16 val) +static void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { - struct ksz_device *dev = ds->priv; - /* No real PHY after this. */ if (addr >= dev->phy_port_cnt) - return 0; + return; /* No gigabit support. Do not write to this register. */ if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000) - return 0; - ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + return; - return 0; + ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); } static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, @@ -361,12 +343,6 @@ static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); } -static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port, - u8 state) -{ - ksz_port_stp_state_set(ds, port, state, P_STP_CTRL); -} - static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) { u8 data; @@ -389,12 +365,10 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) } } -static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, +static int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port, bool flag, struct netlink_ext_ack *extack) { - struct ksz_device *dev = ds->priv; - if (flag) { ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, PORT_VLAN_LOOKUP_VID_0, true); @@ -408,11 +382,10 @@ static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, return 0; } -static int ksz9477_port_vlan_add(struct dsa_switch *ds, int port, +static int ksz9477_port_vlan_add(struct ksz_device *dev, int port, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) { - struct ksz_device *dev = ds->priv; u32 vlan_table[3]; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; int err; @@ -445,10 +418,9 @@ static int ksz9477_port_vlan_add(struct dsa_switch *ds, int port, return 0; } -static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port, +static int ksz9477_port_vlan_del(struct ksz_device *dev, int port, const struct switchdev_obj_port_vlan *vlan) { - struct ksz_device *dev = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; u32 vlan_table[3]; u16 pvid; @@ -479,11 +451,10 @@ static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port, return 0; } -static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid, - struct dsa_db db) +static int ksz9477_fdb_add(struct ksz_device *dev, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) { - struct ksz_device *dev = ds->priv; u32 alu_table[4]; u32 data; int ret = 0; @@ -537,11 +508,10 @@ exit: return ret; } -static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid, - struct dsa_db db) +static int ksz9477_fdb_del(struct ksz_device *dev, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) { - struct ksz_device *dev = ds->priv; u32 alu_table[4]; u32 data; int ret = 0; @@ -628,10 +598,9 @@ static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table) alu->mac[5] = alu_table[3] & 0xFF; } -static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port, - dsa_fdb_dump_cb_t *cb, void *data) +static int ksz9477_fdb_dump(struct ksz_device *dev, int port, + dsa_fdb_dump_cb_t *cb, void *data) { - struct ksz_device *dev = ds->priv; int ret = 0; u32 ksz_data; u32 alu_table[4]; @@ -680,11 +649,10 @@ exit: return ret; } -static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb, - struct dsa_db db) +static int ksz9477_mdb_add(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) { - struct ksz_device *dev = ds->priv; u32 static_table[4]; u32 data; int index; @@ -756,11 +724,10 @@ exit: return err; } -static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb, - struct dsa_db db) +static int ksz9477_mdb_del(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) { - struct ksz_device *dev = ds->priv; u32 static_table[4]; u32 data; int index; @@ -832,11 +799,10 @@ exit: return ret; } -static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port, +static 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) { - struct ksz_device *dev = ds->priv; u8 data; int p; @@ -872,10 +838,9 @@ static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port, return 0; } -static void ksz9477_port_mirror_del(struct dsa_switch *ds, int port, +static void ksz9477_port_mirror_del(struct ksz_device *dev, int port, struct dsa_mall_mirror_tc_entry *mirror) { - struct ksz_device *dev = ds->priv; bool in_use = false; u8 data; int p; @@ -1097,11 +1062,9 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee); } -static void ksz9477_get_caps(struct dsa_switch *ds, int port, +static void ksz9477_get_caps(struct ksz_device *dev, int port, struct phylink_config *config) { - ksz_phylink_get_caps(ds, port, config); - config->mac_capabilities = MAC_10 | MAC_100 | MAC_1000FD | MAC_ASYM_PAUSE | MAC_SYM_PAUSE; } @@ -1260,7 +1223,7 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds) continue; p = &dev->ports[i]; - ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED); + ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); p->on = 1; if (i < dev->phy_port_cnt) p->phy = 1; @@ -1326,33 +1289,33 @@ static int ksz9477_setup(struct dsa_switch *ds) } static const struct dsa_switch_ops ksz9477_switch_ops = { - .get_tag_protocol = ksz9477_get_tag_protocol, + .get_tag_protocol = ksz_get_tag_protocol, .setup = ksz9477_setup, - .phy_read = ksz9477_phy_read16, - .phy_write = ksz9477_phy_write16, + .phy_read = ksz_phy_read16, + .phy_write = ksz_phy_write16, .phylink_mac_link_down = ksz_mac_link_down, - .phylink_get_caps = ksz9477_get_caps, + .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 = ksz9477_port_stp_state_set, + .port_stp_state_set = ksz_port_stp_state_set, .port_fast_age = ksz_port_fast_age, - .port_vlan_filtering = ksz9477_port_vlan_filtering, - .port_vlan_add = ksz9477_port_vlan_add, - .port_vlan_del = ksz9477_port_vlan_del, - .port_fdb_dump = ksz9477_port_fdb_dump, - .port_fdb_add = ksz9477_port_fdb_add, - .port_fdb_del = ksz9477_port_fdb_del, - .port_mdb_add = ksz9477_port_mdb_add, - .port_mdb_del = ksz9477_port_mdb_del, - .port_mirror_add = ksz9477_port_mirror_add, - .port_mirror_del = ksz9477_port_mirror_del, + .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 = ksz9477_change_mtu, - .port_max_mtu = ksz9477_max_mtu, + .port_change_mtu = ksz_change_mtu, + .port_max_mtu = ksz_max_mtu, }; static u32 ksz9477_get_port_addr(int port, int offset) @@ -1360,14 +1323,15 @@ static u32 ksz9477_get_port_addr(int port, int offset) return PORT_CTRL_ADDR(port, offset); } -static int ksz9477_switch_detect(struct ksz_device *dev) +static int ksz9477_switch_init(struct ksz_device *dev) { u8 data8; - u8 id_hi; - u8 id_lo; - u32 id32; int ret; + dev->ds->ops = &ksz9477_switch_ops; + + dev->port_mask = (1 << dev->info->port_cnt) - 1; + /* turn off SPI DO Edge select */ ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); if (ret) @@ -1378,10 +1342,6 @@ static int ksz9477_switch_detect(struct ksz_device *dev) if (ret) return ret; - /* read chip id */ - ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32); - if (ret) - return ret; ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8); if (ret) return ret; @@ -1392,12 +1352,7 @@ static int ksz9477_switch_detect(struct ksz_device *dev) /* Default capability is gigabit capable. */ dev->features = GBIT_SUPPORT; - dev_dbg(dev->dev, "Switch detect: ID=%08x%02x\n", id32, data8); - id_hi = (u8)(id32 >> 16); - id_lo = (u8)(id32 >> 8); - if ((id_lo & 0xf) == 3) { - /* Chip is from KSZ9893 design. */ - dev_info(dev->dev, "Found KSZ9893\n"); + if (dev->chip_id == KSZ9893_CHIP_ID) { dev->features |= IS_9893; /* Chip does not support gigabit. */ @@ -1405,7 +1360,6 @@ static int ksz9477_switch_detect(struct ksz_device *dev) dev->features &= ~GBIT_SUPPORT; dev->phy_port_cnt = 2; } else { - dev_info(dev->dev, "Found KSZ9477 or compatible\n"); /* Chip uses new XMII register definitions. */ dev->features |= NEW_XMII; @@ -1413,21 +1367,6 @@ static int ksz9477_switch_detect(struct ksz_device *dev) if (!(data8 & SW_GIGABIT_ABLE)) dev->features &= ~GBIT_SUPPORT; } - - /* Change chip id to known ones so it can be matched against them. */ - id32 = (id_hi << 16) | (id_lo << 8); - - dev->chip_id = id32; - - return 0; -} - -static int ksz9477_switch_init(struct ksz_device *dev) -{ - dev->ds->ops = &ksz9477_switch_ops; - - dev->port_mask = (1 << dev->info->port_cnt) - 1; - return 0; } @@ -1441,13 +1380,27 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { .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, - .detect = ksz9477_switch_detect, .init = ksz9477_switch_init, .exit = ksz9477_switch_exit, }; diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h b/drivers/net/dsa/microchip/ksz9477_reg.h index 7a2c8d4767af..077e35ab11b5 100644 --- a/drivers/net/dsa/microchip/ksz9477_reg.h +++ b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -25,7 +25,6 @@ #define REG_CHIP_ID2__1 0x0002 -#define CHIP_ID_63 0x63 #define CHIP_ID_66 0x66 #define CHIP_ID_67 0x67 #define CHIP_ID_77 0x77 diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 9ca8c8d7740f..3fc401959f00 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -16,6 +16,7 @@ #include <linux/if_bridge.h> #include <linux/of_device.h> #include <linux/of_net.h> +#include <linux/micrel_phy.h> #include <net/dsa.h> #include <net/switchdev.h> @@ -151,6 +152,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x02, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -183,6 +185,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x02, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -201,6 +204,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x02, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -218,6 +222,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz88xx_mib_names, .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x02, .supports_mii = {false, false, true}, .supports_rmii = {false, false, true}, .internal_phy = {true, true, false}, @@ -235,6 +240,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, false, true, false}, .supports_rmii = {false, false, false, false, @@ -257,6 +263,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, @@ -278,6 +285,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, true}, .supports_rmii = {false, false, true}, .supports_rgmii = {false, false, true}, @@ -296,6 +304,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, @@ -317,6 +326,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -334,6 +344,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, true, true}, .supports_rgmii = {false, false, false, false, true, true}, @@ -351,6 +362,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -372,6 +384,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -393,6 +406,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, + .stp_ctrl_reg = 0x0B04, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -456,6 +470,9 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port, if (dev->info->internal_phy[port]) __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); + + if (dev->dev_ops->get_caps) + dev->dev_ops->get_caps(dev, port, config); } EXPORT_SYMBOL_GPL(ksz_phylink_get_caps); @@ -532,7 +549,7 @@ void ksz_get_strings(struct dsa_switch *ds, int port, } EXPORT_SYMBOL_GPL(ksz_get_strings); -void ksz_update_port_member(struct ksz_device *dev, int port) +static void ksz_update_port_member(struct ksz_device *dev, int port) { struct ksz_port *p = &dev->ports[port]; struct dsa_switch *ds = dev->ds; @@ -589,7 +606,6 @@ void ksz_update_port_member(struct ksz_device *dev, int port) dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); } -EXPORT_SYMBOL_GPL(ksz_update_port_member); static void port_r_cnt(struct ksz_device *dev, int port) { @@ -690,6 +706,23 @@ int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) } EXPORT_SYMBOL_GPL(ksz_phy_write16); +u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + + if (dev->chip_id == KSZ8830_CHIP_ID) { + /* Silicon Errata Sheet (DS80000830A): + * Port 1 does not work with LinkMD Cable-Testing. + * Port 1 does not respond to received PAUSE control frames. + */ + if (!port) + return MICREL_KSZ8_P1_ERRATA; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ksz_get_phy_flags); + void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) { @@ -763,34 +796,39 @@ void ksz_port_fast_age(struct dsa_switch *ds, int port) } EXPORT_SYMBOL_GPL(ksz_port_fast_age); +int ksz_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, struct dsa_db db) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->fdb_add) + return -EOPNOTSUPP; + + 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, + const unsigned char *addr, u16 vid, struct dsa_db db) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->fdb_del) + return -EOPNOTSUPP; + + 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, void *data) { struct ksz_device *dev = ds->priv; - int ret = 0; - u16 i = 0; - u16 entries = 0; - u8 timestamp = 0; - u8 fid; - u8 member; - struct alu_struct alu; - - do { - alu.is_static = false; - ret = dev->dev_ops->r_dyn_mac_table(dev, i, alu.mac, &fid, - &member, ×tamp, - &entries); - if (!ret && (member & BIT(port))) { - ret = cb(alu.mac, alu.fid, alu.is_static, data); - if (ret) - break; - } - i++; - } while (i < entries); - if (i >= entries) - ret = 0; - return ret; + if (!dev->dev_ops->fdb_dump) + return -EOPNOTSUPP; + + return dev->dev_ops->fdb_dump(dev, port, cb, data); } EXPORT_SYMBOL_GPL(ksz_port_fdb_dump); @@ -799,44 +837,11 @@ int ksz_port_mdb_add(struct dsa_switch *ds, int port, struct dsa_db db) { struct ksz_device *dev = ds->priv; - struct alu_struct alu; - int index; - int empty = 0; - - alu.port_forward = 0; - for (index = 0; index < dev->info->num_statics; index++) { - if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) { - /* Found one already in static MAC table. */ - if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && - alu.fid == mdb->vid) - break; - /* Remember the first empty entry. */ - } else if (!empty) { - empty = index + 1; - } - } - - /* no available entry */ - if (index == dev->info->num_statics && !empty) - return -ENOSPC; - /* add entry */ - if (index == dev->info->num_statics) { - index = empty - 1; - memset(&alu, 0, sizeof(alu)); - memcpy(alu.mac, mdb->addr, ETH_ALEN); - alu.is_static = true; - } - alu.port_forward |= BIT(port); - if (mdb->vid) { - alu.is_use_fid = true; + if (!dev->dev_ops->mdb_add) + return -EOPNOTSUPP; - /* Need a way to map VID to FID. */ - alu.fid = mdb->vid; - } - dev->dev_ops->w_sta_mac_table(dev, index, &alu); - - return 0; + return dev->dev_ops->mdb_add(dev, port, mdb, db); } EXPORT_SYMBOL_GPL(ksz_port_mdb_add); @@ -845,30 +850,11 @@ int ksz_port_mdb_del(struct dsa_switch *ds, int port, struct dsa_db db) { struct ksz_device *dev = ds->priv; - struct alu_struct alu; - int index; - - for (index = 0; index < dev->info->num_statics; index++) { - if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) { - /* Found one already in static MAC table. */ - if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && - alu.fid == mdb->vid) - break; - } - } - - /* no available entry */ - if (index == dev->info->num_statics) - goto exit; - /* clear port */ - alu.port_forward &= ~BIT(port); - if (!alu.port_forward) - alu.is_static = false; - dev->dev_ops->w_sta_mac_table(dev, index, &alu); + if (!dev->dev_ops->mdb_del) + return -EOPNOTSUPP; -exit: - return 0; + return dev->dev_ops->mdb_del(dev, port, mdb, db); } EXPORT_SYMBOL_GPL(ksz_port_mdb_del); @@ -890,12 +876,14 @@ int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) } EXPORT_SYMBOL_GPL(ksz_enable_port); -void ksz_port_stp_state_set(struct dsa_switch *ds, int port, - u8 state, int reg) +void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { struct ksz_device *dev = ds->priv; struct ksz_port *p; u8 data; + int reg; + + reg = dev->info->stp_ctrl_reg; ksz_pread8(dev, port, reg, &data); data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); @@ -930,6 +918,178 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, } EXPORT_SYMBOL_GPL(ksz_port_stp_state_set); +enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, + int port, enum dsa_tag_protocol mp) +{ + struct ksz_device *dev = ds->priv; + enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE; + + if (dev->chip_id == KSZ8795_CHIP_ID || + dev->chip_id == KSZ8794_CHIP_ID || + dev->chip_id == KSZ8765_CHIP_ID) + proto = DSA_TAG_PROTO_KSZ8795; + + if (dev->chip_id == KSZ8830_CHIP_ID || + dev->chip_id == KSZ9893_CHIP_ID) + proto = DSA_TAG_PROTO_KSZ9893; + + if (dev->chip_id == KSZ9477_CHIP_ID || + dev->chip_id == KSZ9897_CHIP_ID || + dev->chip_id == KSZ9567_CHIP_ID) + proto = DSA_TAG_PROTO_KSZ9477; + + return proto; +} +EXPORT_SYMBOL_GPL(ksz_get_tag_protocol); + +int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, + bool flag, struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->vlan_filtering) + return -EOPNOTSUPP; + + 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, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->vlan_add) + return -EOPNOTSUPP; + + 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, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->vlan_del) + return -EOPNOTSUPP; + + 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, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress, struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->mirror_add) + return -EOPNOTSUPP; + + 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, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct ksz_device *dev = ds->priv; + + if (dev->dev_ops->mirror_del) + 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) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->change_mtu) + return -EOPNOTSUPP; + + 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) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->max_mtu) + return -EOPNOTSUPP; + + return dev->dev_ops->max_mtu(dev, port); +} +EXPORT_SYMBOL_GPL(ksz_max_mtu); + +static int ksz_switch_detect(struct ksz_device *dev) +{ + u8 id1, id2; + u16 id16; + u32 id32; + int ret; + + /* read chip id */ + ret = ksz_read16(dev, REG_CHIP_ID0, &id16); + if (ret) + return ret; + + id1 = FIELD_GET(SW_FAMILY_ID_M, id16); + id2 = FIELD_GET(SW_CHIP_ID_M, id16); + + switch (id1) { + case KSZ87_FAMILY_ID: + if (id2 == KSZ87_CHIP_ID_95) { + u8 val; + + dev->chip_id = KSZ8795_CHIP_ID; + + ksz_read8(dev, KSZ8_PORT_STATUS_0, &val); + if (val & KSZ8_PORT_FIBER_MODE) + dev->chip_id = KSZ8765_CHIP_ID; + } else if (id2 == KSZ87_CHIP_ID_94) { + dev->chip_id = KSZ8794_CHIP_ID; + } else { + return -ENODEV; + } + break; + case KSZ88_FAMILY_ID: + if (id2 == KSZ88_CHIP_ID_63) + dev->chip_id = KSZ8830_CHIP_ID; + else + return -ENODEV; + break; + default: + ret = ksz_read32(dev, REG_CHIP_ID0, &id32); + if (ret) + return ret; + + dev->chip_rev = FIELD_GET(SW_REV_ID_M, id32); + id32 &= ~0xFF; + + switch (id32) { + case KSZ9477_CHIP_ID: + case KSZ9897_CHIP_ID: + case KSZ9893_CHIP_ID: + case KSZ9567_CHIP_ID: + case LAN9370_CHIP_ID: + case LAN9371_CHIP_ID: + case LAN9372_CHIP_ID: + case LAN9373_CHIP_ID: + case LAN9374_CHIP_ID: + dev->chip_id = id32; + break; + default: + dev_err(dev->dev, + "unsupported switch detected %x)\n", id32); + return -ENODEV; + } + } + return 0; +} + struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) { struct dsa_switch *ds; @@ -986,10 +1146,9 @@ int ksz_switch_register(struct ksz_device *dev, mutex_init(&dev->alu_mutex); mutex_init(&dev->vlan_mutex); - dev->dev_ops = ops; - - if (dev->dev_ops->detect(dev)) - return -EINVAL; + ret = ksz_switch_detect(dev); + if (ret) + return ret; info = ksz_lookup_info(dev->chip_id); if (!info) @@ -998,10 +1157,15 @@ int ksz_switch_register(struct ksz_device *dev, /* Update the compatible info with the probed one */ dev->info = info; + dev_info(dev->dev, "found switch: %s, rev %i\n", + dev->info->dev_name, dev->chip_rev); + ret = ksz_check_device_id(dev); if (ret) return ret; + dev->dev_ops = ops; + ret = dev->dev_ops->init(dev); if (ret) return ret; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 8500eaedad67..ebcfa688ea2c 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -46,6 +46,7 @@ struct ksz_chip_data { const struct ksz_mib_names *mib_names; int mib_cnt; u8 reg_mib_cnt; + int stp_ctrl_reg; bool supports_mii[KSZ_MAX_NUM_PORTS]; bool supports_rmii[KSZ_MAX_NUM_PORTS]; bool supports_rgmii[KSZ_MAX_NUM_PORTS]; @@ -90,6 +91,7 @@ struct ksz_device { /* chip specific data */ u32 chip_id; + u8 chip_rev; int cpu_port; /* port connected to CPU */ int phy_port_cnt; phy_interface_t compat_interface; @@ -167,22 +169,42 @@ struct ksz_dev_ops { void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); void (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); void (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); - int (*r_dyn_mac_table)(struct ksz_device *dev, u16 addr, u8 *mac_addr, - u8 *fid, u8 *src_port, u8 *timestamp, - u16 *entries); - int (*r_sta_mac_table)(struct ksz_device *dev, u16 addr, - struct alu_struct *alu); - void (*w_sta_mac_table)(struct ksz_device *dev, u16 addr, - struct alu_struct *alu); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, u64 *dropped, u64 *cnt); void (*r_mib_stat64)(struct ksz_device *dev, int port); + int (*vlan_filtering)(struct ksz_device *dev, int port, + bool flag, struct netlink_ext_ack *extack); + int (*vlan_add)(struct ksz_device *dev, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack); + int (*vlan_del)(struct ksz_device *dev, int port, + const struct switchdev_obj_port_vlan *vlan); + int (*mirror_add)(struct ksz_device *dev, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress, struct netlink_ext_ack *extack); + void (*mirror_del)(struct ksz_device *dev, int port, + struct dsa_mall_mirror_tc_entry *mirror); + int (*fdb_add)(struct ksz_device *dev, int port, + const unsigned char *addr, u16 vid, struct dsa_db db); + int (*fdb_del)(struct ksz_device *dev, int port, + const unsigned char *addr, u16 vid, struct dsa_db db); + int (*fdb_dump)(struct ksz_device *dev, int port, + dsa_fdb_dump_cb_t *cb, void *data); + int (*mdb_add)(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db); + int (*mdb_del)(struct ksz_device *dev, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db); + void (*get_caps)(struct ksz_device *dev, int port, + struct phylink_config *config); + int (*change_mtu)(struct ksz_device *dev, int port, int mtu); + int (*max_mtu)(struct ksz_device *dev, int port); void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); void (*port_init_cnt)(struct ksz_device *dev, int port); int (*shutdown)(struct ksz_device *dev); - int (*detect)(struct ksz_device *dev); int (*init)(struct ksz_device *dev); void (*exit)(struct ksz_device *dev); }; @@ -195,7 +217,6 @@ 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_update_port_member(struct ksz_device *dev, int port); void ksz_init_mib_timer(struct ksz_device *dev); void ksz_r_mib_stats64(struct ksz_device *dev, int port); void ksz_get_stats64(struct dsa_switch *ds, int port, @@ -208,6 +229,7 @@ extern const struct ksz_chip_data ksz_switch_chips[]; 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); @@ -217,9 +239,12 @@ int ksz_port_bridge_join(struct dsa_switch *ds, int port, 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, int reg); +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); +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, @@ -231,6 +256,22 @@ int ksz_port_mdb_del(struct dsa_switch *ds, int port, 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 */ @@ -353,6 +394,23 @@ static inline void ksz_regmap_unlock(void *__mtx) #define PORT_RX_ENABLE BIT(1) #define PORT_LEARN_DISABLE BIT(0) +/* Switch ID Defines */ +#define REG_CHIP_ID0 0x00 + +#define SW_FAMILY_ID_M GENMASK(15, 8) +#define KSZ87_FAMILY_ID 0x87 +#define KSZ88_FAMILY_ID 0x88 + +#define KSZ8_PORT_STATUS_0 0x08 +#define KSZ8_PORT_FIBER_MODE BIT(7) + +#define SW_CHIP_ID_M GENMASK(7, 4) +#define KSZ87_CHIP_ID_94 0x6 +#define KSZ87_CHIP_ID_95 0x9 +#define KSZ88_CHIP_ID_63 0x3 + +#define SW_REV_ID_M GENMASK(7, 4) + /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 |