Re: Inconsistent use of spinlocks in serial interrupts

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

 



[ +cc Felipe, Tony ]

On 08/03/2015 08:18 PM, Charles Manning wrote:
> On Tue, Aug 4, 2015 at 11:56 AM, Greg KH <greg@xxxxxxxxx> wrote:
>> On Tue, Aug 04, 2015 at 10:23:12AM +1200, Charles Manning wrote:
>>> I am debugging an issue on the OMAP where the serial irq processing is
>>> normally low (around 1%) but can sometimes rise to much higher (well
>>> over 10%).
>>>
>>> This lead me to sniff around the locking....
>>>
>>> I notice that in some drivers eg. omap-serial.c the whole interrupt
>>> handling loop is locked via spin_lock().

That looks like a deadlock waiting-to-happen to me.  For example,

==> IRQ
    serial_omap_irq()
       spin_lock(port->lock)
       ...
       ==> higher priority IRQ
          handler in some other driver
             printk()
                console_unlock()
                   call_console_drivers()
                      serial_omap_console_write()
                         spin_lock(port->lock)
                         ** DEADLOCK **

Felipe, Tony, this is possible on OMAP, right?

>>> However, other drivers such as serial-tegra.c use spin_lock_irqsave()
>>> for a loop that pretty much has the same form.
>>>
>>> Why is it that they don't use the same locking strategy? What would be better?
>>
>> If something can be accessed from in interrupt, you have to use
>> spin_lock_irqsave everywhere else for that same lock to properly protect
>> the data.
> 
> Thanks Greg
> 
> So to repeat that back to make sure it was what I understand...
> 
> Resource accesses from outside the interrupt must have
> spin_lock_irqsave()  (eg. in set_termios or to kick off a tx) to
> prevent the interrupt from occurring while the registers are being
> touched.

Yes, but only for resource or state changes which affect
interrupt processing.

Also, the port->lock protects certain state variables as well.
For example, changes to the mctrl shadow are protected by the port->lock.

Most configuration hardware programming changes are mutually excluded by
the port->mutex (fixed since 3.19). For example, 8250 FCR register changes.

There's still plenty of brokenness though so I wouldn't look at any
particular driver as canonical reference atm. For example, IER register and
shadow register changes should be protected by port->lock in the 8250
driver; otherwise the following is possible:

CPU 0                               | CPU 1
serial8250_console_write()          | serial8250_do_shutdown()
   spin_lock_irqsave(port->lock)    |
   ier = serial_port_in(UART_IER)   |
    .                               |    up->ier = 0
    .                               |    serial_port_out(UART_IER, 0)
    .                               |    ...
   serial_port_out(UART_IER, ier)   |

   ** whoops, just re-enabled serial interrupts after shutdown **


> The interrupt itself just needs to do a spin_lock().

IFF:
1. the arch/platform/irqchip doesn't enable/allow nested interrupts, OR
2. the serial driver doesn't support console


>> So it depends on the hardware implementation here, both are probably
>> necessary because of that.
> 
> So by using a spin_lock_irqsave() within the interrupt, this is
> preventing another interrupt from occurring.

Yes.

> Is it correct to assume spin_lock_irqsave() is needed when there are
> multiple interrupts for the same driver  (eg. dma channels etc,)

Drivers with different tx and rx interrupts (for example) may or may
not require interrupts disabled. Without knowing the specific hardware,
it's safest to assume interrupts should be disabled in the presence of
multiple handlers.

> whereas spin_lock() is fine on simpler drivers with just one interrupt
> source (eg. "dumb" 16550 style drivers).

With the earlier proviso, that either nested interrupts are not possible
or the driver doesn't support console.

In other words, it's really printk()/console support that may force a serial
driver to use spin_lock_irqsave() in its irq handler. Other classes of
drivers don't typically have this additional requirement.


Regards,
Peter Hurley
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux