Starting to pull out the I/O operations
Subsystems (3)
cover Starting to pull out the I/O operations
This is an untested WIP but as it was coming in discussion about device-tree as well I figured it will be useful to post the prototype code at this point.
There is lots left to do - in particular resource claim/release should be an ops method, and it's going to need people to update various embedded 8250 drivers when we finally go for a version of it.
On the bright side once we have an ops structure we have the basis for avoiding further mayhem in the arch code.
---
Alan Cox (5):
8250: extract out the "odd" port types
8250: evict the hub6 I/O operations
8250: register upio users
8250: introduce the idea of an operations struct for an 8250 port 8250: Make serial_dl_write a port operation
drivers/char/mwave/mwavedd.c | 2 drivers/tty/serial/8250.c | 450 ++++++++++++++------------------------- drivers/tty/serial/8250.h | 27 ++ drivers/tty/serial/8250_au.c | 90 ++++++++ drivers/tty/serial/8250_dwapb.c | 120 ++++++++++ drivers/tty/serial/8250_hub6.c | 39 +++ drivers/tty/serial/8250_pci.c | 2 drivers/tty/serial/8250_pnp.c | 2 drivers/tty/serial/8250_rm9k.c | 95 ++++++++ drivers/tty/serial/Kconfig | 9 + drivers/tty/serial/Makefile | 3 drivers/tty/serial/of_serial.c | 2 drivers/tty/serial/serial_cs.c | 2 include/linux/serial_8250.h | 36 ++- include/linux/serial_core.h | 5 15 files changed, 579 insertions(+), 305 deletions(-) create mode 100644 drivers/tty/serial/8250_au.c create mode 100644 drivers/tty/serial/8250_dwapb.c create mode 100644 drivers/tty/serial/8250_rm9k.c
Signature · 1 line
Words without body bare winter barren trees much unspoken
RFC 1/5 8250: Make serial_dl_write a port operation
From: Alan Cox <[email protected]>
This is pre-requisite to splitting out some of the platform specific stuff
---
drivers/tty/serial/8250.c | 122 +++++++++++++++++++++++++------------------ include/linux/serial_8250.h | 2 + include/linux/serial_core.h | 2 + 3 files changed, 74 insertions(+), 52 deletions(-)
drivers/tty/serial/8250.c +70 -52
@@ -503,10 +503,50 @@ static void io_serial_out(struct uart_port *p, int offset, int value)outb (value, p->iobase + offset); } +/* Uart divisor latch read */ +static unsigned int _serial_dl_read (struct uart_port *p) +{ +return p->serial_in (p,UART_DLL ) | p->serial_in (p,UART_DLM ) <<8 ; +} + +/* Uart divisor latch write */ +static void _serial_dl_write (struct uart_port *p,unsigned int value) +{ + p->serial_out (p,UART_DLL , value &0xff ); + p->serial_out (p,UART_DLM , value >>8 &0xff ); +} + +/* Au1x00 haven't got a standard divisor latch */ +static unsigned int au_serial_dl_read (struct uart_port *p) +{ +return __raw_readl (p->membase +0x28 ); +} + +static void au_serial_dl_write (struct uart_port *p,unsigned int value) +{ +__raw_writel (value, p->membase +0x28 ); +} + +static unsigned int rm9k_serial_dl_read (struct uart_port *p) +{ +return (((__raw_readl (p->membase +0x10 ) <<8 ) | + (__raw_readl (p->membase +0x08 ) &0xff )) &0xffff ); +} + +static void rm9k_serial_dl_write (struct uart_port *p,unsigned int value) +{ +__raw_writel (value, p->membase +0x08 ); +__raw_writel (value >>8 , p->membase +0x10 ); +} +static void set_io_from_upio (struct uart_port *p) {struct uart_8250_port *up = container_of(p, struct uart_8250_port, port); + + p->serial_dl_read = _serial_dl_read; + p->serial_dl_write = _serial_dl_write; +switch (p->iotype) {case UPIO_HUB6 : p->serial_in = hub6_serial_in;
@@ -519,6 +559,8 @@ static void set_io_from_upio(struct uart_port *p)break ;case UPIO_RM9000 : + p->serial_dl_read = rm9k_serial_dl_read; + p->serial_dl_write = rm9k_serial_dl_write;case UPIO_MEM32 : p->serial_in = mem32_serial_in; p->serial_out = mem32_serial_out;
@@ -527,6 +569,8 @@ static void set_io_from_upio(struct uart_port *p)case UPIO_AU : p->serial_in = au_serial_in; p->serial_out = au_serial_out; + p->serial_dl_read = au_serial_dl_read; + p->serial_dl_write = au_serial_dl_write;break ;case UPIO_TSI :
@@ -575,6 +619,17 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) (up->port.serial_in(&(up)->port, (offset)))#define serial_out (up, offset, value) \ (up->port.serial_out(&(up)->port, (offset), (value))) + +static unsigned int serial_dl_read (struct uart_8250_port *up) +{ +return up->port.serial_dl_read (&up->port); +} + +static void serial_dl_write (struct uart_8250_port *up,unsigned int value) +{ + up->port.serial_dl_write (&up->port, value); +} +/* * We used to support using pause I/O for certain machines. We * haven't supported this for a while, but just in case it's badly
@@ -584,58 +639,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)#define serial_inp (up, offset) serial_in(up, offset)#define serial_outp (up, offset, value) serial_out(up, offset, value) -/* Uart divisor latch read */ -static inline int _serial_dl_read (struct uart_8250_port *up) -{ -return serial_inp (up,UART_DLL ) |serial_inp (up,UART_DLM ) <<8 ; -} - -/* Uart divisor latch write */ -static inline void _serial_dl_write (struct uart_8250_port *up,int value) -{ -serial_outp (up,UART_DLL , value &0xff ); -serial_outp (up,UART_DLM , value >>8 &0xff ); -} - -#if defined(CONFIG_MIPS_ALCHEMY ) -/* Au1x00 haven't got a standard divisor latch */ -static int serial_dl_read (struct uart_8250_port *up) -{ -if (up->port.iotype ==UPIO_AU ) -return __raw_readl (up->port.membase +0x28 ); -else -return _serial_dl_read (up); -} - -static void serial_dl_write (struct uart_8250_port *up,int value) -{ -if (up->port.iotype ==UPIO_AU ) -__raw_writel (value, up->port.membase +0x28 ); -else -_serial_dl_write (up, value); -} -#elif defined(CONFIG_SERIAL_8250_RM9K ) -static int serial_dl_read (struct uart_8250_port *up) -{ -return (up->port.iotype ==UPIO_RM9000 ) ? - (((__raw_readl (up->port.membase +0x10 ) <<8 ) | - (__raw_readl (up->port.membase +0x08 ) &0xff )) &0xffff ) : -_serial_dl_read (up); -} - -static void serial_dl_write (struct uart_8250_port *up,int value) -{ -if (up->port.iotype ==UPIO_RM9000 ) { -__raw_writel (value, up->port.membase +0x08 ); -__raw_writel (value >>8 , up->port.membase +0x10 ); - }else { -_serial_dl_write (up, value); - } -} -#else -#define serial_dl_read (up) _serial_dl_read(up) -#define serial_dl_write (up, value) _serial_dl_write(up, value) -#endif /* * For the 16C950
@@ -3008,10 +3011,15 @@ int __init early_serial_setup(struct uart_port *port) p->line = port->line;set_io_from_upio (p); +if (port->serial_in) p->serial_in = port->serial_in;if (port->serial_out) p->serial_out = port->serial_out; +if (port->serial_dl_read) + p->serial_dl_read = port->serial_dl_read; +if (port->serial_dl_write) + p->serial_dl_write = port->serial_dl_write;return 0 ; }
@@ -3080,6 +3088,16 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.type = p->type; port.serial_in = p->serial_in; port.serial_out = p->serial_out; + port.serial_dl_read = p->serial_dl_read; + port.serial_dl_write = p->serial_dl_write; +/* Temporary to help people transferring */ +if (port.serial_dl_read ==NULL || + port.serial_dl_write ==NULL ) { +dev_warn (&dev->dev, +"needs updating to set dl_read/write.\n" ); + port.serial_dl_read = _serial_dl_read; + port.serial_dl_write = _serial_dl_write; + } port.set_termios = p->set_termios; port.pm = p->pm; port.dev = &dev->dev;
include/linux/serial_8250.h +2 -0
@@ -37,6 +37,8 @@ struct plat_serial8250_port { struct ktermios *old);void (*pm)(struct uart_port *,unsigned int state,unsigned old); +unsigned int (*serial_dl_read)(struct uart_port *); +void (*serial_dl_write)(struct uart_port *,unsigned int ); };/*
include/linux/serial_core.h +2 -0
@@ -291,6 +291,8 @@ struct uart_port {spinlock_t lock;/* port lock */ unsigned long iobase;/* in/out[bwl] */ unsigned char __iomem *membase;/* read/write[bwl] */ +unsigned int (*serial_dl_read)(struct uart_port *); +void (*serial_dl_write)(struct uart_port *,unsigned int );unsigned int (*serial_in)(struct uart_port *,int );void (*serial_out)(struct uart_port *,int ,int ); void (*set_termios)(struct uart_port *,
RFC 2/5 8250: introduce the idea of an operations struct for an 8250 port
In reply to Alan CoxFrom: Alan Cox <[email protected]>
We can then round up all the port specific bits and push them into the drivers or standard library code where they belong. This will need all the embedded driver people to tweak their board code - sorry but there's not a nice way to do this. Once it is done however then it should be easy to keep sane as we can add new ops for new hardware insanity without disturbance.
---
drivers/char/mwave/mwavedd.c | 2 drivers/tty/serial/8250.c | 230 +++++++++++++++++++++++----------------- drivers/tty/serial/8250_pci.c | 2 drivers/tty/serial/8250_pnp.c | 2 drivers/tty/serial/of_serial.c | 2 drivers/tty/serial/serial_cs.c | 2 include/linux/serial_8250.h | 34 ++++-- include/linux/serial_core.h | 3 + 8 files changed, 165 insertions(+), 112 deletions(-)
drivers/char/mwave/mwavedd.c +1 -1
@@ -469,7 +469,7 @@ static int register_serial_portandirq(unsigned int port, int irq) uart.irq = irq; uart.iotype =UPIO_PORT ; uart.flags =UPF_SHARE_IRQ ; -return serial8250_register_port (&uart); +return serial8250_register_port (&uart,NULL ); }
drivers/tty/serial/8250.c +134 -96
411 lines not on this page · raw message
drivers/tty/serial/8250_pci.c +1 -1
@@ -2473,7 +2473,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) serial_port.iobase, serial_port.irq, serial_port.iotype);#endif - priv->line[i] =serial8250_register_port (&serial_port); + priv->line[i] =serial8250_register_port (&serial_port,NULL );if (priv->line[i] <0 ) {printk (KERN_WARNING "Couldn't register serial port %s: %d\n" ,pci_name (dev), priv->line[i]);break ;
drivers/tty/serial/8250_pnp.c +1 -1
@@ -457,7 +457,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) port.uartclk =1843200 ; port.dev = &dev->dev; - line =serial8250_register_port (&port); + line =serial8250_register_port (&port,NULL );if (line <0 )return -ENODEV ;
drivers/tty/serial/of_serial.c +1 -1
@@ -105,7 +105,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)switch (port_type) {#ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: - ret =serial8250_register_port (&port); + ret =serial8250_register_port (&port,NULL );break ;#endif #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
drivers/tty/serial/serial_cs.c +1 -1
@@ -359,7 +359,7 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,if (info->quirk && info->quirk->setup) info->quirk->setup (handle, &port); - line =serial8250_register_port (&port); + line =serial8250_register_port (&port,NULL );if (line <0 ) {printk (KERN_NOTICE "serial_cs: serial8250_register_port() at " "0x%04lx, irq %d failed\n" , (u_long )iobase, irq);
include/linux/serial_8250.h +23 -11
@@ -14,6 +14,18 @@#include <linux/serial_core.h> #include <linux/platform_device.h> +struct serial8250_ops { +unsigned int (*serial_in)(struct uart_port *,int ); +void (*serial_out)(struct uart_port *,int ,int ); +void (*set_termios)(struct uart_port *, +struct ktermios *new, +struct ktermios *old); +void (*pm)(struct uart_port *,unsigned int state, +unsigned old); +unsigned int (*serial_dl_read)(struct uart_port *); +void (*serial_dl_write)(struct uart_port *,unsigned int ); +}; +/* * This is the platform device platform_data structure */
@@ -30,15 +42,8 @@ struct plat_serial8250_port {unsigned char hub6;upf_t flags;/* UPF_* flags */ unsigned int type;/* If UPF_FIXED_TYPE */ -unsigned int (*serial_in)(struct uart_port *,int ); -void (*serial_out)(struct uart_port *,int ,int ); -void (*set_termios)(struct uart_port *, -struct ktermios *new, -struct ktermios *old); -void (*pm)(struct uart_port *,unsigned int state, -unsigned old); -unsigned int (*serial_dl_read)(struct uart_port *); -void (*serial_dl_write)(struct uart_port *,unsigned int ); +struct serial8250_ops *ops;/* Optional ops (UPIO defaults are +applied otherwise */ };/*
@@ -68,13 +73,14 @@ enum {*/ struct uart_port ; -int serial8250_register_port (struct uart_port *); +int serial8250_register_port (struct uart_port *,const struct serial8250_ops *ops);void serial8250_unregister_port (int line);void serial8250_suspend_port (int line);void serial8250_resume_port (int line); -extern int early_serial_setup (struct uart_port *port); +extern int serial8250_early_setup (struct uart_port *port, +struct serial8250_ops *ops);extern int serial8250_find_port (struct uart_port *p);extern int serial8250_find_port_for_earlycon (void );extern int setup_early_serial8250_console (char *cmdline);
@@ -87,4 +93,10 @@ extern void serial8250_set_isa_configurator(void (*v) (int port, struct uart_port *up, unsigned short *capabilities)); + +static inline int __deprecated early_serial_setup (struct uart_port *port) +{ +return serial8250_early_setup (port,NULL ); +} +#endif
include/linux/serial_core.h +3 -0
@@ -291,10 +291,12 @@ struct uart_port {spinlock_t lock;/* port lock */ unsigned long iobase;/* in/out[bwl] */ unsigned char __iomem *membase;/* read/write[bwl] */ +#if 0 unsigned int (*serial_dl_read)(struct uart_port *);void (*serial_dl_write)(struct uart_port *,unsigned int );unsigned int (*serial_in)(struct uart_port *,int );void (*serial_out)(struct uart_port *,int ,int ); +#endif void (*set_termios)(struct uart_port *,struct ktermios *new,struct ktermios *old);
@@ -318,6 +320,7 @@ struct uart_port {#define UPIO_DWAPB (6)/* DesignWare APB UART */ #define UPIO_RM9000 (7)/* RM9000 type IO */ #define UPIO_DWAPB32 (8)/* DesignWare APB UART (32 bit accesses) */ +#define UPIO_MAX (8)unsigned int read_status_mask;/* driver specific */ unsigned int ignore_status_mask;/* driver specific */
RFC 3/5 8250: register upio users
In reply to Alan CoxFrom: Alan Cox <[email protected]>
We need to do this so we can continue to offer the setserial upio interface while dumping I/O methods back out into the drivers.
---
drivers/tty/serial/8250.c | 103 ++++++++++++++++++++++++++++++------------- include/linux/serial_8250.h | 4 ++ 2 files changed, 77 insertions(+), 30 deletions(-)
drivers/tty/serial/8250.c +73 -30
@@ -612,46 +612,87 @@ static const struct serial8250_ops rm9k_ops = { .serial_dl_write = rm9k_serial_dl_write }; -/* This needs to move to a table where drivers register their ops. Needs -some thought on the module count side */ + +static const struct serial8250_ops *upio_ops[UPIO_MAX +1 ] = { +/* We rely upon pio_ops being built in */ + &pio_ops,/* UPIO_PORT */ + &hub6_ops,/* UPIO_HUB6 */ + &mem_ops,/* UPIO_MEM */ + &mem32_ops,/* UPIO_MEM32 */ + &au_ops,/* UPIO_AU */ + &tsi_ops,/* UPIO_TSI */ + &dwapb_ops,/* UPIO_DWAPB */ + &rm9k_ops,/* UPIO_RM9000 */ + &dwapb32_ops/* UPIO_DWAPB32 */ +}; + +static DEFINE_MUTEX (upio_mutex); +static void set_io_from_upio (struct uart_port *p) {struct uart_8250_port *up = container_of(p, struct uart_8250_port, port); -switch (p->iotype) { -case UPIO_HUB6 : - up->ops = &hub6_ops; -break ; -case UPIO_MEM : - up->ops = &mem_ops; -break ; -case UPIO_RM9000 : - up->ops = &rm9k_ops; -break ; -case UPIO_MEM32 : - up->ops = &mem32_ops; -break ; -case UPIO_AU : - up->ops = &au_ops; -break ; -case UPIO_TSI : - up->ops = &tsi_ops; -break ; -case UPIO_DWAPB : - up->ops = &dwapb_ops; -break ; -case UPIO_DWAPB32 : - up->ops = &dwapb32_ops; -break ; -default : +mutex_lock (&upio_mutex); +if (p->iotype >UPIO_MAX ) { +WARN_ON (1 ); up->ops = &pio_ops; -break ; + p->iotype =UPIO_PORT ; + } +/* up->ops may differ from up->cur_iotype ops +For now work off cur_iotype, we should address this better later */ +module_put (upio_ops[up->cur_iotype]->owner); + up->ops = upio_ops[p->iotype]; +if (up->ops ==NULL || !try_module_get (up->ops->owner)) { + up->ops = &pio_ops; + p->iotype =UPIO_PORT ; } +/* Remember loaded iotype */ up->cur_iotype = p->iotype; +mutex_unlock (&upio_mutex); } +/** +* serial8250_upio_register - register UPIO methods +* @upio: upio number +* @ops: operations for this upio +* +* Registers a set of upio operations and makes them available via +* the serial configuration interface for tty devices, and via the +* registration interfaces via upio value setting. Unless there are +* specific reasons new drivers should pass an ops structure directly +* instead. +*/ +int serial8250_upio_register (int upio,struct serial8250_ops *ops) +{ +int ret =0 ; +mutex_lock (&upio_mutex); +if (upio <1 || upio >UPIO_MAX ) + ret = -EINVAL ; +else if (upio_ops[upio]) + ret = -EBUSY ; +else + upio_ops[upio] = ops; +mutex_unlock (&upio_mutex); +return ret; +} +EXPORT_SYMBOL_GPL (serial8250_upio_register); + +int serial8250_upio_unregister (int upio) +{ +int ret =0 ; +mutex_lock (&upio_mutex); +if (upio_ops[upio] ==NULL ) { +WARN_ON (1 ); + ret = -EINVAL ; + } + upio_ops[upio] =NULL ; +mutex_unlock (&upio_mutex); +return ret; +} +EXPORT_SYMBOL_GPL (serial8250_upio_unregister); +static void serial_out_sync (struct uart_8250_port *up,int offset,int value) {
@@ -3305,7 +3346,7 @@ int serial8250_register_port(struct uart_port *port,set_io_from_upio (&uart->port);if (ops) - uart->port.ops = ops; + uart->ops = ops;if (serial8250_isa_config !=NULL ) serial8250_isa_config(0, &uart->port,
@@ -3337,6 +3378,8 @@ void serial8250_unregister_port(int line)if (serial8250_isa_devs) { uart->port.flags &= ~UPF_BOOT_AUTOCONF ; uart->port.type =PORT_UNKNOWN ; + uart->port.iotype =UPIO_PORT ; +set_io_from_upio (&uart->port); uart->port.dev = &serial8250_isa_devs->dev;uart_add_one_port (&serial8250_reg, &uart->port); }else {
include/linux/serial_8250.h +4 -0
@@ -24,6 +24,7 @@ struct serial8250_ops { unsigned old);unsigned int (*serial_dl_read)(struct uart_port *);void (*serial_dl_write)(struct uart_port *,unsigned int ); +struct module *owner; };/*
@@ -99,4 +100,7 @@ static inline int __deprecated early_serial_setup(struct uart_port *port) return serial8250_early_setup(port, NULL); } +extern int serial8250_upio_register (int upio,struct serial8250_ops *ops); +extern int serial8250_upio_unregister (int upio); +#endif
RFC 4/5 8250: evict the hub6 I/O operations
In reply to Alan CoxFrom: Alan Cox <[email protected]>
This is a test to see how the split looks when we do this, there is other hub6 code buried in the core because of the way the 8250 and serial core manage resources. That needs addressing.
---
drivers/tty/serial/8250.c | 52 ++-------------------------------------- drivers/tty/serial/8250.h | 27 +++++++++++++++++++++ drivers/tty/serial/8250_hub6.c | 39 ++++++++++++++++++++++++++++++ include/linux/serial_8250.h | 2 +- 4 files changed, 69 insertions(+), 51 deletions(-)
drivers/tty/serial/8250.c +2 -50
@@ -131,32 +131,6 @@ static unsigned long probe_rsa[PORT_RSA_MAX];static unsigned int probe_rsa_count;#endif /* CONFIG_SERIAL_8250_RSA */ -struct uart_8250_port { -struct uart_port port; -const struct serial8250_ops *ops;/* I/O access methods */ -struct timer_list timer;/* "no irq" timer */ -struct list_head list;/* ports on this IRQ */ -unsigned short capabilities;/* port capabilities */ -unsigned short bugs;/* port bugs */ -unsigned int tx_loadsz;/* transmit fifo load size */ -unsigned char acr; -unsigned char ier; -unsigned char lcr; -unsigned char mcr; -unsigned char mcr_mask;/* mask of user bits */ -unsigned char mcr_force;/* mask of forced bits */ -unsigned char cur_iotype;/* Running I/O type */ - -/* -* Some bits in registers are cleared on a read, so they must -* be saved whenever the register is read but the bits will not -* be immediately processed. -*/ -#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS -unsigned char lsr_saved_flags; -#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA -unsigned char msr_saved_flags; -};struct irq_info {struct hlist_node node;
@@ -406,28 +380,6 @@ static void std_serial_dl_write(struct uart_port *p, unsigned int value) up->ops->serial_out (p,UART_DLM , value >>8 &0xff ); } - -static unsigned int hub6_serial_in (struct uart_port *p,int offset) -{ - offset =map_8250_in_reg (p, offset) << p->regshift; -outb (p->hub6 -1 + offset, p->iobase); -return inb (p->iobase +1 ); -} - -static void hub6_serial_out (struct uart_port *p,int offset,int value) -{ - offset =map_8250_out_reg (p, offset) << p->regshift; -outb (p->hub6 -1 + offset, p->iobase); -outb (value, p->iobase +1 ); -} - -static const struct serial8250_ops hub6_ops = { - .serial_in = hub6_serial_in, - .serial_out = hub6_serial_out, - .serial_dl_read = std_serial_dl_read, - .serial_dl_write = std_serial_dl_write -}; -static unsigned int mem_serial_in (struct uart_port *p,int offset) { offset =map_8250_in_reg (p, offset) << p->regshift;
@@ -616,7 +568,7 @@ static const struct serial8250_ops rm9k_ops = {static const struct serial8250_ops *upio_ops[UPIO_MAX +1 ] = {/* We rely upon pio_ops being built in */ &pio_ops,/* UPIO_PORT */ - &hub6_ops,/* UPIO_HUB6 */ +NULL ,/* UPIO_HUB6 */ &mem_ops,/* UPIO_MEM */ &mem32_ops,/* UPIO_MEM32 */ &au_ops,/* UPIO_AU */
@@ -664,7 +616,7 @@ static void set_io_from_upio(struct uart_port *p)* specific reasons new drivers should pass an ops structure directly * instead. */ -int serial8250_upio_register (int upio,struct serial8250_ops *ops) +int serial8250_upio_register (int upio,const struct serial8250_ops *ops) {int ret =0 ;mutex_lock (&upio_mutex);
drivers/tty/serial/8250.h +27 -0
@@ -28,6 +28,33 @@ struct old_serial_port {unsigned long irqflags; }; +struct uart_8250_port { +struct uart_port port; +const struct serial8250_ops *ops;/* I/O access methods */ +struct timer_list timer;/* "no irq" timer */ +struct list_head list;/* ports on this IRQ */ +unsigned short capabilities;/* port capabilities */ +unsigned short bugs;/* port bugs */ +unsigned int tx_loadsz;/* transmit fifo load size */ +unsigned char acr; +unsigned char ier; +unsigned char lcr; +unsigned char mcr; +unsigned char mcr_mask;/* mask of user bits */ +unsigned char mcr_force;/* mask of forced bits */ +unsigned char cur_iotype;/* Running I/O type */ + +/* +* Some bits in registers are cleared on a read, so they must +* be saved whenever the register is read but the bits will not +* be immediately processed. +*/ +#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS +unsigned char lsr_saved_flags; +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA +unsigned char msr_saved_flags; +}; +/* * This replaces serial_uart_config in include/linux/serial.h */
drivers/tty/serial/8250_hub6.c +39 -0
@@ -11,6 +11,8 @@#include <linux/module.h> #include <linux/init.h> #include <linux/serial_8250.h> +#include <linux/serial_reg.h> +#include "8250.h" #define HUB6 (card,port) \ { \
@@ -38,6 +40,42 @@ static struct plat_serial8250_port hub6_data[] = { { }, }; + +static unsigned int hub6_serial_in (struct uart_port *p,int offset) +{ +outb (p->hub6 -1 + offset, p->iobase); +return inb (p->iobase +1 ); +} + +static void hub6_serial_out (struct uart_port *p,int offset,int value) +{ +outb (p->hub6 -1 + offset, p->iobase); +outb (value, p->iobase +1 ); +} + +/* Uart divisor latch read */ +static unsigned hub6_serial_dl_read (struct uart_port *p) +{ +return hub6_serial_in (p,UART_DLL ) | +hub6_serial_in (p,UART_DLM ) <<8 ; +} + +/* Uart divisor latch write */ +static void hub6_serial_dl_write (struct uart_port *p,unsigned int value) +{ +hub6_serial_out (p,UART_DLL , value &0xff ); +hub6_serial_out (p,UART_DLM , value >>8 &0xff ); +} + +static const struct serial8250_ops hub6_ops = { + .owner =THIS_MODULE , + + .serial_in = hub6_serial_in, + .serial_out = hub6_serial_out, + .serial_dl_read = hub6_serial_dl_read, + .serial_dl_write = hub6_serial_dl_write +}; +static struct platform_device hub6_device = { .name ="serial8250" , .id =PLAT8250_DEV_HUB6 ,
@@ -48,6 +86,7 @@ static struct platform_device hub6_device = {static int __init hub6_init (void ) { +serial8250_upio_register (UPIO_HUB6 , &hub6_ops);return platform_device_register (&hub6_device); }
include/linux/serial_8250.h +1 -1
@@ -100,7 +100,7 @@ static inline int __deprecated early_serial_setup(struct uart_port *port) return serial8250_early_setup(port, NULL); } -extern int serial8250_upio_register (int upio,struct serial8250_ops *ops); +extern int serial8250_upio_register (int upio,const struct serial8250_ops *ops);extern int serial8250_upio_unregister (int upio);#endif
RFC 5/5 8250: extract out the "odd" port types
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Possibly these want to end up in arch code but for the moment make them little separate files in the serial layer
---
drivers/tty/serial/8250.c | 207 ++------------------------------------- drivers/tty/serial/8250_au.c | 90 +++++++++++++++++ drivers/tty/serial/8250_dwapb.c | 120 +++++++++++++++++++++++ drivers/tty/serial/8250_rm9k.c | 95 ++++++++++++++++++ drivers/tty/serial/Kconfig | 9 ++ drivers/tty/serial/Makefile | 3 + 6 files changed, 329 insertions(+), 195 deletions(-) create mode 100644 drivers/tty/serial/8250_au.c create mode 100644 drivers/tty/serial/8250_dwapb.c create mode 100644 drivers/tty/serial/8250_rm9k.c
drivers/tty/serial/8250.c +12 -195
@@ -280,88 +280,6 @@ static const struct serial8250_config uart_config[] = { }, }; -#if defined(CONFIG_MIPS_ALCHEMY ) - -/* Au1x00 UART hardware has a weird register layout */ -static const u8 au_io_in_map[] = { - [UART_RX ] =0 , - [UART_IER ] =2 , - [UART_IIR ] =3 , - [UART_LCR ] =5 , - [UART_MCR ] =6 , - [UART_LSR ] =7 , - [UART_MSR ] =8 , -}; - -static const u8 au_io_out_map[] = { - [UART_TX ] =1 , - [UART_IER ] =2 , - [UART_FCR ] =4 , - [UART_LCR ] =5 , - [UART_MCR ] =6 , -}; - -/* sane hardware needs no mapping */ -static inline int map_8250_in_reg (struct uart_port *p,int offset) -{ -if (p->iotype !=UPIO_AU ) -return offset; -return au_io_in_map[offset]; -} - -static inline int map_8250_out_reg (struct uart_port *p,int offset) -{ -if (p->iotype !=UPIO_AU ) -return offset; -return au_io_out_map[offset]; -} - -#elif defined(CONFIG_SERIAL_8250_RM9K ) - -static const u8 - regmap_in[8 ] = { - [UART_RX ] =0x00 , - [UART_IER ] =0x0c , - [UART_IIR ] =0x14 , - [UART_LCR ] =0x1c , - [UART_MCR ] =0x20 , - [UART_LSR ] =0x24 , - [UART_MSR ] =0x28 , - [UART_SCR ] =0x2c - }, - regmap_out[8 ] = { - [UART_TX ] =0x04 , - [UART_IER ] =0x0c , - [UART_FCR ] =0x18 , - [UART_LCR ] =0x1c , - [UART_MCR ] =0x20 , - [UART_LSR ] =0x24 , - [UART_MSR ] =0x28 , - [UART_SCR ] =0x2c - }; - -static inline int map_8250_in_reg (struct uart_port *p,int offset) -{ -if (p->iotype !=UPIO_RM9000 ) -return offset; -return regmap_in[offset]; -} - -static inline int map_8250_out_reg (struct uart_port *p,int offset) -{ -if (p->iotype !=UPIO_RM9000 ) -return offset; -return regmap_out[offset]; -} - -#else - -/* sane hardware needs no mapping */ -#define map_8250_in_reg (up, offset) (offset) -#define map_8250_out_reg (up, offset) (offset) - -#endif -/* Uart divisor latch read */ static unsigned int std_serial_dl_read (struct uart_port *p) {
@@ -382,13 +300,13 @@ static void std_serial_dl_write(struct uart_port *p, unsigned int value)static unsigned int mem_serial_in (struct uart_port *p,int offset) { - offset =map_8250_in_reg (p, offset) << p->regshift; + offset <<= p->regshift;return readb (p->membase + offset); }static void mem_serial_out (struct uart_port *p,int offset,int value) { - offset =map_8250_out_reg (p, offset) << p->regshift; + offset <<= p->regshift;writeb (value, p->membase + offset); }
@@ -401,13 +319,13 @@ static const struct serial8250_ops mem_ops = {static void mem32_serial_out (struct uart_port *p,int offset,int value) { - offset =map_8250_out_reg (p, offset) << p->regshift; + offset <<= p->regshift;writel (value, p->membase + offset); }static unsigned int mem32_serial_in (struct uart_port *p,int offset) { - offset =map_8250_in_reg (p, offset) << p->regshift; + offset <<= p->regshift;return readl (p->membase + offset); }
@@ -421,7 +339,7 @@ static const struct serial8250_ops mem32_ops = {static unsigned int tsi_serial_in (struct uart_port *p,int offset) {unsigned int tmp; - offset =map_8250_in_reg (p, offset) << p->regshift; + offset <<= p->regshift;if (offset ==UART_IIR ) { tmp =readl (p->membase + (UART_IIR & ~3 ));return (tmp >>16 ) &0xff ;/* UART_IIR % 4 == 2 */
@@ -431,7 +349,7 @@ static unsigned int tsi_serial_in(struct uart_port *p, int offset)static void tsi_serial_out (struct uart_port *p,int offset,int value) { - offset =map_8250_out_reg (p, offset) << p->regshift; + offset <<= p->regshift;if (!((offset ==UART_IER ) && (value &UART_IER_UUE )))writeb (value, p->membase + offset); }
@@ -443,67 +361,16 @@ static const struct serial8250_ops tsi_ops = { .serial_dl_write = std_serial_dl_write }; -/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ -static inline void dwapb_save_out_value (struct uart_port *p,int offset, -int value) -{ -struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); - -if (offset ==UART_LCR ) - up->lcr = value; -} - -/* Read the IER to ensure any interrupt is cleared before returning from ISR. */ -static inline void dwapb_check_clear_ier (struct uart_port *p,int offset) -{ -struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); -if (offset ==UART_TX || offset ==UART_IER ) - up->ops->serial_in (p,UART_IER ); -} - -static void dwapb_serial_out (struct uart_port *p,int offset,int value) -{ -int save_offset = offset; - offset =map_8250_out_reg (p, offset) << p->regshift; -dwapb_save_out_value (p, save_offset, value); -writeb (value, p->membase + offset); -dwapb_check_clear_ier (p, save_offset); -} - -static const struct serial8250_ops dwapb_ops = { - .serial_in = mem_serial_in, - .serial_out = dwapb_serial_out, - .serial_dl_read = std_serial_dl_read, - .serial_dl_write = std_serial_dl_write -}; - -static void dwapb32_serial_out (struct uart_port *p,int offset,int value) -{ -int save_offset = offset; - offset =map_8250_out_reg (p, offset) << p->regshift; -dwapb_save_out_value (p, save_offset, value); -writel (value, p->membase + offset); -dwapb_check_clear_ier (p, save_offset); -} - -static const struct serial8250_ops dwapb32_ops = { - .serial_in = mem32_serial_in, - .serial_out = dwapb32_serial_out, - .serial_dl_read = std_serial_dl_read, - .serial_dl_write = std_serial_dl_write -};static unsigned int io_serial_in (struct uart_port *p,int offset) { - offset =map_8250_in_reg (p, offset) << p->regshift; + offset <<= p->regshift;return inb (p->iobase + offset); }static void io_serial_out (struct uart_port *p,int offset,int value) { - offset =map_8250_out_reg (p, offset) << p->regshift; + offset <<= p->regshift;outb (value, p->iobase + offset); }
@@ -515,67 +382,17 @@ static const struct serial8250_ops pio_ops = { .serial_dl_write = std_serial_dl_write }; -static unsigned int au_serial_in (struct uart_port *p,int offset) -{ - offset =map_8250_in_reg (p, offset) << p->regshift; -return __raw_readl (p->membase + offset); -} - -static void au_serial_out (struct uart_port *p,int offset,int value) -{ - offset =map_8250_out_reg (p, offset) << p->regshift; -__raw_writel (value, p->membase + offset); -} - -/* Au1x00 haven't got a standard divisor latch */ -static unsigned int au_serial_dl_read (struct uart_port *p) -{ -return __raw_readl (p->membase +0x28 ); -} - -static void au_serial_dl_write (struct uart_port *p,unsigned int value) -{ -__raw_writel (value, p->membase +0x28 ); -} - -static const struct serial8250_ops au_ops = { - .serial_in = au_serial_in, - .serial_out = au_serial_out, - .serial_dl_read = au_serial_dl_read, - .serial_dl_write = au_serial_dl_write -}; - -static unsigned int rm9k_serial_dl_read (struct uart_port *p) -{ -return (((__raw_readl (p->membase +0x10 ) <<8 ) | - (__raw_readl (p->membase +0x08 ) &0xff )) &0xffff ); -} - -static void rm9k_serial_dl_write (struct uart_port *p,unsigned int value) -{ -__raw_writel (value, p->membase +0x08 ); -__raw_writel (value >>8 , p->membase +0x10 ); -} - -static const struct serial8250_ops rm9k_ops = { - .serial_in = mem32_serial_in, - .serial_out = mem32_serial_out, - .serial_dl_read = rm9k_serial_dl_read, - .serial_dl_write = rm9k_serial_dl_write -}; - -static const struct serial8250_ops *upio_ops[UPIO_MAX +1 ] = {/* We rely upon pio_ops being built in */ &pio_ops,/* UPIO_PORT */ NULL ,/* UPIO_HUB6 */ &mem_ops,/* UPIO_MEM */ &mem32_ops,/* UPIO_MEM32 */ - &au_ops,/* UPIO_AU */ +NULL ,/* UPIO_AU */ &tsi_ops,/* UPIO_TSI */ - &dwapb_ops,/* UPIO_DWAPB */ - &rm9k_ops,/* UPIO_RM9000 */ - &dwapb32_ops/* UPIO_DWAPB32 */ +NULL ,/* UPIO_DWAPB */ +NULL ,/* UPIO_RM9000 */ +NULL ,/* UPIO_DWAPB32 */ };static DEFINE_MUTEX (upio_mutex);
drivers/tty/serial/8250_au.c new file +90 -0
90 lines not on this page · raw message
drivers/tty/serial/8250_dwapb.c new file +120 -0
120 lines not on this page · raw message
drivers/tty/serial/8250_rm9k.c new file +95 -0
95 lines not on this page · raw message
drivers/tty/serial/Kconfig +9 -0
@@ -80,6 +80,12 @@ config SERIAL_8250_GSC depends on SERIAL_8250 && GSC default SERIAL_8250 +config SERIAL_8250_AU + tristate "8250 support for AU1000 serial I/O methods" + +config SERIAL_8250_DWAPB + tristate "8250 support for DWAPB serial I/O methods" + config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI
@@ -267,6 +273,9 @@ config SERIAL_8250_RM9K port hardware found on MIPS RM9122 and similar processors. If unsure, say N. +config SERIAL_8250_RM9K_OPS + tristate "8250 support for RM9000 serial I/O methods" + comment "Non-8250 serial port support" config SERIAL_AMBA_PL010
drivers/tty/serial/Makefile +3 -0
@@ -15,6 +15,9 @@ obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o obj-$(CONFIG_SERIAL_8250) += 8250.o +obj-$(CONFIG_SERIAL_8250_AU) += 8250_au.o +obj-$(CONFIG_SERIAL_8250_RM9K_OPS) += 8250_rm9k.o +obj-$(CONFIG_SERIAL_8250_DWAPB) += 8250_dwapb.o obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
Quoted 9 lines · Alan Cox
This is an untested WIP but as it was coming in discussion about device-tree as well I figured it will be useful to post the prototype code at this point.
There is lots left to do - in particular resource claim/release should be an ops method, and it's going to need people to update various embedded 8250 drivers when we finally go for a version of it.
On the bright side once we have an ops structure we have the basis for avoiding further mayhem in the arch code.
This looks great to me, nice job.
Feel free to resend it when you want me to queue it up for .40.
thanks,
greg k-h