Re: [PATCH v3] serial: 8250_uniphier: add UniPhier serial driver
From: Matthias Brugger <matthias.bgg@gmail.com>
Date: 2015-05-19 11:31:30
Also in:
lkml
2015-05-19 13:18 GMT+02:00 Masahiro Yamada [off-list ref]:
Hi Alan, 2015-05-19 18:48 GMT+09:00 One Thousand Gnomes [off-list ref]:quoted
quoted
I intentionally use deeper indentation for *_SHIFT because I want to clearly show UNIPHIER_UART_LCR_SHIFT belongs to UNIPHIER_UART_LCR_MCR register.Seems sensible to do it that way to me and a lot of other bits of the kernel do. The only other question I have is about the unipher_serial_out. If I am writing a "special" register then the sequence becomes - read 32bits - modify - write 32bits That means that it's no longer atomic safe as the kernel expects. Checking the users FCR seems safe, LCR is probably safe and MCR likewise so I don't see a problem but I think it's worth noting in case anyone else does.Uh, I missed this. I am a bit afraid what if LCR and MCR are updated at the same time. Is it better to add mutex for writing special case registers? if (normal) { writel(value, p->membase + offset); } else { /* special case: two registers share the same address. */ u32 tmp = readl(p->membase + offset); struct uniphier8250_priv *priv = p->private_data; mutex_lock(&priv->atomic_write_lock); tmp &= ~(0xff << valshift); tmp |= value << valshift; writel(tmp, p->membase + offset); mutex_unlock(&priv->atomic_write_lock); } If it is OK, I can fix it in v4.quoted
Finally can you add a comment in serial_in and serial_out where one switch case drops through into the next so its obvious to anyone looking at Coverity and other analyser output that this drop through was intentional ?I thought about it, too. My previous version was as follows: +#define UNIPHIER_UART_CHAR_FCR 3 +#define UNIPHIER_UART_CHAR_SHIFT 8 /* Character Register */ +#define UNIPHIER_UART_FCR_SHIFT 0 /* FIFO Control Register */ +#define UNIPHIER_UART_LCR_MCR 4 +#define UNIPHIER_UART_LCR_SHIFT 8 /* Line Control Register */ +#define UNIPHIER_UART_MCR_SHIFT 0 /* Modem Control Register */ +#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */ [snip] +static void uniphier_serial_out(struct uart_port *p, int offset, int value) +{ + int valshift = 0; + bool normal = false; + + switch (offset) { + case UART_FCR: + offset = UNIPHIER_UART_CHAR_FCR; + valshift = UNIPHIER_UART_FCR_SHIFT; + break; + case UART_LCR: + offset = UNIPHIER_UART_LCR_MCR; + valshift = UNIPHIER_UART_LCR_SHIFT; + /* Divisor latch access bit does not exist. */ + value &= ~(UART_LCR_DLAB << valshift); + break; + case UART_MCR: + offset = UNIPHIER_UART_LCR_MCR; + valshift = UNIPHIER_UART_MCR_SHIFT; + break; + default: + normal = true; + break; + } I thought it was clear to anyone although it was a bit redundant and Matthias was opposed to it. I personally prefer clear code to tricky code that requires comments.
Me too :) What I wanted to say was, that in the case statement you don't need to set valshift to zero as this is the default value when entering uniphier_serial_out. This way you can get rid of UNIPHIER_UART_MCR_SHIFT and UNIPHIER_UART_FCR_SHIFT. Sorry, I didn't explained myself. Cheers, Matthias -- motzblog.wordpress.com