[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20210207084412.252259-3-parav@nvidia.com>
Date: Sun, 7 Feb 2021 10:44:07 +0200
From: Parav Pandit <parav@...dia.com>
To: <netdev@...r.kernel.org>, <davem@...emloft.net>, <kuba@...nel.org>
CC: Parav Pandit <parav@...dia.com>, Jiri Pirko <jiri@...dia.com>
Subject: [PATCH net-next v2 2/7] netdevsim: Add support for add and delete PCI SF port
Simulate PCI SF ports. Allow user to create one or more PCI SF ports.
Examples:
echo "10 1" > /sys/bus/netdevsim/new_device
Add PCI PF port:
$ devlink port add netdevsim/netdevsim10 flavour pcipf pfnum 2
netdevsim/netdevsim10/1: type eth netdev eth1 flavour pcipf controller 0 pfnum 2 external false splittable false
Add PCI SF port where port index and sfnum are auto assigned by driver.
$ devlink port add netdevsim/netdevsim10 flavour pcisf pfnum 2
netdevsim/netdevsim10/2: type eth netdev eth2 flavour pcisf controller 0 pfnum 2 sfnum 0 splittable false
Show devlink ports:
$ devlink port show
netdevsim/netdevsim10/0: type eth netdev eth0 flavour physical port 1 splittable false
netdevsim/netdevsim10/1: type eth netdev eth1 flavour pcipf controller 0 pfnum 2 external false splittable false
netdevsim/netdevsim10/2: type eth netdev eth2 flavour pcisf controller 0 pfnum 2 sfnum 0 splittable false
Create a PCI SF port whose port index and SF number are assigned by
the user.
$ devlink port add netdevsim/netdevsim10/66 flavour pcisf pfnum 2 sfnum 66
netdevsim/netdevsim10/66: type eth netdev eth3 flavour pcisf controller 0 pfnum 2 sfnum 66 splittable false
Delete PCI SF and PF ports:
$ devlink port del netdevsim/netdevsim10/66
$ devlink port del netdevsim/netdevsim10/2
$ devlink port del netdevsim/netdevsim10/1
Signed-off-by: Parav Pandit <parav@...dia.com>
Reviewed-by: Jiri Pirko <jiri@...dia.com>
---
drivers/net/netdevsim/netdevsim.h | 1 +
drivers/net/netdevsim/port_function.c | 99 ++++++++++++++++++++++++++-
2 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 31beddede0f2..efa7c08d842a 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -233,6 +233,7 @@ struct nsim_dev {
struct list_head head;
struct ida ida;
struct ida pfnum_ida;
+ struct ida sfnum_ida;
struct mutex disable_mutex; /* protects port deletion
* by driver unload context
*/
diff --git a/drivers/net/netdevsim/port_function.c b/drivers/net/netdevsim/port_function.c
index 7df1ca5ad7b8..86607d574930 100644
--- a/drivers/net/netdevsim/port_function.c
+++ b/drivers/net/netdevsim/port_function.c
@@ -9,9 +9,12 @@
struct nsim_port_fn {
struct devlink_port dl_port;
struct net_device *netdev;
+ struct nsim_port_fn *pf_pfn;
struct list_head list;
unsigned int port_index;
enum devlink_port_flavour flavour;
+ int refcount; /* Counts how many sf ports are bound attached to this pf port. */
+ u32 sfnum;
u16 pfnum;
};
@@ -91,9 +94,24 @@ nsim_devlink_port_fn_alloc(struct nsim_dev *dev,
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:
@@ -110,6 +128,9 @@ nsim_devlink_port_fn_free(struct nsim_dev *dev, struct nsim_port_fn *port)
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;
}
@@ -139,6 +160,12 @@ nsim_dev_port_port_exists(struct nsim_dev *nsim_dev,
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 &&
+ attrs->sfnum_valid &&
+ tmp->sfnum == attrs->sfnum && tmp->pfnum == attrs->pfnum)
+ return true;
}
return false;
}
@@ -153,20 +180,72 @@ nsim_dev_devlink_port_index_lookup(const struct nsim_dev *nsim_dev,
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_fn *
+pf_port_get(struct nsim_dev *nsim_dev, struct nsim_port_fn *port)
+{
+ struct nsim_port_fn *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_pfn = tmp;
+ tmp->refcount++;
+ return tmp;
+ }
+ return ERR_PTR(-ENOENT);
+}
+
+static void pf_port_put(struct nsim_port_fn *port)
+{
+ if (port->pf_pfn) {
+ port->pf_pfn->refcount--;
+ WARN_ON(port->pf_pfn->refcount < 0);
+ }
+ port->refcount--;
+ WARN_ON(port->refcount != 0);
+}
+
static int nsim_devlink_port_fn_add(struct devlink *devlink,
struct nsim_dev *nsim_dev,
struct nsim_port_fn *port,
struct netlink_ext_ack *extack)
{
+ struct nsim_port_fn *pf_pfn;
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_pfn = pf_port_get(nsim_dev, port);
+ if (IS_ERR(pf_pfn)) {
+ NL_SET_ERR_MSG_MOD(extack, "Fail to get pf port");
+ err = PTR_ERR(pf_pfn);
+ goto pf_err;
+ }
err = devlink_port_register(devlink, &port->dl_port, port->port_index);
if (err)
@@ -183,6 +262,8 @@ static int nsim_devlink_port_fn_add(struct devlink *devlink,
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;
}
@@ -194,13 +275,15 @@ static void nsim_devlink_port_fn_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,
@@ -245,7 +328,12 @@ int nsim_dev_devlink_port_new(struct devlink *devlink,
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, 0, port->pfnum, false);
+ if (attrs->flavour == DEVLINK_PORT_FLAVOUR_PCI_PF)
+ devlink_port_attrs_pci_pf_set(&port->dl_port, 0,
+ port->pfnum, false);
+ else
+ devlink_port_attrs_pci_sf_set(&port->dl_port, 0, port->pfnum,
+ port->sfnum);
err = nsim_devlink_port_fn_add(devlink, nsim_dev, port, extack);
if (err)
@@ -300,10 +388,13 @@ void nsim_dev_port_fn_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_fn_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));
@@ -332,6 +423,8 @@ void nsim_dev_port_fn_disable(struct nsim_dev *nsim_dev)
* commands have completed, so it is safe to delete all user created
* 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_fn_del(nsim_dev, port);
--
2.26.2
Powered by blists - more mailing lists