All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
To: Loic Poulain <loic.poulain@linaro.org>,
	"David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org, linux-wireless@vger.kernel.org
Subject: [PATCH 06/10] net: wwan: core: make port names more user-friendly
Date: Tue,  8 Jun 2021 07:02:37 +0300	[thread overview]
Message-ID: <20210608040241.10658-7-ryazanov.s.a@gmail.com> (raw)
In-Reply-To: <20210608040241.10658-1-ryazanov.s.a@gmail.com>

At the moment, the port name is allocated based on the parent device
name, port id and the port type. Where the port id specifies nothing but
the ports registration order and is only used to make the port name
unique.

Most likely, to configure a WWAN device, the user will look for a port
of a specific type (e.g. AT port or MBIM port, etc.). The current naming
scheme can make it difficult to find a port of a specific type.

Consider a WWAN device that has 3 ports: AT port, MBIM port, and another
one AT port. With the global port index, the port names will be:
* wwan0p1at
* wwan0p2mbim
* wwan0p3at

To find the MBIM port, user should know in advance the device ports
composition (i.e. the user should know that the MBIM port is the 2nd
one) or carefully examine the whole ports list. It is not unusual for
USB modems to have a different composition, even if they are build on a
same chipset. Moreover, some modems able to change the ports composition
based on the user's configuration. All this makes port names fully
unpredictable.

To make naming more user-friendly, remove the global port id and
enumerate ports by its type. E.g.:
* wwan0p1at   -> wwan0at0
* wwan0p2mbim -> wwan0mbim0
* wwan0p3at   -> wwan0at1

With this naming scheme, the first AT port name will always be wwanXat0,
the first MBIM port name will always be wwanXmbim0, etc.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 drivers/net/wwan/wwan_core.c | 67 ++++++++++++++++++++++++++++++++----
 1 file changed, 61 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index ba4392d71b80..2844b17a724c 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -33,12 +33,10 @@ static int wwan_major;
  *
  * @id: WWAN device unique ID.
  * @dev: Underlying device.
- * @port_id: Current available port ID to pick.
  */
 struct wwan_device {
 	unsigned int id;
 	struct device dev;
-	atomic_t port_id;
 };
 
 /**
@@ -258,6 +256,56 @@ static struct wwan_port *wwan_port_get_by_minor(unsigned int minor)
 	return to_wwan_port(dev);
 }
 
+/* Allocate and set unique name based on passed format
+ *
+ * Name allocation approach is highly inspired by the __dev_alloc_name()
+ * function.
+ *
+ * To avoid names collision, the caller must prevent the new port device
+ * registration as well as concurrent invocation of this function.
+ */
+static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt)
+{
+	struct wwan_device *wwandev = to_wwan_dev(port->dev.parent);
+	const unsigned int max_ports = PAGE_SIZE * 8;
+	struct class_dev_iter iter;
+	unsigned long *idmap;
+	struct device *dev;
+	char buf[0x20];
+	int id;
+
+	idmap = (unsigned long *)get_zeroed_page(GFP_KERNEL);
+	if (!idmap)
+		return -ENOMEM;
+
+	/* Collect ids of same name format ports */
+	class_dev_iter_init(&iter, wwan_class, NULL, &wwan_port_dev_type);
+	while ((dev = class_dev_iter_next(&iter))) {
+		if (dev->parent != &wwandev->dev)
+			continue;
+		if (sscanf(dev_name(dev), fmt, &id) != 1)
+			continue;
+		if (id < 0 || id >= max_ports)
+			continue;
+		set_bit(id, idmap);
+	}
+	class_dev_iter_exit(&iter);
+
+	/* Allocate unique id */
+	id = find_first_zero_bit(idmap, max_ports);
+	free_page((unsigned long)idmap);
+
+	snprintf(buf, sizeof(buf), fmt, id);	/* Name generation */
+
+	dev = device_find_child_by_name(&wwandev->dev, buf);
+	if (dev) {
+		put_device(dev);
+		return -ENFILE;
+	}
+
+	return dev_set_name(&port->dev, buf);
+}
+
 struct wwan_port *wwan_create_port(struct device *parent,
 				   enum wwan_port_type type,
 				   const struct wwan_port_ops *ops,
@@ -266,6 +314,7 @@ struct wwan_port *wwan_create_port(struct device *parent,
 	struct wwan_device *wwandev;
 	struct wwan_port *port;
 	int minor, err = -ENOMEM;
+	char namefmt[0x20];
 
 	if (type > WWAN_PORT_MAX || !ops)
 		return ERR_PTR(-EINVAL);
@@ -300,12 +349,18 @@ struct wwan_port *wwan_create_port(struct device *parent,
 	port->dev.devt = MKDEV(wwan_major, minor);
 	dev_set_drvdata(&port->dev, drvdata);
 
-	/* create unique name based on wwan device id, port index and type */
-	dev_set_name(&port->dev, "wwan%up%u%s", wwandev->id,
-		     atomic_inc_return(&wwandev->port_id),
-		     wwan_port_types[port->type].devsuf);
+	/* allocate unique name based on wwan device id, port type and number */
+	snprintf(namefmt, sizeof(namefmt), "wwan%u%s%%d", wwandev->id,
+		 wwan_port_types[port->type].devsuf);
 
+	/* Serialize ports registration */
+	mutex_lock(&wwan_register_lock);
+
+	__wwan_port_dev_assign_name(port, namefmt);
 	err = device_register(&port->dev);
+
+	mutex_unlock(&wwan_register_lock);
+
 	if (err)
 		goto error_put_device;
 
-- 
2.26.3


  parent reply	other threads:[~2021-06-08  4:03 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-08  4:02 [PATCH 00/10] net: WWAN subsystem improvements Sergey Ryazanov
2021-06-08  4:02 ` [PATCH 01/10] wwan_hwsim: WWAN device simulator Sergey Ryazanov
2021-06-08  4:02 ` [PATCH 02/10] wwan_hwsim: add debugfs management interface Sergey Ryazanov
2021-06-08  4:02 ` [PATCH 03/10] net: wwan: make WWAN_PORT_MAX meaning less surprised Sergey Ryazanov
2021-06-08  8:35   ` Loic Poulain
2021-06-08  4:02 ` [PATCH 04/10] net: wwan: core: init port type string array using enum values Sergey Ryazanov
2021-06-08  8:36   ` Loic Poulain
2021-06-08  4:02 ` [PATCH 05/10] net: wwan: core: spell port device name in lowercase Sergey Ryazanov
2021-06-08  8:37   ` Loic Poulain
2021-06-08  4:02 ` Sergey Ryazanov [this message]
2021-06-08  4:02 ` [PATCH 07/10] net: wwan: core: expand ports number limit Sergey Ryazanov
2021-06-08  8:47   ` Loic Poulain
2021-06-08  4:02 ` [PATCH 08/10] net: wwan: core: implement TIOCINQ ioctl Sergey Ryazanov
2021-06-08  8:51   ` Loic Poulain
2021-06-08  4:02 ` [PATCH 09/10] net: wwan: core: implement terminal ioctls for AT port Sergey Ryazanov
2021-06-08  4:02 ` [PATCH 10/10] net: wwan: core: purge rx queue on port close Sergey Ryazanov
2021-06-08 21:50 ` [PATCH 00/10] net: WWAN subsystem improvements patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210608040241.10658-7-ryazanov.s.a@gmail.com \
    --to=ryazanov.s.a@gmail.com \
    --cc=davem@davemloft.net \
    --cc=kuba@kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=loic.poulain@linaro.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.