Messages in this thread Patch in this message | | | From | Oleksandr Mazur <> | Subject | [PATCH net-next 10/11] net: marvell: prestera: add storm control (rate limiter) implementation | Date | Wed, 9 Jun 2021 18:16:00 +0300 |
| |
Storm control (BUM) provides a mechanism to limit rate of ingress port traffic (matched by type). Devlink port parameter API is used: driver registers a set of per-port parameters that can be accessed to both get/set per-port per-type rate limit. Add new FW command - RATE_LIMIT_MODE_SET.
Signed-off-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu> --- .../net/ethernet/marvell/prestera/prestera.h | 7 + .../marvell/prestera/prestera_devlink.c | 134 +++++++++++++++++- .../ethernet/marvell/prestera/prestera_hw.c | 25 ++++ .../ethernet/marvell/prestera/prestera_hw.h | 9 ++ 4 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/prestera/prestera.h b/drivers/net/ethernet/marvell/prestera/prestera.h index 2c94bdec84b1..4b99a7421452 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera.h +++ b/drivers/net/ethernet/marvell/prestera/prestera.h @@ -60,6 +60,12 @@ struct prestera_port_caps { u8 transceiver; }; +struct prestera_strom_control_cfg { + u32 bc_kbyte_per_sec_rate; + u32 unk_uc_kbyte_per_sec_rate; + u32 unreg_mc_kbyte_per_sec_rate; +}; + struct prestera_port { struct net_device *dev; struct prestera_switch *sw; @@ -79,6 +85,7 @@ struct prestera_port { struct prestera_port_stats stats; struct delayed_work caching_dw; } cached_hw_stats; + struct prestera_strom_control_cfg storm_control; }; struct prestera_device { diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c index d12e21db9fd6..0786fbb09f71 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c @@ -2,6 +2,8 @@ /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */ #include <net/devlink.h> +#include <linux/bitops.h> +#include <linux/bitfield.h> #include "prestera_devlink.h" #include "prestera_hw.h" @@ -159,6 +161,34 @@ struct prestera_trap_data { DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ PRESTERA_TRAP_METADATA) +#define PRESTERA_PORT_PARAM_DRIVER_RUNTIME(_id, _name, _type) \ + DEVLINK_PARAM_DRIVER(PRESTERA_DEVLINK_PORT_PARAM_ID_##_id, _name, \ + _type, BIT(DEVLINK_PARAM_CMODE_RUNTIME), NULL, \ + NULL, NULL) + +struct prestera_storm_control { + struct prestera_switch *sw; + struct prestera_strom_control_cfg *cfg; +}; + +enum prestera_devlink_port_param_id { + PRESTERA_DEVLINK_PORT_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX + 1, + PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE, + PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE, + PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE, +}; + +struct devlink_param prestera_devlink_port_params[] = { + PRESTERA_PORT_PARAM_DRIVER_RUNTIME(BC_RATE, "bc_kbyte_per_sec_rate", + DEVLINK_PARAM_TYPE_U32), + PRESTERA_PORT_PARAM_DRIVER_RUNTIME(UC_UNK_RATE, + "unk_uc_kbyte_per_sec_rate", + DEVLINK_PARAM_TYPE_U32), + PRESTERA_PORT_PARAM_DRIVER_RUNTIME(MC_RATE, + "unreg_mc_kbyte_per_sec_rate", + DEVLINK_PARAM_TYPE_U32), +}; + static const struct devlink_trap_group prestera_trap_groups_arr[] = { /* No policer is associated with following groups (policerid == 0)*/ DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), @@ -350,6 +380,10 @@ static void prestera_devlink_traps_fini(struct prestera_switch *sw); static int prestera_drop_counter_get(struct devlink *devlink, const struct devlink_trap *trap, u64 *p_drops); +static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id, + struct devlink_param_gset_ctx *ctx); +static int prestera_devlink_port_param_get(struct devlink_port *dl_port, u32 id, + struct devlink_param_gset_ctx *ctx); static int prestera_dl_info_get(struct devlink *dl, struct devlink_info_req *req, @@ -383,11 +417,17 @@ static int prestera_trap_action_set(struct devlink *devlink, static int prestera_devlink_traps_register(struct prestera_switch *sw); +static const struct devlink_port_param_ops prestera_devlink_port_param_ops = { + .get = prestera_devlink_port_param_get, + .set = prestera_devlink_port_param_set, +}; + static const struct devlink_ops prestera_dl_ops = { .info_get = prestera_dl_info_get, .trap_init = prestera_trap_init, .trap_action_set = prestera_trap_action_set, .trap_drop_counter_get = prestera_drop_counter_get, + .port_param_ops = &prestera_devlink_port_param_ops, }; struct prestera_switch *prestera_devlink_alloc(void) @@ -443,10 +483,12 @@ void prestera_devlink_unregister(struct prestera_switch *sw) int prestera_devlink_port_register(struct prestera_port *port) { struct prestera_switch *sw = port->sw; - struct devlink *dl = priv_to_devlink(sw); struct devlink_port_attrs attrs = {}; + struct devlink *dl; int err; + dl = priv_to_devlink(sw); + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; attrs.phys.port_number = port->fp_id; attrs.switch_id.id_len = sizeof(sw->id); @@ -460,12 +502,32 @@ int prestera_devlink_port_register(struct prestera_port *port) return err; } + err = devlink_port_params_register( + &port->dl_port, + prestera_devlink_port_params, + ARRAY_SIZE(prestera_devlink_port_params)); + if (err) { + devlink_port_unregister(&port->dl_port); + dev_err(sw->dev->dev, "devlink_port_params_register failed\n"); + return err; + } + + devlink_port_params_publish(&port->dl_port); + return 0; } void prestera_devlink_port_unregister(struct prestera_port *port) { + devlink_port_params_unpublish(&port->dl_port); + + devlink_port_params_unregister( + &port->dl_port, + prestera_devlink_port_params, + ARRAY_SIZE(prestera_devlink_port_params)); + devlink_port_unregister(&port->dl_port); + } void prestera_devlink_port_set(struct prestera_port *port) @@ -622,6 +684,76 @@ static int prestera_drop_counter_get(struct devlink *devlink, cpu_code_type, p_drops); } +static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct prestera_strom_control_cfg *cfg; + u32 kbyte_per_sec_rate = ctx->val.vu32; + struct prestera_port *port; + struct prestera_switch *sw; + u32 *param_to_set; + u32 storm_type; + int ret; + + port = container_of(dl_port, struct prestera_port, dl_port); + sw = devlink_priv(dl_port->devlink); + cfg = &port->storm_control; + + switch (id) { + case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE: + param_to_set = &cfg->bc_kbyte_per_sec_rate; + storm_type = PRESTERA_PORT_STORM_CTL_TYPE_BC; + break; + case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE: + param_to_set = &cfg->unk_uc_kbyte_per_sec_rate; + storm_type = PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK; + break; + case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE: + param_to_set = &cfg->unreg_mc_kbyte_per_sec_rate; + storm_type = PRESTERA_PORT_STORM_CTL_TYPE_MC; + break; + default: + return -EINVAL; + } + + if (kbyte_per_sec_rate != *param_to_set) { + ret = prestera_hw_port_storm_control_cfg_set(port, storm_type, + kbyte_per_sec_rate); + if (ret) + return ret; + + *param_to_set = kbyte_per_sec_rate; + } + + return 0; +} + +static int prestera_devlink_port_param_get(struct devlink_port *dl_port, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct prestera_strom_control_cfg *cfg; + struct prestera_port *port; + struct prestera_switch *sw; + + port = container_of(dl_port, struct prestera_port, dl_port); + sw = devlink_priv(dl_port->devlink); + cfg = &port->storm_control; + + switch (id) { + case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE: + ctx->val.vu32 = cfg->bc_kbyte_per_sec_rate; + return 0; + case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE: + ctx->val.vu32 = cfg->unk_uc_kbyte_per_sec_rate; + return 0; + case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE: + ctx->val.vu32 = cfg->unreg_mc_kbyte_per_sec_rate; + return 0; + default: + return -EINVAL; + } +} + static void prestera_devlink_traps_fini(struct prestera_switch *sw) { struct devlink *dl = priv_to_devlink(sw); diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c index 0e5b3f8e7dc7..85a1a15717df 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c @@ -20,6 +20,7 @@ enum prestera_cmd_type_t { PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100, PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101, PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110, + PRESTERA_CMD_TYPE_PORT_RATE_LIMIT_MODE_SET = 0x111, PRESTERA_CMD_TYPE_VLAN_CREATE = 0x200, PRESTERA_CMD_TYPE_VLAN_DELETE = 0x201, @@ -251,6 +252,14 @@ struct prestera_msg_port_info_resp { u16 fp_id; }; +struct prestera_msg_port_storm_control_cfg_set_req { + struct prestera_msg_cmd cmd; + u32 port; + u32 dev; + u32 storm_type; + u32 kbyte_per_sec_rate; +}; + struct prestera_msg_vlan_req { struct prestera_msg_cmd cmd; u32 port; @@ -639,6 +648,22 @@ int prestera_hw_port_accept_frm_type(struct prestera_port *port, &req.cmd, sizeof(req)); } +int prestera_hw_port_storm_control_cfg_set(const struct prestera_port *port, + u32 storm_type, + u32 kbyte_per_sec_rate) +{ + struct prestera_msg_port_storm_control_cfg_set_req req = { + .port = port->hw_id, + .dev = port->dev_id, + .storm_type = storm_type, + .kbyte_per_sec_rate = kbyte_per_sec_rate + }; + + return prestera_cmd(port->sw, + PRESTERA_CMD_TYPE_PORT_RATE_LIMIT_MODE_SET, + &req.cmd, sizeof(req)); +} + int prestera_hw_port_cap_get(const struct prestera_port *port, struct prestera_port_caps *caps) { diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h index aafecf0ecd16..85373f1d3971 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h @@ -89,6 +89,12 @@ enum { PRESTERA_STP_FORWARD, }; +enum { + PRESTERA_PORT_STORM_CTL_TYPE_BC = 0, + PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK = 1, + PRESTERA_PORT_STORM_CTL_TYPE_MC = 2 +}; + enum prestera_hw_cpu_code_cnt_t { PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP = 0, PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1, @@ -123,6 +129,9 @@ int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac); int prestera_hw_port_mac_get(const struct prestera_port *port, char *mac); int prestera_hw_port_cap_get(const struct prestera_port *port, struct prestera_port_caps *caps); +int prestera_hw_port_storm_control_cfg_set(const struct prestera_port *port, + u32 storm_type, + u32 kbyte_per_sec_rate); int prestera_hw_port_remote_cap_get(const struct prestera_port *port, u64 *link_mode_bitmap); int prestera_hw_port_remote_fc_get(const struct prestera_port *port, -- 2.17.1
| |