Subject: Re: m68k comman part (was Re: mips ports ...)
To: Justin T. Gibbs <>
From: Chris G Demetriou <Chris_G_Demetriou@UX2.SP.CS.CMU.EDU>
List: current-users
Date: 03/21/1996 11:53:57
> >i figure, if you're writing a device that has to deal with that case,
> >and you _really_ _really_ _really_ want it to work with both memory
> >and I/O spaces, you'll do one of two things:
> >	(1) #ifdef, which is plenty fast, but will only let you
> >	    use one method, in any given kernel, or
> >	(2) run-time test a flag, which is slower, but which will
> >	    let you do whatever you want.
> I don't see why you can't have your cake and eat it too.  On architectures
> that don't have a PIO capability, why not make the *io functions a
> compatibility interface that does memory references.
> [ ... ]

<machine/bus.h> mem* and io* functions say nothing about what access
types the host CPU has, it talks only about the access types that the
bus expects.

For instance, a given host CPU architecture may only have memory
space, but devices that it uses may require accesses to device memory
and device I/O space, with the mapping from CPU->device spaces
performed by some bridge.  bus_io_* functions access device I/O space,
bus_mem_* functions access device memory space.

Now, consider the case of the 8390 NIC:

On ISA, it always uses I/O space (i.e. for the chip registers, etc.),
and sometimes uses memory space (i.e. for shared memory regions on the
wd boards.)

On the Amiga, the registers are in the bus's 'memory' space.

Therefore, to have a common back-end (say, that worked with 'native'
amiga memory boards, and with ISA boards in an amiga at the same
time), you'd need to:
	(1) change the 'native' bus to treat bus_io_ functions like
	    their memory counterparts, with the appropriate frobs, and
	    have the common back-end use the I/O-space functions, or
	(2) have the back-end driver check before each access, to see
	    which it's supposed to do.

For the sake of this discussion, i'm going to consider the case where
you compile the back-end two different ways, and include them both,
as 'assumed, but nasty.'  Arguably, doing that's better than suffering
the performance loss, but you do it at the cost of expanding your

(2) is slow.  (1) doesn't scale.

What i mean by the latter comment is that that works until you have
an instance of that board that actually _does_ live in memory space on
a bus that supports memory and I/O spaces.

That conflict may not happen for the current ports we support that use
the 8390 (i don't know), but it may happen for a future port, and it
certainly doesn't/won't apply to some other drivers in our tree.

The goal here was not to provide an interface that would allow
radically different drivers (in terms of the basic ways that they're
addressed, e.g. via memory or I/O space) to be merged into a single
source driver and single piece of object code.  I don't think you can
do that, for the general case, without the performance degredation
caused by function calls.

On the Alpha, my original interface to allow me to use ISA drivers
looked a fair bit like the <machine/bus.h> one does.  At some point, I
decided that getting rid of the memory vs. I/O space destinction in
the function call set was worth the performance hit.  On fast machines
(e.g. the ones that I have at work), where the cost of accessing
device memory is relatively high, it doesn't matter.  In a serial
driver running on slow machines (e.g. the 386-20 that i'm typing this
from, at home), it makes a _lot_ of difference.

> >You will note that I/O and memory operations do have the same set of
> >arguments, etc., though on different architectures their arguments'
> >types may be different.
> Hmmm.  Why would their argument types change?  I thought you provided
> a full set of 1,2,4,8 byte operations and that only the opaque bus_t
> type and the size of the offset type might change.  You should be able
> to export a common interface to the device driver.

The bus chipset tag is fixed per-architecture, but may change from
architecture to architecture.

Bus memory handles, addresses and sizes are fixed per architecture by
may change from architecture to architecture.

Bus I/O handles, addresses and sizes are fixed per architecture by may
change from architecture to architecture.

Note that nothing says that the various types for memory must be the
same size as the corresponding types for I/O, on a given architecture.

I can think of reasons why one might, for instance, want to have the
I/O handles, addresses, and sizes by 32 bits, and the memory versions
be 64-bits.