tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Waiting for a bit in a register to be cleared: which strategy?



On lug 03 14:56, Taylor R Campbell wrote:

> It's quite common to read a whole device register just to get at a
> single bit.  Don't worry about the efficiency -- the cost of the I/O
> transaction over the PCI bus or similar far exceeds the cost of
> pulling one bit out of 32.

OK then! Great!

> The usual idea for __BIT is that if there's a device register FOO, and
> it has various fields BAR, BAZ, and QUUX, with a hardware manual that
> says:
[...]
> 	if ((foo & FOO_BAR) == 0)
> 		return ENOENT;
> 	baz = __SHIFTOUT(foo, FOO_BAZ);
> 	quux = __SHIFTOUT(foo, FOO_QUUX);

Thanks for this very explanatory example.

> A typical approach is to set a reasonable timeout, either in register
> reads or in microseconds, and count down to it:
> 
> 	unsigned timo = 1000;
> 
> 	while ((bus_space_read_4(bst, bsh, FOO) & FOO_BAR) == 0) {
> 		if (--timo == 0)
> 			return ETIMEDOUT;
> 		/* optionally, space the reads out by a microsecond */
> 		DELAY(1);
> 	}

OK! I think I would insert a delay.

> If you might need to wait for longer periods of time, like
> milliseconds, then you can use kpause with mstohz which lets other
> threads run, and if you're working under a lock, you can pass it to
> kpause to release the lock while other threads run.
> 
> 	unsigned timo = 1000;
> 
> 	mutex_enter(&sc->sc_lock);
> 	while ((bus_space_read_4(bst, bsh, FOO) & FOO_BAR) == 0) {
> 		if (--timo == 0)
> 			return ETIMEDOUT;
> 		kpause("foobar", false, mstohz(10), &sc->sc_lock);
> 	}

This is also very useful. I never used a mutex, however, but:
- maybe I can use it just adding a sc_lock member in the driver's softc
  and use your example as a model;
- otherwise, I can completely avoid the lock, passing a NULL as last
  argument for `kpause'.

Hope this is correct in both cases.

> However, if you may need to wait for a long period of time, you should
> see if there's a way to get an interrupt notification instead of
> polling the device register, and use a condvar to signal the
> notification from the interrupt handler and to wait for the
> notification elsewhere in software.

In fact, I'm using this device:

 <https://github.com/qemu/qemu/blob/v2.7.0/docs/specs/edu.txt>

and the bit of the question is the LSB of the status register 0x20,
which is cleared when the factorial computation is over. It is also
possible to raise an interrupt when this event occurs, but I do not know
interrupt handling at all in NetBSD kernel. If you know some simple
example, I would check them out. But so far I can't figure them out.

Thanks for your very useful suggestions!

Rocky


Home | Main Index | Thread Index | Old Index