Commit 58f9f9b5 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'configuring-congestion-watermarks-on-ocelot-switch-using-devlink-sb'

Vladimir Oltean says:

====================
Configuring congestion watermarks on ocelot switch using devlink-sb

In some applications, it is important to create resource reservations in
the Ethernet switches, to prevent background traffic, or deliberate
attacks, from inducing denial of service into the high-priority traffic.

These patches give the user some knobs to turn. The ocelot switches
support per-port and per-port-tc reservations, on ingress and on egress.
The resources that are monitored are packet buffers (in cells of 60
bytes each) and frame references.

The frames that exceed the reservations can optionally consume from
sharing watermarks which are not per-port but global across the switch.
There are 10 sharing watermarks, 8 of them are per traffic class and 2
are per drop priority.

I am configuring the hardware using the best of my knowledge, and mostly
through trial and error. Same goes for devlink-sb integration. Feedback
is welcome.
====================

Link: https://lore.kernel.org/r/20210115021120.3055988-1-olteanv@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 2d9116be f59fd9ca
...@@ -299,7 +299,7 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port) ...@@ -299,7 +299,7 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
ANA_PORT_QOS_CFG, ANA_PORT_QOS_CFG,
port); port);
for (i = 0; i < FELIX_NUM_TC * 2; i++) { for (i = 0; i < OCELOT_NUM_TC * 2; i++) {
ocelot_rmw_ix(ocelot, ocelot_rmw_ix(ocelot,
(ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
...@@ -422,12 +422,12 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -422,12 +422,12 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
ocelot->map = felix->info->map; ocelot->map = felix->info->map;
ocelot->stats_layout = felix->info->stats_layout; ocelot->stats_layout = felix->info->stats_layout;
ocelot->num_stats = felix->info->num_stats; ocelot->num_stats = felix->info->num_stats;
ocelot->shared_queue_sz = felix->info->shared_queue_sz;
ocelot->num_mact_rows = felix->info->num_mact_rows; ocelot->num_mact_rows = felix->info->num_mact_rows;
ocelot->vcap = felix->info->vcap; ocelot->vcap = felix->info->vcap;
ocelot->ops = felix->info->ops; ocelot->ops = felix->info->ops;
ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT; ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT;
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_SHORT; ocelot->xtr_prefix = OCELOT_TAG_PREFIX_SHORT;
ocelot->devlink = felix->ds->devlink;
port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
GFP_KERNEL); GFP_KERNEL);
...@@ -589,6 +589,10 @@ static int felix_setup(struct dsa_switch *ds) ...@@ -589,6 +589,10 @@ static int felix_setup(struct dsa_switch *ds)
felix_port_qos_map_init(ocelot, port); felix_port_qos_map_init(ocelot, port);
} }
err = ocelot_devlink_sb_register(ocelot);
if (err)
return err;
/* Include the CPU port module in the forwarding mask for unknown /* Include the CPU port module in the forwarding mask for unknown
* unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST
* excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since
...@@ -610,14 +614,15 @@ static void felix_teardown(struct dsa_switch *ds) ...@@ -610,14 +614,15 @@ static void felix_teardown(struct dsa_switch *ds)
struct felix *felix = ocelot_to_felix(ocelot); struct felix *felix = ocelot_to_felix(ocelot);
int port; int port;
if (felix->info->mdio_bus_free) ocelot_devlink_sb_unregister(ocelot);
felix->info->mdio_bus_free(ocelot); ocelot_deinit_timestamp(ocelot);
ocelot_deinit(ocelot);
for (port = 0; port < ocelot->num_phys_ports; port++) for (port = 0; port < ocelot->num_phys_ports; port++)
ocelot_deinit_port(ocelot, port); ocelot_deinit_port(ocelot, port);
ocelot_deinit_timestamp(ocelot);
/* stop workqueue thread */ if (felix->info->mdio_bus_free)
ocelot_deinit(ocelot); felix->info->mdio_bus_free(ocelot);
} }
static int felix_hwtstamp_get(struct dsa_switch *ds, int port, static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
...@@ -751,6 +756,108 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port, ...@@ -751,6 +756,108 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index,
u16 pool_index,
struct devlink_sb_pool_info *pool_info)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
}
static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index,
u16 pool_index, u32 size,
enum devlink_sb_threshold_type threshold_type,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
threshold_type, extack);
}
static int felix_sb_port_pool_get(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
p_threshold);
}
static int felix_sb_port_pool_set(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 threshold, struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
threshold, extack);
}
static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 *p_pool_index, u32 *p_threshold)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
pool_type, p_pool_index,
p_threshold);
}
static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 pool_index, u32 threshold,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
pool_type, pool_index, threshold,
extack);
}
static int felix_sb_occ_snapshot(struct dsa_switch *ds,
unsigned int sb_index)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_occ_snapshot(ocelot, sb_index);
}
static int felix_sb_occ_max_clear(struct dsa_switch *ds,
unsigned int sb_index)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_occ_max_clear(ocelot, sb_index);
}
static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_cur, u32 *p_max)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
p_cur, p_max);
}
static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max)
{
struct ocelot *ocelot = ds->priv;
return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index,
pool_type, p_cur, p_max);
}
const struct dsa_switch_ops felix_switch_ops = { const struct dsa_switch_ops felix_switch_ops = {
.get_tag_protocol = felix_get_tag_protocol, .get_tag_protocol = felix_get_tag_protocol,
.setup = felix_setup, .setup = felix_setup,
...@@ -789,6 +896,16 @@ const struct dsa_switch_ops felix_switch_ops = { ...@@ -789,6 +896,16 @@ const struct dsa_switch_ops felix_switch_ops = {
.cls_flower_del = felix_cls_flower_del, .cls_flower_del = felix_cls_flower_del,
.cls_flower_stats = felix_cls_flower_stats, .cls_flower_stats = felix_cls_flower_stats,
.port_setup_tc = felix_port_setup_tc, .port_setup_tc = felix_port_setup_tc,
.devlink_sb_pool_get = felix_sb_pool_get,
.devlink_sb_pool_set = felix_sb_pool_set,
.devlink_sb_port_pool_get = felix_sb_port_pool_get,
.devlink_sb_port_pool_set = felix_sb_port_pool_set,
.devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get,
.devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set,
.devlink_sb_occ_snapshot = felix_sb_occ_snapshot,
.devlink_sb_occ_max_clear = felix_sb_occ_max_clear,
.devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get,
.devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get,
}; };
struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#define _MSCC_FELIX_H #define _MSCC_FELIX_H
#define ocelot_to_felix(o) container_of((o), struct felix, ocelot) #define ocelot_to_felix(o) container_of((o), struct felix, ocelot)
#define FELIX_NUM_TC 8
/* Platform-specific information */ /* Platform-specific information */
struct felix_info { struct felix_info {
...@@ -15,7 +14,6 @@ struct felix_info { ...@@ -15,7 +14,6 @@ struct felix_info {
const struct reg_field *regfields; const struct reg_field *regfields;
const u32 *const *map; const u32 *const *map;
const struct ocelot_ops *ops; const struct ocelot_ops *ops;
int shared_queue_sz;
int num_mact_rows; int num_mact_rows;
const struct ocelot_stat_layout *stats_layout; const struct ocelot_stat_layout *stats_layout;
unsigned int num_stats; unsigned int num_stats;
......
...@@ -1006,9 +1006,27 @@ static u16 vsc9959_wm_enc(u16 value) ...@@ -1006,9 +1006,27 @@ static u16 vsc9959_wm_enc(u16 value)
return value; return value;
} }
static u16 vsc9959_wm_dec(u16 wm)
{
WARN_ON(wm & ~GENMASK(8, 0));
if (wm & BIT(8))
return (wm & GENMASK(7, 0)) * 16;
return wm;
}
static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
{
*inuse = (val & GENMASK(23, 12)) >> 12;
*maxuse = val & GENMASK(11, 0);
}
static const struct ocelot_ops vsc9959_ops = { static const struct ocelot_ops vsc9959_ops = {
.reset = vsc9959_reset, .reset = vsc9959_reset,
.wm_enc = vsc9959_wm_enc, .wm_enc = vsc9959_wm_enc,
.wm_dec = vsc9959_wm_dec,
.wm_stat = vsc9959_wm_stat,
.port_to_netdev = felix_port_to_netdev, .port_to_netdev = felix_port_to_netdev,
.netdev_to_port = felix_netdev_to_port, .netdev_to_port = felix_netdev_to_port,
}; };
...@@ -1356,10 +1374,9 @@ static const struct felix_info felix_info_vsc9959 = { ...@@ -1356,10 +1374,9 @@ static const struct felix_info felix_info_vsc9959 = {
.stats_layout = vsc9959_stats_layout, .stats_layout = vsc9959_stats_layout,
.num_stats = ARRAY_SIZE(vsc9959_stats_layout), .num_stats = ARRAY_SIZE(vsc9959_stats_layout),
.vcap = vsc9959_vcap_props, .vcap = vsc9959_vcap_props,
.shared_queue_sz = 128 * 1024,
.num_mact_rows = 2048, .num_mact_rows = 2048,
.num_ports = 6, .num_ports = 6,
.num_tx_queues = FELIX_NUM_TC, .num_tx_queues = OCELOT_NUM_TC,
.switch_pci_bar = 4, .switch_pci_bar = 4,
.imdio_pci_bar = 0, .imdio_pci_bar = 0,
.ptp_caps = &vsc9959_ptp_caps, .ptp_caps = &vsc9959_ptp_caps,
...@@ -1418,7 +1435,7 @@ static int felix_pci_probe(struct pci_dev *pdev, ...@@ -1418,7 +1435,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, felix); pci_set_drvdata(pdev, felix);
ocelot = &felix->ocelot; ocelot = &felix->ocelot;
ocelot->dev = &pdev->dev; ocelot->dev = &pdev->dev;
ocelot->num_flooding_pgids = FELIX_NUM_TC; ocelot->num_flooding_pgids = OCELOT_NUM_TC;
felix->info = &felix_info_vsc9959; felix->info = &felix_info_vsc9959;
felix->switch_base = pci_resource_start(pdev, felix->switch_base = pci_resource_start(pdev,
felix->info->switch_pci_bar); felix->info->switch_pci_bar);
......
...@@ -1057,9 +1057,27 @@ static u16 vsc9953_wm_enc(u16 value) ...@@ -1057,9 +1057,27 @@ static u16 vsc9953_wm_enc(u16 value)
return value; return value;
} }
static u16 vsc9953_wm_dec(u16 wm)
{
WARN_ON(wm & ~GENMASK(9, 0));
if (wm & BIT(9))
return (wm & GENMASK(8, 0)) * 16;
return wm;
}
static void vsc9953_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
{
*inuse = (val & GENMASK(25, 13)) >> 13;
*maxuse = val & GENMASK(12, 0);
}
static const struct ocelot_ops vsc9953_ops = { static const struct ocelot_ops vsc9953_ops = {
.reset = vsc9953_reset, .reset = vsc9953_reset,
.wm_enc = vsc9953_wm_enc, .wm_enc = vsc9953_wm_enc,
.wm_dec = vsc9953_wm_dec,
.wm_stat = vsc9953_wm_stat,
.port_to_netdev = felix_port_to_netdev, .port_to_netdev = felix_port_to_netdev,
.netdev_to_port = felix_netdev_to_port, .netdev_to_port = felix_netdev_to_port,
}; };
...@@ -1181,9 +1199,9 @@ static const struct felix_info seville_info_vsc9953 = { ...@@ -1181,9 +1199,9 @@ static const struct felix_info seville_info_vsc9953 = {
.stats_layout = vsc9953_stats_layout, .stats_layout = vsc9953_stats_layout,
.num_stats = ARRAY_SIZE(vsc9953_stats_layout), .num_stats = ARRAY_SIZE(vsc9953_stats_layout),
.vcap = vsc9953_vcap_props, .vcap = vsc9953_vcap_props,
.shared_queue_sz = 256 * 1024,
.num_mact_rows = 2048, .num_mact_rows = 2048,
.num_ports = 10, .num_ports = 10,
.num_tx_queues = OCELOT_NUM_TC,
.mdio_bus_alloc = vsc9953_mdio_bus_alloc, .mdio_bus_alloc = vsc9953_mdio_bus_alloc,
.mdio_bus_free = vsc9953_mdio_bus_free, .mdio_bus_free = vsc9953_mdio_bus_free,
.phylink_validate = vsc9953_phylink_validate, .phylink_validate = vsc9953_phylink_validate,
......
...@@ -6,7 +6,8 @@ mscc_ocelot_switch_lib-y := \ ...@@ -6,7 +6,8 @@ mscc_ocelot_switch_lib-y := \
ocelot_police.o \ ocelot_police.o \
ocelot_vcap.o \ ocelot_vcap.o \
ocelot_flower.o \ ocelot_flower.o \
ocelot_ptp.o ocelot_ptp.o \
ocelot_devlink.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
mscc_ocelot-y := \ mscc_ocelot-y := \
ocelot_vsc7514.o \ ocelot_vsc7514.o \
......
...@@ -1354,7 +1354,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu) ...@@ -1354,7 +1354,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
pause_stop); pause_stop);
/* Tail dropping watermarks */ /* Tail dropping watermarks */
atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) / atop_tot = (ocelot->packet_buffer_size - 9 * maxlen) /
OCELOT_BUFFER_CELL_SZ; OCELOT_BUFFER_CELL_SZ;
atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ; atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port); ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
...@@ -1467,6 +1467,21 @@ static void ocelot_cpu_port_init(struct ocelot *ocelot) ...@@ -1467,6 +1467,21 @@ static void ocelot_cpu_port_init(struct ocelot *ocelot)
ANA_PORT_VLAN_CFG, cpu); ANA_PORT_VLAN_CFG, cpu);
} }
static void ocelot_detect_features(struct ocelot *ocelot)
{
int mmgt, eq_ctrl;
/* For Ocelot, Felix, Seville, Serval etc, SYS:MMGT:MMGT:FREECNT holds
* the number of 240-byte free memory words (aka 4-cell chunks) and not
* 192 bytes as the documentation incorrectly says.
*/
mmgt = ocelot_read(ocelot, SYS_MMGT);
ocelot->packet_buffer_size = 240 * SYS_MMGT_FREECNT(mmgt);
eq_ctrl = ocelot_read(ocelot, QSYS_EQ_CTRL);
ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl);
}
int ocelot_init(struct ocelot *ocelot) int ocelot_init(struct ocelot *ocelot)
{ {
char queue_name[32]; char queue_name[32];
...@@ -1509,6 +1524,7 @@ int ocelot_init(struct ocelot *ocelot) ...@@ -1509,6 +1524,7 @@ int ocelot_init(struct ocelot *ocelot)
INIT_LIST_HEAD(&ocelot->multicast); INIT_LIST_HEAD(&ocelot->multicast);
INIT_LIST_HEAD(&ocelot->pgids); INIT_LIST_HEAD(&ocelot->pgids);
ocelot_detect_features(ocelot);
ocelot_mact_init(ocelot); ocelot_mact_init(ocelot);
ocelot_vlan_init(ocelot); ocelot_vlan_init(ocelot);
ocelot_vcap_init(ocelot); ocelot_vcap_init(ocelot);
......
...@@ -121,13 +121,15 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); ...@@ -121,13 +121,15 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target, int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
struct phy_device *phy); struct phy_device *phy);
int ocelot_devlink_init(struct ocelot *ocelot);
void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, void ocelot_devlink_teardown(struct ocelot *ocelot);
enum ocelot_tag_prefix injection, int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
enum ocelot_tag_prefix extraction); enum devlink_port_flavour flavour);
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port);
extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb; extern struct notifier_block ocelot_switchdev_blocking_nb;
extern const struct devlink_ops ocelot_devlink_ops;
#endif #endif
This diff is collapsed.
// SPDX-License-Identifier: (GPL-2.0 OR MIT) // SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Microsemi Ocelot Switch driver /* Microsemi Ocelot Switch driver
*
* This contains glue logic between the switchdev driver operations and the
* mscc_ocelot_switch_lib.
* *
* Copyright (c) 2017, 2019 Microsemi Corporation * Copyright (c) 2017, 2019 Microsemi Corporation
* Copyright 2020-2021 NXP Semiconductors
*/ */
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include "ocelot.h" #include "ocelot.h"
#include "ocelot_vcap.h" #include "ocelot_vcap.h"
static struct ocelot *devlink_port_to_ocelot(struct devlink_port *dlp)
{
return devlink_priv(dlp->devlink);
}
static int devlink_port_to_port(struct devlink_port *dlp)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
return dlp - ocelot->devlink_ports;
}
static int ocelot_devlink_sb_pool_get(struct devlink *dl,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info)
{
struct ocelot *ocelot = devlink_priv(dl);
return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
}
static int ocelot_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index,
u16 pool_index, u32 size,
enum devlink_sb_threshold_type threshold_type,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = devlink_priv(dl);
return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
threshold_type, extack);
}
static int ocelot_devlink_sb_port_pool_get(struct devlink_port *dlp,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
p_threshold);
}
static int ocelot_devlink_sb_port_pool_set(struct devlink_port *dlp,
unsigned int sb_index, u16 pool_index,
u32 threshold,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
threshold, extack);
}
static int
ocelot_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 *p_pool_index, u32 *p_threshold)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
pool_type, p_pool_index,
p_threshold);
}
static int
ocelot_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 pool_index, u32 threshold,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
pool_type, pool_index, threshold,
extack);
}
static int ocelot_devlink_sb_occ_snapshot(struct devlink *dl,
unsigned int sb_index)
{
struct ocelot *ocelot = devlink_priv(dl);
return ocelot_sb_occ_snapshot(ocelot, sb_index);
}
static int ocelot_devlink_sb_occ_max_clear(struct devlink *dl,
unsigned int sb_index)
{
struct ocelot *ocelot = devlink_priv(dl);
return ocelot_sb_occ_max_clear(ocelot, sb_index);
}
static int ocelot_devlink_sb_occ_port_pool_get(struct devlink_port *dlp,
unsigned int sb_index,
u16 pool_index, u32 *p_cur,
u32 *p_max)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
p_cur, p_max);
}
static int
ocelot_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max)
{
struct ocelot *ocelot = devlink_port_to_ocelot(dlp);
int port = devlink_port_to_port(dlp);
return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index,
tc_index, pool_type,
p_cur, p_max);
}
const struct devlink_ops ocelot_devlink_ops = {
.sb_pool_get = ocelot_devlink_sb_pool_get,
.sb_pool_set = ocelot_devlink_sb_pool_set,
.sb_port_pool_get = ocelot_devlink_sb_port_pool_get,
.sb_port_pool_set = ocelot_devlink_sb_port_pool_set,
.sb_tc_pool_bind_get = ocelot_devlink_sb_tc_pool_bind_get,
.sb_tc_pool_bind_set = ocelot_devlink_sb_tc_pool_bind_set,
.sb_occ_snapshot = ocelot_devlink_sb_occ_snapshot,
.sb_occ_max_clear = ocelot_devlink_sb_occ_max_clear,
.sb_occ_port_pool_get = ocelot_devlink_sb_occ_port_pool_get,
.sb_occ_tc_port_bind_get = ocelot_devlink_sb_occ_tc_port_bind_get,
};
int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
enum devlink_port_flavour flavour)
{
struct devlink_port *dlp = &ocelot->devlink_ports[port];
int id_len = sizeof(ocelot->base_mac);
struct devlink *dl = ocelot->devlink;
struct devlink_port_attrs attrs = {};
memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
attrs.switch_id.id_len = id_len;
attrs.phys.port_number = port;
attrs.flavour = flavour;
devlink_port_attrs_set(dlp, &attrs);
return devlink_port_register(dl, dlp, port);
}
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port)
{
struct devlink_port *dlp = &ocelot->devlink_ports[port];
devlink_port_unregister(dlp);
}
static struct devlink_port *ocelot_get_devlink_port(struct net_device *dev)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
int port = priv->chip_port;
return &ocelot->devlink_ports[port];
}
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv, int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
struct flow_cls_offload *f, struct flow_cls_offload *f,
bool ingress) bool ingress)
...@@ -525,20 +702,6 @@ static void ocelot_set_rx_mode(struct net_device *dev) ...@@ -525,20 +702,6 @@ static void ocelot_set_rx_mode(struct net_device *dev)
__dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync); __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
} }
static int ocelot_port_get_phys_port_name(struct net_device *dev,
char *buf, size_t len)
{
struct ocelot_port_private *priv = netdev_priv(dev);
int port = priv->chip_port;
int ret;
ret = snprintf(buf, len, "p%d", port);
if (ret >= len)
return -EINVAL;
return 0;
}
static int ocelot_port_set_mac_address(struct net_device *dev, void *p) static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
{ {
struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port_private *priv = netdev_priv(dev);
...@@ -689,18 +852,6 @@ static int ocelot_set_features(struct net_device *dev, ...@@ -689,18 +852,6 @@ static int ocelot_set_features(struct net_device *dev,
return 0; return 0;
} }
static int ocelot_get_port_parent_id(struct net_device *dev,
struct netdev_phys_item_id *ppid)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
ppid->id_len = sizeof(ocelot->base_mac);
memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
return 0;
}
static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port_private *priv = netdev_priv(dev);
...@@ -727,7 +878,6 @@ static const struct net_device_ops ocelot_port_netdev_ops = { ...@@ -727,7 +878,6 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_stop = ocelot_port_stop, .ndo_stop = ocelot_port_stop,
.ndo_start_xmit = ocelot_port_xmit, .ndo_start_xmit = ocelot_port_xmit,
.ndo_set_rx_mode = ocelot_set_rx_mode, .ndo_set_rx_mode = ocelot_set_rx_mode,
.ndo_get_phys_port_name = ocelot_port_get_phys_port_name,
.ndo_set_mac_address = ocelot_port_set_mac_address, .ndo_set_mac_address = ocelot_port_set_mac_address,
.ndo_get_stats64 = ocelot_get_stats64, .ndo_get_stats64 = ocelot_get_stats64,
.ndo_fdb_add = ocelot_port_fdb_add, .ndo_fdb_add = ocelot_port_fdb_add,
...@@ -736,9 +886,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = { ...@@ -736,9 +886,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
.ndo_set_features = ocelot_set_features, .ndo_set_features = ocelot_set_features,
.ndo_get_port_parent_id = ocelot_get_port_parent_id,
.ndo_setup_tc = ocelot_setup_tc, .ndo_setup_tc = ocelot_setup_tc,
.ndo_do_ioctl = ocelot_ioctl, .ndo_do_ioctl = ocelot_ioctl,
.ndo_get_devlink_port = ocelot_get_devlink_port,
}; };
struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port) struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port)
......
...@@ -517,7 +517,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) ...@@ -517,7 +517,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
ocelot->map = ocelot_regmap; ocelot->map = ocelot_regmap;
ocelot->stats_layout = ocelot_stats_layout; ocelot->stats_layout = ocelot_stats_layout;
ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout); ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout);
ocelot->shared_queue_sz = 224 * 1024;
ocelot->num_mact_rows = 1024; ocelot->num_mact_rows = 1024;
ocelot->ops = ops; ocelot->ops = ops;
...@@ -764,9 +763,25 @@ static u16 ocelot_wm_enc(u16 value) ...@@ -764,9 +763,25 @@ static u16 ocelot_wm_enc(u16 value)
return value; return value;
} }
static u16 ocelot_wm_dec(u16 wm)
{
if (wm & BIT(8))
return (wm & GENMASK(7, 0)) * 16;
return wm;
}
static void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
{
*inuse = (val & GENMASK(23, 12)) >> 12;
*maxuse = val & GENMASK(11, 0);
}
static const struct ocelot_ops ocelot_ops = { static const struct ocelot_ops ocelot_ops = {
.reset = ocelot_reset, .reset = ocelot_reset,
.wm_enc = ocelot_wm_enc, .wm_enc = ocelot_wm_enc,
.wm_dec = ocelot_wm_dec,
.wm_stat = ocelot_wm_stat,
.port_to_netdev = ocelot_port_to_netdev, .port_to_netdev = ocelot_port_to_netdev,
.netdev_to_port = ocelot_netdev_to_port, .netdev_to_port = ocelot_netdev_to_port,
}; };
...@@ -1036,6 +1051,14 @@ static struct ptp_clock_info ocelot_ptp_clock_info = { ...@@ -1036,6 +1051,14 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
.enable = ocelot_ptp_enable, .enable = ocelot_ptp_enable,
}; };
static void mscc_ocelot_teardown_devlink_ports(struct ocelot *ocelot)
{
int port;
for (port = 0; port < ocelot->num_phys_ports; port++)
ocelot_port_devlink_teardown(ocelot, port);
}
static void mscc_ocelot_release_ports(struct ocelot *ocelot) static void mscc_ocelot_release_ports(struct ocelot *ocelot)
{ {
int port; int port;
...@@ -1063,28 +1086,44 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev, ...@@ -1063,28 +1086,44 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
{ {
struct ocelot *ocelot = platform_get_drvdata(pdev); struct ocelot *ocelot = platform_get_drvdata(pdev);
struct device_node *portnp; struct device_node *portnp;
int err; bool *registered_ports;
int port, err;
u32 reg;
ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
sizeof(struct ocelot_port *), GFP_KERNEL); sizeof(struct ocelot_port *), GFP_KERNEL);
if (!ocelot->ports) if (!ocelot->ports)
return -ENOMEM; return -ENOMEM;
ocelot->devlink_ports = devm_kcalloc(ocelot->dev,
ocelot->num_phys_ports,
sizeof(*ocelot->devlink_ports),
GFP_KERNEL);
if (!ocelot->devlink_ports)
return -ENOMEM;
registered_ports = kcalloc(ocelot->num_phys_ports, sizeof(bool),
GFP_KERNEL);
if (!registered_ports)
return -ENOMEM;
for_each_available_child_of_node(ports, portnp) { for_each_available_child_of_node(ports, portnp) {
struct ocelot_port_private *priv; struct ocelot_port_private *priv;
struct ocelot_port *ocelot_port; struct ocelot_port *ocelot_port;
struct device_node *phy_node; struct device_node *phy_node;
struct devlink_port *dlp;
phy_interface_t phy_mode; phy_interface_t phy_mode;
struct phy_device *phy; struct phy_device *phy;
struct regmap *target; struct regmap *target;
struct resource *res; struct resource *res;
struct phy *serdes; struct phy *serdes;
char res_name[8]; char res_name[8];
u32 port;
if (of_property_read_u32(portnp, "reg", &port)) if (of_property_read_u32(portnp, "reg", &reg))
continue; continue;
port = reg;
snprintf(res_name, sizeof(res_name), "port%d", port); snprintf(res_name, sizeof(res_name), "port%d", port);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
...@@ -1102,15 +1141,26 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev, ...@@ -1102,15 +1141,26 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
if (!phy) if (!phy)
continue; continue;
err = ocelot_port_devlink_init(ocelot, port,
DEVLINK_PORT_FLAVOUR_PHYSICAL);
if (err) {
of_node_put(portnp);
goto out_teardown;
}
err = ocelot_probe_port(ocelot, port, target, phy); err = ocelot_probe_port(ocelot, port, target, phy);
if (err) { if (err) {
of_node_put(portnp); of_node_put(portnp);
return err; goto out_teardown;
} }
registered_ports[port] = true;
ocelot_port = ocelot->ports[port]; ocelot_port = ocelot->ports[port];
priv = container_of(ocelot_port, struct ocelot_port_private, priv = container_of(ocelot_port, struct ocelot_port_private,
port); port);
dlp = &ocelot->devlink_ports[port];
devlink_port_type_eth_set(dlp, priv->dev);
of_get_phy_mode(portnp, &phy_mode); of_get_phy_mode(portnp, &phy_mode);
...@@ -1135,7 +1185,8 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev, ...@@ -1135,7 +1185,8 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
"invalid phy mode for port%d, (Q)SGMII only\n", "invalid phy mode for port%d, (Q)SGMII only\n",
port); port);
of_node_put(portnp); of_node_put(portnp);
return -EINVAL; err = -EINVAL;
goto out_teardown;
} }
serdes = devm_of_phy_get(ocelot->dev, portnp, NULL); serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
...@@ -1149,13 +1200,46 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev, ...@@ -1149,13 +1200,46 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
port); port);
of_node_put(portnp); of_node_put(portnp);
return err; goto out_teardown;
} }
priv->serdes = serdes; priv->serdes = serdes;
} }
/* Initialize unused devlink ports at the end */
for (port = 0; port < ocelot->num_phys_ports; port++) {
if (registered_ports[port])
continue;
err = ocelot_port_devlink_init(ocelot, port,
DEVLINK_PORT_FLAVOUR_UNUSED);
if (err) {
while (port-- >= 0) {
if (!registered_ports[port])
continue;
ocelot_port_devlink_teardown(ocelot, port);
}
goto out_teardown;
}
}
kfree(registered_ports);
return 0; return 0;
out_teardown:
/* Unregister the network interfaces */
mscc_ocelot_release_ports(ocelot);
/* Tear down devlink ports for the registered network interfaces */
for (port = 0; port < ocelot->num_phys_ports; port++) {
if (!registered_ports[port])
continue;
ocelot_port_devlink_teardown(ocelot, port);
}
kfree(registered_ports);
return err;
} }
static int mscc_ocelot_probe(struct platform_device *pdev) static int mscc_ocelot_probe(struct platform_device *pdev)
...@@ -1163,6 +1247,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1163,6 +1247,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
int err, irq_xtr, irq_ptp_rdy; int err, irq_xtr, irq_ptp_rdy;
struct device_node *ports; struct device_node *ports;
struct devlink *devlink;
struct ocelot *ocelot; struct ocelot *ocelot;
struct regmap *hsio; struct regmap *hsio;
unsigned int i; unsigned int i;
...@@ -1186,10 +1271,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1186,10 +1271,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
if (!np && !pdev->dev.platform_data) if (!np && !pdev->dev.platform_data)
return -ENODEV; return -ENODEV;
ocelot = devm_kzalloc(&pdev->dev, sizeof(*ocelot), GFP_KERNEL); devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot));
if (!ocelot) if (!devlink)
return -ENOMEM; return -ENOMEM;
ocelot = devlink_priv(devlink);
ocelot->devlink = priv_to_devlink(ocelot);
platform_set_drvdata(pdev, ocelot); platform_set_drvdata(pdev, ocelot);
ocelot->dev = &pdev->dev; ocelot->dev = &pdev->dev;
...@@ -1206,7 +1293,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1206,7 +1293,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->targets[io_target[i].id] = NULL; ocelot->targets[io_target[i].id] = NULL;
continue; continue;
} }
return PTR_ERR(target); err = PTR_ERR(target);
goto out_free_devlink;
} }
ocelot->targets[io_target[i].id] = target; ocelot->targets[io_target[i].id] = target;
...@@ -1215,24 +1303,25 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1215,24 +1303,25 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio"); hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
if (IS_ERR(hsio)) { if (IS_ERR(hsio)) {
dev_err(&pdev->dev, "missing hsio syscon\n"); dev_err(&pdev->dev, "missing hsio syscon\n");
return PTR_ERR(hsio); err = PTR_ERR(hsio);
goto out_free_devlink;
} }
ocelot->targets[HSIO] = hsio; ocelot->targets[HSIO] = hsio;
err = ocelot_chip_init(ocelot, &ocelot_ops); err = ocelot_chip_init(ocelot, &ocelot_ops);
if (err) if (err)
return err; goto out_free_devlink;
irq_xtr = platform_get_irq_byname(pdev, "xtr"); irq_xtr = platform_get_irq_byname(pdev, "xtr");
if (irq_xtr < 0) if (irq_xtr < 0)
return -ENODEV; goto out_free_devlink;
err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL, err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
ocelot_xtr_irq_handler, IRQF_ONESHOT, ocelot_xtr_irq_handler, IRQF_ONESHOT,
"frame extraction", ocelot); "frame extraction", ocelot);
if (err) if (err)
return err; goto out_free_devlink;
irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy"); irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) { if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
...@@ -1241,7 +1330,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1241,7 +1330,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
IRQF_ONESHOT, "ptp ready", IRQF_ONESHOT, "ptp ready",
ocelot); ocelot);
if (err) if (err)
return err; goto out_free_devlink;
/* Both the PTP interrupt and the PTP bank are available */ /* Both the PTP interrupt and the PTP bank are available */
ocelot->ptp = 1; ocelot->ptp = 1;
...@@ -1250,7 +1339,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1250,7 +1339,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ports = of_get_child_by_name(np, "ethernet-ports"); ports = of_get_child_by_name(np, "ethernet-ports");
if (!ports) { if (!ports) {
dev_err(ocelot->dev, "no ethernet-ports child node found\n"); dev_err(ocelot->dev, "no ethernet-ports child node found\n");
return -ENODEV; err = -ENODEV;
goto out_free_devlink;
} }
ocelot->num_phys_ports = of_get_child_count(ports); ocelot->num_phys_ports = of_get_child_count(ports);
...@@ -1265,10 +1355,18 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1265,10 +1355,18 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
if (err) if (err)
goto out_put_ports; goto out_put_ports;
err = mscc_ocelot_init_ports(pdev, ports); err = devlink_register(devlink, ocelot->dev);
if (err) if (err)
goto out_ocelot_deinit; goto out_ocelot_deinit;
err = mscc_ocelot_init_ports(pdev, ports);
if (err)
goto out_ocelot_devlink_unregister;
err = ocelot_devlink_sb_register(ocelot);
if (err)
goto out_ocelot_release_ports;
if (ocelot->ptp) { if (ocelot->ptp) {
err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
if (err) { if (err) {
...@@ -1288,10 +1386,17 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1288,10 +1386,17 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
return 0; return 0;
out_ocelot_release_ports:
mscc_ocelot_release_ports(ocelot);
mscc_ocelot_teardown_devlink_ports(ocelot);
out_ocelot_devlink_unregister:
devlink_unregister(devlink);
out_ocelot_deinit: out_ocelot_deinit:
ocelot_deinit(ocelot); ocelot_deinit(ocelot);
out_put_ports: out_put_ports:
of_node_put(ports); of_node_put(ports);
out_free_devlink:
devlink_free(devlink);
return err; return err;
} }
...@@ -1300,11 +1405,15 @@ static int mscc_ocelot_remove(struct platform_device *pdev) ...@@ -1300,11 +1405,15 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
struct ocelot *ocelot = platform_get_drvdata(pdev); struct ocelot *ocelot = platform_get_drvdata(pdev);
ocelot_deinit_timestamp(ocelot); ocelot_deinit_timestamp(ocelot);
ocelot_devlink_sb_unregister(ocelot);
mscc_ocelot_release_ports(ocelot); mscc_ocelot_release_ports(ocelot);
mscc_ocelot_teardown_devlink_ports(ocelot);
devlink_unregister(ocelot->devlink);
ocelot_deinit(ocelot); ocelot_deinit(ocelot);
unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
unregister_switchdev_notifier(&ocelot_switchdev_nb); unregister_switchdev_notifier(&ocelot_switchdev_nb);
unregister_netdevice_notifier(&ocelot_netdevice_nb); unregister_netdevice_notifier(&ocelot_netdevice_nb);
devlink_free(ocelot->devlink);
return 0; return 0;
} }
......
...@@ -699,6 +699,40 @@ struct dsa_switch_ops { ...@@ -699,6 +699,40 @@ struct dsa_switch_ops {
int (*devlink_info_get)(struct dsa_switch *ds, int (*devlink_info_get)(struct dsa_switch *ds,
struct devlink_info_req *req, struct devlink_info_req *req,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int (*devlink_sb_pool_get)(struct dsa_switch *ds,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info);
int (*devlink_sb_pool_set)(struct dsa_switch *ds, unsigned int sb_index,
u16 pool_index, u32 size,
enum devlink_sb_threshold_type threshold_type,
struct netlink_ext_ack *extack);
int (*devlink_sb_port_pool_get)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold);
int (*devlink_sb_port_pool_set)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 threshold,
struct netlink_ext_ack *extack);
int (*devlink_sb_tc_pool_bind_get)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 *p_pool_index, u32 *p_threshold);
int (*devlink_sb_tc_pool_bind_set)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 pool_index, u32 threshold,
struct netlink_ext_ack *extack);
int (*devlink_sb_occ_snapshot)(struct dsa_switch *ds,
unsigned int sb_index);
int (*devlink_sb_occ_max_clear)(struct dsa_switch *ds,
unsigned int sb_index);
int (*devlink_sb_occ_port_pool_get)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_cur, u32 *p_max);
int (*devlink_sb_occ_tc_port_bind_get)(struct dsa_switch *ds, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max);
/* /*
* MTU change functionality. Switches can also adjust their MRU through * MTU change functionality. Switches can also adjust their MRU through
......
...@@ -98,6 +98,7 @@ ...@@ -98,6 +98,7 @@
#define IFH_REW_OP_TWO_STEP_PTP 0x3 #define IFH_REW_OP_TWO_STEP_PTP 0x3
#define IFH_REW_OP_ORIGIN_PTP 0x5 #define IFH_REW_OP_ORIGIN_PTP 0x5
#define OCELOT_NUM_TC 8
#define OCELOT_TAG_LEN 16 #define OCELOT_TAG_LEN 16
#define OCELOT_SHORT_PREFIX_LEN 4 #define OCELOT_SHORT_PREFIX_LEN 4
#define OCELOT_LONG_PREFIX_LEN 16 #define OCELOT_LONG_PREFIX_LEN 16
...@@ -563,6 +564,8 @@ struct ocelot_ops { ...@@ -563,6 +564,8 @@ struct ocelot_ops {
int (*netdev_to_port)(struct net_device *dev); int (*netdev_to_port)(struct net_device *dev);
int (*reset)(struct ocelot *ocelot); int (*reset)(struct ocelot *ocelot);
u16 (*wm_enc)(u16 value); u16 (*wm_enc)(u16 value);
u16 (*wm_dec)(u16 value);
void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse);
}; };
struct ocelot_vcap_block { struct ocelot_vcap_block {
...@@ -576,6 +579,18 @@ struct ocelot_vlan { ...@@ -576,6 +579,18 @@ struct ocelot_vlan {
u16 vid; u16 vid;
}; };
enum ocelot_sb {
OCELOT_SB_BUF,
OCELOT_SB_REF,
OCELOT_SB_NUM,
};
enum ocelot_sb_pool {
OCELOT_SB_POOL_ING,
OCELOT_SB_POOL_EGR,
OCELOT_SB_POOL_NUM,
};
struct ocelot_port { struct ocelot_port {
struct ocelot *ocelot; struct ocelot *ocelot;
...@@ -599,6 +614,8 @@ struct ocelot_port { ...@@ -599,6 +614,8 @@ struct ocelot_port {
struct ocelot { struct ocelot {
struct device *dev; struct device *dev;
struct devlink *devlink;
struct devlink_port *devlink_ports;
const struct ocelot_ops *ops; const struct ocelot_ops *ops;
struct regmap *targets[TARGET_MAX]; struct regmap *targets[TARGET_MAX];
...@@ -607,7 +624,9 @@ struct ocelot { ...@@ -607,7 +624,9 @@ struct ocelot {
const struct ocelot_stat_layout *stats_layout; const struct ocelot_stat_layout *stats_layout;
unsigned int num_stats; unsigned int num_stats;
int shared_queue_sz; u32 pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM];
int packet_buffer_size;
int num_frame_refs;
int num_mact_rows; int num_mact_rows;
struct net_device *hw_bridge_dev; struct net_device *hw_bridge_dev;
...@@ -777,4 +796,38 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port, ...@@ -777,4 +796,38 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port,
int ocelot_port_mdb_del(struct ocelot *ocelot, int port, int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_port_mdb *mdb); const struct switchdev_obj_port_mdb *mdb);
int ocelot_devlink_sb_register(struct ocelot *ocelot);
void ocelot_devlink_sb_unregister(struct ocelot *ocelot);
int ocelot_sb_pool_get(struct ocelot *ocelot, unsigned int sb_index,
u16 pool_index,
struct devlink_sb_pool_info *pool_info);
int ocelot_sb_pool_set(struct ocelot *ocelot, unsigned int sb_index,
u16 pool_index, u32 size,
enum devlink_sb_threshold_type threshold_type,
struct netlink_ext_ack *extack);
int ocelot_sb_port_pool_get(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold);
int ocelot_sb_port_pool_set(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 pool_index,
u32 threshold, struct netlink_ext_ack *extack);
int ocelot_sb_tc_pool_bind_get(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 *p_pool_index, u32 *p_threshold);
int ocelot_sb_tc_pool_bind_set(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 pool_index, u32 threshold,
struct netlink_ext_ack *extack);
int ocelot_sb_occ_snapshot(struct ocelot *ocelot, unsigned int sb_index);
int ocelot_sb_occ_max_clear(struct ocelot *ocelot, unsigned int sb_index);
int ocelot_sb_occ_port_pool_get(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 pool_index,
u32 *p_cur, u32 *p_max);
int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max);
#endif #endif
...@@ -71,11 +71,8 @@ ...@@ -71,11 +71,8 @@
#define QSYS_RES_STAT_GSZ 0x8 #define QSYS_RES_STAT_GSZ 0x8
#define QSYS_RES_STAT_INUSE(x) (((x) << 12) & GENMASK(23, 12)) #define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(x) ((x) & GENMASK(15, 0))
#define QSYS_RES_STAT_INUSE_M GENMASK(23, 12) #define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT_M GENMASK(15, 0)
#define QSYS_RES_STAT_INUSE_X(x) (((x) & GENMASK(23, 12)) >> 12)
#define QSYS_RES_STAT_MAXUSE(x) ((x) & GENMASK(11, 0))
#define QSYS_RES_STAT_MAXUSE_M GENMASK(11, 0)
#define QSYS_EVENTS_CORE_EV_FDC(x) (((x) << 2) & GENMASK(4, 2)) #define QSYS_EVENTS_CORE_EV_FDC(x) (((x) << 2) & GENMASK(4, 2))
#define QSYS_EVENTS_CORE_EV_FDC_M GENMASK(4, 2) #define QSYS_EVENTS_CORE_EV_FDC_M GENMASK(4, 2)
......
...@@ -463,8 +463,165 @@ static int dsa_devlink_info_get(struct devlink *dl, ...@@ -463,8 +463,165 @@ static int dsa_devlink_info_get(struct devlink *dl,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int dsa_devlink_sb_pool_get(struct devlink *dl,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info)
{
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
if (!ds->ops->devlink_sb_pool_get)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_pool_get(ds, sb_index, pool_index,
pool_info);
}
static int dsa_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index,
u16 pool_index, u32 size,
enum devlink_sb_threshold_type threshold_type,
struct netlink_ext_ack *extack)
{
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
if (!ds->ops->devlink_sb_pool_set)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_pool_set(ds, sb_index, pool_index, size,
threshold_type, extack);
}
static int dsa_devlink_sb_port_pool_get(struct devlink_port *dlp,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_port_pool_get)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_port_pool_get(ds, port, sb_index,
pool_index, p_threshold);
}
static int dsa_devlink_sb_port_pool_set(struct devlink_port *dlp,
unsigned int sb_index, u16 pool_index,
u32 threshold,
struct netlink_ext_ack *extack)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_port_pool_set)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_port_pool_set(ds, port, sb_index,
pool_index, threshold, extack);
}
static int
dsa_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 *p_pool_index, u32 *p_threshold)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_tc_pool_bind_get)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_tc_pool_bind_get(ds, port, sb_index,
tc_index, pool_type,
p_pool_index, p_threshold);
}
static int
dsa_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u16 pool_index, u32 threshold,
struct netlink_ext_ack *extack)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_tc_pool_bind_set)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_tc_pool_bind_set(ds, port, sb_index,
tc_index, pool_type,
pool_index, threshold,
extack);
}
static int dsa_devlink_sb_occ_snapshot(struct devlink *dl,
unsigned int sb_index)
{
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
if (!ds->ops->devlink_sb_occ_snapshot)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_occ_snapshot(ds, sb_index);
}
static int dsa_devlink_sb_occ_max_clear(struct devlink *dl,
unsigned int sb_index)
{
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
if (!ds->ops->devlink_sb_occ_max_clear)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_occ_max_clear(ds, sb_index);
}
static int dsa_devlink_sb_occ_port_pool_get(struct devlink_port *dlp,
unsigned int sb_index,
u16 pool_index, u32 *p_cur,
u32 *p_max)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_occ_port_pool_get)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_occ_port_pool_get(ds, port, sb_index,
pool_index, p_cur, p_max);
}
static int
dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max)
{
struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
int port = dsa_devlink_port_to_port(dlp);
if (!ds->ops->devlink_sb_occ_tc_port_bind_get)
return -EOPNOTSUPP;
return ds->ops->devlink_sb_occ_tc_port_bind_get(ds, port,
sb_index, tc_index,
pool_type, p_cur,
p_max);
}
static const struct devlink_ops dsa_devlink_ops = { static const struct devlink_ops dsa_devlink_ops = {
.info_get = dsa_devlink_info_get, .info_get = dsa_devlink_info_get,
.sb_pool_get = dsa_devlink_sb_pool_get,
.sb_pool_set = dsa_devlink_sb_pool_set,
.sb_port_pool_get = dsa_devlink_sb_port_pool_get,
.sb_port_pool_set = dsa_devlink_sb_port_pool_set,
.sb_tc_pool_bind_get = dsa_devlink_sb_tc_pool_bind_get,
.sb_tc_pool_bind_set = dsa_devlink_sb_tc_pool_bind_set,
.sb_occ_snapshot = dsa_devlink_sb_occ_snapshot,
.sb_occ_max_clear = dsa_devlink_sb_occ_max_clear,
.sb_occ_port_pool_get = dsa_devlink_sb_occ_port_pool_get,
.sb_occ_tc_port_bind_get = dsa_devlink_sb_occ_tc_port_bind_get,
}; };
static int dsa_switch_setup(struct dsa_switch *ds) static int dsa_switch_setup(struct dsa_switch *ds)
......
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