On 9/17/20 11:20 AM, Parav Pandit wrote: > Simulate PCI SF ports. Allow user to create one or more PCI SF ports. > > Examples: > > Create a PCI PF and PCI SF port. > $ devlink port add netdevsim/netdevsim10/10 flavour pcipf pfnum 0 > $ devlink port add netdevsim/netdevsim10/11 flavour pcisf pfnum 0 sfnum 44 > $ devlink port show netdevsim/netdevsim10/11 > netdevsim/netdevsim10/11: type eth netdev eni10npf0sf44 flavour pcisf > controller 0 pfnum 0 sfnum 44 external true splittable false > function: > hw_addr 00:00:00:00:00:00 state inactive > > $ devlink port function set netdevsim/netdevsim10/11 hw_addr > 00:11:22:33:44:55 state active > > $ devlink port show netdevsim/netdevsim10/11 -jp > { > "port": { > "netdevsim/netdevsim10/11": { > "type": "eth", > "netdev": "eni10npf0sf44",
I could be missing something, but it does not seem like this patch creates the netdevice for the subfunction. > "flavour": "pcisf", > "controller": 0, > "pfnum": 0, > "sfnum": 44, > "external": true, > "splittable": false, > "function": { > "hw_addr": "00:11:22:33:44:55", > "state": "active" > } > } > } > } > > Delete newly added devlink port > $ devlink port add netdevsim/netdevsim10/11 > > Add devlink port of flavour 'pcisf' where port index and sfnum are > auto assigned by driver. > $ devlink port add netdevsim/netdevsim10 flavour pcisf controller 0 pfnum 0 > > Signed-off-by: Parav Pandit <pa...@nvidia.com> > Reviewed-by: Jiri Pirko <j...@nvidia.com> > --- > drivers/net/netdevsim/netdevsim.h | 1 + > drivers/net/netdevsim/port_function.c | 95 +++++++++++++++++++++++++-- > 2 files changed, 92 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/netdevsim/netdevsim.h > b/drivers/net/netdevsim/netdevsim.h > index 0ea9705eda38..c70782e444d5 100644 > --- a/drivers/net/netdevsim/netdevsim.h > +++ b/drivers/net/netdevsim/netdevsim.h > @@ -222,6 +222,7 @@ struct nsim_dev { > struct list_head head; > struct ida ida; > struct ida pfnum_ida; > + struct ida sfnum_ida; > } port_functions; > }; > > diff --git a/drivers/net/netdevsim/port_function.c > b/drivers/net/netdevsim/port_function.c > index 99581d3d15fe..e1812acd55b4 100644 > --- a/drivers/net/netdevsim/port_function.c > +++ b/drivers/net/netdevsim/port_function.c > @@ -13,10 +13,12 @@ struct nsim_port_function { > unsigned int port_index; > enum devlink_port_flavour flavour; > u32 controller; > + u32 sfnum; > u16 pfnum; > struct nsim_port_function *pf_port; /* Valid only for SF port */ > u8 hw_addr[ETH_ALEN]; > u8 state; /* enum devlink_port_function_state */ > + int refcount; /* Counts how many sf ports are bound attached to this pf > port. */ > }; > > void nsim_dev_port_function_init(struct nsim_dev *nsim_dev) > @@ -25,10 +27,13 @@ void nsim_dev_port_function_init(struct nsim_dev > *nsim_dev) > INIT_LIST_HEAD(&nsim_dev->port_functions.head); > ida_init(&nsim_dev->port_functions.ida); > ida_init(&nsim_dev->port_functions.pfnum_ida); > + ida_init(&nsim_dev->port_functions.sfnum_ida); > } > > void nsim_dev_port_function_exit(struct nsim_dev *nsim_dev) > { > + WARN_ON(!ida_is_empty(&nsim_dev->port_functions.sfnum_ida)); > + ida_destroy(&nsim_dev->port_functions.sfnum_ida); > WARN_ON(!ida_is_empty(&nsim_dev->port_functions.pfnum_ida)); > ida_destroy(&nsim_dev->port_functions.pfnum_ida); > WARN_ON(!ida_is_empty(&nsim_dev->port_functions.ida)); > @@ -119,9 +124,24 @@ nsim_devlink_port_function_alloc(struct nsim_dev *dev, > const struct devlink_port > goto fn_ida_err; > port->pfnum = ret; > break; > + case DEVLINK_PORT_FLAVOUR_PCI_SF: > + if (attrs->sfnum_valid) > + ret = ida_alloc_range(&dev->port_functions.sfnum_ida, > attrs->sfnum, > + attrs->sfnum, GFP_KERNEL); > + else > + ret = ida_alloc(&dev->port_functions.sfnum_ida, > GFP_KERNEL); > + if (ret < 0) > + goto fn_ida_err; > + port->sfnum = ret; > + port->pfnum = attrs->pfnum; > + break; > default: > break; > } > + /* refcount_t is not needed as port is protected by > port_functions.mutex. > + * This count is to keep track of how many SF ports are attached a PF > port. > + */ > + port->refcount = 1; > return port; > > fn_ida_err: > @@ -137,6 +157,9 @@ static void nsim_devlink_port_function_free(struct > nsim_dev *dev, struct nsim_po > case DEVLINK_PORT_FLAVOUR_PCI_PF: > ida_simple_remove(&dev->port_functions.pfnum_ida, port->pfnum); > break; > + case DEVLINK_PORT_FLAVOUR_PCI_SF: > + ida_simple_remove(&dev->port_functions.sfnum_ida, port->sfnum); > + break; > default: > break; > } > @@ -170,6 +193,11 @@ nsim_dev_port_port_exists(struct nsim_dev *nsim_dev, > const struct devlink_port_n > if (attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF && > tmp->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF && tmp->pfnum > == attrs->pfnum) > return true; > + > + if (attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_SF && > + tmp->flavour == DEVLINK_PORT_FLAVOUR_PCI_SF && > + tmp->sfnum == attrs->sfnum && tmp->pfnum == attrs->pfnum) > + return true; > } > return false; > } > @@ -183,21 +211,71 @@ nsim_dev_devlink_port_index_lookup(const struct > nsim_dev *nsim_dev, unsigned int > list_for_each_entry(port, &nsim_dev->port_functions.head, list) { > if (port->port_index != port_index) > continue; > + if (port->refcount > 1) { > + NL_SET_ERR_MSG_MOD(extack, "Port is in use"); > + return ERR_PTR(-EBUSY); > + } > return port; > } > NL_SET_ERR_MSG_MOD(extack, "User created port not found"); > return ERR_PTR(-ENOENT); > } > > +static struct nsim_port_function * > +pf_port_get(struct nsim_dev *nsim_dev, struct nsim_port_function *port) > +{ > + struct nsim_port_function *tmp; > + > + /* PF port addition doesn't need a parent. */ > + if (port->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) > + return NULL; > + > + list_for_each_entry(tmp, &nsim_dev->port_functions.head, list) { > + if (tmp->flavour != DEVLINK_PORT_FLAVOUR_PCI_PF || tmp->pfnum > != port->pfnum) > + continue; > + > + if (tmp->refcount + 1 == INT_MAX) > + return ERR_PTR(-ENOSPC); > + > + port->pf_port = tmp; > + tmp->refcount++; > + return tmp; > + } > + return ERR_PTR(-ENOENT); > +} > + > +static void pf_port_put(struct nsim_port_function *port) > +{ > + if (port->pf_port) { > + port->pf_port->refcount--; > + WARN_ON(port->pf_port->refcount < 0); > + } > + port->refcount--; > + WARN_ON(port->refcount != 0); > +} > + > static int nsim_devlink_port_function_add(struct devlink *devlink, struct > nsim_dev *nsim_dev, > struct nsim_port_function *port, > struct netlink_ext_ack *extack) > { > + struct nsim_port_function *pf_port; > int err; > > - list_add(&port->list, &nsim_dev->port_functions.head); > + /* Keep all PF ports at the start, so that when driver is unloaded > + * All SF ports from the end of the list can be removed first. > + */ > + if (port->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) > + list_add(&port->list, &nsim_dev->port_functions.head); > + else > + list_add_tail(&port->list, &nsim_dev->port_functions.head); > + > + pf_port = pf_port_get(nsim_dev, port); > + if (IS_ERR(pf_port)) { > + NL_SET_ERR_MSG_MOD(extack, "Fail to get pf port"); > + err = PTR_ERR(pf_port); > + goto pf_err; > + } > > - port->state = DEVLINK_PORT_FUNCTION_STATE_INACTIVE; > err = devlink_port_register(devlink, &port->dl_port, port->port_index); > if (err) > goto reg_err; > @@ -213,6 +291,8 @@ static int nsim_devlink_port_function_add(struct devlink > *devlink, struct nsim_d > devlink_port_type_clear(&port->dl_port); > devlink_port_unregister(&port->dl_port); > reg_err: > + pf_port_put(port); > +pf_err: > list_del(&port->list); > return err; > } > @@ -224,12 +304,14 @@ static void nsim_devlink_port_function_del(struct > nsim_dev *nsim_dev, > unregister_netdev(port->netdev); > devlink_port_unregister(&port->dl_port); > list_del(&port->list); > + pf_port_put(port); > } > > static bool nsim_dev_port_flavour_supported(const struct nsim_dev *nsim_dev, > const struct devlink_port_new_attrs > *attrs) > { > - return attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF; > + return attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF || > + attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_SF; > } > > int nsim_dev_devlink_port_new(struct devlink *devlink, const struct > devlink_port_new_attrs *attrs, > @@ -266,7 +348,11 @@ int nsim_dev_devlink_port_new(struct devlink *devlink, > const struct devlink_port > nsim_dev->switch_id.id_len); > port->dl_port.attrs.switch_id.id_len = nsim_dev->switch_id.id_len; > > - devlink_port_attrs_pci_pf_set(&port->dl_port, port->controller, > port->pfnum, false); > + if (attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) > + devlink_port_attrs_pci_pf_set(&port->dl_port, port->controller, > port->pfnum, false); > + else > + devlink_port_attrs_pci_sf_set(&port->dl_port, port->controller, > port->pfnum, > + port->sfnum, false); > > err = nsim_devlink_port_function_add(devlink, nsim_dev, port, extack); > if (err) > @@ -333,6 +419,7 @@ void nsim_dev_port_function_disable(struct nsim_dev > *nsim_dev) > * ports. > */ > > + /* Remove SF ports first, followed by PF ports. */ > list_for_each_entry_safe_reverse(port, tmp, > &nsim_dev->port_functions.head, list) { > nsim_devlink_port_function_del(nsim_dev, port); > nsim_devlink_port_function_free(nsim_dev, port); >