diff mbox series

[net-next,10/11] net: marvell: prestera: add storm control (rate limiter) implementation

Message ID 20210609151602.29004-11-oleksandr.mazur@plvision.eu
State New
Headers show
Series Marvell Prestera driver implementation of devlink functionality. | expand

Commit Message

Oleksandr Mazur June 9, 2021, 3:16 p.m. UTC
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(-)

Comments

kernel test robot June 16, 2021, 7:15 a.m. UTC | #1
Hi Oleksandr,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on kselftest/next]
[also build test WARNING on net/master linus/master v5.13-rc6]
[cannot apply to net-next/master sparc-next/master next-20210615]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Oleksandr-Mazur/Marvell-Prestera-driver-implementation-of-devlink-functionality/20210616-112917
base:   https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/d1e2db61850ee143f7aa180d34efb413f0956abd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Oleksandr-Mazur/Marvell-Prestera-driver-implementation-of-devlink-functionality/20210616-112917
        git checkout d1e2db61850ee143f7aa180d34efb413f0956abd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/marvell/prestera/prestera_devlink.c: In function 'prestera_devlink_port_param_set':
>> drivers/net/ethernet/marvell/prestera/prestera_devlink.c:693:26: warning: variable 'sw' set but not used [-Wunused-but-set-variable]

     693 |  struct prestera_switch *sw;
         |                          ^~
   drivers/net/ethernet/marvell/prestera/prestera_devlink.c: In function 'prestera_devlink_port_param_get':
   drivers/net/ethernet/marvell/prestera/prestera_devlink.c:736:26: warning: variable 'sw' set but not used [-Wunused-but-set-variable]
     736 |  struct prestera_switch *sw;
         |                          ^~


vim +/sw +693 drivers/net/ethernet/marvell/prestera/prestera_devlink.c

   686	
   687	static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id,
   688						   struct devlink_param_gset_ctx *ctx)
   689	{
   690		struct prestera_strom_control_cfg *cfg;
   691		u32 kbyte_per_sec_rate = ctx->val.vu32;
   692		struct prestera_port *port;
 > 693		struct prestera_switch *sw;

   694		u32 *param_to_set;
   695		u32 storm_type;
   696		int ret;
   697	
   698		port = container_of(dl_port, struct prestera_port, dl_port);
   699		sw = devlink_priv(dl_port->devlink);
   700		cfg = &port->storm_control;
   701	
   702		switch (id) {
   703		case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE:
   704			param_to_set = &cfg->bc_kbyte_per_sec_rate;
   705			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_BC;
   706			break;
   707		case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE:
   708			param_to_set = &cfg->unk_uc_kbyte_per_sec_rate;
   709			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK;
   710			break;
   711		case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE:
   712			param_to_set = &cfg->unreg_mc_kbyte_per_sec_rate;
   713			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_MC;
   714			break;
   715		default:
   716			return -EINVAL;
   717		}
   718	
   719		if (kbyte_per_sec_rate != *param_to_set) {
   720			ret = prestera_hw_port_storm_control_cfg_set(port, storm_type,
   721								     kbyte_per_sec_rate);
   722			if (ret)
   723				return ret;
   724	
   725			*param_to_set = kbyte_per_sec_rate;
   726		}
   727	
   728		return 0;
   729	}
   730	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

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,