1908 lines · 52.2 KB · C
RawDownload
} static void nsim_dev_traps_exit(struct devlink *devlink){	struct nsim_dev *nsim_dev = devlink_priv(devlink); 	/* caution, trap work takes devlink lock */	cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw);	devl_traps_unregister(devlink, nsim_traps_arr,			      ARRAY_SIZE(nsim_traps_arr));	devl_trap_groups_unregister(devlink, nsim_trap_groups_arr,				    ARRAY_SIZE(nsim_trap_groups_arr));	devl_trap_policers_unregister(devlink, nsim_trap_policers_arr,				      ARRAY_SIZE(nsim_trap_policers_arr));	kfree(nsim_dev->trap_data->trap_policers_cnt_arr);	kfree(nsim_dev->trap_data->trap_items_arr);	kfree(nsim_dev->trap_data);} static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,				  struct netlink_ext_ack *extack);static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change,				enum devlink_reload_action action, enum devlink_reload_limit limit,				struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink); 	if (nsim_dev->dont_allow_reload) {		/* For testing purposes, user set debugfs dont_allow_reload		 * value to true. So forbid it.		 */		NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes");		return -EOPNOTSUPP;	} 	nsim_dev_reload_destroy(nsim_dev);	return 0;} static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action,			      enum devlink_reload_limit limit, u32 *actions_performed,			      struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink); 	if (nsim_dev->fail_reload) {		/* For testing purposes, user set debugfs fail_reload		 * value to true. Fail right away.		 */		NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes");		return -EINVAL;	} 	*actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 	return nsim_dev_reload_create(nsim_dev, extack);} static int nsim_dev_info_get(struct devlink *devlink,			     struct devlink_info_req *req,			     struct netlink_ext_ack *extack){	int err; 	err = devlink_info_version_stored_put_ext(req, "fw.mgmt", "10.20.30",						  DEVLINK_INFO_VERSION_TYPE_COMPONENT);	if (err)		return err;	return devlink_info_version_running_put_ext(req, "fw.mgmt", "10.20.30",						    DEVLINK_INFO_VERSION_TYPE_COMPONENT);} #define NSIM_DEV_FLASH_SIZE 50000#define NSIM_DEV_FLASH_CHUNK_SIZE 1000#define NSIM_DEV_FLASH_CHUNK_TIME_MS_DEFAULT 100 static int nsim_dev_flash_update(struct devlink *devlink,				 struct devlink_flash_update_params *params,				 struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink);	int i; 	if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0)		return -EOPNOTSUPP; 	if (nsim_dev->fw_update_status) {		devlink_flash_update_status_notify(devlink,						   "Preparing to flash",						   params->component, 0, 0);	} 	for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) {		if (nsim_dev->fw_update_status)			devlink_flash_update_status_notify(devlink, "Flashing",							   params->component,							   i * NSIM_DEV_FLASH_CHUNK_SIZE,							   NSIM_DEV_FLASH_SIZE);		msleep(nsim_dev->fw_update_flash_chunk_time_ms ?: 1);	} 	if (nsim_dev->fw_update_status) {		devlink_flash_update_status_notify(devlink, "Flashing",						   params->component,						   NSIM_DEV_FLASH_SIZE,						   NSIM_DEV_FLASH_SIZE);		devlink_flash_update_timeout_notify(devlink, "Flash select",						    params->component, 81);		devlink_flash_update_status_notify(devlink, "Flashing done",						   params->component, 0, 0);	} 	return 0;} static struct nsim_trap_item *nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id){	struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data;	int i; 	for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {		if (nsim_traps_arr[i].id == trap_id)			return &nsim_trap_data->trap_items_arr[i];	} 	return NULL;} static int nsim_dev_devlink_trap_init(struct devlink *devlink,				      const struct devlink_trap *trap,				      void *trap_ctx){	struct nsim_dev *nsim_dev = devlink_priv(devlink);	struct nsim_trap_item *nsim_trap_item; 	nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);	if (WARN_ON(!nsim_trap_item))		return -ENOENT; 	nsim_trap_item->trap_ctx = trap_ctx;	nsim_trap_item->action = trap->init_action; 	return 0;} static intnsim_dev_devlink_trap_action_set(struct devlink *devlink,				 const struct devlink_trap *trap,				 enum devlink_trap_action action,				 struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink);	struct nsim_trap_item *nsim_trap_item; 	nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);	if (WARN_ON(!nsim_trap_item))		return -ENOENT; 	spin_lock(&nsim_dev->trap_data->trap_lock);	nsim_trap_item->action = action;	spin_unlock(&nsim_dev->trap_data->trap_lock); 	return 0;} static intnsim_dev_devlink_trap_group_set(struct devlink *devlink,				const struct devlink_trap_group *group,				const struct devlink_trap_policer *policer,				struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink); 	if (nsim_dev->fail_trap_group_set)		return -EINVAL; 	return 0;} static intnsim_dev_devlink_trap_policer_set(struct devlink *devlink,				  const struct devlink_trap_policer *policer,				  u64 rate, u64 burst,				  struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(devlink); 	if (nsim_dev->fail_trap_policer_set) {		NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes");		return -EINVAL;	} 	return 0;} static intnsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink,					  const struct devlink_trap_policer *policer,					  u64 *p_drops){	struct nsim_dev *nsim_dev = devlink_priv(devlink);	u64 *cnt; 	if (nsim_dev->fail_trap_policer_counter_get)		return -EINVAL; 	cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1];	*p_drops = (*cnt)++; 	return 0;} #define NSIM_LINK_SPEED_MAX     5000 /* Mbps */#define NSIM_LINK_SPEED_UNIT    125000 /* 1 Mbps given in bytes/sec to avoid					* u64 overflow during conversion from					* bytes to bits.					*/ static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack){	u64 val;	u32 rem; 	val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem);	if (rem) {		pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",		       name, *rate);		NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps.");		return -EINVAL;	} 	if (val > NSIM_LINK_SPEED_MAX) {		pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n",		       name, val);		NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps.");		return -EINVAL;	}	*rate = val;	return 0;} static int nsim_leaf_tc_bw_set(struct devlink_rate *devlink_rate,			       void *priv, u32 *tc_bw,			       struct netlink_ext_ack *extack){	struct nsim_dev_port *nsim_dev_port = priv;	int i; 	for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++)		nsim_dev_port->tc_bw[i] = tc_bw[i]; 	return 0;} static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv,				  u64 tx_share, struct netlink_ext_ack *extack){	struct nsim_dev_port *nsim_dev_port = priv;	struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev;	int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);	int err; 	err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);	if (err)		return err; 	nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share;	return 0;} static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv,				u64 tx_max, struct netlink_ext_ack *extack){	struct nsim_dev_port *nsim_dev_port = priv;	struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev;	int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);	int err; 	err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);	if (err)		return err; 	nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max;	return 0;} struct nsim_rate_node {	struct dentry *ddir;	struct dentry *rate_parent;	char *parent_name;	u16 tx_share;	u16 tx_max;	u32 tc_bw[DEVLINK_RATE_TCS_MAX];}; static int nsim_node_tc_bw_set(struct devlink_rate *devlink_rate, void *priv,			       u32 *tc_bw, struct netlink_ext_ack *extack){	struct nsim_rate_node *nsim_node = priv;	int i; 	for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++)		nsim_node->tc_bw[i] = tc_bw[i]; 	return 0;} static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv,				  u64 tx_share, struct netlink_ext_ack *extack){	struct nsim_rate_node *nsim_node = priv;	int err; 	err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);	if (err)		return err; 	nsim_node->tx_share = tx_share;	return 0;} static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv,				u64 tx_max, struct netlink_ext_ack *extack){	struct nsim_rate_node *nsim_node = priv;	int err; 	err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);	if (err)		return err; 	nsim_node->tx_max = tx_max;	return 0;} static int nsim_rate_node_new(struct devlink_rate *node, void **priv,			      struct netlink_ext_ack *extack){	struct nsim_dev *nsim_dev = devlink_priv(node->devlink);	struct nsim_rate_node *nsim_node; 	if (!nsim_esw_mode_is_switchdev(nsim_dev)) {		NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode.");		return -EOPNOTSUPP;	} 	nsim_node = kzalloc_obj(*nsim_node);	if (!nsim_node)		return -ENOMEM; 	nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 	debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share);	debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max);	nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400,						     nsim_node->ddir,						     &nsim_node->parent_name,						     &nsim_dev_rate_parent_fops); 	nsim_dev_tc_bw_debugfs_init(nsim_node->ddir, nsim_node->tc_bw); 	*priv = nsim_node;	return 0;} static int nsim_rate_node_del(struct devlink_rate *node, void *priv,			      struct netlink_ext_ack *extack){	struct nsim_rate_node *nsim_node = priv; 	debugfs_remove(nsim_node->rate_parent);	debugfs_remove_recursive(nsim_node->ddir);	kfree(nsim_node);	return 0;} static int nsim_rate_leaf_parent_set(struct devlink_rate *child,				     struct devlink_rate *parent,				     void *priv_child, void *priv_parent,				     struct netlink_ext_ack *extack){	struct nsim_dev_port *nsim_dev_port = priv_child; 	if (parent)		nsim_dev_port->parent_name = parent->name;	else		nsim_dev_port->parent_name = NULL;	return 0;} static int nsim_rate_node_parent_set(struct devlink_rate *child,				     struct devlink_rate *parent,				     void *priv_child, void *priv_parent,				     struct netlink_ext_ack *extack){	struct nsim_rate_node *nsim_node = priv_child; 	if (parent)		nsim_node->parent_name = parent->name;	else		nsim_node->parent_name = NULL;	return 0;} static intnsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink,				       const struct devlink_trap *trap,				       u64 *p_drops){	struct nsim_dev *nsim_dev = devlink_priv(devlink);	u64 *cnt; 	if (nsim_dev->fail_trap_drop_counter_get)		return -EINVAL; 	cnt = &nsim_dev->trap_data->trap_pkt_cnt;	*p_drops = (*cnt)++; 	return 0;} static const struct devlink_ops nsim_dev_devlink_ops = {	.eswitch_mode_set = nsim_devlink_eswitch_mode_set,	.eswitch_mode_get = nsim_devlink_eswitch_mode_get,	.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),	.reload_down = nsim_dev_reload_down,	.reload_up = nsim_dev_reload_up,	.info_get = nsim_dev_info_get,	.flash_update = nsim_dev_flash_update,	.trap_init = nsim_dev_devlink_trap_init,	.trap_action_set = nsim_dev_devlink_trap_action_set,	.trap_group_set = nsim_dev_devlink_trap_group_set,	.trap_policer_set = nsim_dev_devlink_trap_policer_set,	.trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get,	.rate_leaf_tx_share_set = nsim_leaf_tx_share_set,	.rate_leaf_tx_max_set = nsim_leaf_tx_max_set,	.rate_leaf_tc_bw_set = nsim_leaf_tc_bw_set,	.rate_node_tx_share_set = nsim_node_tx_share_set,	.rate_node_tx_max_set = nsim_node_tx_max_set,	.rate_node_tc_bw_set = nsim_node_tc_bw_set,	.rate_node_new = nsim_rate_node_new,	.rate_node_del = nsim_rate_node_del,	.rate_leaf_parent_set = nsim_rate_leaf_parent_set,	.rate_node_parent_set = nsim_rate_node_parent_set,	.trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get,}; #define NSIM_DEV_MAX_MACS_DEFAULT 32#define NSIM_DEV_TEST1_DEFAULT true static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type,			       unsigned int port_index, u8 perm_addr[ETH_ALEN]){	struct devlink_port_attrs attrs = {};	struct nsim_dev_port *nsim_dev_port;	struct devlink_port *devlink_port;	int err; 	if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_dev_get_vfs(nsim_dev))		return -EINVAL; 	nsim_dev_port = kzalloc_obj(*nsim_dev_port);	if (!nsim_dev_port)		return -ENOMEM;	nsim_dev_port->port_index = nsim_dev_port_index(type, port_index);	nsim_dev_port->port_type = type; 	devlink_port = &nsim_dev_port->devlink_port;	if (nsim_dev_port_is_pf(nsim_dev_port)) {		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;		attrs.phys.port_number = port_index + 1;	} else {		attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;		attrs.pci_vf.pf = 0;		attrs.pci_vf.vf = port_index;	}	memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);	attrs.switch_id.id_len = nsim_dev->switch_id.id_len;	devlink_port_attrs_set(devlink_port, &attrs);	err = devl_port_register(priv_to_devlink(nsim_dev), devlink_port,				 nsim_dev_port->port_index);	if (err)		goto err_port_free; 	if (nsim_dev_port_is_pf(nsim_dev_port)) {		u64 parent_id = DEVLINK_RESOURCE_ID_PARENT_TOP;		struct devlink_resource_size_params params = {			.size_max = 100,			.size_granularity = 1,			.unit = DEVLINK_RESOURCE_UNIT_ENTRY		}; 		err = devl_port_resource_register(devlink_port,						  "test_resource", 20,						  NSIM_PORT_RESOURCE_TEST,						  parent_id, &params);

Lines 1001–1500 of 1908. Previous lines