diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-09-10 15:06:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 00:19:35 -0400 |
commit | d01f4d181c92877ecc678adce248a30cb7077ff1 (patch) | |
tree | f4b9a5723be98e63e2b238f8290fd418179a238a | |
parent | 317c1360200059a7a8a832294a58409c73b784bf (diff) |
serial: core: Privatize tty->hw_stopped
tty->hw_stopped is not used by the tty core and is thread-unsafe;
hw_stopped is a member of a bitfield whose fields are updated
non-atomically and no lock is suitable for serializing updates.
Replace serial core usage of tty->hw_stopped with uport->hw_stopped.
Use int storage which works around Alpha EV4/5 non-atomic byte storage,
since uart_port uses different locks to protect certain fields within the
structure.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/serial/bfin_uart.c | 14 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 28 | ||||
-rw-r--r-- | include/linux/serial_core.h | 3 |
3 files changed, 22 insertions, 23 deletions
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index dec0fd725d80..fc9fbf3f24a7 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c | |||
@@ -108,22 +108,22 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
108 | static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) | 108 | static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) |
109 | { | 109 | { |
110 | struct bfin_serial_port *uart = dev_id; | 110 | struct bfin_serial_port *uart = dev_id; |
111 | unsigned int status = bfin_serial_get_mctrl(&uart->port); | 111 | struct uart_port *uport = &uart->port; |
112 | unsigned int status = bfin_serial_get_mctrl(uport); | ||
112 | #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS | 113 | #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS |
113 | struct tty_struct *tty = uart->port.state->port.tty; | ||
114 | 114 | ||
115 | UART_CLEAR_SCTS(uart); | 115 | UART_CLEAR_SCTS(uart); |
116 | if (tty->hw_stopped) { | 116 | if (uport->hw_stopped) { |
117 | if (status) { | 117 | if (status) { |
118 | tty->hw_stopped = 0; | 118 | uport->hw_stopped = 0; |
119 | uart_write_wakeup(&uart->port); | 119 | uart_write_wakeup(uport); |
120 | } | 120 | } |
121 | } else { | 121 | } else { |
122 | if (!status) | 122 | if (!status) |
123 | tty->hw_stopped = 1; | 123 | uport->hw_stopped = 1; |
124 | } | 124 | } |
125 | #endif | 125 | #endif |
126 | uart_handle_cts_change(&uart->port, status & TIOCM_CTS); | 126 | uart_handle_cts_change(uport, status & TIOCM_CTS); |
127 | 127 | ||
128 | return IRQ_HANDLED; | 128 | return IRQ_HANDLED; |
129 | } | 129 | } |
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index dd21ed900635..7d51e26627fb 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c | |||
@@ -95,7 +95,7 @@ static void __uart_start(struct tty_struct *tty) | |||
95 | struct uart_state *state = tty->driver_data; | 95 | struct uart_state *state = tty->driver_data; |
96 | struct uart_port *port = state->uart_port; | 96 | struct uart_port *port = state->uart_port; |
97 | 97 | ||
98 | if (!tty->stopped && !tty->hw_stopped) | 98 | if (!uart_tx_stopped(port)) |
99 | port->ops->start_tx(port); | 99 | port->ops->start_tx(port); |
100 | } | 100 | } |
101 | 101 | ||
@@ -181,10 +181,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, | |||
181 | } | 181 | } |
182 | 182 | ||
183 | spin_lock_irq(&uport->lock); | 183 | spin_lock_irq(&uport->lock); |
184 | if (uart_cts_enabled(uport)) { | 184 | if (uart_cts_enabled(uport) && |
185 | if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) | 185 | !(uport->ops->get_mctrl(uport) & TIOCM_CTS)) |
186 | tty->hw_stopped = 1; | 186 | uport->hw_stopped = 1; |
187 | } | 187 | else |
188 | uport->hw_stopped = 0; | ||
188 | spin_unlock_irq(&uport->lock); | 189 | spin_unlock_irq(&uport->lock); |
189 | } | 190 | } |
190 | 191 | ||
@@ -949,7 +950,7 @@ static int uart_get_lsr_info(struct tty_struct *tty, | |||
949 | */ | 950 | */ |
950 | if (uport->x_char || | 951 | if (uport->x_char || |
951 | ((uart_circ_chars_pending(&state->xmit) > 0) && | 952 | ((uart_circ_chars_pending(&state->xmit) > 0) && |
952 | !tty->stopped && !tty->hw_stopped)) | 953 | !uart_tx_stopped(uport))) |
953 | result &= ~TIOCSER_TEMT; | 954 | result &= ~TIOCSER_TEMT; |
954 | 955 | ||
955 | return put_user(result, value); | 956 | return put_user(result, value); |
@@ -1295,7 +1296,7 @@ static void uart_set_termios(struct tty_struct *tty, | |||
1295 | 1296 | ||
1296 | /* | 1297 | /* |
1297 | * If the port is doing h/w assisted flow control, do nothing. | 1298 | * If the port is doing h/w assisted flow control, do nothing. |
1298 | * We assume that tty->hw_stopped has never been set. | 1299 | * We assume that port->hw_stopped has never been set. |
1299 | */ | 1300 | */ |
1300 | if (uport->flags & UPF_HARD_FLOW) | 1301 | if (uport->flags & UPF_HARD_FLOW) |
1301 | return; | 1302 | return; |
@@ -1303,7 +1304,7 @@ static void uart_set_termios(struct tty_struct *tty, | |||
1303 | /* Handle turning off CRTSCTS */ | 1304 | /* Handle turning off CRTSCTS */ |
1304 | if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { | 1305 | if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { |
1305 | spin_lock_irqsave(&uport->lock, flags); | 1306 | spin_lock_irqsave(&uport->lock, flags); |
1306 | tty->hw_stopped = 0; | 1307 | uport->hw_stopped = 0; |
1307 | __uart_start(tty); | 1308 | __uart_start(tty); |
1308 | spin_unlock_irqrestore(&uport->lock, flags); | 1309 | spin_unlock_irqrestore(&uport->lock, flags); |
1309 | } | 1310 | } |
@@ -1311,7 +1312,7 @@ static void uart_set_termios(struct tty_struct *tty, | |||
1311 | else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { | 1312 | else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { |
1312 | spin_lock_irqsave(&uport->lock, flags); | 1313 | spin_lock_irqsave(&uport->lock, flags); |
1313 | if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { | 1314 | if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { |
1314 | tty->hw_stopped = 1; | 1315 | uport->hw_stopped = 1; |
1315 | uport->ops->stop_tx(uport); | 1316 | uport->ops->stop_tx(uport); |
1316 | } | 1317 | } |
1317 | spin_unlock_irqrestore(&uport->lock, flags); | 1318 | spin_unlock_irqrestore(&uport->lock, flags); |
@@ -2788,23 +2789,20 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change); | |||
2788 | */ | 2789 | */ |
2789 | void uart_handle_cts_change(struct uart_port *uport, unsigned int status) | 2790 | void uart_handle_cts_change(struct uart_port *uport, unsigned int status) |
2790 | { | 2791 | { |
2791 | struct tty_port *port = &uport->state->port; | ||
2792 | struct tty_struct *tty = port->tty; | ||
2793 | |||
2794 | lockdep_assert_held_once(&uport->lock); | 2792 | lockdep_assert_held_once(&uport->lock); |
2795 | 2793 | ||
2796 | uport->icount.cts++; | 2794 | uport->icount.cts++; |
2797 | 2795 | ||
2798 | if (uart_cts_enabled(uport)) { | 2796 | if (uart_cts_enabled(uport)) { |
2799 | if (tty->hw_stopped) { | 2797 | if (uport->hw_stopped) { |
2800 | if (status) { | 2798 | if (status) { |
2801 | tty->hw_stopped = 0; | 2799 | uport->hw_stopped = 0; |
2802 | uport->ops->start_tx(uport); | 2800 | uport->ops->start_tx(uport); |
2803 | uart_write_wakeup(uport); | 2801 | uart_write_wakeup(uport); |
2804 | } | 2802 | } |
2805 | } else { | 2803 | } else { |
2806 | if (!status) { | 2804 | if (!status) { |
2807 | tty->hw_stopped = 1; | 2805 | uport->hw_stopped = 1; |
2808 | uport->ops->stop_tx(uport); | 2806 | uport->ops->stop_tx(uport); |
2809 | } | 2807 | } |
2810 | } | 2808 | } |
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 452c9cc9d717..204c452a7567 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
@@ -197,6 +197,7 @@ struct uart_port { | |||
197 | #define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0)) | 197 | #define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0)) |
198 | #define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1)) | 198 | #define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1)) |
199 | 199 | ||
200 | int hw_stopped; /* sw-assisted CTS flow state */ | ||
200 | unsigned int mctrl; /* current modem ctrl settings */ | 201 | unsigned int mctrl; /* current modem ctrl settings */ |
201 | unsigned int timeout; /* character-based timeout */ | 202 | unsigned int timeout; /* character-based timeout */ |
202 | unsigned int type; /* port type */ | 203 | unsigned int type; /* port type */ |
@@ -357,7 +358,7 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); | |||
357 | static inline int uart_tx_stopped(struct uart_port *port) | 358 | static inline int uart_tx_stopped(struct uart_port *port) |
358 | { | 359 | { |
359 | struct tty_struct *tty = port->state->port.tty; | 360 | struct tty_struct *tty = port->state->port.tty; |
360 | if(tty->stopped || tty->hw_stopped) | 361 | if (tty->stopped || port->hw_stopped) |
361 | return 1; | 362 | return 1; |
362 | return 0; | 363 | return 0; |
363 | } | 364 | } |