Commit a4416cd1 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6e281571
Loading
Loading
Loading
Loading
+53 −30
Original line number Diff line number Diff line
@@ -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);
	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.
		 */
+15 −0
Original line number Diff line number Diff line
@@ -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 *);