Date: Tue, 20 Jan 2009 13:31:13 -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.133113.-1630673491.imp@bsdimp.com> In-Reply-To: <4976297C.7020405@bluezbox.com> References: <4976297C.7020405@bluezbox.com>
next in thread | previous in thread | raw e-mail | index | archive | help
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... Warner
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090120.133113.-1630673491.imp>