Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 Jun 2012 03:11:15 -0600
From:      PseudoCylon <moonlightakkiy@yahoo.ca>
To:        Adrian Chadd <adrian@freebsd.org>
Cc:        freebsd-wireless@freebsd.org
Subject:   Re: if_start / if_transmit handling and packet ordering - how can I guarantee it?
Message-ID:  <CAFZ_MYKiTUt_5%2BXRUdYurH7tvdYzD4Tz_eb-i1Zwvq8j0EAJ_Q@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Fri, 1 Jun 2012 00:46:02 -0700
> From: Adrian Chadd <adrian@freebsd.org>
> Subject: if_start / if_transmit handling and packet ordering - how can
> =A0 =A0 =A0 =A0I guarantee it?
> To: freebsd-net@freebsd.org
> Cc: freebsd-wireless@freebsd.org
> Message-ID:
> =A0 =A0 =A0 =A0<CAJ-Vmo=3D58aZcWJub8uej4xjddHsBLCOeRCZ1_MXAgiA4nQsG_g@mai=
l.gmail.com>
> Content-Type: text/plain; charset=3DISO-8859-1
>
> Ok, so now that I've mostly tried to lucidly dump what's going on-
> what do people think about holding the locks for (potentially) so
> long? I know iwn(4) holds the driver lock for as long as it can for
> _everything_, so it avoids this issue. But again, I don't really like
> the idea of holding a lock for this long.

Nether do I. Basically, this is how things go with holding a lock.

if_start()
{
        LOCK();
        for (;;) {
                add_slot();
                if (++queue_counter > MAX)
                        break;
        }
        UNLOCK();
}

_txeof() or usb_bulk_callback()
{
        LOCK();
        clear_slot();
        queue_counter--;
        UNLOCK();
        if_start();
}

When if_start() is called first time, it will loop until slots get
full. This is guaranteed because both functions want the lock, so no
slot will be cleared until if_start() exits.
When _txeof() is called, it frees one slot. Then calls if_start().
After enqueuing one frame, slots get full again. Then, _txeof() frees
one slot, if_start() adds one ...
So, the driver processes one frame at a time. The packet order is
maintained, but it seems wasting memory for queue slots.

> Does anyone else have any
> other ideas?

Maybe...
If we guarantee only one thread/process runs the if_start(), we won't
have to hold the lock for that long. i.e

if_start()
{
        if (!atomic_cmpset(&running, 0, 1))
                return;

        for(;;) {
                if (full) {
                        running =3D 0;
                        break;
                }
        }
}

> FWIW - I temporarily converted the ath driver to make ath_start()
> enqueue a taskqueue task, which then did all of the TX inside the
> taskqueue.

I have tried the similar thing with run(4), because I thought calling
taskqueue_enqueue() is better than calling if_start() in
usb_bulk_callback(). (if_start() is a big process.) I got extra
bandwidth (forget the actual number).

> I unfortunately
> then become very, very susceptible to scheduling latency

I had to use a private taskqueue instead of shared one to over come
the latency. Other than that, it worked well, at least under 1 ap + 1
sta both use run(4) environment.


AK



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAFZ_MYKiTUt_5%2BXRUdYurH7tvdYzD4Tz_eb-i1Zwvq8j0EAJ_Q>