what is the purpose of the following LE->BE patch to arch/mips/include/asm/io.h?
was recently handed a MIPS-based dev board (can't name the vendor,
NDA) that *typically* runs in LE mode but, because of a proprietary binary that must be run on the board and was compiled as BE, has to be run in BE mode.
the vendor supplied a yoctoproject layer that seems to work fine
but, in changing the DEFAULTTUNE to big-endian, the following patch had to be applied to the 3.14 kernel tree to the file arch/mips/include/asm/io.h in order to get output from the console port as the system was booting:
326c326,333
< *__mem = __val; \
---
Quoted 8 lines
{ \
if (sizeof(type) == sizeof(u32)) \
{ \
*__mem = __cpu_to_le32(__val); \
} \
else \
*__mem = __val; \
} \356a364
Quoted 1 line
{ \357a366,368
Quoted 3 lines
if (sizeof(type) == sizeof(u32)) \ __val = __cpu_to_le32(__val); \ } \
without that patch, the initial conclusion was that the board was
just hanging at boot, but i was told, no, it was booting, there was just no output at the console port. applied the patch and, voila.
can someone explain *precisely* what the above is doing? i am by no
means a MIPS expert, but clearly the above is doing some sort of explicit BE/LE conversion. can anyone supply more detail? thanks.
rday
Signature · 7 lines
========================================================================
Robert P. J. Day Ottawa, Ontario, CANADA
http://crashcourse.ca
Twitter: http://twitter.com/rpjday
LinkedIn: http://ca.linkedin.com/in/rpjday
========================================================================Quoted 12 lines · Robert P. J. Day
was recently handed a MIPS-based dev board (can't name the vendor,
NDA) that *typically* runs in LE mode but, because of a proprietary binary that must be run on the board and was compiled as BE, has to be run in BE mode.the vendor supplied a yoctoproject layer that seems to work fine
but, in changing the DEFAULTTUNE to big-endian, the following patch had to be applied to the 3.14 kernel tree to the filearch/mips/include/asm/io.hin order to get output from the console port as the system was booting:
Quoted 7 lines
326c326,333
<*__mem=__val; \
---Quoted 4 lines
{ \ if (sizeof(type) == sizeof(u32)) \ { \ *__mem = __cpu_to_le32(__val); \
They're byte swapping a value if they're in big endian mode.
Quoted 3 lines
Quoted 3 lines
} \ else \ *__mem = __val; \
And they don't seem to really understand the __cpu_to_le32 macro...
Quoted 21 lines · Matt Turner
Quoted 12 lines · Robert P. J. Day
was recently handed a MIPS-based dev board (can't name the vendor,
NDA) that *typically* runs in LE mode but, because of a proprietary binary that must be run on the board and was compiled as BE, has to be run in BE mode.the vendor supplied a yoctoproject layer that seems to work fine
but, in changing the DEFAULTTUNE to big-endian, the following patch had to be applied to the 3.14 kernel tree to the filearch/mips/include/asm/io.hin order to get output from the console port as the system was booting:Quoted 7 lines
326c326,333
<*__mem=__val; \
---Quoted 4 lines
{ \ if (sizeof(type) == sizeof(u32)) \ { \ *__mem = __cpu_to_le32(__val); \
Quoted 7 lines
They're byte swapping a value if they're in big endian mode.
Quoted 3 lines
Quoted 3 lines
} \ else \ *__mem = __val; \And they don't seem to really understand the
__cpu_to_le32macro...
Sorry, I should be more precise. They're byte swapping 32-bit values if they're in big endian mode, and copying everything else without conversion.
Quoted 28 lines · Matt Turner
Quoted 27 lines · Matt Turner
Quoted 12 lines · Robert P. J. Day
was recently handed a MIPS-based dev board (can't name the vendor,
NDA) that *typically* runs in LE mode but, because of a proprietary binary that must be run on the board and was compiled as BE, has to be run in BE mode.the vendor supplied a yoctoproject layer that seems to work fine
but, in changing the DEFAULTTUNE to big-endian, the following patch had to be applied to the 3.14 kernel tree to the filearch/mips/include/asm/io.hin order to get output from the console port as the system was booting:Quoted 7 lines
326c326,333
<*__mem=__val; \
---Quoted 4 lines
{ \ if (sizeof(type) == sizeof(u32)) \ { \ *__mem = __cpu_to_le32(__val); \They're byte swapping a value if they're in big endian mode.
Quoted 3 lines
Quoted 3 lines
} \ else \ *__mem = __val; \
Quoted 5 lines
Quoted 1 line
And they don't seem to really understand the
__cpu_to_le32macro...Sorry, I should be more precise. They're byte swapping 32-bit values if they're in big endian mode, and copying everything else without conversion.
i understand *in general* what the above is doing ... what i don't
understand is why it's necessary to hack a fundamental kernel header file this way in order to run this board in BE versus LE mode.
the kernel was already configured for BE mode, which i would have
thought would be sufficient, so it's a mystery to me why one would still have to *further* hack the io.h file this way -- if the above is a necessity, shouldn't it be a conditional change based on selecting BE configuration?
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?
rday
Signature · 7 lines
========================================================================
Robert P. J. Day Ottawa, Ontario, CANADA
http://crashcourse.ca
Twitter: http://twitter.com/rpjday
LinkedIn: http://ca.linkedin.com/in/rpjday
========================================================================Quoted 4 lines · Robert P. J. Day
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 isthat 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.
Manuel
Quoted 10 lines · Manuel Lauss
Quoted 4 lines · Robert P. J. Day
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.
rday
Signature · 7 lines
========================================================================
Robert P. J. Day Ottawa, Ontario, CANADA
http://crashcourse.ca
Twitter: http://twitter.com/rpjday
LinkedIn: http://ca.linkedin.com/in/rpjday
========================================================================Quoted 11 lines · Robert P. J. Day
Quoted 8 lines
Quoted 3 lines
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
Quoted 25 lines · Robert P. J. Day
was recently handed a MIPS-based dev board (can't name the vendor,
NDA) that *typically* runs in LE mode but, because of a proprietary binary that must be run on the board and was compiled as BE, has to be run in BE mode.the vendor supplied a yoctoproject layer that seems to work fine
but, in changing the DEFAULTTUNE to big-endian, the following patch had to be applied to the 3.14 kernel tree to the filearch/mips/include/asm/io.hin order to get output from the console port as the system was booting:326c326,333
<*__mem=__val; \
---Quoted 8 lines
{ \ if (sizeof(type) == sizeof(u32)) \ { \ *__mem = __cpu_to_le32(__val); \ } \ else \ *__mem = __val; \ } \356a364
Quoted 1 line
{ \
Quoted 8 lines
357a366,368
Quoted 3 lines
if (sizeof(type) == sizeof(u32)) \ __val = __cpu_to_le32(__val); \ } \without that patch, the initial conclusion was that the board was
just hanging at boot, but i was told, no, it was booting, there was just no output at the console port. applied the patch and, voila.
If it's using the serial8250 driver with a standard 16550A-ish UART, MMIO accesses via readl()/writel() may be byteswapped on a BE system.
Historically I've dealt with this problem by locally modifying the serial8250 driver to use the __raw_* variants, but here is a patch that lets you instruct the driver to use either LE or BE accessors: