Date: Tue, 20 Jan 2009 14:16:31 -0700 (MST) From: "M. Warner Losh" <imp@bsdimp.com> To: gonzo@bluezbox.com Cc: freebsd-hackers@freebsd.org Subject: Re: uart and big-endian targets Message-ID: <20090120.141631.-1146313365.imp@bsdimp.com> In-Reply-To: <20090120.133113.-1630673491.imp@bsdimp.com> References: <4976297C.7020405@bluezbox.com> <20090120.133113.-1630673491.imp@bsdimp.com>
next in thread | previous in thread | raw e-mail | index | archive | help
In message: <20090120.133113.-1630673491.imp@bsdimp.com> "M. Warner Losh" <imp@bsdimp.com> writes: : In message: <4976297C.7020405@bluezbox.com> : Oleksandr Tymoshenko <gonzo@bluezbox.com> writes: : : Yesterday I ran into a "problem" with uart(4) on big-endian MIPS : : board. uart code treats registers as bytes and reads/writes them using : : bus_space_read_1/bus_space_write_1. To handle word-aligned registers we : : have regshft in uart_bas structure. It works for little-endian flags : : where lowest byte resides at uart_base + (regnum << regshft) address : : but for big endian targets actual data resides at : : uart_base + ((regnum + 1) << regshft) - 1. : : That's not the problem. The problem is that we're trying to do byte : accesses to word registers. That's why we see a disconnect between : the addresses since we're reading the wrong byte. also, we may be : getting lucky with this access, but many chips have issues when you : access word registers as bytes. : : : One way to solve it is to increase uart_base when setting uart_bas, : : but it's not obvious and requires knowledge of uart(4) internals. : : I think better solution would be to take into account endianess : : when defining uart_regofs. Or if other BE devices have data in : : highest byte new field should be added to uart_bas (defaulted to 0) : : : : Any thoughts? : : The base problem here is: : : uart.h: : : #define uart_getreg(bas, reg) \ : bus_space_read_1((bas)->bst, (bas)->bsh, uart_regofs(bas, reg)) : #define uart_setreg(bas, reg, value) \ : bus_space_write_1((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value) : : These should be, for the platform you are using: : : #define uart_getreg(bas, reg) \ : bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg)) : #define uart_setreg(bas, reg, value) \ : bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value) : : There's no easy way to swap these out, nor is there a way to have : variants for different kinds of hardware attached to the same machine : (the UART on the SoC will have different access patterns than the UART : on the modem on the PC Card that's plugged in, for example). This is : a short-coming in the design of UART. One that's relatively easy to : fix, mind you, and one that could easily be fixed. There's so many : twists like this that it can be hard to anticipate them all. : : The Octeon port basically copies uart_dev_ns8250.c and provides its : own set of accessors. This is right from a accessing the hardware : correctly point of view, but a pita from a code reuse point of view. : Were it not for the other quirks in Cavium's serial ports, there'd be : little reason to go this route... actually, the more I've thought about this, and chatted with folks offline, I think the right way to fix this is in bus_space... Warner
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090120.141631.-1146313365.imp>