Commit f59fd9ca authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Jakub Kicinski

net: mscc: ocelot: configure watermarks using devlink-sb

Using devlink-sb, we can configure 12/16 (the important 75%) of the
switch's controlling watermarks for congestion drops, and we can monitor
50% of the watermark occupancies (we can monitor the reservation
watermarks, but not the sharing watermarks, which are exposed as pool
sizes).

The following definitions can be made:

SB_BUF=0 # The devlink-sb for frame buffers
SB_REF=1 # The devlink-sb for frame references
POOL_ING=0 # The pool for ingress traffic. Both devlink-sb instances
           # have one of these.
POOL_EGR=1 # The pool for egress traffic. Both devlink-sb instances
           # have one of these.

Editing the hardware watermarks is done in the following way:
BUF_xxxx_I is accessed when sb=$SB_BUF and pool=$POOL_ING
REF_xxxx_I is accessed when sb=$SB_REF and pool=$POOL_ING
BUF_xxxx_E is accessed when sb=$SB_BUF and pool=$POOL_EGR
REF_xxxx_E is accessed when sb=$SB_REF and pool=$POOL_EGR

Configuring the sharing watermarks for COL_SHR(dp=0) is done implicitly
by modifying the corresponding pool size. By default, the pool size has
maximum size, so this can be skipped.

devlink sb pool set pci/0000:00:00.5 sb $SB_BUF pool $POOL_ING \
	size 129840 thtype static

Since by default there is no buffer reservation, the above command has
maxed out BUF_COL_SHR_I(dp=0).

Configuring the per-port reservation watermark (P_RSRV) is done in the
following way:

devlink sb port pool set pci/0000:00:00.5/0 sb $SB_BUF \
	pool $POOL_ING th 1000

The above command sets BUF_P_RSRV_I(port 0) to 1000 bytes. After this
command, the sharing watermarks are internally reconfigured with 1000
bytes less, i.e. from 129840 bytes to 128840 bytes.

Configuring the per-port-tc reservation watermarks (Q_RSRV) is done in
the following way:

for tc in {0..7}; do
	devlink sb tc bind set pci/0000:00:00.5/0 sb 0 tc $tc \
		type ingress pool $POOL_ING \
		th 3000
done

The above command sets BUF_Q_RSRV_I(port 0, tc 0..7) to 3000 bytes.
The sharing watermarks are again reconfigured with 24000 bytes less.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a4ae997a
...@@ -427,6 +427,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -427,6 +427,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
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);
...@@ -588,6 +589,10 @@ static int felix_setup(struct dsa_switch *ds) ...@@ -588,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
...@@ -609,6 +614,7 @@ static void felix_teardown(struct dsa_switch *ds) ...@@ -609,6 +614,7 @@ 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;
ocelot_devlink_sb_unregister(ocelot);
ocelot_deinit_timestamp(ocelot); ocelot_deinit_timestamp(ocelot);
ocelot_deinit(ocelot); ocelot_deinit(ocelot);
...@@ -750,6 +756,108 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port, ...@@ -750,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,
...@@ -788,6 +896,16 @@ const struct dsa_switch_ops felix_switch_ops = { ...@@ -788,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)
......
...@@ -1480,10 +1480,6 @@ static void ocelot_detect_features(struct ocelot *ocelot) ...@@ -1480,10 +1480,6 @@ static void ocelot_detect_features(struct ocelot *ocelot)
eq_ctrl = ocelot_read(ocelot, QSYS_EQ_CTRL); eq_ctrl = ocelot_read(ocelot, QSYS_EQ_CTRL);
ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl); ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl);
dev_info(ocelot->dev,
"Detected %d bytes of packet buffer and %d frame references\n",
ocelot->packet_buffer_size, ocelot->num_frame_refs);
} }
int ocelot_init(struct ocelot *ocelot) int ocelot_init(struct ocelot *ocelot)
...@@ -1624,7 +1620,6 @@ int ocelot_init(struct ocelot *ocelot) ...@@ -1624,7 +1620,6 @@ int ocelot_init(struct ocelot *ocelot)
INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work); INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
OCELOT_STATS_CHECK_DELAY); OCELOT_STATS_CHECK_DELAY);
ocelot_watermark_init(ocelot);
return 0; return 0;
} }
......
...@@ -126,7 +126,6 @@ void ocelot_devlink_teardown(struct ocelot *ocelot); ...@@ -126,7 +126,6 @@ void ocelot_devlink_teardown(struct ocelot *ocelot);
int ocelot_port_devlink_init(struct ocelot *ocelot, int port, int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
enum devlink_port_flavour flavour); enum devlink_port_flavour flavour);
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port); void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port);
void ocelot_watermark_init(struct ocelot *ocelot);
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;
......
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 = { 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, int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
......
...@@ -1363,6 +1363,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1363,6 +1363,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
if (err) if (err)
goto out_ocelot_devlink_unregister; 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) {
...@@ -1382,6 +1386,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1382,6 +1386,9 @@ 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: out_ocelot_devlink_unregister:
devlink_unregister(devlink); devlink_unregister(devlink);
out_ocelot_deinit: out_ocelot_deinit:
...@@ -1398,6 +1405,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev) ...@@ -1398,6 +1405,7 @@ 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); mscc_ocelot_teardown_devlink_ports(ocelot);
devlink_unregister(ocelot->devlink); devlink_unregister(ocelot->devlink);
......
...@@ -579,6 +579,18 @@ struct ocelot_vlan { ...@@ -579,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;
...@@ -612,6 +624,7 @@ struct ocelot { ...@@ -612,6 +624,7 @@ struct ocelot {
const struct ocelot_stat_layout *stats_layout; const struct ocelot_stat_layout *stats_layout;
unsigned int num_stats; unsigned int num_stats;
u32 pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM];
int packet_buffer_size; int packet_buffer_size;
int num_frame_refs; int num_frame_refs;
int num_mact_rows; int num_mact_rows;
...@@ -783,4 +796,38 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port, ...@@ -783,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
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