Subject: Re: Data Alignment in mbufs
To: Curt Sampson <cjs@portal.ca>
From: Chris G. Demetriou <cgd@pa.dec.com>
List: tech-net
Date: 05/24/1997 15:41:42
> Unfortunately, the TCP layer is handing me mbufs that have data
> start addresses that are not word-aligned. (It's always the address
> in the second mbuf of a pair.) Currently the ed driver cannot handle
> copying these from system RAM into the Ethernet card's RAM without
> doing unaligned 16-bit reads from system RAM.
> 
> So what's the best way to solve this problem? I can tweak the driver
> so that it will do a bit of buffering between the reads and the
> writes (though possibly at a small loss of efficiency--on the other
> hand, the shared memory on the ISA bus is probably slow enough that
> it would make no difference). However, I'm wondering if other
> drivers are affected by similar problems, and if perhaps we don't
> want to consider adding alignment guarantees to some of the mbuf
> operations.

How _can_ you add alignment guarantees to some of the mbuf operations?
It doesn't seem reasonable, especially given all the different
possibilities on why an mbuf could end up starting at an odd address.
For instance, a packet consists of N mbufs, all of which start at even
addresses, but one of which has an odd _size_, you'll lose, too.
(Worth noting: I found that 'odd-ness' of various types happened quite
often with interactive 'text', e.g. telnet or rlogin, connections.)

Some code that I wrote to handle the same problem in another ISA
driver is below.

It has to deal with:
	(1) mbufs that start at an odd boundary,
	(2) mbufs that end on an odd boundary,
	(3) mbufs that start at an even boundary but which act like
	    they started at an odd boundary because the previous
	    mbuf ended on an odd boundary, etc.
etc.

I didn't notice any significant slowdown while using it.  If you
notice any bugs, by all means tell me!  8-)



chris
=============================================================================
        bus_space_tag_t memt = sc->sc_memt;
        bus_space_handle_t memh = sc->sc_memh;
        struct mbuf *m;
        int len, leftover, frameoff;
        u_int16_t dbuf;
        u_int8_t *p, *lim;

        /* Initialize frame pointer and data port address */
        frameoff = PKTPG_TX_FRAME;

        /* start out with no leftover data */
        leftover = 0;
        dbuf = 0;

        /* Process the chain of mbufs */
        for (m = m0; m != NULL; m = m->m_next) {

                /*
                 * Process all of the data in a single mbuf.
                 */
                p = mtod(m, u_int8_t *);
                len = m->m_len;
#ifdef DIAGNOSTIC
                lim = p + len;
#endif

                while (len > 0) {
                        if (leftover) {
                                /*
                                 * Data left over (from mbuf or realignment).
                                 * Buffer the next byte, and write it and
                                 * the leftover data out.
                                 */
                                dbuf |= *p++ << 8;
                                len--;

                                bus_space_write_2(memt, memh, frameoff,
                                    dbuf);
                                frameoff += 2;

                                leftover = 0;
                        } else if ((long)p & 1) {
                                /*
                                 * Misaligned data.  Buffer the next byte.
                                 */
                                dbuf = *p++;
                                len--;

                                leftover = 1;
                        } else {
                                /*
                                 * Aligned data.  This is the case we like.
                                 *
                                 * Write-region out as much as we can, then
                                 * buffer the remaining byte (if any).
                                 */
                                leftover = len & 1;
                                len &= ~1;

                                bus_space_write_region_2(memt, memh, frameoff,
                                    (u_int16_t *)p, len >> 1);
                                p += len;
                                frameoff += len;

                                if (leftover)
                                        dbuf = *p++;
                                len = 0;
                        }
                }
                if (len < 0)
                        panic("XXX rename me 8-): negative len");
#ifdef DIAGNOSTIC
                if (p != lim)
                        panic("XXX rename me 8-): p != lim");
#endif
        }
        if (leftover)
                bus_space_write_2(memt, memh, frameoff, dbuf);