tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Network drivers and memory allocation in interrupt context
On On 2011-12-08 at 21:03 David Young wrote
> On Thu, Dec 08, 2011 at 07:06:29PM -0700, Sverre Froyen wrote:
> > Hi,
> >
> > I now have a semi-working pool_cache based memory allocator for network
> > drivers (tested using the iwn driver). I am uncertain, however, about how
> > to get it fully functioning. The issue is memory allocation in interrupt
> > context.
>
> Is there some reason that the code in ixgbe(4) cannot be adapted to your
> needs? For ixgbe(4), I had to solve the precise problem that stops you,
> now.
The iwn driver's iwn_tx_done function requests buffer space in interrupt
context. If it does not receive a buffer, the interface loops and basically
stops working. It seems that I have two choices, (1) allocate a new buffer in
interrupt context or (2) make sure that I have a large enough pool of free
buffers so that the iwn_tx_done request succeeds.
Option 1 is not available because the bus_dmamem_map call fails in interrupt
context (but see below).
For option 2, I would like to utilize the machinery of pool_cache / pool. I
found that the pool_cache_setlowat can be used to guarantee a minimum number
of free items in the pool (the man page could be clearer on this). When I
attempt to utilize this with the iwn driver, however, I invariably run into a
kassert panic in some lower level pool that is using an ipl level of IPL_NONE.
I believe that the issue is that my pool needs to use IPL_VM (as otherwise
pool_cache_get_paddr will trigger a panic when called in interrupt context),
which together with my pool_cache_setlowat setting, results in an attempt to
grow the pool in interrupt context.
It seems to me that the pool_get kassert:
if ((cpu_intr_p() || cpu_softintr_p()) && pp->pr_ipl == IPL_NONE &&
!cold && panicstr == NULL)
panic("pool '%s' is IPL_NONE, but called from "
"interrupt context\n", pp->pr_wchan);
is a bit heavy handed. Say that a pool has an ipl level of IPL_NONE. Why
cannot pool_get return an already allocated item from this pool even in
interrupt context? Unfortunately, the mutex(9) choices in pool / pool_cache
appears to prevent this as the adaptive mutexes that are used for IPL_NONE
cannot be acquired from interrupt context. A simpleminded solution might be to
replace the adaptive mutex with a spin mutex plus a condition variable and use
the same locking for all ipl values. Something like this:
------------------------------------------------------------------------------
mutex mutex_spin
condition variable cv
bool busy = false
/*** Code sections that will never sleep ***/
mutex_enter(mutex_spin)
if (! busy)
do work
else
set / return error
mutex_exit(mutex_spin)
/*** Code sections that may sleep ***/
mutex_enter(mutex_spin)
while (! busy)
cv_wait(cv, mutex_spin)
busy = true
mutex_exit(mutex_spin)
do work that may include sleep
mutex_enter(mutex_spin)
busy = false
cv_signal(cv)
mutex_exit(mutex_spin)
------------------------------------------------------------------------------
Before I take stab at this, however, I would appreciate some feedback:
Am I way off base here and there are reasons why this cannot poossible work?
Does the locking code look reasonable?
Am I attempting to use the pool / pool_cache code in a way that it was never
intended?
Thanks,
Sverre
Home |
Main Index |
Thread Index |
Old Index