Subject: Re: ncr53cxxx driver design issues
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-kern
Date: 04/17/2000 18:34:13
On Sun, Apr 16, 2000 at 09:49:48PM +0200, Manuel Bouyer wrote:

 > So I think a more natural way of doing thing is to have a driver for
 > the 720, 810, 815 and 860; and another one for the 825, 875 and 895.

I think I agree with your assessment.  I can even suggest names for the
drivers:

	osiop -- NCR 53c710
	siop  -- NCR 53c720, NCR 53c810, NCR 53c815, NCR 53c860
	esiop -- NCR 53c825, SYM 53c875, SYM 53c895, SYM 53c896

They're "old siop", "siop", and "enhanced siop", respectively :-)

 > Another issue is endianess: all 53c8xx are assumed to be little endian (as
 > they live behind a PCI bus); but I guess the 720 can be either big or little
 > depending on which bus it's connected. A flag set by the bus front end
 > will probably be needed so that the bus-independant part can use htole/htobe
 > as appropriate.

While I completely understand where Eduardo is coming from, we already have
some ways to deal with the byte-order problem in DMA'd data structures, of
sorts...

If you'll take a look at the SMC 83c170 Ethernet driver, you'll note that
it does:

#if BYTE_ORDER == BIG_ENDIAN
	... put the device into "data structures are big-endian" mode ...
#else
	... put the device into "data structures are little-endian" mode ...
#endif

This can pretty easily handle at least the 720 case.

As far as handling both 720 and 810 in the same driver, making the
byte-order decision at runtime:

	<example 810 front-end code>
	sc->sc_byteorder = LITTLE_ENDIAN;

	<example common back-end code>

static __inline u_int32_t
LOAD_4(struct siop_softc *sc, __volatile u_int32_t *ptr)
{

	if (sc->sc_byteorder == BYTE_ORDER)
		return (*ptr);

	return (bswap32(*ptr));
}

static __inline void
STORE_4(struct siop_softc *sc, __volatile u_int32_t *ptr, u_int32_t val)
{

	if (sc->sc_byteorder == BYTE_ORDER)
		*ptr = val;
	else
		*ptr = bswap32(val);
}

This just doesn't seem that difficult a problem to me :-)

I acknowledge that Eduardo would like some sort of generic bus_dma
enhancement for this, but it seems to me like we're then adding a lot
of overhead (like the function calls, comparisons, etc.) in places
where we *KNOW* we won't need it (e.g. any PCI device which is
hardwired as little-endian).

I do, BTW, completely agree with Eduardo that we should have load_le32(),
store_le32(), load_be32(), store_be32(), etc. primitives in our endian.h
facility to make optimizing these sorts of things easier on platforms like
the UltraSPARC and PowerPC (which can do this with an ASI and/or special
instructions).  Unfortunately, that wouldn't make my above example any
nicer because the byte-order is relative to the host, but it would change
things like:

	desc->d_addr = htole32(dma_addr);

into:

	store_le32(&desc->d_addr, dma_addr);

I also acknowledge that Eduardo would like some way of doing byte-swapping
of DMA'd data via logic on the bus controller.  However, I think we're
getting into a serious can of worms, there.  The UltraSPARC isn't the first
PCI platform to support that; I have a PowerPC system that does the same
thing (and I know it was available before PCI UltraSPARCs :-).  However,
I think using open-coded htole32(), etc. type calls make it a little more
explicit what's going on, and doens't require extra work to get the case
of octet streams (e.g. packet data) right.

Along these lines, if someone would like to loan me a PCI HME card, I
would be more than happy to make it work on the i386 and/or Alpha ports
(both little-endian) as a proof-of-concept :-)

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>