E450 Support and bus_space cleanup
First of all, if you don't like experimental code, don't even think of using this.
First Generation
Here are some changes that let my E450 run OpenBSD -current. There were a few things that needed to be fixed and this was my first hack at it:
- The E450 ("SUNW,Ultra-4") seems to need the same OpenFirmware work-around as the E250 ("SUNW,Ultra-250"). Without docs regarding the "test"/"test-method" code, I can only say that without the change, OF REDs back to the OF console when called. [Checked in 30-Jan-03]
- The
bus_space_map2()
call modifies the ASI of the bus tag (indirectly, it really modifies an index into a table that looks up the ASI). This causes all sorts of grief (especially when the root bus tag is clobbered). Then meaning of anybus_space*()
call using that tag then depends on what was passed tobus_space_map2()
the last time someone called it with the same bus tag (or, in some cases, with any child of the same bus tag). The implemented change is to makebus_space_handle_t
a struct that includes the ASI and pass it by value. That isn't quite as bad as it sounds since most (all?) calls that use it in the critical path get inlined anyway. - Many places simply cast addresses to
bus_space_handle_t
's. Quite apart from the stupendously ugly hack that it is, using a struct forbus_space_handle_t
breaks this code completely. - The streaming buffer code assumed flushes used 8-byte buffers to indicate completion. The psycho actually writes 64-bytes to a truncated 64-byte boundary (leading to trouble if the pointer supplied to the hardware doesn't point to an appropriate area of the required size).
- The streaming buffer code was missing a some
membar()
s (??? The v9, US-II, IIi, and III manuals all seem to have different things to say about this). - The psycho's interrupts are mapped to UPA port 0. Since this box only has CPUs 1 and
3 populated, no interrupts ever got through.
intr_establish()
now insists on remapping interrupts to point to the current CPU (this needs to be revisited for MP support, but even then, there are certain advantages to sending interrupts to someplace other than /dev/null). - The mainbus bus tag has been made
const
. This puts it in "rodata" which makes it much more difficult to accidentally clobber it (the system faults). This could perhaps be useful for other kernel objects. This change is not required to get the E450 booting. bus_space_tag_t
was made a pointer toconst
. The only code that has any reason to muck with it should be working with (a pointer to) the underlying struct anyway. (There is no abstraction in a constructor; it needs to know what it's creating.) This change is not required to get the E450 booting.- In order to try to be more strict about argument types and to prevent the odd bugs
that can result from using macros that declare variables (consider a macro with an
argument that evaluates to the name of one of the local variables), much of
bus_space*()
code inbus.h
was converted from macros to inline functions. A spot check suggests that the generated code is pretty much identical.
This diff against -current gets my E450 up and running well
enough to do “make build
” (there are still occasional messages along the lines
of, “timeout delayed -3,” but they are no longer spewing out continually and since they
only show up on DEBUG kernels, I don't know if this has anything to do with these patches).
It is also happy on my U5. Here's what an OpenBSD
E450 boot looks like. This diff was made against -current as of
Nov 6th; there may be some conflicts if applied to a later version of current (hint: check
out with -D "Nov 7"). I'm leaving this diff around as it has run both a U5 and
E450 without grief since early November (no warmboot issues, panic()
s, or
other strangeness).
Second Generation
I'm working on a cleaner solution for these issues. The basic idea is to add some
diagnostic code to the bus API, get rid of bus_space_map2()
, and force each
different kind of bus access to use a bus tag appropriate for that particular way to access
a bus (so, each bus tag has an ASI for normal accesses). A flag bit has been added to allow
bus_space_map()
to support pre-mapped addresses (previously mapped by the boot
loader). The streaming buffer code still needs to be split into per-buffer pieces. e450_new_20021213.diff.gz.
Third Generation
A later generation of this code adds a script to generate the four copies of each
fundamental bus_space operation (one for each of the word sizes: 1, 2, 4, 8). Some more awk
hacking and it should be possible to generate the raw and non-raw functions from the same
template. Most of the implementations for these functions are huge and have been moved out
of the headers to save kernel space (looks like GENERIC shrinks by ~200k). This makes
experimenting with the bus_space implementation much less painful. Some
changes/optimizations to the low-level ld*
/st*
operations have
been made; much of it is from FreeBSD's sparc64 port. The existing
*_wenable()
code in clock.c
has been changed to use a new
function: bus_space_protect()
. (This could also have been handled by calling
the pmap code directly.) Previous versions of the clock.c
change had no effect
other than rendering the RTC unreadable. There are also a few minor changes that allow the
kernel to compile with gcc-3.2.x. At any rate, a full diff between my “sys” tree and
-current that appears to be happy on Ultra 1, Ultra 5, Blade 100, and Enterprise 450 can be
found here: bus_space_20030215b.diff.gz.
The End
bus_space_20030215.bdiff.gz was merged into the OpenBSD CVS repository on
Feb. 16th. All resulting gremlins, glitches, and grief are probably my fault. Let me
(henric [ at ] openbsd [ period ] com) know so that I can fix them. If at all possible,
build a kernel with the below debug options and send dmesg output and the output of a
trace
if the system drops into ddb.
If there are problems on a machine, it is probably a good idea to enable bus_space
assertions. Make sure the BSDB_ASSERT
flag is set when
sparc64/sparc64/machdep.c
initializes bus_space_debug
and use a
kernel config like this:
include "../sys/arch/sparc64/conf/GENERIC" option DEBUG makeoptions DEBUG="-g" # compile full symbol table option BUS_SPACE_DEBUG
To do
- The ASIs used by the new code should be reviewed to make sure they make sense (which is hopefully equivalent to making sure they match what was intended before the bus_space changes).
- The streaming buffer code needs to be reviewed. There are six PCI busses in this box, each with a streaming buffer. The right one (or all of 'em) need to be properly flushed after each DMA or it could lead to nasty, difficult to reproduce data IO corruption.
- The whole sparc64 codebase should probably be reviewed for proper use of of
membar
s. The system runs TSO (?), but that only relates to interactions within the coherency domain. Talking hardware devices and the like can have surprising results if the propermembar
s are not there. BTW, getting this thing to run RMO (or PSO) might not be so hard, after all, there is no existing MP infrastructure worry about. A config option coupled with some kind of conditionalmembar
directive could be implemented. - Review the ASI/
membar
/etc. usage in pmap. - IOMMU and streaming buffer access needs to happen at a safe enough PL such that it doesn't get clobbered if one driver interrupts another while it is being used. (Can this happen?)
- Verify clobbers for the inline assembly (esp., “
cc
” and “memory
“). - The sparc64 tree uses two each of
sbusvar.h
andsbusreg.h
. (A variant of the former also apears in the sparc tree.) - The code that creates new bus space tags can probably be consolidated.
- The code that searches for parent tag with non-zero function pointers can probably be consolidated.
- There are redundant
membar
s scattered throughout (and some that may not be redundant). - The
default_type
member ofbus_space_tag_t
isn't used for anything close to what the name suggests. - There may be some debugging code still left in there (pciide/wdc comes to mind).
- Some places in the code use C++ style comments. This is to make sure I remember to
revisit them before thinking about checking in stuff. (“
XXX
” was already used.) - Console drivers should protect themselves from
BSDB_ALL_ACCESS
by setting theBSHDB_NO_ACCESS
flag. This is only relevant whenBUS_SPACE_DEBUG
is defined in the kernel config (not the default). At present, only thesab.c
driver does so and it does it unconditionally (it should only do so when it is the console). - Testing on other boxes...
Notes
Here's a diagnostic boot on the thing.
This is what booting a FreeBSD ISO looks like and here's the same for Gentoo.
Sun has some stuff to say about the E450.