Re: [PATCH] uart: pl011: Add support to ZTE uart

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 03/18/2015 12:08 PM, Peter Hurley wrote:
> Hi Jun,
> 
> On 03/18/2015 04:01 AM, Jun Nie wrote:
>> 2015-03-14 2:09 GMT+08:00 Russell King - ARM Linux <linux@xxxxxxxxxxxxxxxx <mailto:linux@xxxxxxxxxxxxxxxx>>:
>>
>>     On Fri, Mar 13, 2015 at 02:02:49PM -0400, Peter Hurley wrote:
>>     > On 03/13/2015 01:46 PM, Russell King - ARM Linux wrote:
>>     > > On Fri, Mar 13, 2015 at 01:41:02PM -0400, Peter Hurley wrote:
>>     > >> I think this would be much cleaner keeping the existing register index
>>     > >> symbolic constants and using a remapping LUT with inline i/o accessors.
>>     > >>
>>     > >> Plus it has the advantage of disallowing certain indexes which are not
>>     > >> mapped (rather than an accidental alias).
>>     > >>
>>     > >> I realize that was not the original model set forth but I don't think
>>     > >> the original model contemplated a complete remap.
>>     > >
>>     > > In that case, we will want to ensure that we cache the data register
>>     > > and flag register iomem pointer in loops, so we don't have to
>>     > > constantly reload the base and offsets.
>>     > >
>>     > > This code gets run on some fairly slow ARM systems - including entirely
>>     > > FPGA based systems.
>>     >
>>     > I would the think the compiler would factor ptr calculations outside
>>     > any loop, but maybe not.
>>
>>     It can't.  IO accessors tend to have barriers, possibly calling out
>>     to functions, and the barriers force the compiler to reload almost
>>     everything which is not in a local variable.
>>
>>     (Note that none of the accessors in amba-pl011.c needs to have these
>>     barriers, and the driver probably should've been converted to the
>>     relaxed accessors when they were merged.)
>>
>> Could you help elaborate IO accessors? Any example code for reference?
> 
> By "i/o accessors", I mean wrapper functions that abstract the register i/o.
> Generally, UART drivers handle significant model/platform i/o differences
> with some functional abstraction, although the details vary.
> 
> Some drivers assign and call through the struct uart_port::serial_in() and
> ::serial_out() methods, but that's usually because the underlying
> platform i/o is different (readl() vs. inb()).
> 
> For this driver, what you outline below seems basically acceptable with the
> following comments:
> 
>> I am thinking below style code according to your comments.
>>
>> enum pl011_reg {
>> UART01x_DR/* Data read or written from the interface. */
>> UART01x_RSR/* Receive status register (Read). */
>> UART01x_ECR= 1;/* Error clear register (Write). */
>> UART010_LCRH/* Line control register, high byte. */
>> UART010_LCRM/* Line control register, middle byte. */
>> ...
>> };
> 
> I don't think it's necessary to re-define the register index
> symbolic constants; the compiler will constant-fold expressions,
> even through inline functions. For example,
> 
> static unsigned int pl011_in(struct uart_port *port, int index)
> {
> 	return readl_relaxed(port->membase + lut[index << 2];
                                                 ^^^^^^^^^^
Sorry if this confused you ---------------------------^
it should be:  index >> 2


> }
> 
> ....
> 
> 	ibrd = pl011_in(uap->port, UART011_IBRD);
> 
> will be folded as
> 
> 	ibrd = readl_relaxed(port->membase + lut[9];
> 
> 
> Also, performing i/o with an inline helper function will allow you
> to range-check the register index.
> 	
> 
>> unsigned int zte_uart[0x23] = {
>> 0x04,/* UART01x_DR */
>> 0x04,/* UART01x_RSR,UART01x_ECR  */
>> 0x08,/* UART010_LCRH */
>> 0x1C/* UART010_LCRM   */
>> ...
>> };
>>
>> unsigned int st_uart[0x23] = {
>> 0x0,/* UART01x_DR */
>> 0x04,/* UART01x_RSR,UART01x_ECR  */
>> 0x08,/* UART010_LCRH */
>> 0x1C/* UART010_LCRM*/
>> ...
>> };
>>
>> unsigned int (*reg_lut)[23];
> 
> The table could be 'u8' type.
> 
> This is basically a space/time trade-off.
> AFAICT, the driver never accesses an offset > 0x48 (ie, index > 0x12),
> so range-checking the index would allow you to use smaller tables.
> 
> I would ask Russell which he would prefer.
> 
> 
>> static int zx_uart_probe(struct platform_device *pdev)
>> {
>> ...
>> reg_lut = zte_uart;
>> ...
>> }
>>
>> /* Normal usage */
>> writew(val, uap->port.membase + reg_lut[UART01x_DR]);
>>
>> /* Usage in loop */
>> void __iomem *dr = uap->port.membase + reg_lut[UART01x_DR];
>> while (..) {
>> ..
>> writew(val, dr);
>> ..
>> }
> 
> One issue that arises is how to handle register i/o to unmapped
> registers. An error message is not possible because of the 
> certainty of deadlock on the port spinlock.
> 
> Regards,
> Peter Hurley
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux