linux_dsm_epyc7002/drivers/tty/serial/sn_console.c

1036 lines
28 KiB
C
Raw Normal View History

/*
* C-Brick Serial Port (and console) driver for SGI Altix machines.
*
* This driver is NOT suitable for talking to the l1-controller for
* anything other than 'console activities' --- please use the l1
* driver for that.
*
*
* Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved.
*
* Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan
*/
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/sysrq.h>
#include <linux/circ_buf.h>
#include <linux/serial_reg.h>
#include <linux/delay.h> /* for mdelay */
#include <linux/miscdevice.h>
#include <linux/serial_core.h>
#include <asm/io.h>
#include <asm/sn/simulator.h>
#include <asm/sn/sn_sal.h>
/* number of characters we can transmit to the SAL console at a time */
#define SN_SAL_MAX_CHARS 120
/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
* avoid losing chars, (always has to be a power of 2) */
#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
#define SN_SAL_UART_FIFO_DEPTH 16
#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
/* sn_transmit_chars() calling args */
#define TRANSMIT_BUFFERED 0
#define TRANSMIT_RAW 1
/* To use dynamic numbers only and not use the assigned major and minor,
* define the following.. */
/* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */
/* Device name we're using */
#define DEVICE_NAME "ttySG"
#define DEVICE_NAME_DYNAMIC "ttySG0" /* need full name for misc_register */
/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
#define DEVICE_MAJOR 204
#define DEVICE_MINOR 40
#ifdef CONFIG_MAGIC_SYSRQ
static char sysrq_serial_str[] = "\eSYS";
static char *sysrq_serial_ptr = sysrq_serial_str;
static unsigned long sysrq_requested;
#endif /* CONFIG_MAGIC_SYSRQ */
/*
* Port definition - this kinda drives it all
*/
struct sn_cons_port {
struct timer_list sc_timer;
struct uart_port sc_port;
struct sn_sal_ops {
int (*sal_puts_raw) (const char *s, int len);
int (*sal_puts) (const char *s, int len);
int (*sal_getc) (void);
int (*sal_input_pending) (void);
void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
} *sc_ops;
unsigned long sc_interrupt_timeout;
int sc_is_asynch;
};
static struct sn_cons_port sal_console_port;
static int sn_process_input;
/* Only used if USE_DYNAMIC_MINOR is set to 1 */
static struct miscdevice misc; /* used with misc_register for dynamic */
extern void early_sn_setup(void);
#undef DEBUG
#ifdef DEBUG
static int sn_debug_printf(const char *fmt, ...);
#define DPRINTF(x...) sn_debug_printf(x)
#else
#define DPRINTF(x...) do { } while (0)
#endif
/* Prototypes */
static int snt_hw_puts_raw(const char *, int);
static int snt_hw_puts_buffered(const char *, int);
static int snt_poll_getc(void);
static int snt_poll_input_pending(void);
static int snt_intr_getc(void);
static int snt_intr_input_pending(void);
static void sn_transmit_chars(struct sn_cons_port *, int);
/* A table for polling:
*/
static struct sn_sal_ops poll_ops = {
.sal_puts_raw = snt_hw_puts_raw,
.sal_puts = snt_hw_puts_raw,
.sal_getc = snt_poll_getc,
.sal_input_pending = snt_poll_input_pending
};
/* A table for interrupts enabled */
static struct sn_sal_ops intr_ops = {
.sal_puts_raw = snt_hw_puts_raw,
.sal_puts = snt_hw_puts_buffered,
.sal_getc = snt_intr_getc,
.sal_input_pending = snt_intr_input_pending,
.sal_wakeup_transmit = sn_transmit_chars
};
/* the console does output in two distinctly different ways:
* synchronous (raw) and asynchronous (buffered). initially, early_printk
* does synchronous output. any data written goes directly to the SAL
* to be output (incidentally, it is internally buffered by the SAL)
* after interrupts and timers are initialized and available for use,
* the console init code switches to asynchronous output. this is
* also the earliest opportunity to begin polling for console input.
* after console initialization, console output and tty (serial port)
* output is buffered and sent to the SAL asynchronously (either by
* timer callback or by UART interrupt) */
/* routines for running the console in polling mode */
/**
* snt_poll_getc - Get a character from the console in polling mode
*
*/
static int snt_poll_getc(void)
{
int ch;
ia64_sn_console_getc(&ch);
return ch;
}
/**
* snt_poll_input_pending - Check if any input is waiting - polling mode.
*
*/
static int snt_poll_input_pending(void)
{
int status, input;
status = ia64_sn_console_check(&input);
return !status && input;
}
/* routines for an interrupt driven console (normal) */
/**
* snt_intr_getc - Get a character from the console, interrupt mode
*
*/
static int snt_intr_getc(void)
{
return ia64_sn_console_readc();
}
/**
* snt_intr_input_pending - Check if input is pending, interrupt mode
*
*/
static int snt_intr_input_pending(void)
{
return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
}
/* these functions are polled and interrupt */
/**
* snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
* @s: String
* @len: Length
*
*/
static int snt_hw_puts_raw(const char *s, int len)
{
/* this will call the PROM and not return until this is done */
return ia64_sn_console_putb(s, len);
}
/**
* snt_hw_puts_buffered - Send string to console, polled or interrupt mode
* @s: String
* @len: Length
*
*/
static int snt_hw_puts_buffered(const char *s, int len)
{
/* queue data to the PROM */
return ia64_sn_console_xmit_chars((char *)s, len);
}
/* uart interface structs
* These functions are associated with the uart_port that the serial core
* infrastructure calls.
*
* Note: Due to how the console works, many routines are no-ops.
*/
/**
* snp_type - What type of console are we?
* @port: Port to operate with (we ignore since we only have one port)
*
*/
static const char *snp_type(struct uart_port *port)
{
return ("SGI SN L1");
}
/**
* snp_tx_empty - Is the transmitter empty? We pretend we're always empty
* @port: Port to operate on (we ignore since we only have one port)
*
*/
static unsigned int snp_tx_empty(struct uart_port *port)
{
return 1;
}
/**
* snp_stop_tx - stop the transmitter - no-op for us
* @port: Port to operat eon - we ignore - no-op function
*
*/
static void snp_stop_tx(struct uart_port *port)
{
}
/**
* snp_release_port - Free i/o and resources for port - no-op for us
* @port: Port to operate on - we ignore - no-op function
*
*/
static void snp_release_port(struct uart_port *port)
{
}
/**
* snp_shutdown - shut down the port - free irq and disable - no-op for us
* @port: Port to shut down - we ignore
*
*/
static void snp_shutdown(struct uart_port *port)
{
}
/**
* snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
* @port: Port to operate on - we ignore
* @mctrl: Lines to set/unset - we ignore
*
*/
static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
/**
* snp_get_mctrl - get contorl line info, we just return a static value
* @port: port to operate on - we only have one port so we ignore this
*
*/
static unsigned int snp_get_mctrl(struct uart_port *port)
{
return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
}
/**
* snp_stop_rx - Stop the receiver - we ignor ethis
* @port: Port to operate on - we ignore
*
*/
static void snp_stop_rx(struct uart_port *port)
{
}
/**
* snp_start_tx - Start transmitter
* @port: Port to operate on
*
*/
static void snp_start_tx(struct uart_port *port)
{
if (sal_console_port.sc_ops->sal_wakeup_transmit)
sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
TRANSMIT_BUFFERED);
}
/**
* snp_break_ctl - handle breaks - ignored by us
* @port: Port to operate on
* @break_state: Break state
*
*/
static void snp_break_ctl(struct uart_port *port, int break_state)
{
}
/**
* snp_startup - Start up the serial port - always return 0 (We're always on)
* @port: Port to operate on
*
*/
static int snp_startup(struct uart_port *port)
{
return 0;
}
/**
* snp_set_termios - set termios stuff - we ignore these
* @port: port to operate on
* @termios: New settings
* @termios: Old
*
*/
static void
snp_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
}
/**
* snp_request_port - allocate resources for port - ignored by us
* @port: port to operate on
*
*/
static int snp_request_port(struct uart_port *port)
{
return 0;
}
/**
* snp_config_port - allocate resources, set up - we ignore, we're always on
* @port: Port to operate on
* @flags: flags used for port setup
*
*/
static void snp_config_port(struct uart_port *port, int flags)
{
}
/* Associate the uart functions above - given to serial core */
tty: serial: constify uart_ops structures Declare uart_ops structures as const as they are only stored in the ops field of an uart_port structure. This field is of type const, so uart_ops structures having this property can be made const too. File size details before and after patching. First line of every .o file shows the file size before patching and second line shows the size after patching. text data bss dec hex filename 2977 456 64 3497 da9 drivers/tty/serial/amba-pl010.o 3169 272 64 3505 db1 drivers/tty/serial/amba-pl010.o 3109 456 0 3565 ded drivers/tty/serial/efm32-uart.o 3301 272 0 3573 df5 drivers/tty/serial/efm32-uart.o 10668 753 1 11422 2c9e drivers/tty/serial/icom.o 10860 561 1 11422 2c9e drivers/tty/serial/icom.o 23904 408 8 24320 5f00 drivers/tty/serial/ioc3_serial.o 24088 224 8 24320 5f00 drivers/tty/serial/ioc3_serial.o 10516 560 4 11080 2b48 drivers/tty/serial/ioc4_serial.o 10709 368 4 11081 2b49 drivers/tty/serial/ioc4_serial.o 7853 648 1216 9717 25f5 drivers/tty/serial/mpsc.o 8037 456 1216 9709 25ed drivers/tty/serial/mpsc.o 10248 456 0 10704 29d0 drivers/tty/serial/omap-serial.o 10440 272 0 10712 29d8 drivers/tty/serial/omap-serial.o 8122 532 1984 10638 298e drivers/tty/serial/pmac_zilog.o 8306 340 1984 10630 2986 drivers/tty/serial/pmac_zilog.o 3808 456 0 4264 10a8 drivers/tty/serial/pxa.o 4000 264 0 4264 10a8 drivers/tty/serial/pxa.o 21781 3864 0 25645 642d drivers/tty/serial/serial-tegra.o 22037 3608 0 25645 642d drivers/tty/serial/serial-tegra.o 2481 456 96 3033 bd9 drivers/tty/serial/sprd_serial.o 2673 272 96 3041 be1 drivers/tty/serial/sprd_serial.o 5534 300 512 6346 18ca drivers/tty/serial/vr41xx_siu.o 5630 204 512 6346 18ca drivers/tty/serial/vr41xx_siu.o 6730 1576 128 8434 20f2 drivers/tty/serial/vt8500_serial.o 6986 1320 128 8434 20f2 drivers/tty/serial/vt8500_serial.o Cross compiled for mips architecture. 3005 488 0 3493 da5 drivers/tty/serial/pnx8xxx_uart.o 3189 304 0 3493 da5 drivers/tty/serial/pnx8xxx_uart.o 4272 196 1056 5524 1594 drivers/tty/serial/dz.o 4368 100 1056 5524 1594 drivers/tty/serial/dz.o 6551 144 16 6711 1a37 drivers/tty/serial/ip22zilog.o 6647 48 16 6711 1a37 drivers/tty/serial/ip22zilog.o 9612 428 1520 11560 2d28 drivers/tty/serial/serial_txx9.o 9708 332 1520 11560 2d28 drivers/tty/serial/serial_txx9.o 4156 296 16 4468 1174 drivers/tty/serial/ar933x_uart.o 4252 200 16 4468 1174 drivers/tty/serial/ar933x_uart.o Cross compiled for arm archiecture. 11716 1780 44 13540 34e4 drivers/tty/serial/sirfsoc_uart.o 11808 1688 44 13540 34e4 drivers/tty/serial/sirfsoc_uart.o 13352 596 56 14004 36b4 drivers/tty/serial/amba-pl011.o 13444 504 56 14004 36b4 drivers/tty/serial/amba-pl011.o Cross compiled for sparc architecture. 4664 528 32 5224 1468 drivers/tty/serial/sunhv.o 4848 344 32 5224 1468 drivers/tty/serial/sunhv.o 8080 332 28 8440 20f8 drivers/tty/serial/sunzilog.o 8184 228 28 8440 20f8 drivers/tty/serial/sunzilog.o Cross compiled for ia64 architecture. 10226 549 472 11247 2bef drivers/tty/serial/sn_console.o 10414 365 472 11251 2bf3 drivers/tty/serial/sn_console.o The files drivers/tty/serial/zs.o, drivers/tty/serial/lpc32xx_hs.o and drivers/tty/serial/lantiq.o did not compile. Signed-off-by: Bhumika Goyal <bhumirks@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-01-26 00:48:52 +07:00
static const struct uart_ops sn_console_ops = {
.tx_empty = snp_tx_empty,
.set_mctrl = snp_set_mctrl,
.get_mctrl = snp_get_mctrl,
.stop_tx = snp_stop_tx,
.start_tx = snp_start_tx,
.stop_rx = snp_stop_rx,
.break_ctl = snp_break_ctl,
.startup = snp_startup,
.shutdown = snp_shutdown,
.set_termios = snp_set_termios,
.pm = NULL,
.type = snp_type,
.release_port = snp_release_port,
.request_port = snp_request_port,
.config_port = snp_config_port,
.verify_port = NULL,
};
/* End of uart struct functions and defines */
#ifdef DEBUG
/**
* sn_debug_printf - close to hardware debugging printf
* @fmt: printf format
*
* This is as "close to the metal" as we can get, used when the driver
* itself may be broken.
*
*/
static int sn_debug_printf(const char *fmt, ...)
{
static char printk_buf[1024];
int printed_len;
va_list args;
va_start(args, fmt);
printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
if (!sal_console_port.sc_ops) {
sal_console_port.sc_ops = &poll_ops;
early_sn_setup();
}
sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
va_end(args);
return printed_len;
}
#endif /* DEBUG */
/*
* Interrupt handling routines.
*/
/**
* sn_receive_chars - Grab characters, pass them to tty layer
* @port: Port to operate on
* @flags: irq flags
*
* Note: If we're not registered with the serial core infrastructure yet,
* we don't try to send characters to it...
*
*/
static void
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
{
struct tty_port *tport = NULL;
int ch;
if (!port) {
printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
return;
}
if (!port->sc_ops) {
printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receive\n");
return;
}
if (port->sc_port.state) {
/* The serial_core stuffs are initialized, use them */
tport = &port->sc_port.state->port;
}
while (port->sc_ops->sal_input_pending()) {
ch = port->sc_ops->sal_getc();
if (ch < 0) {
printk(KERN_ERR "sn_console: An error occurred while "
"obtaining data from the console (0x%0x)\n", ch);
break;
}
#ifdef CONFIG_MAGIC_SYSRQ
if (sysrq_requested) {
unsigned long sysrq_timeout = sysrq_requested + HZ*5;
sysrq_requested = 0;
if (ch && time_before(jiffies, sysrq_timeout)) {
spin_unlock_irqrestore(&port->sc_port.lock, flags);
handle_sysrq(ch);
spin_lock_irqsave(&port->sc_port.lock, flags);
/* ignore actual sysrq command char */
continue;
}
}
if (ch == *sysrq_serial_ptr) {
if (!(*++sysrq_serial_ptr)) {
sysrq_requested = jiffies;
sysrq_serial_ptr = sysrq_serial_str;
}
/*
* ignore the whole sysrq string except for the
* leading escape
*/
if (ch != '\e')
continue;
}
else
sysrq_serial_ptr = sysrq_serial_str;
#endif /* CONFIG_MAGIC_SYSRQ */
/* record the character to pass up to the tty layer */
if (tport) {
if (tty_insert_flip_char(tport, ch, TTY_NORMAL) == 0)
break;
}
port->sc_port.icount.rx++;
}
if (tport)
tty_flip_buffer_push(tport);
}
/**
* sn_transmit_chars - grab characters from serial core, send off
* @port: Port to operate on
* @raw: Transmit raw or buffered
*
* Note: If we're early, before we're registered with serial core, the
* writes are going through sn_sal_console_write because that's how
* register_console has been set up. We currently could have asynch
* polls calling this function due to sn_sal_switch_to_asynch but we can
* ignore them until we register with the serial core stuffs.
*
*/
static void sn_transmit_chars(struct sn_cons_port *port, int raw)
{
int xmit_count, tail, head, loops, ii;
int result;
char *start;
struct circ_buf *xmit;
if (!port)
return;
BUG_ON(!port->sc_is_asynch);
if (port->sc_port.state) {
/* We're initialized, using serial core infrastructure */
xmit = &port->sc_port.state->xmit;
} else {
/* Probably sn_sal_switch_to_asynch has been run but serial core isn't
* initialized yet. Just return. Writes are going through
* sn_sal_console_write (due to register_console) at this time.
*/
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
/* Nothing to do. */
ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
return;
}
head = xmit->head;
tail = xmit->tail;
start = &xmit->buf[tail];
/* twice around gets the tail to the end of the buffer and
* then to the head, if needed */
loops = (head < tail) ? 2 : 1;
for (ii = 0; ii < loops; ii++) {
xmit_count = (head < tail) ?
(UART_XMIT_SIZE - tail) : (head - tail);
if (xmit_count > 0) {
if (raw == TRANSMIT_RAW)
result =
port->sc_ops->sal_puts_raw(start,
xmit_count);
else
result =
port->sc_ops->sal_puts(start, xmit_count);
#ifdef DEBUG
if (!result)
DPRINTF("`");
#endif
if (result > 0) {
xmit_count -= result;
port->sc_port.icount.tx += result;
tail += result;
tail &= UART_XMIT_SIZE - 1;
xmit->tail = tail;
start = &xmit->buf[tail];
}
}
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&port->sc_port);
if (uart_circ_empty(xmit))
snp_stop_tx(&port->sc_port); /* no-op for us */
}
/**
* sn_sal_interrupt - Handle console interrupts
* @irq: irq #, useful for debug statements
* @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
*
*/
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
{
struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
unsigned long flags;
int status = ia64_sn_console_intr_status();
if (!port)
return IRQ_NONE;
spin_lock_irqsave(&port->sc_port.lock, flags);
if (status & SAL_CONSOLE_INTR_RECV) {
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
sn_receive_chars(port, flags);
}
if (status & SAL_CONSOLE_INTR_XMIT) {
sn_transmit_chars(port, TRANSMIT_BUFFERED);
}
spin_unlock_irqrestore(&port->sc_port.lock, flags);
return IRQ_HANDLED;
}
/**
* sn_sal_timer_poll - this function handles polled console mode
* @data: A pointer to our sn_cons_port (which contains the uart port)
*
* data is the pointer that init_timer will store for us. This function is
* associated with init_timer to see if there is any console traffic.
* Obviously not used in interrupt mode
*
*/
treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 04:43:17 +07:00
static void sn_sal_timer_poll(struct timer_list *t)
{
treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 04:43:17 +07:00
struct sn_cons_port *port = from_timer(port, t, sc_timer);
unsigned long flags;
if (!port)
return;
if (!port->sc_port.irq) {
spin_lock_irqsave(&port->sc_port.lock, flags);
if (sn_process_input)
sn_receive_chars(port, flags);
sn_transmit_chars(port, TRANSMIT_RAW);
spin_unlock_irqrestore(&port->sc_port.lock, flags);
mod_timer(&port->sc_timer,
jiffies + port->sc_interrupt_timeout);
}
}
/*
* Boot-time initialization code
*/
/**
* sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
* @port: Our sn_cons_port (which contains the uart port)
*
* So this is used by sn_sal_serial_console_init (early on, before we're
* registered with serial core). It's also used by sn_sal_init
* right after we've registered with serial core. The later only happens
* if we didn't already come through here via sn_sal_serial_console_init.
*
*/
static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
{
unsigned long flags;
if (!port)
return;
DPRINTF("sn_console: about to switch to asynchronous console\n");
/* without early_printk, we may be invoked late enough to race
* with other cpus doing console IO at this point, however
* console interrupts will never be enabled */
spin_lock_irqsave(&port->sc_port.lock, flags);
/* early_printk invocation may have done this for us */
if (!port->sc_ops)
port->sc_ops = &poll_ops;
/* we can't turn on the console interrupt (as request_irq
* calls kmalloc, which isn't set up yet), so we rely on a
* timer to poll for input and push data from the console
* buffer.
*/
treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 04:43:17 +07:00
timer_setup(&port->sc_timer, sn_sal_timer_poll, 0);
if (IS_RUNNING_ON_SIMULATOR())
port->sc_interrupt_timeout = 6;
else {
/* 960cps / 16 char FIFO = 60HZ
* HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
port->sc_interrupt_timeout =
HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
}
mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
port->sc_is_asynch = 1;
spin_unlock_irqrestore(&port->sc_port.lock, flags);
}
/**
* sn_sal_switch_to_interrupts - Switch to interrupt driven mode
* @port: Our sn_cons_port (which contains the uart port)
*
* In sn_sal_init, after we're registered with serial core and
* the port is added, this function is called to switch us to interrupt
* mode. We were previously in asynch/polling mode (using init_timer).
*
* We attempt to switch to interrupt mode here by calling
* request_irq. If that works out, we enable receive interrupts.
*/
static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
{
unsigned long flags;
if (port) {
DPRINTF("sn_console: switching to interrupt driven console\n");
if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
IRQF_SHARED,
"SAL console driver", port) >= 0) {
spin_lock_irqsave(&port->sc_port.lock, flags);
port->sc_port.irq = SGI_UART_VECTOR;
port->sc_ops = &intr_ops;
irq_set_handler(port->sc_port.irq, handle_level_irq);
/* turn on receive interrupts */
ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
spin_unlock_irqrestore(&port->sc_port.lock, flags);
}
else {
printk(KERN_INFO
"sn_console: console proceeding in polled mode\n");
}
}
}
/*
* Kernel console definitions
*/
static void sn_sal_console_write(struct console *, const char *, unsigned);
static int sn_sal_console_setup(struct console *, char *);
static struct uart_driver sal_console_uart;
extern struct tty_driver *uart_console_device(struct console *, int *);
static struct console sal_console = {
.name = DEVICE_NAME,
.write = sn_sal_console_write,
.device = uart_console_device,
.setup = sn_sal_console_setup,
.index = -1, /* unspecified */
.data = &sal_console_uart,
};
#define SAL_CONSOLE &sal_console
static struct uart_driver sal_console_uart = {
.owner = THIS_MODULE,
.driver_name = "sn_console",
.dev_name = DEVICE_NAME,
.major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */
.minor = 0,
.nr = 1, /* one port */
.cons = SAL_CONSOLE,
};
/**
* sn_sal_init - When the kernel loads us, get us rolling w/ serial core
*
* Before this is called, we've been printing kernel messages in a special
* early mode not making use of the serial core infrastructure. When our
* driver is loaded for real, we register the driver and port with serial
* core and try to enable interrupt driven mode.
*
*/
static int __init sn_sal_init(void)
{
int retval;
if (!ia64_platform_is("sn2"))
return 0;
printk(KERN_INFO "sn_console: Console driver init\n");
if (USE_DYNAMIC_MINOR == 1) {
misc.minor = MISC_DYNAMIC_MINOR;
misc.name = DEVICE_NAME_DYNAMIC;
retval = misc_register(&misc);
if (retval != 0) {
printk(KERN_WARNING "Failed to register console "
"device using misc_register.\n");
return -ENODEV;
}
sal_console_uart.major = MISC_MAJOR;
sal_console_uart.minor = misc.minor;
} else {
sal_console_uart.major = DEVICE_MAJOR;
sal_console_uart.minor = DEVICE_MINOR;
}
/* We register the driver and the port before switching to interrupts
* or async above so the proper uart structures are populated */
if (uart_register_driver(&sal_console_uart) < 0) {
printk
("ERROR sn_sal_init failed uart_register_driver, line %d\n",
__LINE__);
return -ENODEV;
}
spin_lock_init(&sal_console_port.sc_port.lock);
/* Setup the port struct with the minimum needed */
sal_console_port.sc_port.membase = (char *)1; /* just needs to be non-zero */
sal_console_port.sc_port.type = PORT_16550A;
sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
sal_console_port.sc_port.ops = &sn_console_ops;
sal_console_port.sc_port.line = 0;
if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
/* error - not sure what I'd do - so I'll do nothing */
printk(KERN_ERR "%s: unable to add port\n", __func__);
}
/* when this driver is compiled in, the console initialization
* will have already switched us into asynchronous operation
* before we get here through the initcalls */
if (!sal_console_port.sc_is_asynch) {
sn_sal_switch_to_asynch(&sal_console_port);
}
/* at this point (device_init) we can try to turn on interrupts */
if (!IS_RUNNING_ON_SIMULATOR()) {
sn_sal_switch_to_interrupts(&sal_console_port);
}
sn_process_input = 1;
return 0;
}
device_initcall(sn_sal_init);
/**
* puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
* @puts_raw : puts function to do the writing
* @s: input string
* @count: length
*
* We need a \r ahead of every \n for direct writes through
* ia64_sn_console_putb (what sal_puts_raw below actually does).
*
*/
static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
const char *s, int count)
{
const char *s1;
/* Output '\r' before each '\n' */
while ((s1 = memchr(s, '\n', count)) != NULL) {
puts_raw(s, s1 - s);
puts_raw("\r\n", 2);
count -= s1 + 1 - s;
s = s1 + 1;
}
puts_raw(s, count);
}
/**
* sn_sal_console_write - Print statements before serial core available
* @console: Console to operate on - we ignore since we have just one
* @s: String to send
* @count: length
*
* This is referenced in the console struct. It is used for early
* console printing before we register with serial core and for things
* such as kdb. The console_lock must be held when we get here.
*
* This function has some code for trying to print output even if the lock
* is held. We try to cover the case where a lock holder could have died.
* We don't use this special case code if we're not registered with serial
* core yet. After we're registered with serial core, the only time this
* function would be used is for high level kernel output like magic sys req,
* kdb, and printk's.
*/
static void
sn_sal_console_write(struct console *co, const char *s, unsigned count)
{
unsigned long flags = 0;
struct sn_cons_port *port = &sal_console_port;
static int stole_lock = 0;
BUG_ON(!port->sc_is_asynch);
/* We can't look at the xmit buffer if we're not registered with serial core
* yet. So only do the fancy recovery after registering
*/
if (!port->sc_port.state) {
/* Not yet registered with serial core - simple case */
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
return;
}
/* somebody really wants this output, might be an
* oops, kdb, panic, etc. make sure they get it. */
if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
int lhead = port->sc_port.state->xmit.head;
int ltail = port->sc_port.state->xmit.tail;
int counter, got_lock = 0;
/*
* We attempt to determine if someone has died with the
* lock. We wait ~20 secs after the head and tail ptrs
* stop moving and assume the lock holder is not functional
* and plow ahead. If the lock is freed within the time out
* period we re-get the lock and go ahead normally. We also
* remember if we have plowed ahead so that we don't have
* to wait out the time out period again - the asumption
* is that we will time out again.
*/
for (counter = 0; counter < 150; mdelay(125), counter++) {
if (stole_lock)
break;
if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
got_lock = 1;
break;
} else {
/* still locked */
if ((lhead != port->sc_port.state->xmit.head)
|| (ltail !=
port->sc_port.state->xmit.tail)) {
lhead =
port->sc_port.state->xmit.head;
ltail =
port->sc_port.state->xmit.tail;
counter = 0;
}
}
}
/* flush anything in the serial core xmit buffer, raw */
sn_transmit_chars(port, 1);
if (got_lock) {
spin_unlock_irqrestore(&port->sc_port.lock, flags);
stole_lock = 0;
} else {
/* fell thru */
stole_lock = 1;
}
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
} else {
stole_lock = 0;
sn_transmit_chars(port, 1);
spin_unlock_irqrestore(&port->sc_port.lock, flags);
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
}
}
/**
* sn_sal_console_setup - Set up console for early printing
* @co: Console to work with
* @options: Options to set
*
* Altix console doesn't do anything with baud rates, etc, anyway.
*
* This isn't required since not providing the setup function in the
* console struct is ok. However, other patches like KDB plop something
* here so providing it is easier.
*
*/
static int sn_sal_console_setup(struct console *co, char *options)
{
return 0;
}
/**
* sn_sal_console_write_early - simple early output routine
* @co - console struct
* @s - string to print
* @count - count
*
* Simple function to provide early output, before even
* sn_sal_serial_console_init is called. Referenced in the
* console struct registerd in sn_serial_console_early_setup.
*
*/
static void __init
sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
{
puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
}
/* Used for very early console printing - again, before
* sn_sal_serial_console_init is run */
static struct console sal_console_early __initdata = {
.name = "sn_sal",
.write = sn_sal_console_write_early,
.flags = CON_PRINTBUFFER,
.index = -1,
};
/**
* sn_serial_console_early_setup - Sets up early console output support
*
* Register a console early on... This is for output before even
* sn_sal_serial_cosnole_init is called. This function is called from
* setup.c. This allows us to do really early polled writes. When
* sn_sal_serial_console_init is called, this console is unregistered
* and a new one registered.
*/
int __init sn_serial_console_early_setup(void)
{
if (!ia64_platform_is("sn2"))
return -1;
sal_console_port.sc_ops = &poll_ops;
spin_lock_init(&sal_console_port.sc_port.lock);
early_sn_setup(); /* Find SAL entry points */
register_console(&sal_console_early);
return 0;
}
/**
* sn_sal_serial_console_init - Early console output - set up for register
*
* This function is called when regular console init happens. Because we
* support even earlier console output with sn_serial_console_early_setup
* (called from setup.c directly), this function unregisters the really
* early console.
*
* Note: Even if setup.c doesn't register sal_console_early, unregistering
* it here doesn't hurt anything.
*
*/
static int __init sn_sal_serial_console_init(void)
{
if (ia64_platform_is("sn2")) {
sn_sal_switch_to_asynch(&sal_console_port);
DPRINTF("sn_sal_serial_console_init : register console\n");
register_console(&sal_console);
unregister_console(&sal_console_early);
}
return 0;
}
console_initcall(sn_sal_serial_console_init);