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>
This commit is contained in:
Родитель
6e28157173
Коммит
a4416cd1ac
|
@ -1890,6 +1890,48 @@ static void serial8250_backup_timeout(unsigned long data)
|
|||
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
|
||||
}
|
||||
|
||||
static int univ8250_setup_irq(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
int retval = 0;
|
||||
|
||||
/*
|
||||
* The above check will only give an accurate result the first time
|
||||
* the port is opened so this value needs to be preserved.
|
||||
*/
|
||||
if (up->bugs & UART_BUG_THRE) {
|
||||
pr_debug("ttyS%d - using backup timer\n", serial_index(port));
|
||||
|
||||
up->timer.function = serial8250_backup_timeout;
|
||||
up->timer.data = (unsigned long)up;
|
||||
mod_timer(&up->timer, jiffies +
|
||||
uart_poll_timeout(port) + HZ / 5);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the "interrupt" for this port doesn't correspond with any
|
||||
* hardware interrupt, we use a timer-based system. The original
|
||||
* driver used to do this with IRQ0.
|
||||
*/
|
||||
if (!port->irq) {
|
||||
up->timer.data = (unsigned long)up;
|
||||
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
|
||||
} else
|
||||
retval = serial_link_irq_chain(up);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void univ8250_release_irq(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
|
||||
del_timer_sync(&up->timer);
|
||||
up->timer.function = serial8250_timeout;
|
||||
if (port->irq)
|
||||
serial_unlink_irq_chain(up);
|
||||
}
|
||||
|
||||
static unsigned int serial8250_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
@ -2194,35 +2236,12 @@ int serial8250_do_startup(struct uart_port *port)
|
|||
if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) ||
|
||||
up->port.flags & UPF_BUG_THRE) {
|
||||
up->bugs |= UART_BUG_THRE;
|
||||
pr_debug("ttyS%d - using backup timer\n",
|
||||
serial_index(port));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The above check will only give an accurate result the first time
|
||||
* the port is opened so this value needs to be preserved.
|
||||
*/
|
||||
if (up->bugs & UART_BUG_THRE) {
|
||||
up->timer.function = serial8250_backup_timeout;
|
||||
up->timer.data = (unsigned long)up;
|
||||
mod_timer(&up->timer, jiffies +
|
||||
uart_poll_timeout(port) + HZ / 5);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the "interrupt" for this port doesn't correspond with any
|
||||
* hardware interrupt, we use a timer-based system. The original
|
||||
* driver used to do this with IRQ0.
|
||||
*/
|
||||
if (!port->irq) {
|
||||
up->timer.data = (unsigned long)up;
|
||||
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
|
||||
} else {
|
||||
retval = serial_link_irq_chain(up);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
retval = up->ops->setup_irq(up);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Now, initialize the UART
|
||||
|
@ -2380,10 +2399,7 @@ void serial8250_do_shutdown(struct uart_port *port)
|
|||
serial_port_in(port, UART_RX);
|
||||
serial8250_rpm_put(up);
|
||||
|
||||
del_timer_sync(&up->timer);
|
||||
up->timer.function = serial8250_timeout;
|
||||
if (port->irq)
|
||||
serial_unlink_irq_chain(up);
|
||||
up->ops->release_irq(up);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_do_shutdown);
|
||||
|
||||
|
@ -3083,6 +3099,11 @@ static struct uart_ops serial8250_pops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const struct uart_8250_ops univ8250_driver_ops = {
|
||||
.setup_irq = univ8250_setup_irq,
|
||||
.release_irq = univ8250_release_irq,
|
||||
};
|
||||
|
||||
static struct uart_8250_port serial8250_ports[UART_NR];
|
||||
|
||||
/**
|
||||
|
@ -3137,6 +3158,8 @@ static void __init serial8250_isa_init_ports(void)
|
|||
up->timer.function = serial8250_timeout;
|
||||
up->cur_iotype = 0xFF;
|
||||
|
||||
up->ops = &univ8250_driver_ops;
|
||||
|
||||
/*
|
||||
* ALPHA_KLUDGE_MCR needs to be killed.
|
||||
*/
|
||||
|
|
|
@ -60,6 +60,20 @@ enum {
|
|||
};
|
||||
|
||||
struct uart_8250_dma;
|
||||
struct uart_8250_port;
|
||||
|
||||
/**
|
||||
* 8250 core driver operations
|
||||
*
|
||||
* @setup_irq() Setup irq handling. The universal 8250 driver links this
|
||||
* port to the irq chain. Other drivers may @request_irq().
|
||||
* @release_irq() Undo irq handling. The universal 8250 driver unlinks
|
||||
* the port from the irq chain.
|
||||
*/
|
||||
struct uart_8250_ops {
|
||||
int (*setup_irq)(struct uart_8250_port *);
|
||||
void (*release_irq)(struct uart_8250_port *);
|
||||
};
|
||||
|
||||
/*
|
||||
* This should be used by drivers which want to register
|
||||
|
@ -100,6 +114,7 @@ struct uart_8250_port {
|
|||
unsigned char msr_saved_flags;
|
||||
|
||||
struct uart_8250_dma *dma;
|
||||
const struct uart_8250_ops *ops;
|
||||
|
||||
/* 8250 specific callbacks */
|
||||
int (*dl_read)(struct uart_8250_port *);
|
||||
|
|
Загрузка…
Ссылка в новой задаче