diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2015-02-24 14:25:07 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-26 13:15:16 -0400 |
commit | a4416cd1ac7b48988f0f41a17769d65c71ffc504 (patch) | |
tree | a6bd6908872ae2f37b8334ffcc0ab4735d955555 | |
parent | 6e28157173037b779fcf90715416a21a1e5ea2f9 (diff) |
serial: 8250: Separate legacy irq handling from core port operations
Prepare for 8250 split; decouple irq setup/teardown and handler from
core port operations.
Introduce setup_irq() and release_irq() 8250 driver methods; the 8250
core will use these methods to install and remove irq handling for
the given 8250 port.
Refactor irq chain linking/unlinking from 8250 core into
univ8250_setup_irq()/univ8250_release_irq() for the universal 8250 driver.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 83 | ||||
-rw-r--r-- | include/linux/serial_8250.h | 15 |
2 files changed, 68 insertions, 30 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 625f81c9b55e..06bb2ced2c94 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c | |||
@@ -1890,6 +1890,48 @@ static void serial8250_backup_timeout(unsigned long data) | |||
1890 | jiffies + uart_poll_timeout(&up->port) + HZ / 5); | 1890 | jiffies + uart_poll_timeout(&up->port) + HZ / 5); |
1891 | } | 1891 | } |
1892 | 1892 | ||
1893 | static int univ8250_setup_irq(struct uart_8250_port *up) | ||
1894 | { | ||
1895 | struct uart_port *port = &up->port; | ||
1896 | int retval = 0; | ||
1897 | |||
1898 | /* | ||
1899 | * The above check will only give an accurate result the first time | ||
1900 | * the port is opened so this value needs to be preserved. | ||
1901 | */ | ||
1902 | if (up->bugs & UART_BUG_THRE) { | ||
1903 | pr_debug("ttyS%d - using backup timer\n", serial_index(port)); | ||
1904 | |||
1905 | up->timer.function = serial8250_backup_timeout; | ||
1906 | up->timer.data = (unsigned long)up; | ||
1907 | mod_timer(&up->timer, jiffies + | ||
1908 | uart_poll_timeout(port) + HZ / 5); | ||
1909 | } | ||
1910 | |||
1911 | /* | ||
1912 | * If the "interrupt" for this port doesn't correspond with any | ||
1913 | * hardware interrupt, we use a timer-based system. The original | ||
1914 | * driver used to do this with IRQ0. | ||
1915 | */ | ||
1916 | if (!port->irq) { | ||
1917 | up->timer.data = (unsigned long)up; | ||
1918 | mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); | ||
1919 | } else | ||
1920 | retval = serial_link_irq_chain(up); | ||
1921 | |||
1922 | return retval; | ||
1923 | } | ||
1924 | |||
1925 | static void univ8250_release_irq(struct uart_8250_port *up) | ||
1926 | { | ||
1927 | struct uart_port *port = &up->port; | ||
1928 | |||
1929 | del_timer_sync(&up->timer); | ||
1930 | up->timer.function = serial8250_timeout; | ||
1931 | if (port->irq) | ||
1932 | serial_unlink_irq_chain(up); | ||
1933 | } | ||
1934 | |||
1893 | static unsigned int serial8250_tx_empty(struct uart_port *port) | 1935 | static unsigned int serial8250_tx_empty(struct uart_port *port) |
1894 | { | 1936 | { |
1895 | struct uart_8250_port *up = up_to_u8250p(port); | 1937 | struct uart_8250_port *up = up_to_u8250p(port); |
@@ -2194,35 +2236,12 @@ int serial8250_do_startup(struct uart_port *port) | |||
2194 | if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || | 2236 | if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || |
2195 | up->port.flags & UPF_BUG_THRE) { | 2237 | up->port.flags & UPF_BUG_THRE) { |
2196 | up->bugs |= UART_BUG_THRE; | 2238 | up->bugs |= UART_BUG_THRE; |
2197 | pr_debug("ttyS%d - using backup timer\n", | ||
2198 | serial_index(port)); | ||
2199 | } | 2239 | } |
2200 | } | 2240 | } |
2201 | 2241 | ||
2202 | /* | 2242 | retval = up->ops->setup_irq(up); |
2203 | * The above check will only give an accurate result the first time | 2243 | if (retval) |
2204 | * the port is opened so this value needs to be preserved. | 2244 | goto out; |
2205 | */ | ||
2206 | if (up->bugs & UART_BUG_THRE) { | ||
2207 | up->timer.function = serial8250_backup_timeout; | ||
2208 | up->timer.data = (unsigned long)up; | ||
2209 | mod_timer(&up->timer, jiffies + | ||
2210 | uart_poll_timeout(port) + HZ / 5); | ||
2211 | } | ||
2212 | |||
2213 | /* | ||
2214 | * If the "interrupt" for this port doesn't correspond with any | ||
2215 | * hardware interrupt, we use a timer-based system. The original | ||
2216 | * driver used to do this with IRQ0. | ||
2217 | */ | ||
2218 | if (!port->irq) { | ||
2219 | up->timer.data = (unsigned long)up; | ||
2220 | mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); | ||
2221 | } else { | ||
2222 | retval = serial_link_irq_chain(up); | ||
2223 | if (retval) | ||
2224 | goto out; | ||
2225 | } | ||
2226 | 2245 | ||
2227 | /* | 2246 | /* |
2228 | * Now, initialize the UART | 2247 | * Now, initialize the UART |
@@ -2380,10 +2399,7 @@ void serial8250_do_shutdown(struct uart_port *port) | |||
2380 | serial_port_in(port, UART_RX); | 2399 | serial_port_in(port, UART_RX); |
2381 | serial8250_rpm_put(up); | 2400 | serial8250_rpm_put(up); |
2382 | 2401 | ||
2383 | del_timer_sync(&up->timer); | 2402 | up->ops->release_irq(up); |
2384 | up->timer.function = serial8250_timeout; | ||
2385 | if (port->irq) | ||
2386 | serial_unlink_irq_chain(up); | ||
2387 | } | 2403 | } |
2388 | EXPORT_SYMBOL_GPL(serial8250_do_shutdown); | 2404 | EXPORT_SYMBOL_GPL(serial8250_do_shutdown); |
2389 | 2405 | ||
@@ -3083,6 +3099,11 @@ static struct uart_ops serial8250_pops = { | |||
3083 | #endif | 3099 | #endif |
3084 | }; | 3100 | }; |
3085 | 3101 | ||
3102 | static const struct uart_8250_ops univ8250_driver_ops = { | ||
3103 | .setup_irq = univ8250_setup_irq, | ||
3104 | .release_irq = univ8250_release_irq, | ||
3105 | }; | ||
3106 | |||
3086 | static struct uart_8250_port serial8250_ports[UART_NR]; | 3107 | static struct uart_8250_port serial8250_ports[UART_NR]; |
3087 | 3108 | ||
3088 | /** | 3109 | /** |
@@ -3137,6 +3158,8 @@ static void __init serial8250_isa_init_ports(void) | |||
3137 | up->timer.function = serial8250_timeout; | 3158 | up->timer.function = serial8250_timeout; |
3138 | up->cur_iotype = 0xFF; | 3159 | up->cur_iotype = 0xFF; |
3139 | 3160 | ||
3161 | up->ops = &univ8250_driver_ops; | ||
3162 | |||
3140 | /* | 3163 | /* |
3141 | * ALPHA_KLUDGE_MCR needs to be killed. | 3164 | * ALPHA_KLUDGE_MCR needs to be killed. |
3142 | */ | 3165 | */ |
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index ca9f87beac63..50735a9ad598 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h | |||
@@ -60,6 +60,20 @@ enum { | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct uart_8250_dma; | 62 | struct uart_8250_dma; |
63 | struct uart_8250_port; | ||
64 | |||
65 | /** | ||
66 | * 8250 core driver operations | ||
67 | * | ||
68 | * @setup_irq() Setup irq handling. The universal 8250 driver links this | ||
69 | * port to the irq chain. Other drivers may @request_irq(). | ||
70 | * @release_irq() Undo irq handling. The universal 8250 driver unlinks | ||
71 | * the port from the irq chain. | ||
72 | */ | ||
73 | struct uart_8250_ops { | ||
74 | int (*setup_irq)(struct uart_8250_port *); | ||
75 | void (*release_irq)(struct uart_8250_port *); | ||
76 | }; | ||
63 | 77 | ||
64 | /* | 78 | /* |
65 | * This should be used by drivers which want to register | 79 | * This should be used by drivers which want to register |
@@ -100,6 +114,7 @@ struct uart_8250_port { | |||
100 | unsigned char msr_saved_flags; | 114 | unsigned char msr_saved_flags; |
101 | 115 | ||
102 | struct uart_8250_dma *dma; | 116 | struct uart_8250_dma *dma; |
117 | const struct uart_8250_ops *ops; | ||
103 | 118 | ||
104 | /* 8250 specific callbacks */ | 119 | /* 8250 specific callbacks */ |
105 | int (*dl_read)(struct uart_8250_port *); | 120 | int (*dl_read)(struct uart_8250_port *); |