Re: what is the purpose of the following LE->BE patch to arch/mips/include/asm/io.h?

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

 



On Sat, 21 Feb 2015, Robert P. J. Day wrote:

> > >   has anyone else ever needed to do this? or is this some weird,
> > > one-off hack that perhaps applies *only* to some bizarre feature of
> > > this board?
> >
> > My guess is that the peripherals attached to the internal bus
> > only undestand little endian, and the bus doesn't do byte swaps when
> > the core isn't configured for LE. I.e. the BE feature is only
> > implemented in the mips core and the rest was designed for LE only.
> 
>   ok, that makes sense ... so it's very likely a "issue with *this*
> particular board and setup" kind of thing. thanks.

 It looks to me like either a platform setup or a driver bug, as for this 
very purpose we have two sets of these access macros, one that preserves 
the bit ordering (IOW the value accessed) and another that preserves the 
byte ordering (but the value accessed may come out byte-swapped).  The 
former will usually be used for accessing MMIO registers of peripherals 
and the latter for byte streams exchanged between a peripheral and host 
memory via DMA.  This is so that generic code (e.g. a PCI device driver 
that will run on any processor or system it is thrown at) does not have to 
be concerned about the actual host bus endianness.

 The names of these macros reflect their usual purpose, and there's a 
pass-through set of macros too that never byte-swaps, so you'll use:

* `readl'/`writel'/etc. -- to access MMIO, preserving the bit ordering,

* `__mem_readl'/`__mem_writel'/etc. -- to access DMA memory, preserving 
  the byte ordering,

* `__raw_readl'/`__raw_writel'/etc. -- to access data as it shows on the 
  bus it comes from or goes to.

Please note that there is only ever any difference between these accessors 
if a platform has a bus whose endianness is fixed regardless of the host 
endianness.

 For example PCI is fixed at the little endianness and therefore all these 
macros pass data through unchanged on a little-endian host.  When the host 
bus is big-endian then `readl'/`writel' will byte-swap data unless byte 
lane swapping already happens at the PCI host bridge.  In that case it is 
likely that `__mem_readl'/`__mem_writel' will have to swap data instead.  
And then you'll use `__raw_readl'/`__raw_writel' to access host MMIO 
registers that are never swapped, e.g. on-chip SOC registers, or host-side 
registers of the PCI host bridge.

 All this is arranged in a system-specific manner with the use of a set of 
`*ioswab?' macros, that a platform has to define in `mangle-port.h' unless 
it wants to use the defaults.  See the existing examples for a reference.  
There's a set of `__swizzle_addr_?' macros there too, for systems that 
need to adjust the address accessed to account for byte lane swapping done 
in hardware.

 Overall it all is system dependent, and there are systems in existence 
for example that have an alternative byte-lane swapping address space and 
therefore for accesses that need to be swapped they can take advantage of 
that feature and switch the address space rather than shuffling bytes, for 
a small performance advantage.  We don't use this feature at the moment 
though; it would be most beneficial for string I/O where a single address 
adjustment operation would do for the whole transfer whereas byte-swapping 
has to be done for every individual piece of data transferred.

 In any case it looks very likely to me that either a driver uses the 
wrong set of macros to access a resource or the platform has failed to 
define its `*ioswab*' macros correctly.

 Feel free to let me know if you find anything of this unclear or have any 
further questions.

  Maciej





[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux