svn commit: r295557 - head/sys/dev/uart
Bruce Evans
brde at optusnet.com.au
Tue Feb 16 00:01:29 UTC 2016
On Mon, 15 Feb 2016, Ian Lepore wrote:
> On Tue, 2016-02-16 at 09:28 +1100, Bruce Evans wrote:
>> On Mon, 15 Feb 2016, Michal Meloun wrote:
>>
>>> [...]
>>> Please note that ARM architecture does not have vectored interrupts,
>>> CPU must read actual interrupt source from external interrupt
>>> controller (GIC) register. This register contain predefined value if
>>> none of interrupts are active.
>>>
>>> 1 - CPU1: enters ns8250_bus_transmit() and sets IER_ETXRDY.
>>> 2 - HW: UART interrupt is asserted, processed by GIC and signaled
>>> to CPU2.
>>> 3 - CPU2: enters interrupt service.
>>
>> It is blocked by uart_lock(), right?
>>
>>> 4 - CPU1: writes character to into REG_DATA register.
>>> 5 - HW: UART clear its interrupt request
>>> 6 - CPU2: reads interrupt source register. No active interrupt is
>>> found, spurious interrupt is signaled, and CPU leaves interrupted
>>> state.
>>> 7 - CPU1: executes uart_barrier(). This function is not empty on ARM,
>>> and can be slow in some cases.
>>
>> It is not empty even on x86, although it probably should be.
>>
>> BTW, if arm needs the barrier, then how does it work with
>> bus_space_barrier() referenced in just 25 files in all of /sys/dev?
>
> With a hack, of course. In the arm interrupt-controller drivers we
> always call bus_space_barrier() right before doing an EOI. It's not a
> 100% solution, but in practice it seems to work pretty well.
I thought about the x86 behaviour a bit more and now see that it does
need barriers but not the ones given by bus_space_barrier(). All (?)
interrupt handlers use mutexes (if not driver ones, then higher-level
ones). These might give stronger or different ordering than given by
bus_space_barrier(). On x86, they use the same memory bus lock as
the bus_space_barrier(). This is needed to give ordering across
CPUs. But for accessing a single device, you only need program order
for a single CPU. This is automatic on x86 provided a mutex is used
to prevent other CPUs accessing the same device. And if you don't use
a mutex, then bus_space_barrier() cannot give the necessary ordering
since if cannot prevent other CPUs interfering.
So how does bus_space_barrier() before EOI make much difference? It
doesn't affect the order for a bunch of accesses on a single CPU.
It must do more than a mutex to do something good across CPUs.
Arguably, it is a bug in mutexes is they don't gives synchronization
for device memory.
> ...
> The hack code does a drain-write-buffer which doesn't g'tee that the
> slow peripheral write has made it all the way to the device, but it
> does at least g'tee that the write to the bus the perhiperal is on has
> been posted and ack'd by any bus<->bus bridge, and that seems to be
> good enough in practice. (If there were multiple bridged busses
> downstream it probably wouldn't be, but so far things aren't that
> complicated inside the socs we support.)
Hmm, so there is some automatic strong ordering but mutexes don't
work for device memory?
> The g'teed way is to do a readback of the register written-to, or some
> nearby register if it's write-only. That's a hard thing to do in a
> bus_space_barrier implementation that has no knowledge of things like
> which registers in a device might be write-only.
>
> And of course, then you're still left with the problem of hundreds of
> drivers that don't do any barrier calls at all.
Mostly unimportant ones for fast NICs :-). These could be made even slower
using lots of barriers. But the fast ones already have to use special
interfaces DMA since single-word bus accesses are too slow.
>> [...]
>>
>>> Also, at this time, UART driver is last one known to generate spurious
>>> interrupts in ARM world.
>>>
>>> So, whats now? I can #ifdef __arm__ change made in r295557 (for maximum
>>> safety), if you want this. Or we can just wait to see if someone reports
>>> a problem ...
>>
>> Use better methods.
>
> How about a dev.uart.<unit>.broken_txrdy tunable sysctl that defaults
> to the new behavior but can be turned on by anyone with the buggy
> hardware?
It's difficult to know that such knobs even exist.
Bruce
More information about the svn-src-all
mailing list