summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/ocelot
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/ocelot')
-rw-r--r--drivers/net/dsa/ocelot/felix.c255
-rw-r--r--drivers/net/dsa/ocelot/felix.h16
-rw-r--r--drivers/net/dsa/ocelot/felix_vsc9959.c845
-rw-r--r--drivers/net/dsa/ocelot/seville_vsc9953.c518
4 files changed, 558 insertions, 1076 deletions
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index aadb0bd7c24f..dd3a18cc89dd 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -42,6 +42,25 @@ static struct net_device *felix_classify_db(struct dsa_db db)
}
}
+static int felix_cpu_port_for_master(struct dsa_switch *ds,
+ struct net_device *master)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct dsa_port *cpu_dp;
+ int lag;
+
+ if (netif_is_lag_master(master)) {
+ mutex_lock(&ocelot->fwd_domain_lock);
+ lag = ocelot_bond_get_id(ocelot, master);
+ mutex_unlock(&ocelot->fwd_domain_lock);
+
+ return lag;
+ }
+
+ cpu_dp = master->dsa_ptr;
+ return cpu_dp->index;
+}
+
/* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that
* the tagger can perform RX source port identification.
*/
@@ -422,6 +441,40 @@ static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds)
return BIT(ocelot->num_phys_ports);
}
+static int felix_tag_npi_change_master(struct dsa_switch *ds, int port,
+ struct net_device *master,
+ struct netlink_ext_ack *extack)
+{
+ struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
+ struct ocelot *ocelot = ds->priv;
+
+ if (netif_is_lag_master(master)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "LAG DSA master only supported using ocelot-8021q");
+ return -EOPNOTSUPP;
+ }
+
+ /* Changing the NPI port breaks user ports still assigned to the old
+ * one, so only allow it while they're down, and don't allow them to
+ * come back up until they're all changed to the new one.
+ */
+ dsa_switch_for_each_user_port(other_dp, ds) {
+ struct net_device *slave = other_dp->slave;
+
+ if (other_dp != dp && (slave->flags & IFF_UP) &&
+ dsa_port_to_master(other_dp) != master) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot change while old master still has users");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ felix_npi_port_deinit(ocelot, ocelot->npi);
+ felix_npi_port_init(ocelot, felix_cpu_port_for_master(ds, master));
+
+ return 0;
+}
+
/* Alternatively to using the NPI functionality, that same hardware MAC
* connected internally to the enetc or fman DSA master can be configured to
* use the software-defined tag_8021q frame format. As far as the hardware is
@@ -433,6 +486,7 @@ static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = {
.setup = felix_tag_npi_setup,
.teardown = felix_tag_npi_teardown,
.get_host_fwd_mask = felix_tag_npi_get_host_fwd_mask,
+ .change_master = felix_tag_npi_change_master,
};
static int felix_tag_8021q_setup(struct dsa_switch *ds)
@@ -445,6 +499,9 @@ static int felix_tag_8021q_setup(struct dsa_switch *ds)
if (err)
return err;
+ dsa_switch_for_each_cpu_port(dp, ds)
+ ocelot_port_setup_dsa_8021q_cpu(ocelot, dp->index);
+
dsa_switch_for_each_user_port(dp, ds)
ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index,
dp->cpu_dp->index);
@@ -493,6 +550,9 @@ static void felix_tag_8021q_teardown(struct dsa_switch *ds)
dsa_switch_for_each_user_port(dp, ds)
ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index);
+ dsa_switch_for_each_cpu_port(dp, ds)
+ ocelot_port_teardown_dsa_8021q_cpu(ocelot, dp->index);
+
dsa_tag_8021q_unregister(ds);
}
@@ -501,10 +561,24 @@ static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds)
return dsa_cpu_ports(ds);
}
+static int felix_tag_8021q_change_master(struct dsa_switch *ds, int port,
+ struct net_device *master,
+ struct netlink_ext_ack *extack)
+{
+ int cpu = felix_cpu_port_for_master(ds, master);
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_unassign_dsa_8021q_cpu(ocelot, port);
+ ocelot_port_assign_dsa_8021q_cpu(ocelot, port, cpu);
+
+ return felix_update_trapping_destinations(ds, true);
+}
+
static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = {
.setup = felix_tag_8021q_setup,
.teardown = felix_tag_8021q_teardown,
.get_host_fwd_mask = felix_tag_8021q_get_host_fwd_mask,
+ .change_master = felix_tag_8021q_change_master,
};
static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask,
@@ -667,6 +741,16 @@ static void felix_port_set_host_flood(struct dsa_switch *ds, int port,
!!felix->host_flood_mc_mask, true);
}
+static int felix_port_change_master(struct dsa_switch *ds, int port,
+ struct net_device *master,
+ struct netlink_ext_ack *extack)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ return felix->tag_proto_ops->change_master(ds, port, master, extack);
+}
+
static int felix_set_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time)
{
@@ -855,11 +939,21 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port,
static int felix_lag_join(struct dsa_switch *ds, int port,
struct dsa_lag lag,
- struct netdev_lag_upper_info *info)
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
+ int err;
+
+ err = ocelot_port_lag_join(ocelot, port, lag.dev, info, extack);
+ if (err)
+ return err;
+
+ /* Update the logical LAG port that serves as tag_8021q CPU port */
+ if (!dsa_is_cpu_port(ds, port))
+ return 0;
- return ocelot_port_lag_join(ocelot, port, lag.dev, info);
+ return felix_port_change_master(ds, port, lag.dev, extack);
}
static int felix_lag_leave(struct dsa_switch *ds, int port,
@@ -869,7 +963,11 @@ static int felix_lag_leave(struct dsa_switch *ds, int port,
ocelot_port_lag_leave(ocelot, port, lag.dev);
- return 0;
+ /* Update the logical LAG port that serves as tag_8021q CPU port */
+ if (!dsa_is_cpu_port(ds, port))
+ return 0;
+
+ return felix_port_change_master(ds, port, lag.dev, NULL);
}
static int felix_lag_change(struct dsa_switch *ds, int port)
@@ -1007,6 +1105,27 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
felix->info->port_sched_speed_set(ocelot, port, speed);
}
+static int felix_port_enable(struct dsa_switch *ds, int port,
+ struct phy_device *phydev)
+{
+ struct dsa_port *dp = dsa_to_port(ds, port);
+ struct ocelot *ocelot = ds->priv;
+
+ if (!dsa_port_is_user(dp))
+ return 0;
+
+ if (ocelot->npi >= 0) {
+ struct net_device *master = dsa_port_to_master(dp);
+
+ if (felix_cpu_port_for_master(ds, master) != ocelot->npi) {
+ dev_err(ds->dev, "Multiple masters are not allowed\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
{
int i;
@@ -1028,6 +1147,55 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
}
}
+static void felix_get_stats64(struct dsa_switch *ds, int port,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_stats64(ocelot, port, stats);
+}
+
+static void felix_get_pause_stats(struct dsa_switch *ds, int port,
+ struct ethtool_pause_stats *pause_stats)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_pause_stats(ocelot, port, pause_stats);
+}
+
+static void felix_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_rmon_stats(ocelot, port, rmon_stats, ranges);
+}
+
+static void felix_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_eth_ctrl_stats(ocelot, port, ctrl_stats);
+}
+
+static void felix_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_eth_mac_stats(ocelot, port, mac_stats);
+}
+
+static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_phy_stats *phy_stats)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats);
+}
+
static void felix_get_strings(struct dsa_switch *ds, int port,
u32 stringset, u8 *data)
{
@@ -1144,11 +1312,55 @@ static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
return err;
}
+static struct regmap *felix_request_regmap_by_name(struct felix *felix,
+ const char *resource_name)
+{
+ struct ocelot *ocelot = &felix->ocelot;
+ struct resource res;
+ int i;
+
+ for (i = 0; i < felix->info->num_resources; i++) {
+ if (strcmp(resource_name, felix->info->resources[i].name))
+ continue;
+
+ memcpy(&res, &felix->info->resources[i], sizeof(res));
+ res.start += felix->switch_base;
+ res.end += felix->switch_base;
+
+ return ocelot_regmap_init(ocelot, &res);
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+static struct regmap *felix_request_regmap(struct felix *felix,
+ enum ocelot_target target)
+{
+ const char *resource_name = felix->info->resource_names[target];
+
+ /* If the driver didn't provide a resource name for the target,
+ * the resource is optional.
+ */
+ if (!resource_name)
+ return NULL;
+
+ return felix_request_regmap_by_name(felix, resource_name);
+}
+
+static struct regmap *felix_request_port_regmap(struct felix *felix, int port)
+{
+ char resource_name[32];
+
+ sprintf(resource_name, "port%d", port);
+
+ return felix_request_regmap_by_name(felix, resource_name);
+}
+
static int felix_init_structs(struct felix *felix, int num_phys_ports)
{
struct ocelot *ocelot = &felix->ocelot;
phy_interface_t *port_phy_modes;
- struct resource res;
+ struct regmap *target;
int port, i, err;
ocelot->num_phys_ports = num_phys_ports;
@@ -1182,20 +1394,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
}
for (i = 0; i < TARGET_MAX; i++) {
- struct regmap *target;
-
- if (!felix->info->target_io_res[i].name)
- continue;
-
- memcpy(&res, &felix->info->target_io_res[i], sizeof(res));
- res.flags = IORESOURCE_MEM;
- res.start += felix->switch_base;
- res.end += felix->switch_base;
-
- target = felix->info->init_regmap(ocelot, &res);
+ target = felix_request_regmap(felix, i);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
- "Failed to map device memory space\n");
+ "Failed to map device memory space: %pe\n",
+ target);
kfree(port_phy_modes);
return PTR_ERR(target);
}
@@ -1212,7 +1415,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
for (port = 0; port < num_phys_ports; port++) {
struct ocelot_port *ocelot_port;
- struct regmap *target;
ocelot_port = devm_kzalloc(ocelot->dev,
sizeof(struct ocelot_port),
@@ -1224,16 +1426,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
return -ENOMEM;
}
- memcpy(&res, &felix->info->port_io_res[port], sizeof(res));
- res.flags = IORESOURCE_MEM;
- res.start += felix->switch_base;
- res.end += felix->switch_base;
-
- target = felix->info->init_regmap(ocelot, &res);
+ target = felix_request_port_regmap(felix, port);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
- "Failed to map memory space for port %d\n",
- port);
+ "Failed to map memory space for port %d: %pe\n",
+ port, target);
kfree(port_phy_modes);
return PTR_ERR(target);
}
@@ -1842,6 +2039,12 @@ const struct dsa_switch_ops felix_switch_ops = {
.setup = felix_setup,
.teardown = felix_teardown,
.set_ageing_time = felix_set_ageing_time,
+ .get_stats64 = felix_get_stats64,
+ .get_pause_stats = felix_get_pause_stats,
+ .get_rmon_stats = felix_get_rmon_stats,
+ .get_eth_ctrl_stats = felix_get_eth_ctrl_stats,
+ .get_eth_mac_stats = felix_get_eth_mac_stats,
+ .get_eth_phy_stats = felix_get_eth_phy_stats,
.get_strings = felix_get_strings,
.get_ethtool_stats = felix_get_ethtool_stats,
.get_sset_count = felix_get_sset_count,
@@ -1851,6 +2054,7 @@ const struct dsa_switch_ops felix_switch_ops = {
.phylink_mac_select_pcs = felix_phylink_mac_select_pcs,
.phylink_mac_link_down = felix_phylink_mac_link_down,
.phylink_mac_link_up = felix_phylink_mac_link_up,
+ .port_enable = felix_port_enable,
.port_fast_age = felix_port_fast_age,
.port_fdb_dump = felix_fdb_dump,
.port_fdb_add = felix_fdb_add,
@@ -1906,6 +2110,7 @@ const struct dsa_switch_ops felix_switch_ops = {
.port_add_dscp_prio = felix_port_add_dscp_prio,
.port_del_dscp_prio = felix_port_del_dscp_prio,
.port_set_host_flood = felix_port_set_host_flood,
+ .port_change_master = felix_port_change_master,
};
struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index deb8dde1fc19..c9c29999c336 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -16,9 +16,13 @@
/* Platform-specific information */
struct felix_info {
- const struct resource *target_io_res;
- const struct resource *port_io_res;
- const struct resource *imdio_res;
+ /* Hardcoded resources provided by the hardware instantiation. */
+ const struct resource *resources;
+ size_t num_resources;
+ /* Names of the mandatory resources that will be requested during
+ * probe. Must have TARGET_MAX elements, since it is indexed by target.
+ */
+ const char *const *resource_names;
const struct reg_field *regfields;
const u32 *const *map;
const struct ocelot_ops *ops;
@@ -56,8 +60,6 @@ struct felix_info {
void (*tas_guard_bands_update)(struct ocelot *ocelot, int port);
void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
u32 speed);
- struct regmap *(*init_regmap)(struct ocelot *ocelot,
- struct resource *res);
};
/* Methods for initializing the hardware resources specific to a tagging
@@ -71,6 +73,9 @@ struct felix_tag_proto_ops {
int (*setup)(struct dsa_switch *ds);
void (*teardown)(struct dsa_switch *ds);
unsigned long (*get_host_fwd_mask)(struct dsa_switch *ds);
+ int (*change_master)(struct dsa_switch *ds, int port,
+ struct net_device *master,
+ struct netlink_ext_ack *extack);
};
extern const struct dsa_switch_ops felix_switch_ops;
@@ -83,7 +88,6 @@ struct felix {
struct mii_bus *imdio;
struct phylink_pcs **pcs;
resource_size_t switch_base;
- resource_size_t imdio_base;
enum dsa_tag_protocol tag_proto;
const struct felix_tag_proto_ops *tag_proto_ops;
struct kthread_worker *xmit_worker;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 1cdce8a98d1d..26a35ae322d1 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -22,6 +22,7 @@
#define VSC9959_NUM_PORTS 6
#define VSC9959_TAS_GCL_ENTRY_MAX 63
+#define VSC9959_TAS_MIN_GATE_LEN_NS 33
#define VSC9959_VCAP_POLICER_BASE 63
#define VSC9959_VCAP_POLICER_MAX 383
#define VSC9959_SWITCH_PCI_BAR 4
@@ -347,7 +348,7 @@ static const u32 vsc9959_sys_regmap[] = {
REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00026c),
REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000270),
REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000274),
- REG(SYS_COUNT_TX_AGING, 0x000278),
+ REG(SYS_COUNT_TX_AGED, 0x000278),
REG(SYS_COUNT_DROP_LOCAL, 0x000400),
REG(SYS_COUNT_DROP_TAIL, 0x000404),
REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000408),
@@ -366,6 +367,10 @@ static const u32 vsc9959_sys_regmap[] = {
REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00043c),
REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000440),
REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000444),
+ REG(SYS_COUNT_SF_MATCHING_FRAMES, 0x000800),
+ REG(SYS_COUNT_SF_NOT_PASSING_FRAMES, 0x000804),
+ REG(SYS_COUNT_SF_NOT_PASSING_SDU, 0x000808),
+ REG(SYS_COUNT_SF_RED_FRAMES, 0x00080c),
REG(SYS_RESET_CFG, 0x000e00),
REG(SYS_SR_ETYPE_CFG, 0x000e04),
REG(SYS_VLAN_ETYPE_CFG, 0x000e08),
@@ -387,7 +392,6 @@ static const u32 vsc9959_sys_regmap[] = {
REG_RESERVED(SYS_MMGT_FAST),
REG_RESERVED(SYS_EVENTS_DIF),
REG_RESERVED(SYS_EVENTS_CORE),
- REG(SYS_CNT, 0x000000),
REG(SYS_PTP_STATUS, 0x000f14),
REG(SYS_PTP_TXSTAMP, 0x000f18),
REG(SYS_PTP_NXT, 0x000f1c),
@@ -473,100 +477,43 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = {
};
/* Addresses are relative to the PCI device's base address */
-static const struct resource vsc9959_target_io_res[TARGET_MAX] = {
- [ANA] = {
- .start = 0x0280000,
- .end = 0x028ffff,
- .name = "ana",
- },
- [QS] = {
- .start = 0x0080000,
- .end = 0x00800ff,
- .name = "qs",
- },
- [QSYS] = {
- .start = 0x0200000,
- .end = 0x021ffff,
- .name = "qsys",
- },
- [REW] = {
- .start = 0x0030000,
- .end = 0x003ffff,
- .name = "rew",
- },
- [SYS] = {
- .start = 0x0010000,
- .end = 0x001ffff,
- .name = "sys",
- },
- [S0] = {
- .start = 0x0040000,
- .end = 0x00403ff,
- .name = "s0",
- },
- [S1] = {
- .start = 0x0050000,
- .end = 0x00503ff,
- .name = "s1",
- },
- [S2] = {
- .start = 0x0060000,
- .end = 0x00603ff,
- .name = "s2",
- },
- [PTP] = {
- .start = 0x0090000,
- .end = 0x00900cb,
- .name = "ptp",
- },
- [GCB] = {
- .start = 0x0070000,
- .end = 0x00701ff,
- .name = "devcpu_gcb",
- },
+static const struct resource vsc9959_resources[] = {
+ DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"),
+ DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"),
+ DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"),
+ DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"),
+ DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"),
+ DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"),
+ DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"),
+ DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"),
+ DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"),
+ DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"),
+ DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"),
+ DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"),
+ DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"),
+ DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"),
+ DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"),
+ DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"),
};
-static const struct resource vsc9959_port_io_res[] = {
- {
- .start = 0x0100000,
- .end = 0x010ffff,
- .name = "port0",
- },
- {
- .start = 0x0110000,
- .end = 0x011ffff,
- .name = "port1",
- },
- {
- .start = 0x0120000,
- .end = 0x012ffff,
- .name = "port2",
- },
- {
- .start = 0x0130000,
- .end = 0x013ffff,
- .name = "port3",
- },
- {
- .start = 0x0140000,
- .end = 0x014ffff,
- .name = "port4",
- },
- {
- .start = 0x0150000,
- .end = 0x015ffff,
- .name = "port5",
- },
+static const char * const vsc9959_resource_names[TARGET_MAX] = {
+ [SYS] = "sys",
+ [REW] = "rew",
+ [S0] = "s0",
+ [S1] = "s1",
+ [S2] = "s2",
+ [GCB] = "devcpu_gcb",
+ [QS] = "qs",
+ [PTP] = "ptp",
+ [QSYS] = "qsys",
+ [ANA] = "ana",
};
/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
* SGMII/QSGMII MAC PCS can be found.
*/
-static const struct resource vsc9959_imdio_res = {
- .start = 0x8030,
- .end = 0x8040,
- .name = "imdio",
-};
+static const struct resource vsc9959_imdio_res =
+ DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio");
static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
[ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
@@ -619,378 +566,7 @@ static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
};
static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = {
- [OCELOT_STAT_RX_OCTETS] = {
- .name = "rx_octets",
- .reg = SYS_COUNT_RX_OCTETS,
- },
- [OCELOT_STAT_RX_UNICAST] = {
- .name = "rx_unicast",
- .reg = SYS_COUNT_RX_UNICAST,
- },
- [OCELOT_STAT_RX_MULTICAST] = {
- .name = "rx_multicast",
- .reg = SYS_COUNT_RX_MULTICAST,
- },
- [OCELOT_STAT_RX_BROADCAST] = {
- .name = "rx_broadcast",
- .reg = SYS_COUNT_RX_BROADCAST,
- },
- [OCELOT_STAT_RX_SHORTS] = {
- .name = "rx_shorts",
- .reg = SYS_COUNT_RX_SHORTS,
- },
- [OCELOT_STAT_RX_FRAGMENTS] = {
- .name = "rx_fragments",
- .reg = SYS_COUNT_RX_FRAGMENTS,
- },
- [OCELOT_STAT_RX_JABBERS] = {
- .name = "rx_jabbers",
- .reg = SYS_COUNT_RX_JABBERS,
- },
- [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = {
- .name = "rx_crc_align_errs",
- .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS,
- },
- [OCELOT_STAT_RX_SYM_ERRS] = {
- .name = "rx_sym_errs",
- .reg = SYS_COUNT_RX_SYM_ERRS,
- },
- [OCELOT_STAT_RX_64] = {
- .name = "rx_frames_below_65_octets",
- .reg = SYS_COUNT_RX_64,
- },
- [OCELOT_STAT_RX_65_127] = {
- .name = "rx_frames_65_to_127_octets",
- .reg = SYS_COUNT_RX_65_127,
- },
- [OCELOT_STAT_RX_128_255] = {
- .name = "rx_frames_128_to_255_octets",
- .reg = SYS_COUNT_RX_128_255,
- },
- [OCELOT_STAT_RX_256_511] = {
- .name = "rx_frames_256_to_511_octets",
- .reg = SYS_COUNT_RX_256_511,
- },
- [OCELOT_STAT_RX_512_1023] = {
- .name = "rx_frames_512_to_1023_octets",
- .reg = SYS_COUNT_RX_512_1023,
- },
- [OCELOT_STAT_RX_1024_1526] = {
- .name = "rx_frames_1024_to_1526_octets",
- .reg = SYS_COUNT_RX_1024_1526,
- },
- [OCELOT_STAT_RX_1527_MAX] = {
- .name = "rx_frames_over_1526_octets",
- .reg = SYS_COUNT_RX_1527_MAX,
- },
- [OCELOT_STAT_RX_PAUSE] = {
- .name = "rx_pause",
- .reg = SYS_COUNT_RX_PAUSE,
- },
- [OCELOT_STAT_RX_CONTROL] = {
- .name = "rx_control",
- .reg = SYS_COUNT_RX_CONTROL,
- },
- [OCELOT_STAT_RX_LONGS] = {
- .name = "rx_longs",
- .reg = SYS_COUNT_RX_LONGS,
- },
- [OCELOT_STAT_RX_CLASSIFIED_DROPS] = {
- .name = "rx_classified_drops",
- .reg = SYS_COUNT_RX_CLASSIFIED_DROPS,
- },
- [OCELOT_STAT_RX_RED_PRIO_0] = {
- .name = "rx_red_prio_0",
- .reg = SYS_COUNT_RX_RED_PRIO_0,
- },
- [OCELOT_STAT_RX_RED_PRIO_1] = {
- .name = "rx_red_prio_1",
- .reg = SYS_COUNT_RX_RED_PRIO_1,
- },
- [OCELOT_STAT_RX_RED_PRIO_2] = {
- .name = "rx_red_prio_2",
- .reg = SYS_COUNT_RX_RED_PRIO_2,
- },
- [OCELOT_STAT_RX_RED_PRIO_3] = {
- .name = "rx_red_prio_3",
- .reg = SYS_COUNT_RX_RED_PRIO_3,
- },
- [OCELOT_STAT_RX_RED_PRIO_4] = {
- .name = "rx_red_prio_4",
- .reg = SYS_COUNT_RX_RED_PRIO_4,
- },
- [OCELOT_STAT_RX_RED_PRIO_5] = {
- .name = "rx_red_prio_5",
- .reg = SYS_COUNT_RX_RED_PRIO_5,
- },
- [OCELOT_STAT_RX_RED_PRIO_6] = {
- .name = "rx_red_prio_6",
- .reg = SYS_COUNT_RX_RED_PRIO_6,
- },
- [OCELOT_STAT_RX_RED_PRIO_7] = {
- .name = "rx_red_prio_7",
- .reg = SYS_COUNT_RX_RED_PRIO_7,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_0] = {
- .name = "rx_yellow_prio_0",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_1] = {
- .name = "rx_yellow_prio_1",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_2] = {
- .name = "rx_yellow_prio_2",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_3] = {
- .name = "rx_yellow_prio_3",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_4] = {
- .name = "rx_yellow_prio_4",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_5] = {
- .name = "rx_yellow_prio_5",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_6] = {
- .name = "rx_yellow_prio_6",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_7] = {
- .name = "rx_yellow_prio_7",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_0] = {
- .name = "rx_green_prio_0",
- .reg = SYS_COUNT_RX_GREEN_PRIO_0,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_1] = {
- .name = "rx_green_prio_1",
- .reg = SYS_COUNT_RX_GREEN_PRIO_1,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_2] = {
- .name = "rx_green_prio_2",
- .reg = SYS_COUNT_RX_GREEN_PRIO_2,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_3] = {
- .name = "rx_green_prio_3",
- .reg = SYS_COUNT_RX_GREEN_PRIO_3,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_4] = {
- .name = "rx_green_prio_4",
- .reg = SYS_COUNT_RX_GREEN_PRIO_4,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_5] = {
- .name = "rx_green_prio_5",
- .reg = SYS_COUNT_RX_GREEN_PRIO_5,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_6] = {
- .name = "rx_green_prio_6",
- .reg = SYS_COUNT_RX_GREEN_PRIO_6,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_7] = {
- .name = "rx_green_prio_7",
- .reg = SYS_COUNT_RX_GREEN_PRIO_7,
- },
- [OCELOT_STAT_TX_OCTETS] = {
- .name = "tx_octets",
- .reg = SYS_COUNT_TX_OCTETS,
- },
- [OCELOT_STAT_TX_UNICAST] = {
- .name = "tx_unicast",
- .reg = SYS_COUNT_TX_UNICAST,
- },
- [OCELOT_STAT_TX_MULTICAST] = {
- .name = "tx_multicast",
- .reg = SYS_COUNT_TX_MULTICAST,
- },
- [OCELOT_STAT_TX_BROADCAST] = {
- .name = "tx_broadcast",
- .reg = SYS_COUNT_TX_BROADCAST,
- },
- [OCELOT_STAT_TX_COLLISION] = {
- .name = "tx_collision",
- .reg = SYS_COUNT_TX_COLLISION,
- },
- [OCELOT_STAT_TX_DROPS] = {
- .name = "tx_drops",
- .reg = SYS_COUNT_TX_DROPS,
- },
- [OCELOT_STAT_TX_PAUSE] = {
- .name = "tx_pause",
- .reg = SYS_COUNT_TX_PAUSE,
- },
- [OCELOT_STAT_TX_64] = {
- .name = "tx_frames_below_65_octets",
- .reg = SYS_COUNT_TX_64,
- },
- [OCELOT_STAT_TX_65_127] = {
- .name = "tx_frames_65_to_127_octets",
- .reg = SYS_COUNT_TX_65_127,
- },
- [OCELOT_STAT_TX_128_255] = {
- .name = "tx_frames_128_255_octets",
- .reg = SYS_COUNT_TX_128_255,
- },
- [OCELOT_STAT_TX_256_511] = {
- .name = "tx_frames_256_511_octets",
- .reg = SYS_COUNT_TX_256_511,
- },
- [OCELOT_STAT_TX_512_1023] = {
- .name = "tx_frames_512_1023_octets",
- .reg = SYS_COUNT_TX_512_1023,
- },
- [OCELOT_STAT_TX_1024_1526] = {
- .name = "tx_frames_1024_1526_octets",
- .reg = SYS_COUNT_TX_1024_1526,
- },
- [OCELOT_STAT_TX_1527_MAX] = {
- .name = "tx_frames_over_1526_octets",
- .reg = SYS_COUNT_TX_1527_MAX,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_0] = {
- .name = "tx_yellow_prio_0",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_1] = {
- .name = "tx_yellow_prio_1",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_2] = {
- .name = "tx_yellow_prio_2",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_3] = {
- .name = "tx_yellow_prio_3",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_4] = {
- .name = "tx_yellow_prio_4",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_5] = {
- .name = "tx_yellow_prio_5",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_6] = {
- .name = "tx_yellow_prio_6",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_7] = {
- .name = "tx_yellow_prio_7",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_0] = {
- .name = "tx_green_prio_0",
- .reg = SYS_COUNT_TX_GREEN_PRIO_0,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_1] = {
- .name = "tx_green_prio_1",
- .reg = SYS_COUNT_TX_GREEN_PRIO_1,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_2] = {
- .name = "tx_green_prio_2",
- .reg = SYS_COUNT_TX_GREEN_PRIO_2,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_3] = {
- .name = "tx_green_prio_3",
- .reg = SYS_COUNT_TX_GREEN_PRIO_3,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_4] = {
- .name = "tx_green_prio_4",
- .reg = SYS_COUNT_TX_GREEN_PRIO_4,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_5] = {
- .name = "tx_green_prio_5",
- .reg = SYS_COUNT_TX_GREEN_PRIO_5,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_6] = {
- .name = "tx_green_prio_6",
- .reg = SYS_COUNT_TX_GREEN_PRIO_6,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_7] = {
- .name = "tx_green_prio_7",
- .reg = SYS_COUNT_TX_GREEN_PRIO_7,
- },
- [OCELOT_STAT_TX_AGED] = {
- .name = "tx_aged",
- .reg = SYS_COUNT_TX_AGING,
- },
- [OCELOT_STAT_DROP_LOCAL] = {
- .name = "drop_local",
- .reg = SYS_COUNT_DROP_LOCAL,
- },
- [OCELOT_STAT_DROP_TAIL] = {
- .name = "drop_tail",
- .reg = SYS_COUNT_DROP_TAIL,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_0] = {
- .name = "drop_yellow_prio_0",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_1] = {
- .name = "drop_yellow_prio_1",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_2] = {
- .name = "drop_yellow_prio_2",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_3] = {
- .name = "drop_yellow_prio_3",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_4] = {
- .name = "drop_yellow_prio_4",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_5] = {
- .name = "drop_yellow_prio_5",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_6] = {
- .name = "drop_yellow_prio_6",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_7] = {
- .name = "drop_yellow_prio_7",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_0] = {
- .name = "drop_green_prio_0",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_0,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_1] = {
- .name = "drop_green_prio_1",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_1,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_2] = {
- .name = "drop_green_prio_2",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_2,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_3] = {
- .name = "drop_green_prio_3",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_3,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_4] = {
- .name = "drop_green_prio_4",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_4,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_5] = {
- .name = "drop_green_prio_5",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_5,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_6] = {
- .name = "drop_green_prio_6",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_6,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_7] = {
- .name = "drop_green_prio_7",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_7,
- },
+ OCELOT_COMMON_STATS,
};
static const struct vcap_field vsc9959_vcap_es0_keys[] = {
@@ -1370,9 +946,11 @@ static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
{
+ struct pci_dev *pdev = to_pci_dev(ocelot->dev);
struct felix *felix = ocelot_to_felix(ocelot);
struct enetc_mdio_priv *mdio_priv;
struct device *dev = ocelot->dev;
+ resource_size_t imdio_base;
void __iomem *imdio_regs;
struct resource res;
struct enetc_hw *hw;
@@ -1388,10 +966,11 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
return -ENOMEM;
}
- memcpy(&res, felix->info->imdio_res, sizeof(res));
- res.flags = IORESOURCE_MEM;
- res.start += felix->imdio_base;
- res.end += felix->imdio_base;
+ imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR);
+
+ memcpy(&res, &vsc9959_imdio_res, sizeof(res));
+ res.start += imdio_base;
+ res.end += imdio_base;
imdio_regs = devm_ioremap_resource(dev, &res);
if (IS_ERR(imdio_regs))
@@ -1478,6 +1057,23 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
mdiobus_free(felix->imdio);
}
+/* The switch considers any frame (regardless of size) as eligible for
+ * transmission if the traffic class gate is open for at least 33 ns.
+ * Overruns are prevented by cropping an interval at the end of the gate time
+ * slot for which egress scheduling is blocked, but we need to still keep 33 ns
+ * available for one packet to be transmitted, otherwise the port tc will hang.
+ * This function returns the size of a gate interval that remains available for
+ * setting the guard band, after reserving the space for one egress frame.
+ */
+static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns)
+{
+ /* Gate always open */
+ if (gate_len_ns == U64_MAX)
+ return U64_MAX;
+
+ return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC;
+}
+
/* Extract shortest continuous gate open intervals in ns for each traffic class
* of a cyclic tc-taprio schedule. If a gate is always open, the duration is
* considered U64_MAX. If the gate is always closed, it is considered 0.
@@ -1539,6 +1135,73 @@ static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
min_gate_len[tc] = 0;
}
+/* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ,
+ * so we need to spell out the register access to each traffic class in helper
+ * functions, to simplify callers
+ */
+static void vsc9959_port_qmaxsdu_set(struct ocelot *ocelot, int port, int tc,
+ u32 max_sdu)
+{
+ switch (tc) {
+ case 0:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
+ port);
+ break;
+ case 1:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
+ port);
+ break;
+ case 2:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
+ port);
+ break;
+ case 3:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
+ port);
+ break;
+ case 4:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
+ port);
+ break;
+ case 5:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
+ port);
+ break;
+ case 6:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
+ port);
+ break;
+ case 7:
+ ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
+ port);
+ break;
+ }
+}
+
+static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc)
+{
+ switch (tc) {
+ case 0: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_0, port);
+ case 1: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_1, port);
+ case 2: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_2, port);
+ case 3: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_3, port);
+ case 4: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_4, port);
+ case 5: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_5, port);
+ case 6: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_6, port);
+ case 7: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_7, port);
+ default:
+ return 0;
+ }
+}
+
+static u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc)
+{
+ if (!taprio || !taprio->max_sdu[tc])
+ return 0;
+
+ return taprio->max_sdu[tc] + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN;
+}
+
/* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the
* switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU
* values (the default value is 1518). Also, for traffic class windows smaller
@@ -1548,6 +1211,7 @@ static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct tc_taprio_qopt_offload *taprio;
u64 min_gate_len[OCELOT_NUM_TC];
int speed, picos_per_byte;
u64 needed_bit_time_ps;
@@ -1557,6 +1221,8 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
lockdep_assert_held(&ocelot->tas_lock);
+ taprio = ocelot_port->taprio;
+
val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port);
tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val);
@@ -1593,17 +1259,23 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
"port %d: max frame size %d needs %llu ps at speed %d\n",
port, maxlen, needed_bit_time_ps, speed);
- vsc9959_tas_min_gate_lengths(ocelot_port->taprio, min_gate_len);
+ vsc9959_tas_min_gate_lengths(taprio, min_gate_len);
+
+ mutex_lock(&ocelot->fwd_domain_lock);
for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
+ u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc);
+ u64 remaining_gate_len_ps;
u32 max_sdu;
- if (min_gate_len[tc] == U64_MAX /* Gate always open */ ||
- min_gate_len[tc] * PSEC_PER_NSEC > needed_bit_time_ps) {
+ remaining_gate_len_ps =
+ vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]);
+
+ if (remaining_gate_len_ps > needed_bit_time_ps) {
/* Setting QMAXSDU_CFG to 0 disables oversized frame
* dropping.
*/
- max_sdu = 0;
+ max_sdu = requested_max_sdu;
dev_dbg(ocelot->dev,
"port %d tc %d min gate len %llu"
", sending all frames\n",
@@ -1612,9 +1284,15 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
/* If traffic class doesn't support a full MTU sized
* frame, make sure to enable oversize frame dropping
* for frames larger than the smallest that would fit.
+ *
+ * However, the exact same register, QSYS_QMAXSDU_CFG_*,
+ * controls not only oversized frame dropping, but also
+ * per-tc static guard band lengths, so it reduces the
+ * useful gate interval length. Therefore, be careful
+ * to calculate a guard band (and therefore max_sdu)
+ * that still leaves 33 ns available in the time slot.
*/
- max_sdu = div_u64(min_gate_len[tc] * PSEC_PER_NSEC,
- picos_per_byte);
+ max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte);
/* A TC gate may be completely closed, which is a
* special case where all packets are oversized.
* Any limit smaller than 64 octets accomplishes this
@@ -1628,6 +1306,10 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
*/
if (max_sdu > 20)
max_sdu -= 20;
+
+ if (requested_max_sdu && requested_max_sdu < max_sdu)
+ max_sdu = requested_max_sdu;
+
dev_info(ocelot->dev,
"port %d tc %d min gate length %llu"
" ns not enough for max frame size %d at %d"
@@ -1637,47 +1319,14 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
max_sdu);
}
- /* ocelot_write_rix is a macro that concatenates
- * QSYS_MAXSDU_CFG_* with _RSZ, so we need to spell out
- * the writes to each traffic class
- */
- switch (tc) {
- case 0:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
- port);
- break;
- case 1:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
- port);
- break;
- case 2:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
- port);
- break;
- case 3:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
- port);
- break;
- case 4:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
- port);
- break;
- case 5:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
- port);
- break;
- case 6:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
- port);
- break;
- case 7:
- ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
- port);
- break;
- }
+ vsc9959_port_qmaxsdu_set(ocelot, port, tc, max_sdu);
}
ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
+
+ ocelot->ops->cut_through_fwd(ocelot);
+
+ mutex_unlock(&ocelot->fwd_domain_lock);
}
static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
@@ -1704,13 +1353,13 @@ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
break;
}
+ mutex_lock(&ocelot->tas_lock);
+
ocelot_rmw_rix(ocelot,
QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
QSYS_TAG_CONFIG_LINK_SPEED_M,
QSYS_TAG_CONFIG, port);
- mutex_lock(&ocelot->tas_lock);
-
if (ocelot_port->taprio)
vsc9959_tas_guard_bands_update(ocelot, port);
@@ -1950,6 +1599,21 @@ static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
return 0;
}
+static int vsc9959_qos_query_caps(struct tc_query_caps_base *base)
+{
+ switch (base->type) {
+ case TC_SETUP_QDISC_TAPRIO: {
+ struct tc_taprio_caps *caps = base->caps;
+
+ caps->supports_queue_max_sdu = true;
+
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type,
void *type_data)
@@ -1957,6 +1621,8 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
struct ocelot *ocelot = ds->priv;
switch (type) {
+ case TC_QUERY_CAPS:
+ return vsc9959_qos_query_caps(type_data);
case TC_SETUP_QDISC_TAPRIO:
return vsc9959_qos_port_tas_set(ocelot, port, type_data);
case TC_SETUP_QDISC_CBS:
@@ -1988,7 +1654,15 @@ struct felix_stream {
u32 ssid;
};
+struct felix_stream_filter_counters {
+ u64 match;
+ u64 not_pass_gate;
+ u64 not_pass_sdu;
+ u64 red;
+};
+
struct felix_stream_filter {
+ struct felix_stream_filter_counters stats;
struct list_head list;
refcount_t refcount;
u32 index;
@@ -2003,13 +1677,6 @@ struct felix_stream_filter {
u32 maxsdu;
};
-struct felix_stream_filter_counters {
- u32 match;
- u32 not_pass_gate;
- u32 not_pass_sdu;
- u32 red;
-};
-
struct felix_stream_gate {
u32 index;
u8 enable;
@@ -2513,29 +2180,6 @@ static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot,
}
}
-static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
- struct felix_stream_filter_counters *counters)
-{
- spin_lock(&ocelot->stats_lock);
-
- ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index),
- SYS_STAT_CFG_STAT_VIEW_M,
- SYS_STAT_CFG);
-
- counters->match = ocelot_read_gix(ocelot, SYS_CNT, 0x200);
- counters->not_pass_gate = ocelot_read_gix(ocelot, SYS_CNT, 0x201);
- counters->not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202);
- counters->red = ocelot_read_gix(ocelot, SYS_CNT, 0x203);
-
- /* Clear the PSFP counter. */
- ocelot_write(ocelot,
- SYS_STAT_CFG_STAT_VIEW(index) |
- SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
- SYS_STAT_CFG);
-
- spin_unlock(&ocelot->stats_lock);
-}
-
static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
struct flow_cls_offload *f)
{
@@ -2560,6 +2204,8 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
return ret;
}
+ mutex_lock(&psfp->lock);
+
flow_action_for_each(i, a, &f->rule->action) {
switch (a->id) {
case FLOW_ACTION_GATE:
@@ -2601,6 +2247,7 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
sfi.maxsdu = a->police.mtu;
break;
default:
+ mutex_unlock(&psfp->lock);
return -EOPNOTSUPP;
}
}
@@ -2670,6 +2317,8 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
goto err;
}
+ mutex_unlock(&psfp->lock);
+
return 0;
err:
@@ -2679,6 +2328,8 @@ err:
if (sfi.fm_valid)
ocelot_vcap_policer_del(ocelot, sfi.fmid);
+ mutex_unlock(&psfp->lock);
+
return ret;
}
@@ -2686,18 +2337,22 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot,
struct flow_cls_offload *f)
{
struct felix_stream *stream, tmp, *stream_entry;
+ struct ocelot_psfp_list *psfp = &ocelot->psfp;
static struct felix_stream_filter *sfi;
- struct ocelot_psfp_list *psfp;
- psfp = &ocelot->psfp;
+ mutex_lock(&psfp->lock);
stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
- if (!stream)
+ if (!stream) {
+ mutex_unlock(&psfp->lock);
return -ENOMEM;
+ }
sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid);
- if (!sfi)
+ if (!sfi) {
+ mutex_unlock(&psfp->lock);
return -ENOMEM;
+ }
if (sfi->sg_valid)
vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid);
@@ -2723,27 +2378,83 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot,
stream_entry->ports);
}
+ mutex_unlock(&psfp->lock);
+
return 0;
}
+static void vsc9959_update_sfid_stats(struct ocelot *ocelot,
+ struct felix_stream_filter *sfi)
+{
+ struct felix_stream_filter_counters *s = &sfi->stats;
+ u32 match, not_pass_gate, not_pass_sdu, red;
+ u32 sfid = sfi->index;
+
+ lockdep_assert_held(&ocelot->stat_view_lock);
+
+ ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(sfid),
+ SYS_STAT_CFG_STAT_VIEW_M,
+ SYS_STAT_CFG);
+
+ match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES);
+ not_pass_gate = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_FRAMES);
+ not_pass_sdu = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_SDU);
+ red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES);
+
+ /* Clear the PSFP counter. */
+ ocelot_write(ocelot,
+ SYS_STAT_CFG_STAT_VIEW(sfid) |
+ SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
+ SYS_STAT_CFG);
+
+ s->match += match;
+ s->not_pass_gate += not_pass_gate;
+ s->not_pass_sdu += not_pass_sdu;
+ s->red += red;
+}
+
+/* Caller must hold &ocelot->stat_view_lock */
+static void vsc9959_update_stats(struct ocelot *ocelot)
+{
+ struct ocelot_psfp_list *psfp = &ocelot->psfp;
+ struct felix_stream_filter *sfi;
+
+ mutex_lock(&psfp->lock);
+
+ list_for_each_entry(sfi, &psfp->sfi_list, list)
+ vsc9959_update_sfid_stats(ocelot, sfi);
+
+ mutex_unlock(&psfp->lock);
+}
+
static int vsc9959_psfp_stats_get(struct ocelot *ocelot,
struct flow_cls_offload *f,
struct flow_stats *stats)
{
- struct felix_stream_filter_counters counters;
- struct ocelot_psfp_list *psfp;
+ struct ocelot_psfp_list *psfp = &ocelot->psfp;
+ struct felix_stream_filter_counters *s;
+ static struct felix_stream_filter *sfi;
struct felix_stream *stream;
- psfp = &ocelot->psfp;
stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
if (!stream)
return -ENOMEM;
- vsc9959_psfp_counters_get(ocelot, stream->sfid, &counters);
+ sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid);
+ if (!sfi)
+ return -EINVAL;
+
+ mutex_lock(&ocelot->stat_view_lock);
+
+ vsc9959_update_sfid_stats(ocelot, sfi);
- stats->pkts = counters.match;
- stats->drops = counters.not_pass_gate + counters.not_pass_sdu +
- counters.red;
+ s = &sfi->stats;
+ stats->pkts = s->match;
+ stats->drops = s->not_pass_gate + s->not_pass_sdu + s->red;
+
+ memset(s, 0, sizeof(*s));
+
+ mutex_unlock(&ocelot->stat_view_lock);
return 0;
}
@@ -2755,6 +2466,7 @@ static void vsc9959_psfp_init(struct ocelot *ocelot)
INIT_LIST_HEAD(&psfp->stream_list);
INIT_LIST_HEAD(&psfp->sfi_list);
INIT_LIST_HEAD(&psfp->sgi_list);
+ mutex_init(&psfp->lock);
}
/* When using cut-through forwarding and the egress port runs at a higher data
@@ -2770,7 +2482,7 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
{
struct felix *felix = ocelot_to_felix(ocelot);
struct dsa_switch *ds = felix->ds;
- int port, other_port;
+ int tc, port, other_port;
lockdep_assert_held(&ocelot->fwd_domain_lock);
@@ -2814,19 +2526,27 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
min_speed = other_ocelot_port->speed;
}
- /* Enable cut-through forwarding for all traffic classes. */
- if (ocelot_port->speed == min_speed)
+ /* Enable cut-through forwarding for all traffic classes that
+ * don't have oversized dropping enabled, since this check is
+ * bypassed in cut-through mode.
+ */
+ if (ocelot_port->speed == min_speed) {
val = GENMASK(7, 0);
+ for (tc = 0; tc < OCELOT_NUM_TC; tc++)
+ if (vsc9959_port_qmaxsdu_get(ocelot, port, tc))
+ val &= ~BIT(tc);
+ }
+
set:
tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port);
if (tmp == val)
continue;
dev_dbg(ocelot->dev,
- "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding\n",
+ "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x\n",
port, mask, ocelot_port->speed, min_speed,
- val ? "enabling" : "disabling");
+ val ? "enabling" : "disabling", val);
ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port);
}
@@ -2845,12 +2565,13 @@ static const struct ocelot_ops vsc9959_ops = {
.psfp_stats_get = vsc9959_psfp_stats_get,
.cut_through_fwd = vsc9959_cut_through_fwd,
.tas_clock_adjust = vsc9959_tas_clock_adjust,
+ .update_stats = vsc9959_update_stats,
};
static const struct felix_info felix_info_vsc9959 = {
- .target_io_res = vsc9959_target_io_res,
- .port_io_res = vsc9959_port_io_res,
- .imdio_res = &vsc9959_imdio_res,
+ .resources = vsc9959_resources,
+ .num_resources = ARRAY_SIZE(vsc9959_resources),
+ .resource_names = vsc9959_resource_names,
.regfields = vsc9959_regfields,
.map = vsc9959_regmap,
.ops = &vsc9959_ops,
@@ -2872,7 +2593,6 @@ static const struct felix_info felix_info_vsc9959 = {
.port_setup_tc = vsc9959_port_setup_tc,
.port_sched_speed_set = vsc9959_sched_speed_set,
.tas_guard_bands_update = vsc9959_tas_guard_bands_update,
- .init_regmap = ocelot_regmap_init,
};
static irqreturn_t felix_irq_handler(int irq, void *data)
@@ -2924,7 +2644,6 @@ static int felix_pci_probe(struct pci_dev *pdev,
ocelot->num_flooding_pgids = OCELOT_NUM_TC;
felix->info = &felix_info_vsc9959;
felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR);
- felix->imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR);
pci_set_master(pdev);
@@ -2985,8 +2704,6 @@ static void felix_pci_remove(struct pci_dev *pdev)
kfree(felix);
pci_disable_device(pdev);
-
- pci_set_drvdata(pdev, NULL);
}
static void felix_pci_shutdown(struct pci_dev *pdev)
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index b34f4cdfe814..7af33b2c685d 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -343,7 +343,7 @@ static const u32 vsc9953_sys_regmap[] = {
REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00016c),
REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000170),
REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000174),
- REG(SYS_COUNT_TX_AGING, 0x000178),
+ REG(SYS_COUNT_TX_AGED, 0x000178),
REG(SYS_COUNT_DROP_LOCAL, 0x000200),
REG(SYS_COUNT_DROP_TAIL, 0x000204),
REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000208),
@@ -383,7 +383,6 @@ static const u32 vsc9953_sys_regmap[] = {
REG_RESERVED(SYS_MMGT_FAST),
REG_RESERVED(SYS_EVENTS_DIF),
REG_RESERVED(SYS_EVENTS_CORE),
- REG_RESERVED(SYS_CNT),
REG_RESERVED(SYS_PTP_STATUS),
REG_RESERVED(SYS_PTP_TXSTAMP),
REG_RESERVED(SYS_PTP_NXT),
@@ -459,110 +458,40 @@ static const u32 *vsc9953_regmap[TARGET_MAX] = {
};
/* Addresses are relative to the device's base address */
-static const struct resource vsc9953_target_io_res[TARGET_MAX] = {
- [ANA] = {
- .start = 0x0280000,
- .end = 0x028ffff,
- .name = "ana",
- },
- [QS] = {
- .start = 0x0080000,
- .end = 0x00800ff,
- .name = "qs",
- },
- [QSYS] = {
- .start = 0x0200000,
- .end = 0x021ffff,
- .name = "qsys",
- },
- [REW] = {
- .start = 0x0030000,
- .end = 0x003ffff,
- .name = "rew",
- },
- [SYS] = {
- .start = 0x0010000,
- .end = 0x001ffff,
- .name = "sys",
- },
- [S0] = {
- .start = 0x0040000,
- .end = 0x00403ff,
- .name = "s0",
- },
- [S1] = {
- .start = 0x0050000,
- .end = 0x00503ff,
- .name = "s1",
- },
- [S2] = {
- .start = 0x0060000,
- .end = 0x00603ff,
- .name = "s2",
- },
- [PTP] = {
- .start = 0x0090000,
- .end = 0x00900cb,
- .name = "ptp",
- },
- [GCB] = {
- .start = 0x0070000,
- .end = 0x00701ff,
- .name = "devcpu_gcb",
- },
+static const struct resource vsc9953_resources[] = {
+ DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"),
+ DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"),
+ DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"),
+ DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"),
+ DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"),
+ DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"),
+ DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"),
+ DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"),
+ DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"),
+ DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"),
+ DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"),
+ DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"),
+ DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"),
+ DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"),
+ DEFINE_RES_MEM_NAMED(0x0160000, 0x0010000, "port6"),
+ DEFINE_RES_MEM_NAMED(0x0170000, 0x0010000, "port7"),
+ DEFINE_RES_MEM_NAMED(0x0180000, 0x0010000, "port8"),
+ DEFINE_RES_MEM_NAMED(0x0190000, 0x0010000, "port9"),
+ DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"),
+ DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"),
};
-static const struct resource vsc9953_port_io_res[] = {
- {
- .start = 0x0100000,
- .end = 0x010ffff,
- .name = "port0",
- },
- {
- .start = 0x0110000,
- .end = 0x011ffff,
- .name = "port1",
- },
- {
- .start = 0x0120000,
- .end = 0x012ffff,
- .name = "port2",
- },
- {
- .start = 0x0130000,
- .end = 0x013ffff,
- .name = "port3",
- },
- {
- .start = 0x0140000,
- .end = 0x014ffff,
- .name = "port4",
- },
- {
- .start = 0x0150000,
- .end = 0x015ffff,
- .name = "port5",
- },
- {
- .start = 0x0160000,
- .end = 0x016ffff,
- .name = "port6",
- },
- {
- .start = 0x0170000,
- .end = 0x017ffff,
- .name = "port7",
- },
- {
- .start = 0x0180000,
- .end = 0x018ffff,
- .name = "port8",
- },
- {
- .start = 0x0190000,
- .end = 0x019ffff,
- .name = "port9",
- },
+static const char * const vsc9953_resource_names[TARGET_MAX] = {
+ [SYS] = "sys",
+ [REW] = "rew",
+ [S0] = "s0",
+ [S1] = "s1",
+ [S2] = "s2",
+ [GCB] = "devcpu_gcb",
+ [QS] = "qs",
+ [PTP] = "ptp",
+ [QSYS] = "qsys",
+ [ANA] = "ana",
};
static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = {
@@ -615,378 +544,7 @@ static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = {
};
static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = {
- [OCELOT_STAT_RX_OCTETS] = {
- .name = "rx_octets",
- .reg = SYS_COUNT_RX_OCTETS,
- },
- [OCELOT_STAT_RX_UNICAST] = {
- .name = "rx_unicast",
- .reg = SYS_COUNT_RX_UNICAST,
- },
- [OCELOT_STAT_RX_MULTICAST] = {
- .name = "rx_multicast",
- .reg = SYS_COUNT_RX_MULTICAST,
- },
- [OCELOT_STAT_RX_BROADCAST] = {
- .name = "rx_broadcast",
- .reg = SYS_COUNT_RX_BROADCAST,
- },
- [OCELOT_STAT_RX_SHORTS] = {
- .name = "rx_shorts",
- .reg = SYS_COUNT_RX_SHORTS,
- },
- [OCELOT_STAT_RX_FRAGMENTS] = {
- .name = "rx_fragments",
- .reg = SYS_COUNT_RX_FRAGMENTS,
- },
- [OCELOT_STAT_RX_JABBERS] = {
- .name = "rx_jabbers",
- .reg = SYS_COUNT_RX_JABBERS,
- },
- [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = {
- .name = "rx_crc_align_errs",
- .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS,
- },
- [OCELOT_STAT_RX_SYM_ERRS] = {
- .name = "rx_sym_errs",
- .reg = SYS_COUNT_RX_SYM_ERRS,
- },
- [OCELOT_STAT_RX_64] = {
- .name = "rx_frames_below_65_octets",
- .reg = SYS_COUNT_RX_64,
- },
- [OCELOT_STAT_RX_65_127] = {
- .name = "rx_frames_65_to_127_octets",
- .reg = SYS_COUNT_RX_65_127,
- },
- [OCELOT_STAT_RX_128_255] = {
- .name = "rx_frames_128_to_255_octets",
- .reg = SYS_COUNT_RX_128_255,
- },
- [OCELOT_STAT_RX_256_511] = {
- .name = "rx_frames_256_to_511_octets",
- .reg = SYS_COUNT_RX_256_511,
- },
- [OCELOT_STAT_RX_512_1023] = {
- .name = "rx_frames_512_to_1023_octets",
- .reg = SYS_COUNT_RX_512_1023,
- },
- [OCELOT_STAT_RX_1024_1526] = {
- .name = "rx_frames_1024_to_1526_octets",
- .reg = SYS_COUNT_RX_1024_1526,
- },
- [OCELOT_STAT_RX_1527_MAX] = {
- .name = "rx_frames_over_1526_octets",
- .reg = SYS_COUNT_RX_1527_MAX,
- },
- [OCELOT_STAT_RX_PAUSE] = {
- .name = "rx_pause",
- .reg = SYS_COUNT_RX_PAUSE,
- },
- [OCELOT_STAT_RX_CONTROL] = {
- .name = "rx_control",
- .reg = SYS_COUNT_RX_CONTROL,
- },
- [OCELOT_STAT_RX_LONGS] = {
- .name = "rx_longs",
- .reg = SYS_COUNT_RX_LONGS,
- },
- [OCELOT_STAT_RX_CLASSIFIED_DROPS] = {
- .name = "rx_classified_drops",
- .reg = SYS_COUNT_RX_CLASSIFIED_DROPS,
- },
- [OCELOT_STAT_RX_RED_PRIO_0] = {
- .name = "rx_red_prio_0",
- .reg = SYS_COUNT_RX_RED_PRIO_0,
- },
- [OCELOT_STAT_RX_RED_PRIO_1] = {
- .name = "rx_red_prio_1",
- .reg = SYS_COUNT_RX_RED_PRIO_1,
- },
- [OCELOT_STAT_RX_RED_PRIO_2] = {
- .name = "rx_red_prio_2",
- .reg = SYS_COUNT_RX_RED_PRIO_2,
- },
- [OCELOT_STAT_RX_RED_PRIO_3] = {
- .name = "rx_red_prio_3",
- .reg = SYS_COUNT_RX_RED_PRIO_3,
- },
- [OCELOT_STAT_RX_RED_PRIO_4] = {
- .name = "rx_red_prio_4",
- .reg = SYS_COUNT_RX_RED_PRIO_4,
- },
- [OCELOT_STAT_RX_RED_PRIO_5] = {
- .name = "rx_red_prio_5",
- .reg = SYS_COUNT_RX_RED_PRIO_5,
- },
- [OCELOT_STAT_RX_RED_PRIO_6] = {
- .name = "rx_red_prio_6",
- .reg = SYS_COUNT_RX_RED_PRIO_6,
- },
- [OCELOT_STAT_RX_RED_PRIO_7] = {
- .name = "rx_red_prio_7",
- .reg = SYS_COUNT_RX_RED_PRIO_7,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_0] = {
- .name = "rx_yellow_prio_0",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_1] = {
- .name = "rx_yellow_prio_1",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_2] = {
- .name = "rx_yellow_prio_2",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_3] = {
- .name = "rx_yellow_prio_3",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_4] = {
- .name = "rx_yellow_prio_4",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_5] = {
- .name = "rx_yellow_prio_5",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_6] = {
- .name = "rx_yellow_prio_6",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_RX_YELLOW_PRIO_7] = {
- .name = "rx_yellow_prio_7",
- .reg = SYS_COUNT_RX_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_0] = {
- .name = "rx_green_prio_0",
- .reg = SYS_COUNT_RX_GREEN_PRIO_0,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_1] = {
- .name = "rx_green_prio_1",
- .reg = SYS_COUNT_RX_GREEN_PRIO_1,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_2] = {
- .name = "rx_green_prio_2",
- .reg = SYS_COUNT_RX_GREEN_PRIO_2,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_3] = {
- .name = "rx_green_prio_3",
- .reg = SYS_COUNT_RX_GREEN_PRIO_3,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_4] = {
- .name = "rx_green_prio_4",
- .reg = SYS_COUNT_RX_GREEN_PRIO_4,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_5] = {
- .name = "rx_green_prio_5",
- .reg = SYS_COUNT_RX_GREEN_PRIO_5,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_6] = {
- .name = "rx_green_prio_6",
- .reg = SYS_COUNT_RX_GREEN_PRIO_6,
- },
- [OCELOT_STAT_RX_GREEN_PRIO_7] = {
- .name = "rx_green_prio_7",
- .reg = SYS_COUNT_RX_GREEN_PRIO_7,
- },
- [OCELOT_STAT_TX_OCTETS] = {
- .name = "tx_octets",
- .reg = SYS_COUNT_TX_OCTETS,
- },
- [OCELOT_STAT_TX_UNICAST] = {
- .name = "tx_unicast",
- .reg = SYS_COUNT_TX_UNICAST,
- },
- [OCELOT_STAT_TX_MULTICAST] = {
- .name = "tx_multicast",
- .reg = SYS_COUNT_TX_MULTICAST,
- },
- [OCELOT_STAT_TX_BROADCAST] = {
- .name = "tx_broadcast",
- .reg = SYS_COUNT_TX_BROADCAST,
- },
- [OCELOT_STAT_TX_COLLISION] = {
- .name = "tx_collision",
- .reg = SYS_COUNT_TX_COLLISION,
- },
- [OCELOT_STAT_TX_DROPS] = {
- .name = "tx_drops",
- .reg = SYS_COUNT_TX_DROPS,
- },
- [OCELOT_STAT_TX_PAUSE] = {
- .name = "tx_pause",
- .reg = SYS_COUNT_TX_PAUSE,
- },
- [OCELOT_STAT_TX_64] = {
- .name = "tx_frames_below_65_octets",
- .reg = SYS_COUNT_TX_64,
- },
- [OCELOT_STAT_TX_65_127] = {
- .name = "tx_frames_65_to_127_octets",
- .reg = SYS_COUNT_TX_65_127,
- },
- [OCELOT_STAT_TX_128_255] = {
- .name = "tx_frames_128_255_octets",
- .reg = SYS_COUNT_TX_128_255,
- },
- [OCELOT_STAT_TX_256_511] = {
- .name = "tx_frames_256_511_octets",
- .reg = SYS_COUNT_TX_256_511,
- },
- [OCELOT_STAT_TX_512_1023] = {
- .name = "tx_frames_512_1023_octets",
- .reg = SYS_COUNT_TX_512_1023,
- },
- [OCELOT_STAT_TX_1024_1526] = {
- .name = "tx_frames_1024_1526_octets",
- .reg = SYS_COUNT_TX_1024_1526,
- },
- [OCELOT_STAT_TX_1527_MAX] = {
- .name = "tx_frames_over_1526_octets",
- .reg = SYS_COUNT_TX_1527_MAX,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_0] = {
- .name = "tx_yellow_prio_0",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_1] = {
- .name = "tx_yellow_prio_1",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_2] = {
- .name = "tx_yellow_prio_2",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_3] = {
- .name = "tx_yellow_prio_3",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_4] = {
- .name = "tx_yellow_prio_4",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_5] = {
- .name = "tx_yellow_prio_5",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_6] = {
- .name = "tx_yellow_prio_6",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_TX_YELLOW_PRIO_7] = {
- .name = "tx_yellow_prio_7",
- .reg = SYS_COUNT_TX_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_0] = {
- .name = "tx_green_prio_0",
- .reg = SYS_COUNT_TX_GREEN_PRIO_0,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_1] = {
- .name = "tx_green_prio_1",
- .reg = SYS_COUNT_TX_GREEN_PRIO_1,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_2] = {
- .name = "tx_green_prio_2",
- .reg = SYS_COUNT_TX_GREEN_PRIO_2,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_3] = {
- .name = "tx_green_prio_3",
- .reg = SYS_COUNT_TX_GREEN_PRIO_3,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_4] = {
- .name = "tx_green_prio_4",
- .reg = SYS_COUNT_TX_GREEN_PRIO_4,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_5] = {
- .name = "tx_green_prio_5",
- .reg = SYS_COUNT_TX_GREEN_PRIO_5,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_6] = {
- .name = "tx_green_prio_6",
- .reg = SYS_COUNT_TX_GREEN_PRIO_6,
- },
- [OCELOT_STAT_TX_GREEN_PRIO_7] = {
- .name = "tx_green_prio_7",
- .reg = SYS_COUNT_TX_GREEN_PRIO_7,
- },
- [OCELOT_STAT_TX_AGED] = {
- .name = "tx_aged",
- .reg = SYS_COUNT_TX_AGING,
- },
- [OCELOT_STAT_DROP_LOCAL] = {
- .name = "drop_local",
- .reg = SYS_COUNT_DROP_LOCAL,
- },
- [OCELOT_STAT_DROP_TAIL] = {
- .name = "drop_tail",
- .reg = SYS_COUNT_DROP_TAIL,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_0] = {
- .name = "drop_yellow_prio_0",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_0,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_1] = {
- .name = "drop_yellow_prio_1",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_1,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_2] = {
- .name = "drop_yellow_prio_2",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_2,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_3] = {
- .name = "drop_yellow_prio_3",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_3,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_4] = {
- .name = "drop_yellow_prio_4",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_4,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_5] = {
- .name = "drop_yellow_prio_5",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_5,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_6] = {
- .name = "drop_yellow_prio_6",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_6,
- },
- [OCELOT_STAT_DROP_YELLOW_PRIO_7] = {
- .name = "drop_yellow_prio_7",
- .reg = SYS_COUNT_DROP_YELLOW_PRIO_7,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_0] = {
- .name = "drop_green_prio_0",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_0,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_1] = {
- .name = "drop_green_prio_1",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_1,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_2] = {
- .name = "drop_green_prio_2",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_2,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_3] = {
- .name = "drop_green_prio_3",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_3,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_4] = {
- .name = "drop_green_prio_4",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_4,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_5] = {
- .name = "drop_green_prio_5",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_5,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_6] = {
- .name = "drop_green_prio_6",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_6,
- },
- [OCELOT_STAT_DROP_GREEN_PRIO_7] = {
- .name = "drop_green_prio_7",
- .reg = SYS_COUNT_DROP_GREEN_PRIO_7,
- },
+ OCELOT_COMMON_STATS,
};
static const struct vcap_field vsc9953_vcap_es0_keys[] = {
@@ -1432,8 +990,9 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
}
static const struct felix_info seville_info_vsc9953 = {
- .target_io_res = vsc9953_target_io_res,
- .port_io_res = vsc9953_port_io_res,
+ .resources = vsc9953_resources,
+ .num_resources = ARRAY_SIZE(vsc9953_resources),
+ .resource_names = vsc9953_resource_names,
.regfields = vsc9953_regfields,
.map = vsc9953_regmap,
.ops = &vsc9953_ops,
@@ -1450,7 +1009,6 @@ static const struct felix_info seville_info_vsc9953 = {
.mdio_bus_free = vsc9953_mdio_bus_free,
.phylink_validate = vsc9953_phylink_validate,
.port_modes = vsc9953_port_modes,
- .init_regmap = ocelot_regmap_init,
};
static int seville_probe(struct platform_device *pdev)
@@ -1525,8 +1083,6 @@ static int seville_remove(struct platform_device *pdev)
kfree(felix->ds);
kfree(felix);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}