diff options
author | Yury Georgievskiy <ygeorgie@gmail.com> | 2010-07-20 18:26:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 16:47:45 -0400 |
commit | 0ac8382e9cfdd723445692fc97aaa4643929750d (patch) | |
tree | e42c65488ea8d839c39441dce939d21ba6d60ae6 /drivers/serial | |
parent | 1b6331848b69d1ed165a6bdc75c4046d68767563 (diff) |
serial: mcf: don't take spinlocks 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.
Also protect calling mcf_rx_chars/mcf_tx_chars in the interrupt handler by
the port spinlock and use IRQ_RETVAL to return from isr.
[akpm@linux-foundation.org: make irq-handler return value more explicit]
Signed-off-by: Yury Georgievskiy <ygeorgie@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Acked-by: Greg Ungerer <gerg@uclinux.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/mcf.c | 31 |
1 files changed, 13 insertions, 18 deletions
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c index b5aaef965f24..3394b7cc1722 100644 --- a/drivers/serial/mcf.c +++ b/drivers/serial/mcf.c | |||
@@ -70,16 +70,14 @@ static unsigned int mcf_tx_empty(struct uart_port *port) | |||
70 | static unsigned int mcf_get_mctrl(struct uart_port *port) | 70 | static unsigned int mcf_get_mctrl(struct uart_port *port) |
71 | { | 71 | { |
72 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 72 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
73 | unsigned long flags; | ||
74 | unsigned int sigs; | 73 | unsigned int sigs; |
75 | 74 | ||
76 | spin_lock_irqsave(&port->lock, flags); | ||
77 | sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? | 75 | sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? |
78 | 0 : TIOCM_CTS; | 76 | 0 : TIOCM_CTS; |
79 | sigs |= (pp->sigs & TIOCM_RTS); | 77 | sigs |= (pp->sigs & TIOCM_RTS); |
80 | sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); | 78 | sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); |
81 | sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); | 79 | sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); |
82 | spin_unlock_irqrestore(&port->lock, flags); | 80 | |
83 | return sigs; | 81 | return sigs; |
84 | } | 82 | } |
85 | 83 | ||
@@ -88,16 +86,13 @@ static unsigned int mcf_get_mctrl(struct uart_port *port) | |||
88 | static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) | 86 | static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) |
89 | { | 87 | { |
90 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 88 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
91 | unsigned long flags; | ||
92 | 89 | ||
93 | spin_lock_irqsave(&port->lock, flags); | ||
94 | pp->sigs = sigs; | 90 | pp->sigs = sigs; |
95 | mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); | 91 | mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); |
96 | if (sigs & TIOCM_RTS) | 92 | if (sigs & TIOCM_RTS) |
97 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); | 93 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); |
98 | else | 94 | else |
99 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); | 95 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); |
100 | spin_unlock_irqrestore(&port->lock, flags); | ||
101 | } | 96 | } |
102 | 97 | ||
103 | /****************************************************************************/ | 98 | /****************************************************************************/ |
@@ -105,12 +100,9 @@ static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) | |||
105 | static void mcf_start_tx(struct uart_port *port) | 100 | static void mcf_start_tx(struct uart_port *port) |
106 | { | 101 | { |
107 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 102 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
108 | unsigned long flags; | ||
109 | 103 | ||
110 | spin_lock_irqsave(&port->lock, flags); | ||
111 | pp->imr |= MCFUART_UIR_TXREADY; | 104 | pp->imr |= MCFUART_UIR_TXREADY; |
112 | writeb(pp->imr, port->membase + MCFUART_UIMR); | 105 | writeb(pp->imr, port->membase + MCFUART_UIMR); |
113 | spin_unlock_irqrestore(&port->lock, flags); | ||
114 | } | 106 | } |
115 | 107 | ||
116 | /****************************************************************************/ | 108 | /****************************************************************************/ |
@@ -118,12 +110,9 @@ static void mcf_start_tx(struct uart_port *port) | |||
118 | static void mcf_stop_tx(struct uart_port *port) | 110 | static void mcf_stop_tx(struct uart_port *port) |
119 | { | 111 | { |
120 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 112 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
121 | unsigned long flags; | ||
122 | 113 | ||
123 | spin_lock_irqsave(&port->lock, flags); | ||
124 | pp->imr &= ~MCFUART_UIR_TXREADY; | 114 | pp->imr &= ~MCFUART_UIR_TXREADY; |
125 | writeb(pp->imr, port->membase + MCFUART_UIMR); | 115 | writeb(pp->imr, port->membase + MCFUART_UIMR); |
126 | spin_unlock_irqrestore(&port->lock, flags); | ||
127 | } | 116 | } |
128 | 117 | ||
129 | /****************************************************************************/ | 118 | /****************************************************************************/ |
@@ -131,12 +120,9 @@ static void mcf_stop_tx(struct uart_port *port) | |||
131 | static void mcf_stop_rx(struct uart_port *port) | 120 | static void mcf_stop_rx(struct uart_port *port) |
132 | { | 121 | { |
133 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 122 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
134 | unsigned long flags; | ||
135 | 123 | ||
136 | spin_lock_irqsave(&port->lock, flags); | ||
137 | pp->imr &= ~MCFUART_UIR_RXREADY; | 124 | pp->imr &= ~MCFUART_UIR_RXREADY; |
138 | writeb(pp->imr, port->membase + MCFUART_UIMR); | 125 | writeb(pp->imr, port->membase + MCFUART_UIMR); |
139 | spin_unlock_irqrestore(&port->lock, flags); | ||
140 | } | 126 | } |
141 | 127 | ||
142 | /****************************************************************************/ | 128 | /****************************************************************************/ |
@@ -366,13 +352,22 @@ static irqreturn_t mcf_interrupt(int irq, void *data) | |||
366 | struct uart_port *port = data; | 352 | struct uart_port *port = data; |
367 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | 353 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); |
368 | unsigned int isr; | 354 | unsigned int isr; |
355 | irqreturn_t ret = IRQ_NONE; | ||
369 | 356 | ||
370 | isr = readb(port->membase + MCFUART_UISR) & pp->imr; | 357 | isr = readb(port->membase + MCFUART_UISR) & pp->imr; |
371 | if (isr & MCFUART_UIR_RXREADY) | 358 | |
359 | spin_lock(&port->lock); | ||
360 | if (isr & MCFUART_UIR_RXREADY) { | ||
372 | mcf_rx_chars(pp); | 361 | mcf_rx_chars(pp); |
373 | if (isr & MCFUART_UIR_TXREADY) | 362 | ret = IRQ_HANDLED; |
363 | } | ||
364 | if (isr & MCFUART_UIR_TXREADY) { | ||
374 | mcf_tx_chars(pp); | 365 | mcf_tx_chars(pp); |
375 | return IRQ_HANDLED; | 366 | ret = IRQ_HANDLED; |
367 | } | ||
368 | spin_unlock(&port->lock); | ||
369 | |||
370 | return ret; | ||
376 | } | 371 | } |
377 | 372 | ||
378 | /****************************************************************************/ | 373 | /****************************************************************************/ |