Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 7d695d83767c ("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>

authored by

Tony Lindgren and committed by
Greg Kroah-Hartman
04c7f60c 3d9e6f55

+28 -1
+1
drivers/tty/serial/serial_base.h
··· 16 16 17 17 struct serial_ctrl_device { 18 18 struct device dev; 19 + struct ida port_ida; 19 20 }; 20 21 21 22 struct serial_port_device {
+27 -1
drivers/tty/serial/serial_base_bus.c
··· 10 10 11 11 #include <linux/container_of.h> 12 12 #include <linux/device.h> 13 + #include <linux/idr.h> 13 14 #include <linux/module.h> 14 15 #include <linux/serial_core.h> 15 16 #include <linux/slab.h> ··· 113 112 if (!ctrl_dev) 114 113 return ERR_PTR(-ENOMEM); 115 114 115 + ida_init(&ctrl_dev->port_ida); 116 + 116 117 err = serial_base_device_init(port, &ctrl_dev->dev, 117 118 parent, &serial_ctrl_type, 118 119 serial_base_ctrl_release, ··· 145 142 struct serial_ctrl_device *ctrl_dev) 146 143 { 147 144 struct serial_port_device *port_dev; 145 + int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */ 148 146 int err; 149 147 150 148 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); 151 149 if (!port_dev) 152 150 return ERR_PTR(-ENOMEM); 153 151 152 + /* Device driver specified port_id vs automatic assignment? */ 153 + if (port->port_id) { 154 + min = port->port_id; 155 + max = port->port_id; 156 + } 157 + 158 + err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL); 159 + if (err < 0) { 160 + kfree(port_dev); 161 + return ERR_PTR(err); 162 + } 163 + 164 + port->port_id = err; 165 + 154 166 err = serial_base_device_init(port, &port_dev->dev, 155 167 &ctrl_dev->dev, &serial_port_type, 156 168 serial_base_port_release, 157 - port->ctrl_id, port->line); 169 + port->ctrl_id, port->port_id); 158 170 if (err) 159 171 goto err_put_device; 160 172 ··· 183 165 184 166 err_put_device: 185 167 put_device(&port_dev->dev); 168 + ida_free(&ctrl_dev->port_ida, port->port_id); 186 169 187 170 return ERR_PTR(err); 188 171 } 189 172 190 173 void serial_base_port_device_remove(struct serial_port_device *port_dev) 191 174 { 175 + struct serial_ctrl_device *ctrl_dev; 176 + struct device *parent; 177 + 192 178 if (!port_dev) 193 179 return; 194 180 181 + parent = port_dev->dev.parent; 182 + ctrl_dev = to_serial_base_ctrl_device(parent); 183 + 195 184 device_del(&port_dev->dev); 185 + ida_free(&ctrl_dev->port_ida, port_dev->port->port_id); 196 186 put_device(&port_dev->dev); 197 187 } 198 188