Subject: Re: bus_space_barrier shortcomings
To: None <bjh21@netbsd.org, tech-kern@netbsd.org>
From: None <eeh@netbsd.org>
List: tech-kern
Date: 11/16/2000 16:03:44
	Thinking about how bus_space_barrier is specced as working, and especially
	about how one could produce a pathalogical bus_space for debugging, I
	think I've come up with some cases where the semantics of
	bus_space_barrier aren't strong enough to allow a correct driver to be
	written of a device.


	My first example is the transmit half of a very simple UART (based on the
	Archimedes keyboard interface).  It has a single 8-bit register and a
	single (level-sensitive) interrupt output.  Writing a byte to the register
	causes it to start being output.  When the device is ready to accept
	another byte, it asserts its interrupt line, and it deasserts it when a
	new byte is written.

	So, our interrupt handler for such a device might look like:

	int
	foointr(void *cookie)
	{
	        struct foo_softc *sc = cookie;
		u_int8_t byte;

	        /* Get another byte from somewhere */
	        bus_space_write_1(sc->sc_iot, sc->sc_ioh, byte);
		return 1;
	}

	This is all very well, but it has a problem.  If the bus space needs
	barriers, the write might be indefinitely delayed.  Specifically, it might
	be delayed until after the system has re-enabled interrupts, at which
	point this interrupt routine will be called again, with predictable
	results.  As far as I can see, there's no bus_space_barrier call that can
	be used to ensure that this doesn't happen.

Huh?  I'll admit that bus_space_barrier lacks some of the 
flexibility of the barriers available on some architectures,
but a BUS_SPACE_BARRIER_WRITE barrier should be sufficient
to ensure the write completes.  If completion of the memory
operation is not enough to acknowledge the interrupt, your
hardware is broken to the point that it is impossible to 
write a driver for it on any machine.

	Another, more plausible example, is a network card (something like an
	i82586) attached to an ISA bus.  It has some memory (accessed through the
	ISA memory space) and some registers (accessed through the ISA I/O
	space).  To transmit a packet, we compose the packet in the board's
	memory, then poke one of its registers.  We clearly need some kind of
	write barrier between writing to the memory and the registers, but they've
	got different bus_space_tags, and bus_space_barrier doesn't provide for
	barriers that span more than one tag.

The reason for that is that it is possible for different buses
to have different caching.  In this case you would issue the
a BUS_SPACE_BARRIER_WRITE on the board's memory to make sure
that completes, then poke the register and issue another
BUS_SPACE_BARRIER_WRITE on that register to complete that
bus cycle.

Eduardo