[PATCH 31/36] usb: serial: ti_usb_3410_5052: Use a mutex to protect shadow mcr
From: Mathieu OTHACEHE
Date: Thu May 12 2016 - 04:56:25 EST
Only shadow msr is accessed from interrupt context. So use the ti_port
spinlock to protect only shadow msr.
Add a mutex in ti_port to protect mcr from concurrent access.
Also move shadow mcr setting out of ti_set_mcr function.
Signed-off-by: Mathieu OTHACEHE <m.othacehe@xxxxxxxxx>
---
drivers/usb/serial/ti_usb_3410_5052.c | 36 +++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ae77084..0192be9 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -274,7 +274,8 @@ struct ti_port {
u8 tp_shadow_mcr;
u8 tp_uart_mode; /* 232 or 485 modes */
unsigned int tp_uart_base_addr;
- spinlock_t tp_lock;
+ spinlock_t tp_lock; /* Protects tp_msr */
+ struct mutex tp_mutex; /* Protects tp_shadow_mcr */
};
struct ti_device {
@@ -636,6 +637,8 @@ static int ti_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&tport->tp_lock);
+ mutex_init(&tport->tp_mutex);
+
if (port == port->serial->port[0])
tport->tp_uart_base_addr = TI_UART1_BASE_ADDR;
else
@@ -1017,9 +1020,9 @@ static void ti_set_termios(struct tty_struct *tty,
port_number, status);
}
- /* SET_CONFIG asserts RTS and DTR, reset them correctly */
+ mutex_lock(&tport->tp_mutex);
mcr = tport->tp_shadow_mcr;
- /* if baud rate is B0, clear RTS and DTR */
+
if (C_BAUD(tty) == B0)
mcr &= ~(TI_MCR_DTR | TI_MCR_RTS);
else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
@@ -1030,7 +1033,10 @@ static void ti_set_termios(struct tty_struct *tty,
dev_err(&port->dev,
"cannot set modem control on port %d: %d\n",
port_number, status);
+ } else {
+ tport->tp_shadow_mcr = mcr;
}
+ mutex_unlock(&tport->tp_mutex);
kfree(config);
}
@@ -1045,10 +1051,14 @@ static int ti_tiocmget(struct tty_struct *tty)
unsigned int mcr;
unsigned long flags;
+ mutex_lock(&tport->tp_mutex);
spin_lock_irqsave(&tport->tp_lock, flags);
+
msr = tport->tp_msr;
mcr = tport->tp_shadow_mcr;
+
spin_unlock_irqrestore(&tport->tp_lock, flags);
+ mutex_unlock(&tport->tp_mutex);
result = ((mcr & TI_MCR_DTR) ? TIOCM_DTR : 0)
| ((mcr & TI_MCR_RTS) ? TIOCM_RTS : 0)
@@ -1069,10 +1079,10 @@ static int ti_tiocmset(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
+ int err;
unsigned int mcr;
- unsigned long flags;
- spin_lock_irqsave(&tport->tp_lock, flags);
+ mutex_lock(&tport->tp_mutex);
mcr = tport->tp_shadow_mcr;
if (set & TIOCM_RTS)
@@ -1088,9 +1098,14 @@ static int ti_tiocmset(struct tty_struct *tty,
mcr &= ~TI_MCR_DTR;
if (clear & TIOCM_LOOP)
mcr &= ~TI_MCR_LOOP;
- spin_unlock_irqrestore(&tport->tp_lock, flags);
- return ti_set_mcr(port, mcr);
+ err = ti_set_mcr(port, mcr);
+ if (!err)
+ tport->tp_shadow_mcr = mcr;
+
+ mutex_unlock(&tport->tp_mutex);
+
+ return err;
}
@@ -1183,18 +1198,11 @@ exit:
static int ti_set_mcr(struct usb_serial_port *port, unsigned int mcr)
{
struct ti_port *tport = usb_get_serial_port_data(port);
- unsigned long flags;
int status;
status = ti_write_byte(port,
tport->tp_uart_base_addr + TI_UART_OFFSET_MCR,
TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr);
-
- spin_lock_irqsave(&tport->tp_lock, flags);
- if (!status)
- tport->tp_shadow_mcr = mcr;
- spin_unlock_irqrestore(&tport->tp_lock, flags);
-
return status;
}
--
2.8.2