aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2010-05-25 10:59:55 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-04 16:37:17 -0400
commitd8d721f4c005f9a69bd1b5d5c6ba99b7e1d464de (patch)
tree4ff679f2f17605139bdf209179519a03ff911566
parent328be395a396b1333b56e04571365dc614c96e46 (diff)
altera_uart: Don't take spinlock in already protected functions
Don't take the port spinlock in uart functions where the serial core already takes care of locking/unlocking them. The code would actually lock up on architectures where spinlocks are implemented (not the case on nios2 where this driver is primarily used for now, thus this bug didn't trigger). Also protect calling altera_uart_rx_chars/altera_uart_tx_chars in the interrupt handler by the port spinlock. Thanks to Ian Abbott for pointing these issues out. Cc: Ian Abbott <abbotti@mev.co.uk> Cc: Thomas Chou <thomas@wytron.com.tw> Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/serial/altera_uart.c19
1 files changed, 4 insertions, 15 deletions
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
index bcee156d2f2e..b1609cca0ec4 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/serial/altera_uart.c
@@ -89,15 +89,12 @@ static unsigned int altera_uart_tx_empty(struct uart_port *port)
89static unsigned int altera_uart_get_mctrl(struct uart_port *port) 89static unsigned int altera_uart_get_mctrl(struct uart_port *port)
90{ 90{
91 struct altera_uart *pp = container_of(port, struct altera_uart, port); 91 struct altera_uart *pp = container_of(port, struct altera_uart, port);
92 unsigned long flags;
93 unsigned int sigs; 92 unsigned int sigs;
94 93
95 spin_lock_irqsave(&port->lock, flags);
96 sigs = 94 sigs =
97 (readl(port->membase + ALTERA_UART_STATUS_REG) & 95 (readl(port->membase + ALTERA_UART_STATUS_REG) &
98 ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; 96 ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
99 sigs |= (pp->sigs & TIOCM_RTS); 97 sigs |= (pp->sigs & TIOCM_RTS);
100 spin_unlock_irqrestore(&port->lock, flags);
101 98
102 return sigs; 99 return sigs;
103} 100}
@@ -105,49 +102,37 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port)
105static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) 102static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
106{ 103{
107 struct altera_uart *pp = container_of(port, struct altera_uart, port); 104 struct altera_uart *pp = container_of(port, struct altera_uart, port);
108 unsigned long flags;
109 105
110 spin_lock_irqsave(&port->lock, flags);
111 pp->sigs = sigs; 106 pp->sigs = sigs;
112 if (sigs & TIOCM_RTS) 107 if (sigs & TIOCM_RTS)
113 pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; 108 pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
114 else 109 else
115 pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; 110 pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
116 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); 111 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
117 spin_unlock_irqrestore(&port->lock, flags);
118} 112}
119 113
120static void altera_uart_start_tx(struct uart_port *port) 114static void altera_uart_start_tx(struct uart_port *port)
121{ 115{
122 struct altera_uart *pp = container_of(port, struct altera_uart, port); 116 struct altera_uart *pp = container_of(port, struct altera_uart, port);
123 unsigned long flags;
124 117
125 spin_lock_irqsave(&port->lock, flags);
126 pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; 118 pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
127 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); 119 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
128 spin_unlock_irqrestore(&port->lock, flags);
129} 120}
130 121
131static void altera_uart_stop_tx(struct uart_port *port) 122static void altera_uart_stop_tx(struct uart_port *port)
132{ 123{
133 struct altera_uart *pp = container_of(port, struct altera_uart, port); 124 struct altera_uart *pp = container_of(port, struct altera_uart, port);
134 unsigned long flags;
135 125
136 spin_lock_irqsave(&port->lock, flags);
137 pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; 126 pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
138 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); 127 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
139 spin_unlock_irqrestore(&port->lock, flags);
140} 128}
141 129
142static void altera_uart_stop_rx(struct uart_port *port) 130static void altera_uart_stop_rx(struct uart_port *port)
143{ 131{
144 struct altera_uart *pp = container_of(port, struct altera_uart, port); 132 struct altera_uart *pp = container_of(port, struct altera_uart, port);
145 unsigned long flags;
146 133
147 spin_lock_irqsave(&port->lock, flags);
148 pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; 134 pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
149 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); 135 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
150 spin_unlock_irqrestore(&port->lock, flags);
151} 136}
152 137
153static void altera_uart_break_ctl(struct uart_port *port, int break_state) 138static void altera_uart_break_ctl(struct uart_port *port, int break_state)
@@ -272,10 +257,14 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
272 unsigned int isr; 257 unsigned int isr;
273 258
274 isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr; 259 isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
260
261 spin_lock(&port->lock);
275 if (isr & ALTERA_UART_STATUS_RRDY_MSK) 262 if (isr & ALTERA_UART_STATUS_RRDY_MSK)
276 altera_uart_rx_chars(pp); 263 altera_uart_rx_chars(pp);
277 if (isr & ALTERA_UART_STATUS_TRDY_MSK) 264 if (isr & ALTERA_UART_STATUS_TRDY_MSK)
278 altera_uart_tx_chars(pp); 265 altera_uart_tx_chars(pp);
266 spin_unlock(&port->lock);
267
279 return IRQ_RETVAL(isr); 268 return IRQ_RETVAL(isr);
280} 269}
281 270