Commit 04c7f60c authored by Tony Lindgren's avatar Tony Lindgren Committed by Greg Kroah-Hartman
Browse files

serial: core: Fix serial core port id, including multiport devices



We want to fix the serial core port DEVNAME to use a port id of the
hardware specific controller port instance instead of the port->line.

For example, the 8250 driver sets up a number of serial8250 ports
initially that can be inherited by the hardware specific driver. At that
the port->line no longer decribes the port's relation to the serial core
controller instance.

Let's fix the issue by assigning port->port_id for each serial core
controller port instance.

Fixes: 7d695d83 ("serial: core: Fix serial_base_match() after fixing controller port name")
Tested-by: default avatarGuenter Roeck <linux@roeck-us.net>
Reviewed-by: default avatarDhruva Gole <d-gole@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230811103648.2826-1-tony@atomide.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3d9e6f55
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ struct device;

struct serial_ctrl_device {
	struct device dev;
	struct ida port_ida;
};

struct serial_port_device {
+27 −1
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@

#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
@@ -112,6 +113,8 @@ struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port,
	if (!ctrl_dev)
		return ERR_PTR(-ENOMEM);

	ida_init(&ctrl_dev->port_ida);

	err = serial_base_device_init(port, &ctrl_dev->dev,
				      parent, &serial_ctrl_type,
				      serial_base_ctrl_release,
@@ -142,16 +145,31 @@ struct serial_port_device *serial_base_port_add(struct uart_port *port,
						struct serial_ctrl_device *ctrl_dev)
{
	struct serial_port_device *port_dev;
	int min = 0, max = -1;	/* Use -1 for max to apply IDA defaults */
	int err;

	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
	if (!port_dev)
		return ERR_PTR(-ENOMEM);

	/* Device driver specified port_id vs automatic assignment? */
	if (port->port_id) {
		min = port->port_id;
		max = port->port_id;
	}

	err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL);
	if (err < 0) {
		kfree(port_dev);
		return ERR_PTR(err);
	}

	port->port_id = err;

	err = serial_base_device_init(port, &port_dev->dev,
				      &ctrl_dev->dev, &serial_port_type,
				      serial_base_port_release,
				      port->ctrl_id, port->line);
				      port->ctrl_id, port->port_id);
	if (err)
		goto err_put_device;

@@ -165,16 +183,24 @@ struct serial_port_device *serial_base_port_add(struct uart_port *port,

err_put_device:
	put_device(&port_dev->dev);
	ida_free(&ctrl_dev->port_ida, port->port_id);

	return ERR_PTR(err);
}

void serial_base_port_device_remove(struct serial_port_device *port_dev)
{
	struct serial_ctrl_device *ctrl_dev;
	struct device *parent;

	if (!port_dev)
		return;

	parent = port_dev->dev.parent;
	ctrl_dev = to_serial_base_ctrl_device(parent);

	device_del(&port_dev->dev);
	ida_free(&ctrl_dev->port_ida, port_dev->port->port_id);
	put_device(&port_dev->dev);
}