Commit 8720bd95 authored by Paolo Abeni's avatar Paolo Abeni

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: default avatarVladimir Oltean <olteanv@gmail.com>
Link: https://lore.kernel.org/r/20220617084255.19376-1-arun.ramadoss@microchip.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 00bb2920 1fe94f54
......@@ -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,
&timestamp, &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,
};
......
......@@ -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
......
......@@ -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,
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 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
return ret;
}
static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port,
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,
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 @@ static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port,
return ret;
}
static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
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 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
return err;
}
static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
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 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
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,
};
......
......@@ -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
......
......@@ -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, &timestamp,
&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;
if (!dev->dev_ops->mdb_del)
return -EOPNOTSUPP;
/* 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);
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;
......
......@@ -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
......
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