mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
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: 7d695d8376 ("serial: core: Fix serial_base_match() after fixing controller port name")
Tested-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Dhruva Gole <d-gole@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230811103648.2826-1-tony@atomide.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
3d9e6f556e
commit
04c7f60ca4
@@ -16,6 +16,7 @@ struct device;
|
|||||||
|
|
||||||
struct serial_ctrl_device {
|
struct serial_ctrl_device {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
|
struct ida port_ida;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct serial_port_device {
|
struct serial_port_device {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <linux/container_of.h>
|
#include <linux/container_of.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -112,6 +113,8 @@ struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port,
|
|||||||
if (!ctrl_dev)
|
if (!ctrl_dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
ida_init(&ctrl_dev->port_ida);
|
||||||
|
|
||||||
err = serial_base_device_init(port, &ctrl_dev->dev,
|
err = serial_base_device_init(port, &ctrl_dev->dev,
|
||||||
parent, &serial_ctrl_type,
|
parent, &serial_ctrl_type,
|
||||||
serial_base_ctrl_release,
|
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_ctrl_device *ctrl_dev)
|
||||||
{
|
{
|
||||||
struct serial_port_device *port_dev;
|
struct serial_port_device *port_dev;
|
||||||
|
int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
|
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
|
||||||
if (!port_dev)
|
if (!port_dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
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,
|
err = serial_base_device_init(port, &port_dev->dev,
|
||||||
&ctrl_dev->dev, &serial_port_type,
|
&ctrl_dev->dev, &serial_port_type,
|
||||||
serial_base_port_release,
|
serial_base_port_release,
|
||||||
port->ctrl_id, port->line);
|
port->ctrl_id, port->port_id);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_put_device;
|
goto err_put_device;
|
||||||
|
|
||||||
@@ -165,16 +183,24 @@ struct serial_port_device *serial_base_port_add(struct uart_port *port,
|
|||||||
|
|
||||||
err_put_device:
|
err_put_device:
|
||||||
put_device(&port_dev->dev);
|
put_device(&port_dev->dev);
|
||||||
|
ida_free(&ctrl_dev->port_ida, port->port_id);
|
||||||
|
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_base_port_device_remove(struct serial_port_device *port_dev)
|
void serial_base_port_device_remove(struct serial_port_device *port_dev)
|
||||||
{
|
{
|
||||||
|
struct serial_ctrl_device *ctrl_dev;
|
||||||
|
struct device *parent;
|
||||||
|
|
||||||
if (!port_dev)
|
if (!port_dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
parent = port_dev->dev.parent;
|
||||||
|
ctrl_dev = to_serial_base_ctrl_device(parent);
|
||||||
|
|
||||||
device_del(&port_dev->dev);
|
device_del(&port_dev->dev);
|
||||||
|
ida_free(&ctrl_dev->port_ida, port_dev->port->port_id);
|
||||||
put_device(&port_dev->dev);
|
put_device(&port_dev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user