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

serial: mps2-uart: move to dynamic port allocation

Some designs, like MPS3, expose number of virtual serial ports which
already close or exceeds MPS2_MAX_PORTS. Increasing MPS2_MAX_PORTS
would have negative impact (in terms of memory consumption) on tiny
MPS2 platform which, in fact, has only one physically populated UART.

Start with converting existent static port array to idr. As a bonus it
make driver not to fail in case when no alias was specified in device
tree.

Note: there is no need in idr_destroy() because code doesn't unload
since ce87122911f8 ("serial: mps2-uart: make driver explicitly non-modular")

Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vladimir Murzin and committed by
Greg Kroah-Hartman
9f25e07b 3c635e4f

+31 -16
+31 -16
drivers/tty/serial/mps2-uart.c
··· 22 22 #include <linux/serial_core.h> 23 23 #include <linux/tty_flip.h> 24 24 #include <linux/types.h> 25 + #include <linux/idr.h> 25 26 26 27 #define SERIAL_NAME "ttyMPS" 27 28 #define DRIVER_NAME "mps2-uart" ··· 398 397 .verify_port = mps2_uart_verify_port, 399 398 }; 400 399 401 - static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS]; 400 + static DEFINE_IDR(ports_idr); 402 401 403 402 #ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE 404 403 static void mps2_uart_console_putchar(struct uart_port *port, int ch) ··· 411 410 412 411 static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt) 413 412 { 414 - struct uart_port *port = &mps2_uart_ports[co->index].port; 413 + struct mps2_uart_port *mps_port = idr_find(&ports_idr, co->index); 414 + struct uart_port *port = &mps_port->port; 415 415 416 416 uart_console_write(port, s, cnt, mps2_uart_console_putchar); 417 417 } ··· 428 426 if (co->index < 0 || co->index >= MPS2_MAX_PORTS) 429 427 return -ENODEV; 430 428 431 - mps_port = &mps2_uart_ports[co->index]; 429 + mps_port = idr_find(&ports_idr, co->index); 430 + 431 + if (!mps_port) 432 + return -ENODEV; 432 433 433 434 if (options) 434 435 uart_parse_options(options, &baud, &parity, &bits, &flow); ··· 492 487 .cons = MPS2_SERIAL_CONSOLE, 493 488 }; 494 489 495 - static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev) 490 + static int mps2_of_get_port(struct platform_device *pdev, 491 + struct mps2_uart_port *mps_port) 496 492 { 497 493 struct device_node *np = pdev->dev.of_node; 498 494 int id; 499 495 500 496 if (!np) 501 - return NULL; 497 + return -ENODEV; 502 498 503 499 id = of_alias_get_id(np, "serial"); 500 + 504 501 if (id < 0) 505 - id = 0; 502 + id = idr_alloc_cyclic(&ports_idr, (void *)mps_port, 0, MPS2_MAX_PORTS, GFP_KERNEL); 503 + else 504 + id = idr_alloc(&ports_idr, (void *)mps_port, id, MPS2_MAX_PORTS, GFP_KERNEL); 506 505 507 - if (WARN_ON(id >= MPS2_MAX_PORTS)) 508 - return NULL; 506 + if (id < 0) 507 + return id; 509 508 510 - mps2_uart_ports[id].port.line = id; 511 - return &mps2_uart_ports[id]; 509 + mps_port->port.line = id; 510 + 511 + return 0; 512 512 } 513 513 514 - static int mps2_init_port(struct mps2_uart_port *mps_port, 515 - struct platform_device *pdev) 514 + static int mps2_init_port(struct platform_device *pdev, 515 + struct mps2_uart_port *mps_port) 516 516 { 517 517 struct resource *res; 518 518 int ret; ··· 560 550 struct mps2_uart_port *mps_port; 561 551 int ret; 562 552 563 - mps_port = mps2_of_get_port(pdev); 564 - if (!mps_port) 565 - return -ENODEV; 553 + mps_port = devm_kzalloc(&pdev->dev, sizeof(struct mps2_uart_port), GFP_KERNEL); 566 554 567 - ret = mps2_init_port(mps_port, pdev); 555 + if (!mps_port) 556 + return -ENOMEM; 557 + 558 + ret = mps2_of_get_port(pdev, mps_port); 559 + if (ret) 560 + return ret; 561 + 562 + ret = mps2_init_port(pdev, mps_port); 568 563 if (ret) 569 564 return ret; 570 565