if_start / if_transmit handling and packet ordering - how can I
guarantee it?
PseudoCylon
moonlightakkiy at yahoo.ca
Sat Jun 2 09:11:22 UTC 2012
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Fri, 1 Jun 2012 00:46:02 -0700
> From: Adrian Chadd <adrian at freebsd.org>
> Subject: if_start / if_transmit handling and packet ordering - how can
> I guarantee it?
> To: freebsd-net at freebsd.org
> Cc: freebsd-wireless at freebsd.org
> Message-ID:
> <CAJ-Vmo=58aZcWJub8uej4xjddHsBLCOeRCZ1_MXAgiA4nQsG_g at mail.gmail.com>
> Content-Type: text/plain; charset=ISO-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 = 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
More information about the freebsd-wireless
mailing list