diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 09:46:57 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 09:46:57 -0700 |
commit | 55e32a4d9095c0fa0e22e730151a4255c86bee71 (patch) | |
tree | c2f286b98d6e904aec54f9633530873a9b4cee1e | |
parent | eac3d97d10da4d8904524cee5e8dcd63067583d8 (diff) | |
download | ltsi-kernel-55e32a4d9095c0fa0e22e730151a4255c86bee71.tar.gz |
more kzm9g patches added
64 files changed, 13375 insertions, 0 deletions
diff --git a/patches.kzm9g/0001-tty-serial-allow-ports-to-override-the-irq-handler.patch b/patches.kzm9g/0001-tty-serial-allow-ports-to-override-the-irq-handler.patch new file mode 100644 index 00000000000000..3d7f126e8a3640 --- /dev/null +++ b/patches.kzm9g/0001-tty-serial-allow-ports-to-override-the-irq-handler.patch @@ -0,0 +1,36 @@ +From bc8d01eecbc317f8f39268b1e5e4fcb9ac1d89af Mon Sep 17 00:00:00 2001 +From: Jamie Iles <jamie@jamieiles.com> +Date: Mon, 15 Aug 2011 10:17:51 +0100 +Subject: tty: serial: allow ports to override the irq handler + +Some serial ports may have unusal requirements for interrupt handling +(e.g. the Synopsys DesignWare 8250-alike port and it's busy detect +interrupt). Add a .handle_irq callback that can be used for platforms +to override the interrupt behaviour in a similar fashion to the +.serial_out and .serial_in callbacks. + +Signed-off-by: Jamie Iles <jamie@jamieiles.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit a74036f51272975e9538e80cd1bb64dce164b208) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + include/linux/serial_core.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index a5c3114..b6fa317 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -300,6 +300,7 @@ struct uart_port { + void (*set_termios)(struct uart_port *, + struct ktermios *new, + struct ktermios *old); ++ int (*handle_irq)(struct uart_port *); + void (*pm)(struct uart_port *, unsigned int state, + unsigned int old); + unsigned int irq; /* irq number */ +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0002-serial-introduce-generic-port-in-out-helpers.patch b/patches.kzm9g/0002-serial-introduce-generic-port-in-out-helpers.patch new file mode 100644 index 00000000000000..377a496df1eb0e --- /dev/null +++ b/patches.kzm9g/0002-serial-introduce-generic-port-in-out-helpers.patch @@ -0,0 +1,53 @@ +From 790111bbb9291b79c960d33b406ccc7ab9833a76 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:12 -0500 +Subject: serial: introduce generic port in/out helpers + +Looking at the existing serial drivers (esp. the 8250 derived +variants) we see a common trend. They create a hardware specific +port struct, which in turn contains a generic serial_port struct. + +The other trend, is that they all create some sort of shortcut +to go through the hardware specific struct, to the serial_port +struct, which has the basic in/out operations within. Looking +for the serial_in and serial_out in several drivers shows this. + +Rather than let this continue, lets create a generic set of +similar helper wrappers that can be used on a struct port, so +we can eliminate bouncing out through hardware specific struct +pointers just to come back into struct port where possible. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 927353a75602dd97144352f53177e18093fdd198) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + include/linux/serial_core.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index b6fa317..1cb6309 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -376,6 +376,16 @@ struct uart_port { + void *private_data; /* generic platform data pointer */ + }; + ++static inline int serial_port_in(struct uart_port *up, int offset) ++{ ++ return up->serial_in(up, offset); ++} ++ ++static inline void serial_port_out(struct uart_port *up, int offset, int value) ++{ ++ up->serial_out(up, offset, value); ++} ++ + /* + * This is the state information which is persistent across opens. + */ +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0003-serial-8250-increase-PASS_LIMIT.patch b/patches.kzm9g/0003-serial-8250-increase-PASS_LIMIT.patch new file mode 100644 index 00000000000000..f2433d9055fa8a --- /dev/null +++ b/patches.kzm9g/0003-serial-8250-increase-PASS_LIMIT.patch @@ -0,0 +1,39 @@ +From 0028c21552eb37ad26e53e0d6d0a977d886b0abf Mon Sep 17 00:00:00 2001 +From: Jiri Slaby <jirislaby@gmail.com> +Date: Sun, 5 Jun 2011 22:51:49 +0200 +Subject: serial: 8250, increase PASS_LIMIT + +With virtual machines like qemu, it's pretty common to see "too much +work for irq4" messages nowadays. This happens when a bunch of output +is printed on the emulated serial console. This is caused by too low +PASS_LIMIT. When ISR loops more than the limit, it spits the message. + +I've been using a kernel with doubled the limit and I couldn't see no +problems. Maybe it's time to get rid of the message now? + +Signed-off-by: Jiri Slaby <jirislaby@gmail.com> +Cc: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit e7328ae1848966181a7ac47e8ae6cddbd2cf55f3) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 762ce72..7f50999 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -81,7 +81,7 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ + #define DEBUG_INTR(fmt...) do { } while (0) + #endif + +-#define PASS_LIMIT 256 ++#define PASS_LIMIT 512 + + #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0004-serial-Fix-wakeup-init-logic-to-speed-up-startup.patch b/patches.kzm9g/0004-serial-Fix-wakeup-init-logic-to-speed-up-startup.patch new file mode 100644 index 00000000000000..6a58103c6edb37 --- /dev/null +++ b/patches.kzm9g/0004-serial-Fix-wakeup-init-logic-to-speed-up-startup.patch @@ -0,0 +1,60 @@ +From da29566854e9ffb6770255fbd915184073d2d0b1 Mon Sep 17 00:00:00 2001 +From: Simon Glass <sjg@chromium.org> +Date: Thu, 19 Jan 2012 11:28:56 -0800 +Subject: serial: Fix wakeup init logic to speed up startup + +The synchronize_rcu() call resulting from making every serial driver +wake-up capable (commit b3b708fa) slows boot down on my Tegra2x system +(with CONFIG_PREEMPT disabled). + +But this is avoidable since it is the device_set_wakeup_enable() and then +subsequence disable which causes the delay. We might as well just make +the device wakeup capable but not actually enable it for wakeup until +needed. + +Effectively the current code does this: + + device_set_wakeup_capable(dev, 1); + device_set_wakeup_enable(dev, 1); + device_set_wakeup_enable(dev, 0); + +We can just drop the last two lines. + +Before this change my boot log says: +[ 0.227062] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled +[ 0.702928] serial8250.0: ttyS0 at MMIO 0x70006040 (irq = 69) is a Tegra + +after: +[ 0.227264] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled +[ 0.227983] serial8250.0: ttyS0 at MMIO 0x70006040 (irq = 69) is a Tegra + +for saving of 450ms. + +Suggested-by: Rafael J. Wysocki <rjw@sisk.pl> +Acked-by: Rafael J. Wysocki <rjw@sisk.pl> +Signed-off-by: Simon Glass <sjg@chromium.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 773598357c0baf03081cf87f2b444f97744faf1e) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/serial_core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -2391,11 +2391,11 @@ int uart_add_one_port(struct uart_driver + */ + tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); + if (likely(!IS_ERR(tty_dev))) { +- device_init_wakeup(tty_dev, 1); +- device_set_wakeup_enable(tty_dev, 0); +- } else ++ device_set_wakeup_capable(tty_dev, 1); ++ } else { + printk(KERN_ERR "Cannot register tty device on line %d\n", + uport->line); ++ } + + /* + * Ensure UPF_DEAD is not set. diff --git a/patches.kzm9g/0005-tty-serial8250-allow-platforms-to-override-irq-handl.patch b/patches.kzm9g/0005-tty-serial8250-allow-platforms-to-override-irq-handl.patch new file mode 100644 index 00000000000000..a12baef1285a9a --- /dev/null +++ b/patches.kzm9g/0005-tty-serial8250-allow-platforms-to-override-irq-handl.patch @@ -0,0 +1,140 @@ +From 5d815ba3618efabed3571204df30a309d2471aee Mon Sep 17 00:00:00 2001 +From: Jamie Iles <jamie@jamieiles.com> +Date: Mon, 15 Aug 2011 10:17:52 +0100 +Subject: tty: serial8250: allow platforms to override irq handler + +Some ports (e.g. Synopsys DesignWare 8250) have special requirements for +handling the interrupts. Allow these platforms to specify their own +interrupt handler that will override the default. +serial8250_handle_irq() is provided so that platforms can extend the IRQ +handler rather than completely replacing it. + +Signed-off-by: Jamie Iles <jamie@jamieiles.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 583d28e92f667eb6cc81ea87daaa7e321c23fe14) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 39 +++++++++++++++++++++++++++++++++++---- + include/linux/serial_8250.h | 2 ++ + 2 files changed, 37 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 7f50999..97007e5 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -509,6 +509,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value) + outb(value, p->iobase + offset); + } + ++static int serial8250_default_handle_irq(struct uart_port *port); ++ + static void set_io_from_upio(struct uart_port *p) + { + struct uart_8250_port *up = +@@ -557,6 +559,7 @@ static void set_io_from_upio(struct uart_port *p) + } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; ++ p->handle_irq = serial8250_default_handle_irq; + } + + static void +@@ -1621,6 +1624,28 @@ static void serial8250_handle_port(struct uart_8250_port *up) + spin_unlock_irqrestore(&up->port.lock, flags); + } + ++int serial8250_handle_irq(struct uart_port *port, unsigned int iir) ++{ ++ struct uart_8250_port *up = ++ container_of(port, struct uart_8250_port, port); ++ ++ if (!(iir & UART_IIR_NO_INT)) { ++ serial8250_handle_port(up); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int serial8250_default_handle_irq(struct uart_port *port) ++{ ++ struct uart_8250_port *up = ++ container_of(port, struct uart_8250_port, port); ++ unsigned int iir = serial_in(up, UART_IIR); ++ ++ return serial8250_handle_irq(port, iir); ++} ++ + /* + * This is the serial driver's interrupt routine. + * +@@ -1648,13 +1673,12 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) + l = i->head; + do { + struct uart_8250_port *up; +- unsigned int iir; ++ struct uart_port *port; + + up = list_entry(l, struct uart_8250_port, list); ++ port = &up->port; + +- iir = serial_in(up, UART_IIR); +- if (!(iir & UART_IIR_NO_INT)) { +- serial8250_handle_port(up); ++ if (port->handle_irq(port)) { + + handled = 1; + +@@ -3050,6 +3074,10 @@ int __init early_serial_setup(struct uart_port *port) + p->serial_in = port->serial_in; + if (port->serial_out) + p->serial_out = port->serial_out; ++ if (port->handle_irq) ++ p->handle_irq = port->handle_irq; ++ else ++ p->handle_irq = serial8250_default_handle_irq; + + return 0; + } +@@ -3118,6 +3146,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) + port.type = p->type; + port.serial_in = p->serial_in; + port.serial_out = p->serial_out; ++ port.handle_irq = p->handle_irq; + port.set_termios = p->set_termios; + port.pm = p->pm; + port.dev = &dev->dev; +@@ -3283,6 +3312,8 @@ int serial8250_register_port(struct uart_port *port) + uart->port.serial_in = port->serial_in; + if (port->serial_out) + uart->port.serial_out = port->serial_out; ++ if (port->handle_irq) ++ uart->port.handle_irq = port->handle_irq; + /* Possibly override set_termios call */ + if (port->set_termios) + uart->port.set_termios = port->set_termios; +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index 97f5b45..1f05bbe 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -35,6 +35,7 @@ struct plat_serial8250_port { + void (*set_termios)(struct uart_port *, + struct ktermios *new, + struct ktermios *old); ++ int (*handle_irq)(struct uart_port *); + void (*pm)(struct uart_port *, unsigned int state, + unsigned old); + }; +@@ -80,6 +81,7 @@ extern void serial8250_do_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old); + extern void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate); ++int serial8250_handle_irq(struct uart_port *port, unsigned int iir); + + extern void serial8250_set_isa_configurator(void (*v) + (int port, struct uart_port *up, +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0006-tty-serial8250-remove-UPIO_DWAPB-32.patch b/patches.kzm9g/0006-tty-serial8250-remove-UPIO_DWAPB-32.patch new file mode 100644 index 00000000000000..098799ff62900b --- /dev/null +++ b/patches.kzm9g/0006-tty-serial8250-remove-UPIO_DWAPB-32.patch @@ -0,0 +1,167 @@ +From ea7db772ed2f7cf3ce5d40ea3da4f4ead0505fb2 Mon Sep 17 00:00:00 2001 +From: Jamie Iles <jamie@jamieiles.com> +Date: Mon, 15 Aug 2011 10:17:55 +0100 +Subject: tty: serial8250: remove UPIO_DWAPB{,32} + +Now that platforms can override the port IRQ handler and the only user +of these UPIO modes has been converted over, kill off UPIO_DWAPB and +UPIO_DWAPB32. + +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Jamie Iles <jamie@jamieiles.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 4834d028978583dfe8e1fc19f1180ceb03d8dfb7) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 68 --------------------------------------- + drivers/tty/serial/serial_core.c | 4 -- + include/linux/serial_core.h | 4 -- + 3 files changed, 1 insertion(+), 75 deletions(-) + +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -461,42 +461,6 @@ static void tsi_serial_out(struct uart_p + writeb(value, p->membase + offset); + } + +-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ +-static inline void dwapb_save_out_value(struct uart_port *p, int offset, +- int value) +-{ +- struct uart_8250_port *up = +- container_of(p, struct uart_8250_port, port); +- +- if (offset == UART_LCR) +- up->lcr = value; +-} +- +-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */ +-static inline void dwapb_check_clear_ier(struct uart_port *p, int offset) +-{ +- if (offset == UART_TX || offset == UART_IER) +- p->serial_in(p, UART_IER); +-} +- +-static void dwapb_serial_out(struct uart_port *p, int offset, int value) +-{ +- int save_offset = offset; +- offset = map_8250_out_reg(p, offset) << p->regshift; +- dwapb_save_out_value(p, save_offset, value); +- writeb(value, p->membase + offset); +- dwapb_check_clear_ier(p, save_offset); +-} +- +-static void dwapb32_serial_out(struct uart_port *p, int offset, int value) +-{ +- int save_offset = offset; +- offset = map_8250_out_reg(p, offset) << p->regshift; +- dwapb_save_out_value(p, save_offset, value); +- writel(value, p->membase + offset); +- dwapb_check_clear_ier(p, save_offset); +-} +- + static unsigned int io_serial_in(struct uart_port *p, int offset) + { + offset = map_8250_in_reg(p, offset) << p->regshift; +@@ -542,16 +506,6 @@ static void set_io_from_upio(struct uart + p->serial_out = tsi_serial_out; + break; + +- case UPIO_DWAPB: +- p->serial_in = mem_serial_in; +- p->serial_out = dwapb_serial_out; +- break; +- +- case UPIO_DWAPB32: +- p->serial_in = mem32_serial_in; +- p->serial_out = dwapb32_serial_out; +- break; +- + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; +@@ -570,8 +524,6 @@ serial_out_sync(struct uart_8250_port *u + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: +- case UPIO_DWAPB: +- case UPIO_DWAPB32: + p->serial_out(p, offset, value); + p->serial_in(p, UART_LCR); /* safe, no side-effects */ + break; +@@ -1679,23 +1631,7 @@ static irqreturn_t serial8250_interrupt( + port = &up->port; + + if (port->handle_irq(port)) { +- + handled = 1; +- +- end = NULL; +- } else if ((up->port.iotype == UPIO_DWAPB || +- up->port.iotype == UPIO_DWAPB32) && +- (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { +- /* The DesignWare APB UART has an Busy Detect (0x07) +- * interrupt meaning an LCR write attempt occurred while the +- * UART was busy. The interrupt must be cleared by reading +- * the UART status register (USR) and the LCR re-written. */ +- unsigned int status; +- status = *(volatile u32 *)up->port.private_data; +- serial_out(up, UART_LCR, up->lcr); +- +- handled = 1; +- + end = NULL; + } else if (end == NULL) + end = l; +@@ -2594,8 +2530,6 @@ static int serial8250_request_std_resour + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: +- case UPIO_DWAPB: +- case UPIO_DWAPB32: + if (!up->port.mapbase) + break; + +@@ -2632,8 +2566,6 @@ static void serial8250_release_std_resou + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: +- case UPIO_DWAPB: +- case UPIO_DWAPB32: + if (!up->port.mapbase) + break; + +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -2065,8 +2065,6 @@ uart_report_port(struct uart_driver *drv + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: +- case UPIO_DWAPB: +- case UPIO_DWAPB32: + snprintf(address, sizeof(address), + "MMIO 0x%llx", (unsigned long long)port->mapbase); + break; +@@ -2487,8 +2485,6 @@ int uart_match_port(struct uart_port *po + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: +- case UPIO_DWAPB: +- case UPIO_DWAPB32: + return (port1->mapbase == port2->mapbase); + } + return 0; +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -318,9 +318,7 @@ struct uart_port { + #define UPIO_MEM32 (3) + #define UPIO_AU (4) /* Au1x00 type IO */ + #define UPIO_TSI (5) /* Tsi108/109 type IO */ +-#define UPIO_DWAPB (6) /* DesignWare APB UART */ +-#define UPIO_RM9000 (7) /* RM9000 type IO */ +-#define UPIO_DWAPB32 (8) /* DesignWare APB UART (32 bit accesses) */ ++#define UPIO_RM9000 (6) /* RM9000 type IO */ + + unsigned int read_status_mask; /* driver specific */ + unsigned int ignore_status_mask; /* driver specific */ diff --git a/patches.kzm9g/0007-tty-8250-export-serial8250_handle_irq.patch b/patches.kzm9g/0007-tty-8250-export-serial8250_handle_irq.patch new file mode 100644 index 00000000000000..3d88d9e48044bb --- /dev/null +++ b/patches.kzm9g/0007-tty-8250-export-serial8250_handle_irq.patch @@ -0,0 +1,32 @@ +From e54750f312943c2135375552a80f417f969ec95f Mon Sep 17 00:00:00 2001 +From: Jamie Iles <jamie@jamieiles.com> +Date: Fri, 26 Aug 2011 19:04:49 +0100 +Subject: tty: 8250: export serial8250_handle_irq + +Allow modules to use the normal 8250 irq handler inside their own. + +Cc: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jamie Iles <jamie@jamieiles.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit c7a1bdc5c951aae15021d13e3f5c0b2fe9d56112) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 5d92b93..454fc92 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -1588,6 +1588,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + + return 0; + } ++EXPORT_SYMBOL_GPL(serial8250_handle_irq); + + static int serial8250_default_handle_irq(struct uart_port *port) + { +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0008-serial-8250-Move-UPIO_TSI-to-powerpc.patch b/patches.kzm9g/0008-serial-8250-Move-UPIO_TSI-to-powerpc.patch new file mode 100644 index 00000000000000..c6b2a860b26229 --- /dev/null +++ b/patches.kzm9g/0008-serial-8250-Move-UPIO_TSI-to-powerpc.patch @@ -0,0 +1,129 @@ +From 173bc58b2e469e0f92a58de4b3644e171895300f Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann <arnd@arndb.de> +Date: Mon, 27 Jun 2011 11:45:16 +0000 +Subject: serial/8250: Move UPIO_TSI to powerpc + +This iotype is only used by the legacy_serial code in powerpc, so the +code should live there, rather than be compiled in for every 8250 +driver. + +Signed-off-by: Arnd Bergmann <arnd@arndb.de> +Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> +Cc: linuxppc-dev@lists.ozlabs.org +Cc: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-serial@vger.kernel.org +Acked-by: David Daney <david.daney@cavium.com> +Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> +(cherry picked from commit 7df5659eefad9b6d457ccdee016bd78bd064cfc0) + +Conflicts: + + drivers/tty/serial/8250.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/powerpc/kernel/legacy_serial.c | 25 +++++++++++++++++++++++++ + drivers/tty/serial/8250.c | 23 ----------------------- + 2 files changed, 25 insertions(+), 23 deletions(-) + +diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c +index 2b97b80..c7b5afe 100644 +--- a/arch/powerpc/kernel/legacy_serial.c ++++ b/arch/powerpc/kernel/legacy_serial.c +@@ -6,6 +6,7 @@ + #include <linux/pci.h> + #include <linux/of_address.h> + #include <linux/of_device.h> ++#include <linux/serial_reg.h> + #include <asm/io.h> + #include <asm/mmu.h> + #include <asm/prom.h> +@@ -47,6 +48,24 @@ static struct __initdata of_device_id legacy_serial_parents[] = { + static unsigned int legacy_serial_count; + static int legacy_serial_console = -1; + ++static unsigned int tsi_serial_in(struct uart_port *p, int offset) ++{ ++ unsigned int tmp; ++ offset = offset << p->regshift; ++ if (offset == UART_IIR) { ++ tmp = readl(p->membase + (UART_IIR & ~3)); ++ return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ ++ } else ++ return readb(p->membase + offset); ++} ++ ++static void tsi_serial_out(struct uart_port *p, int offset, int value) ++{ ++ offset = offset << p->regshift; ++ if (!((offset == UART_IER) && (value & UART_IER_UUE))) ++ writeb(value, p->membase + offset); ++} ++ + static int __init add_legacy_port(struct device_node *np, int want_index, + int iotype, phys_addr_t base, + phys_addr_t taddr, unsigned long irq, +@@ -102,6 +121,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, + legacy_serial_ports[index].iobase = base; + else + legacy_serial_ports[index].mapbase = base; ++ + legacy_serial_ports[index].iotype = iotype; + legacy_serial_ports[index].uartclk = clock; + legacy_serial_ports[index].irq = irq; +@@ -112,6 +132,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index, + legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0; + legacy_serial_infos[index].irq_check_parent = irq_check_parent; + ++ if (iotype == UPIO_TSI) { ++ legacy_serial_ports[index].serial_in = tsi_serial_in; ++ legacy_serial_ports[index].serial_out = tsi_serial_out; ++ } ++ + printk(KERN_DEBUG "Found legacy serial port %d for %s\n", + index, np->full_name); + printk(KERN_DEBUG " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n", +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 454fc92..a0e502b 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -443,24 +443,6 @@ static void au_serial_out(struct uart_port *p, int offset, int value) + __raw_writel(value, p->membase + offset); + } + +-static unsigned int tsi_serial_in(struct uart_port *p, int offset) +-{ +- unsigned int tmp; +- offset = map_8250_in_reg(p, offset) << p->regshift; +- if (offset == UART_IIR) { +- tmp = readl(p->membase + (UART_IIR & ~3)); +- return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ +- } else +- return readb(p->membase + offset); +-} +- +-static void tsi_serial_out(struct uart_port *p, int offset, int value) +-{ +- offset = map_8250_out_reg(p, offset) << p->regshift; +- if (!((offset == UART_IER) && (value & UART_IER_UUE))) +- writeb(value, p->membase + offset); +-} +- + static unsigned int io_serial_in(struct uart_port *p, int offset) + { + offset = map_8250_in_reg(p, offset) << p->regshift; +@@ -501,11 +483,6 @@ static void set_io_from_upio(struct uart_port *p) + p->serial_out = au_serial_out; + break; + +- case UPIO_TSI: +- p->serial_in = tsi_serial_in; +- p->serial_out = tsi_serial_out; +- break; +- + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0009-serial-Support-the-EFR-register-of-XR1715x-uarts.patch b/patches.kzm9g/0009-serial-Support-the-EFR-register-of-XR1715x-uarts.patch new file mode 100644 index 00000000000000..43c28f5c3a3329 --- /dev/null +++ b/patches.kzm9g/0009-serial-Support-the-EFR-register-of-XR1715x-uarts.patch @@ -0,0 +1,159 @@ +From 5df029e7baab27a7b6f848739659865a006820f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?S=C3=B8ren=20Holm?= <sgh@sgh.dk> +Date: Fri, 2 Sep 2011 22:55:37 +0200 +Subject: serial: Support the EFR-register of XR1715x uarts. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The EFR (Enhenced-Features-Register) is located at a different offset +than the other devices supporting UART_CAP_EFR. This change add a special +setup quick to set UPF_EXAR_EFR on the port. UPF_EXAR_EFR is then used to +the port type to PORT_XR17D15X since it is for sure a XR17D15X uart. + +Signed-off-by: Søren Holm <sgh@sgh.dk> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 06315348b16178e4c006e7892ef8e5e65f49c66a) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 20 +++++++++++++++++++- + drivers/tty/serial/8250_pci.c | 33 +++++++++++++++++++++++++++++++++ + include/linux/serial_core.h | 4 +++- + include/linux/serial_reg.h | 1 + + 4 files changed, 56 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index a0e502b..69802bd 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -309,6 +309,13 @@ static const struct serial8250_config uart_config[] = { + UART_FCR_T_TRIG_01, + .flags = UART_CAP_FIFO | UART_CAP_RTOIE, + }, ++ [PORT_XR17D15X] = { ++ .name = "XR17D15X", ++ .fifo_size = 64, ++ .tx_loadsz = 64, ++ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, ++ .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, ++ }, + }; + + #if defined(CONFIG_MIPS_ALCHEMY) +@@ -1052,6 +1059,14 @@ static void autoconfig_16550a(struct uart_8250_port *up) + serial_outp(up, UART_IER, iersave); + + /* ++ * Exar uarts have EFR in a weird location ++ */ ++ if (up->port.flags & UPF_EXAR_EFR) { ++ up->port.type = PORT_XR17D15X; ++ up->capabilities |= UART_CAP_AFE | UART_CAP_EFR; ++ } ++ ++ /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. + */ +@@ -2396,7 +2411,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + efr |= UART_EFR_CTS; + + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(up, UART_EFR, efr); ++ if (up->port.flags & UPF_EXAR_EFR) ++ serial_outp(up, UART_XR_EFR, efr); ++ else ++ serial_outp(up, UART_EFR, efr); + } + + #ifdef CONFIG_ARCH_OMAP +diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c +index ff48fdb..a213f38 100644 +--- a/drivers/tty/serial/8250_pci.c ++++ b/drivers/tty/serial/8250_pci.c +@@ -1003,6 +1003,15 @@ static int pci_eg20t_init(struct pci_dev *dev) + #endif + } + ++static int ++pci_xr17c154_setup(struct serial_private *priv, ++ const struct pciserial_board *board, ++ struct uart_port *port, int idx) ++{ ++ port->flags |= UPF_EXAR_EFR; ++ return pci_default_setup(priv, board, port, idx); ++} ++ + /* This should be in linux/pci_ids.h */ + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B + #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B +@@ -1407,6 +1416,30 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { + .setup = pci_timedia_setup, + }, + /* ++ * Exar cards ++ */ ++ { ++ .vendor = PCI_VENDOR_ID_EXAR, ++ .device = PCI_DEVICE_ID_EXAR_XR17C152, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .setup = pci_xr17c154_setup, ++ }, ++ { ++ .vendor = PCI_VENDOR_ID_EXAR, ++ .device = PCI_DEVICE_ID_EXAR_XR17C154, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .setup = pci_xr17c154_setup, ++ }, ++ { ++ .vendor = PCI_VENDOR_ID_EXAR, ++ .device = PCI_DEVICE_ID_EXAR_XR17C158, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .setup = pci_xr17c154_setup, ++ }, ++ /* + * Xircom cards + */ + { +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index 4880024..d611ca0 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -46,7 +46,8 @@ + #define PORT_AR7 18 /* Texas Instruments AR7 internal UART */ + #define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */ + #define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */ +-#define PORT_MAX_8250 20 /* max port ID */ ++#define PORT_XR17D15X 21 /* Exar XR17D15x UART */ ++#define PORT_MAX_8250 21 /* max port ID */ + + /* + * ARM specific type numbers. These are not currently guaranteed +@@ -349,6 +350,7 @@ struct uart_port { + #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) + #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) + #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) ++#define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) + /* The exact UART type is known and should not be probed. */ + #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) + #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) +diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h +index c75bda3..8ce70d7 100644 +--- a/include/linux/serial_reg.h ++++ b/include/linux/serial_reg.h +@@ -152,6 +152,7 @@ + * LCR=0xBF (or DLAB=1 for 16C660) + */ + #define UART_EFR 2 /* I/O: Extended Features Register */ ++#define UART_XR_EFR 9 /* I/O: Extended Features Register (XR17D15x) */ + #define UART_EFR_CTS 0x80 /* CTS flow control */ + #define UART_EFR_RTS 0x40 /* RTS flow control */ + #define UART_EFR_SCD 0x20 /* Special character detect */ +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0010-8250-ratelimit-LSR-safety-check-engaged-warning.patch b/patches.kzm9g/0010-8250-ratelimit-LSR-safety-check-engaged-warning.patch new file mode 100644 index 00000000000000..14fcdd5e5e0251 --- /dev/null +++ b/patches.kzm9g/0010-8250-ratelimit-LSR-safety-check-engaged-warning.patch @@ -0,0 +1,44 @@ +From 72ad6d3c5d84c98203676d587b25898690591ab7 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> +Date: Mon, 26 Sep 2011 09:14:34 -0400 +Subject: 8250: ratelimit LSR safety check engaged warning. + +On my BIOSTAR TA890FXE the ttyS0 ends up spewing: + +[904682.485933] ttyS0: LSR safety check engaged! +[904692.505895] ttyS0: LSR safety check engaged! +[904702.525972] ttyS0: LSR safety check engaged! +[904712.545967] ttyS0: LSR safety check engaged! +[904722.566125] ttyS0: LSR safety check engaged! +.. +lets limit it so it won't be the only thing visible +in the ring buffer. + +CC: Alan Cox <alan@linux.intel.com> +Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 7808a4c4853fa0203085cf2217e01823d9f0c70c) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 69802bd..eeadf1b 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -2034,8 +2034,8 @@ static int serial8250_startup(struct uart_port *port) + */ + if (!(up->port.flags & UPF_BUGGY_UART) && + (serial_inp(up, UART_LSR) == 0xff)) { +- printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", +- serial_index(&up->port)); ++ printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", ++ serial_index(&up->port)); + return -ENODEV; + } + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0011-serial-8250-replace-hardcoded-0xbf-with-define.patch b/patches.kzm9g/0011-serial-8250-replace-hardcoded-0xbf-with-define.patch new file mode 100644 index 00000000000000..97c8003f6ac0d1 --- /dev/null +++ b/patches.kzm9g/0011-serial-8250-replace-hardcoded-0xbf-with-define.patch @@ -0,0 +1,33 @@ +From 698dcc00ab4b72502d3b69bf1167b7c3977f5e5a Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Fri, 9 Dec 2011 18:07:13 +0100 +Subject: serial: 8250: replace hardcoded 0xbf with #define + +Makes it easier to find all occurences requesting CONF_MODE_B. + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 7d73aaf1d45d9bd95638680361db4d019ebb75bb) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index eeadf1b..f8f2320 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -2000,7 +2000,7 @@ static int serial8250_startup(struct uart_port *port) + serial_outp(up, UART_IER, 0); + serial_outp(up, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ +- serial_outp(up, UART_LCR, 0xBF); ++ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_LCR, 0); + } +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0012-serial-move-struct-uart_8250_port-from-8250.c-to-825.patch b/patches.kzm9g/0012-serial-move-struct-uart_8250_port-from-8250.c-to-825.patch new file mode 100644 index 00000000000000..1c8f17df539bfc --- /dev/null +++ b/patches.kzm9g/0012-serial-move-struct-uart_8250_port-from-8250.c-to-825.patch @@ -0,0 +1,98 @@ +From 028e3de52cdfd054b54d0ff7c2b576aaf299a1df Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Sun, 4 Dec 2011 18:42:18 -0500 +Subject: serial: move struct uart_8250_port from 8250.c to 8250.h + +Since we want to promote sharing and move away from one single +uart driver with a bunch of platform specific bugfixes all +munged into one, relocate some header like material from +the C file to the header. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 850624c15da4651f4c6b821723419d8777659577) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 26 -------------------------- + drivers/tty/serial/8250.h | 26 ++++++++++++++++++++++++++ + 2 files changed, 26 insertions(+), 26 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index f8f2320..4a60d74 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -129,32 +129,6 @@ static unsigned long probe_rsa[PORT_RSA_MAX]; + static unsigned int probe_rsa_count; + #endif /* CONFIG_SERIAL_8250_RSA */ + +-struct uart_8250_port { +- struct uart_port port; +- struct timer_list timer; /* "no irq" timer */ +- struct list_head list; /* ports on this IRQ */ +- unsigned short capabilities; /* port capabilities */ +- unsigned short bugs; /* port bugs */ +- unsigned int tx_loadsz; /* transmit fifo load size */ +- unsigned char acr; +- unsigned char ier; +- unsigned char lcr; +- unsigned char mcr; +- unsigned char mcr_mask; /* mask of user bits */ +- unsigned char mcr_force; /* mask of forced bits */ +- unsigned char cur_iotype; /* Running I/O type */ +- +- /* +- * Some bits in registers are cleared on a read, so they must +- * be saved whenever the register is read but the bits will not +- * be immediately processed. +- */ +-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS +- unsigned char lsr_saved_flags; +-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA +- unsigned char msr_saved_flags; +-}; +- + struct irq_info { + struct hlist_node node; + int irq; +diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250.h +index 6edf4a6..ae027be 100644 +--- a/drivers/tty/serial/8250.h ++++ b/drivers/tty/serial/8250.h +@@ -13,6 +13,32 @@ + + #include <linux/serial_8250.h> + ++struct uart_8250_port { ++ struct uart_port port; ++ struct timer_list timer; /* "no irq" timer */ ++ struct list_head list; /* ports on this IRQ */ ++ unsigned short capabilities; /* port capabilities */ ++ unsigned short bugs; /* port bugs */ ++ unsigned int tx_loadsz; /* transmit fifo load size */ ++ unsigned char acr; ++ unsigned char ier; ++ unsigned char lcr; ++ unsigned char mcr; ++ unsigned char mcr_mask; /* mask of user bits */ ++ unsigned char mcr_force; /* mask of forced bits */ ++ unsigned char cur_iotype; /* Running I/O type */ ++ ++ /* ++ * Some bits in registers are cleared on a read, so they must ++ * be saved whenever the register is read but the bits will not ++ * be immediately processed. ++ */ ++#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS ++ unsigned char lsr_saved_flags; ++#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA ++ unsigned char msr_saved_flags; ++}; ++ + struct old_serial_port { + unsigned int uart; + unsigned int baud_base; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0013-serial-clean-up-parameter-passing-for-8250-Rx-IRQ-ha.patch b/patches.kzm9g/0013-serial-clean-up-parameter-passing-for-8250-Rx-IRQ-ha.patch new file mode 100644 index 00000000000000..918651f8c8b27b --- /dev/null +++ b/patches.kzm9g/0013-serial-clean-up-parameter-passing-for-8250-Rx-IRQ-ha.patch @@ -0,0 +1,79 @@ +From 955d6b2ede1041858602dacb15c624bf8aa325f8 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Sun, 4 Dec 2011 18:42:19 -0500 +Subject: serial: clean up parameter passing for 8250 Rx IRQ handling + +The receive_chars() was taking a pointer to a passed in LSR value +in status and knocking off bits as it processed them. But since +receive_chars isn't returning a value, we can instead pass in +a normal non-pointer value for LSR, and simply return the +residual (unprocessed) LSR once it is done. + +The value in this cleanup, is that it clarifies the API of the +receive_chars prior to exporting it to other 8250-like drivers +for shared usage. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 0690f41fddd285c3473e4af2a42d15bce7ff3e68) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index 4a60d74..fbcd8a5 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -1375,11 +1375,16 @@ static void clear_rx_fifo(struct uart_8250_port *up) + } while (1); + } + +-static void +-receive_chars(struct uart_8250_port *up, unsigned int *status) ++/* ++ * receive_chars: processes according to the passed in LSR ++ * value, and returns the remaining LSR bits not handled ++ * by this Rx routine. ++ */ ++static unsigned char ++receive_chars(struct uart_8250_port *up, unsigned char lsr) + { + struct tty_struct *tty = up->port.state->port.tty; +- unsigned char ch, lsr = *status; ++ unsigned char ch; + int max_count = 256; + char flag; + +@@ -1455,7 +1460,7 @@ ignore_char: + spin_unlock(&up->port.lock); + tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); +- *status = lsr; ++ return lsr; + } + + static void transmit_chars(struct uart_8250_port *up) +@@ -1524,7 +1529,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) + */ + static void serial8250_handle_port(struct uart_8250_port *up) + { +- unsigned int status; ++ unsigned char status; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); +@@ -1534,7 +1539,7 @@ static void serial8250_handle_port(struct uart_8250_port *up) + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) +- receive_chars(up, &status); ++ status = receive_chars(up, status); + check_modem_status(up); + if (status & UART_LSR_THRE) + transmit_chars(up); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0014-serial-export-the-key-functions-for-an-8250-IRQ-hand.patch b/patches.kzm9g/0014-serial-export-the-key-functions-for-an-8250-IRQ-hand.patch new file mode 100644 index 00000000000000..04b2ab12162ff9 --- /dev/null +++ b/patches.kzm9g/0014-serial-export-the-key-functions-for-an-8250-IRQ-hand.patch @@ -0,0 +1,161 @@ +From d55f600016446155f3d9a86467566353071c7205 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Sun, 4 Dec 2011 18:42:20 -0500 +Subject: serial: export the key functions for an 8250 IRQ handler + +For drivers that need to construct their own IRQ handler, the +three components are seen in the current handle_port -- i.e. +Rx, Tx and modem_status. + +Make these exported symbols so that "almost" 8250 UARTs can +construct their own IRQ handler with these shared components, +while working around their own unique errata issues. + +The function names are given a serial8250 prefix, since they +are now entering the global namespace. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 3986fb2ba67bb30cac18b0cff48c88d69ad37681) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 29 +++++++++++++++-------------- + include/linux/serial_8250.h | 4 ++++ + 2 files changed, 19 insertions(+), 14 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index fbcd8a5..d759fcc 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -1300,8 +1300,6 @@ static void serial8250_stop_tx(struct uart_port *port) + } + } + +-static void transmit_chars(struct uart_8250_port *up); +- + static void serial8250_start_tx(struct uart_port *port) + { + struct uart_8250_port *up = +@@ -1318,7 +1316,7 @@ static void serial8250_start_tx(struct uart_port *port) + if ((up->port.type == PORT_RM9000) ? + (lsr & UART_LSR_THRE) : + (lsr & UART_LSR_TEMT)) +- transmit_chars(up); ++ serial8250_tx_chars(up); + } + } + +@@ -1376,12 +1374,12 @@ static void clear_rx_fifo(struct uart_8250_port *up) + } + + /* +- * receive_chars: processes according to the passed in LSR ++ * serial8250_rx_chars: processes according to the passed in LSR + * value, and returns the remaining LSR bits not handled + * by this Rx routine. + */ +-static unsigned char +-receive_chars(struct uart_8250_port *up, unsigned char lsr) ++unsigned char ++serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + { + struct tty_struct *tty = up->port.state->port.tty; + unsigned char ch; +@@ -1462,8 +1460,9 @@ ignore_char: + spin_lock(&up->port.lock); + return lsr; + } ++EXPORT_SYMBOL_GPL(serial8250_rx_chars); + +-static void transmit_chars(struct uart_8250_port *up) ++void serial8250_tx_chars(struct uart_8250_port *up) + { + struct circ_buf *xmit = &up->port.state->xmit; + int count; +@@ -1500,8 +1499,9 @@ static void transmit_chars(struct uart_8250_port *up) + if (uart_circ_empty(xmit)) + __stop_tx(up); + } ++EXPORT_SYMBOL_GPL(serial8250_tx_chars); + +-static unsigned int check_modem_status(struct uart_8250_port *up) ++unsigned int serial8250_modem_status(struct uart_8250_port *up) + { + unsigned int status = serial_in(up, UART_MSR); + +@@ -1523,6 +1523,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) + + return status; + } ++EXPORT_SYMBOL_GPL(serial8250_modem_status); + + /* + * This handles the interrupt from one port. +@@ -1539,10 +1540,10 @@ static void serial8250_handle_port(struct uart_8250_port *up) + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) +- status = receive_chars(up, status); +- check_modem_status(up); ++ status = serial8250_rx_chars(up, status); ++ serial8250_modem_status(up); + if (status & UART_LSR_THRE) +- transmit_chars(up); ++ serial8250_tx_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + } +@@ -1780,7 +1781,7 @@ static void serial8250_backup_timeout(unsigned long data) + } + + if (!(iir & UART_IIR_NO_INT)) +- transmit_chars(up); ++ serial8250_tx_chars(up); + + if (is_real_interrupt(up->port.irq)) + serial_out(up, UART_IER, ier); +@@ -1814,7 +1815,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) + unsigned int status; + unsigned int ret; + +- status = check_modem_status(up); ++ status = serial8250_modem_status(up); + + ret = 0; + if (status & UART_MSR_DCD) +@@ -2861,7 +2862,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + * while processing with interrupts off. + */ + if (up->msr_saved_flags) +- check_modem_status(up); ++ serial8250_modem_status(up); + + if (locked) + spin_unlock(&up->port.lock); +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index 1f05bbe..b44034e 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -66,6 +66,7 @@ enum { + * dependent on the 8250 driver. + */ + struct uart_port; ++struct uart_8250_port; + + int serial8250_register_port(struct uart_port *); + void serial8250_unregister_port(int line); +@@ -82,6 +83,9 @@ extern void serial8250_do_set_termios(struct uart_port *port, + extern void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate); + int serial8250_handle_irq(struct uart_port *port, unsigned int iir); ++unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); ++void serial8250_tx_chars(struct uart_8250_port *up); ++unsigned int serial8250_modem_status(struct uart_8250_port *up); + + extern void serial8250_set_isa_configurator(void (*v) + (int port, struct uart_port *up, +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0015-serial-make-8250-timeout-use-the-specified-IRQ-handl.patch b/patches.kzm9g/0015-serial-make-8250-timeout-use-the-specified-IRQ-handl.patch new file mode 100644 index 00000000000000..7205efee649dcb --- /dev/null +++ b/patches.kzm9g/0015-serial-make-8250-timeout-use-the-specified-IRQ-handl.patch @@ -0,0 +1,51 @@ +From 6f7a0cbda97ea6ac36b334a2639275f60f830390 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Sun, 4 Dec 2011 18:42:21 -0500 +Subject: serial: make 8250 timeout use the specified IRQ handler + +The current 8250 timeout code duplicates the code path in +serial8250_default_handle_irq and then serial8250_handle_irq +i.e. reading iir, check for IIR_NO_INT, and then calling +serial8250_handle_port. + +So the immediate thought is to replace the duplicated code +with a call to serial8250_default_handle_irq. + +But this highlights a problem. We let 8250 driver variants +use their own IRQ handler via specifying their own custom +->handle_irq, but in the event of a timeout, we ignore their +handler and implicitly run serial8250_default_handle_irq instead. + +So, go through the struct to get ->handle_irq and call that, +which for most will still be serial8250_default_handle_irq. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit a0431476e95d18bb65349e7bcf98eb10b5ad00b9) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index d759fcc..a5c6c7d 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -1738,11 +1738,8 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) + static void serial8250_timeout(unsigned long data) + { + struct uart_8250_port *up = (struct uart_8250_port *)data; +- unsigned int iir; + +- iir = serial_in(up, UART_IIR); +- if (!(iir & UART_IIR_NO_INT)) +- serial8250_handle_port(up); ++ up->port.handle_irq(&up->port); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); + } + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0016-serial-manually-inline-serial8250_handle_port.patch b/patches.kzm9g/0016-serial-manually-inline-serial8250_handle_port.patch new file mode 100644 index 00000000000000..e14803ceb1e44e --- /dev/null +++ b/patches.kzm9g/0016-serial-manually-inline-serial8250_handle_port.patch @@ -0,0 +1,77 @@ +From f1e4b73758b9bead03589febddcb3dba5132ddf7 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Sun, 4 Dec 2011 18:42:22 -0500 +Subject: serial: manually inline serial8250_handle_port + +Currently serial8250_handle_irq is a trivial wrapper around +serial8250_handle_port, which actually does all the work. + +Since there are no other callers of serial8250_handle_port, we +can just move it inline into serial8250_handle_irq. This also +makes it more clear what functionality any custom IRQ handlers +need to provide if not using serial8250_default_handle_irq. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 86b21199fc45e0052e181fefc07c747e9dc903b3) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250.c | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c +index a5c6c7d..047221d 100644 +--- a/drivers/tty/serial/8250.c ++++ b/drivers/tty/serial/8250.c +@@ -1528,10 +1528,15 @@ EXPORT_SYMBOL_GPL(serial8250_modem_status); + /* + * This handles the interrupt from one port. + */ +-static void serial8250_handle_port(struct uart_8250_port *up) ++int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + { + unsigned char status; + unsigned long flags; ++ struct uart_8250_port *up = ++ container_of(port, struct uart_8250_port, port); ++ ++ if (iir & UART_IIR_NO_INT) ++ return 0; + + spin_lock_irqsave(&up->port.lock, flags); + +@@ -1546,19 +1551,7 @@ static void serial8250_handle_port(struct uart_8250_port *up) + serial8250_tx_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); +-} +- +-int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +-{ +- struct uart_8250_port *up = +- container_of(port, struct uart_8250_port, port); +- +- if (!(iir & UART_IIR_NO_INT)) { +- serial8250_handle_port(up); +- return 1; +- } +- +- return 0; ++ return 1; + } + EXPORT_SYMBOL_GPL(serial8250_handle_irq); + +@@ -2825,7 +2818,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + + local_irq_save(flags); + if (up->port.sysrq) { +- /* serial8250_handle_port() already took the lock */ ++ /* serial8250_handle_irq() already took the lock */ + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0017-serial-group-all-the-8250-related-code-together.patch b/patches.kzm9g/0017-serial-group-all-the-8250-related-code-together.patch new file mode 100644 index 00000000000000..d045b50b493364 --- /dev/null +++ b/patches.kzm9g/0017-serial-group-all-the-8250-related-code-together.patch @@ -0,0 +1,746 @@ +From 1ab1670cb4d8cba1870f9dc3fd7806262f72a904 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 5 Jan 2012 18:21:43 -0500 +Subject: serial: group all the 8250 related code together + +The drivers/tty/serial dir is already getting rather busy. +Relocate the 8250 related drivers to their own subdir to +reduce the clutter. + +Note that sunsu.c is not included in this move -- it is +8250-like hardware, but it does not use any of the existing +infrastructure -- and does not depend on SERIAL_8250. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit 9bef3d4197379a995fa80f81950bbbf8d32e9e8b) + +Conflicts: + + drivers/tty/serial/8250/Kconfig + drivers/tty/serial/8250/Makefile + drivers/tty/serial/8250/8250_dw.c + drivers/tty/serial/8250/8250_fsl.c + drivers/tty/serial/Kconfig + drivers/tty/serial/Makefile + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/{ => 8250}/8250.c | 0 + drivers/tty/serial/{ => 8250}/8250.h | 0 + drivers/tty/serial/{ => 8250}/8250_accent.c | 0 + drivers/tty/serial/{ => 8250}/8250_acorn.c | 0 + drivers/tty/serial/{ => 8250}/8250_boca.c | 0 + drivers/tty/serial/{ => 8250}/8250_early.c | 0 + drivers/tty/serial/{ => 8250}/8250_exar_st16c554.c | 0 + drivers/tty/serial/{ => 8250}/8250_fourport.c | 0 + drivers/tty/serial/{ => 8250}/8250_gsc.c | 0 + drivers/tty/serial/{ => 8250}/8250_hp300.c | 0 + drivers/tty/serial/{ => 8250}/8250_hub6.c | 0 + drivers/tty/serial/{ => 8250}/8250_mca.c | 0 + drivers/tty/serial/{ => 8250}/8250_pci.c | 0 + drivers/tty/serial/{ => 8250}/8250_pnp.c | 0 + drivers/tty/serial/8250/Kconfig | 268 ++++++++++++++++++++ + drivers/tty/serial/8250/Makefile | 18 ++ + drivers/tty/serial/{ => 8250}/m32r_sio.c | 0 + drivers/tty/serial/{ => 8250}/m32r_sio.h | 0 + drivers/tty/serial/{ => 8250}/m32r_sio_reg.h | 0 + drivers/tty/serial/{ => 8250}/serial_cs.c | 0 + drivers/tty/serial/Kconfig | 262 +------------------ + drivers/tty/serial/Makefile | 17 +- + 22 files changed, 290 insertions(+), 275 deletions(-) + rename drivers/tty/serial/{ => 8250}/8250.c (100%) + rename drivers/tty/serial/{ => 8250}/8250.h (100%) + rename drivers/tty/serial/{ => 8250}/8250_accent.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_acorn.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_boca.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_early.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_exar_st16c554.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_fourport.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_gsc.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_hp300.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_hub6.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_mca.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_pci.c (100%) + rename drivers/tty/serial/{ => 8250}/8250_pnp.c (100%) + create mode 100644 drivers/tty/serial/8250/Kconfig + create mode 100644 drivers/tty/serial/8250/Makefile + rename drivers/tty/serial/{ => 8250}/m32r_sio.c (100%) + rename drivers/tty/serial/{ => 8250}/m32r_sio.h (100%) + rename drivers/tty/serial/{ => 8250}/m32r_sio_reg.h (100%) + rename drivers/tty/serial/{ => 8250}/serial_cs.c (100%) + +diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250/8250.c +similarity index 100% +rename from drivers/tty/serial/8250.c +rename to drivers/tty/serial/8250/8250.c +diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250/8250.h +similarity index 100% +rename from drivers/tty/serial/8250.h +rename to drivers/tty/serial/8250/8250.h +diff --git a/drivers/tty/serial/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c +similarity index 100% +rename from drivers/tty/serial/8250_accent.c +rename to drivers/tty/serial/8250/8250_accent.c +diff --git a/drivers/tty/serial/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c +similarity index 100% +rename from drivers/tty/serial/8250_acorn.c +rename to drivers/tty/serial/8250/8250_acorn.c +diff --git a/drivers/tty/serial/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c +similarity index 100% +rename from drivers/tty/serial/8250_boca.c +rename to drivers/tty/serial/8250/8250_boca.c +diff --git a/drivers/tty/serial/8250_early.c b/drivers/tty/serial/8250/8250_early.c +similarity index 100% +rename from drivers/tty/serial/8250_early.c +rename to drivers/tty/serial/8250/8250_early.c +diff --git a/drivers/tty/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c +similarity index 100% +rename from drivers/tty/serial/8250_exar_st16c554.c +rename to drivers/tty/serial/8250/8250_exar_st16c554.c +diff --git a/drivers/tty/serial/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c +similarity index 100% +rename from drivers/tty/serial/8250_fourport.c +rename to drivers/tty/serial/8250/8250_fourport.c +diff --git a/drivers/tty/serial/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c +similarity index 100% +rename from drivers/tty/serial/8250_gsc.c +rename to drivers/tty/serial/8250/8250_gsc.c +diff --git a/drivers/tty/serial/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c +similarity index 100% +rename from drivers/tty/serial/8250_hp300.c +rename to drivers/tty/serial/8250/8250_hp300.c +diff --git a/drivers/tty/serial/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c +similarity index 100% +rename from drivers/tty/serial/8250_hub6.c +rename to drivers/tty/serial/8250/8250_hub6.c +diff --git a/drivers/tty/serial/8250_mca.c b/drivers/tty/serial/8250/8250_mca.c +similarity index 100% +rename from drivers/tty/serial/8250_mca.c +rename to drivers/tty/serial/8250/8250_mca.c +diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c +similarity index 100% +rename from drivers/tty/serial/8250_pci.c +rename to drivers/tty/serial/8250/8250_pci.c +diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c +similarity index 100% +rename from drivers/tty/serial/8250_pnp.c +rename to drivers/tty/serial/8250/8250_pnp.c +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +new file mode 100644 +index 0000000..b1bb251 +--- /dev/null ++++ b/drivers/tty/serial/8250/Kconfig +@@ -0,0 +1,268 @@ ++# ++# The 8250/16550 serial drivers. You shouldn't be in this list unless ++# you somehow have an implicit or explicit dependency on SERIAL_8250. ++# ++ ++config SERIAL_8250 ++ tristate "8250/16550 and compatible serial support" ++ select SERIAL_CORE ++ ---help--- ++ This selects whether you want to include the driver for the standard ++ serial ports. The standard answer is Y. People who might say N ++ here are those that are setting up dedicated Ethernet WWW/FTP ++ servers, or users that have one of the various bus mice instead of a ++ serial mouse and don't intend to use their machine's standard serial ++ port for anything. (Note that the Cyclades and Stallion multi ++ serial port drivers do not need this driver built in for them to ++ work.) ++ ++ To compile this driver as a module, choose M here: the ++ module will be called 8250. ++ [WARNING: Do not compile this driver as a module if you are using ++ non-standard serial ports, since the configuration information will ++ be lost when the driver is unloaded. This limitation may be lifted ++ in the future.] ++ ++ BTW1: If you have a mouseman serial mouse which is not recognized by ++ the X window system, try running gpm first. ++ ++ BTW2: If you intend to use a software modem (also called Winmodem) ++ under Linux, forget it. These modems are crippled and require ++ proprietary drivers which are only available under Windows. ++ ++ Most people will say Y or M here, so that they can use serial mice, ++ modems and similar devices connecting to the standard serial ports. ++ ++config SERIAL_8250_CONSOLE ++ bool "Console on 8250/16550 and compatible serial port" ++ depends on SERIAL_8250=y ++ select SERIAL_CORE_CONSOLE ++ ---help--- ++ If you say Y here, it will be possible to use a serial port as the ++ system console (the system console is the device which receives all ++ kernel messages and warnings and which allows logins in single user ++ mode). This could be useful if some terminal or printer is connected ++ to that serial port. ++ ++ Even if you say Y here, the currently visible virtual console ++ (/dev/tty0) will still be used as the system console by default, but ++ you can alter that using a kernel command line option such as ++ "console=ttyS1". (Try "man bootparam" or see the documentation of ++ your boot loader (grub or lilo or loadlin) about how to pass options ++ to the kernel at boot time.) ++ ++ If you don't have a VGA card installed and you say Y here, the ++ kernel will automatically use the first serial line, /dev/ttyS0, as ++ system console. ++ ++ You can set that using a kernel command line option such as ++ "console=uart8250,io,0x3f8,9600n8" ++ "console=uart8250,mmio,0xff5e0000,115200n8". ++ and it will switch to normal serial console when the corresponding ++ port is ready. ++ "earlycon=uart8250,io,0x3f8,9600n8" ++ "earlycon=uart8250,mmio,0xff5e0000,115200n8". ++ it will not only setup early console. ++ ++ If unsure, say N. ++ ++config FIX_EARLYCON_MEM ++ bool ++ depends on X86 ++ default y ++ ++config SERIAL_8250_GSC ++ tristate ++ depends on SERIAL_8250 && GSC ++ default SERIAL_8250 ++ ++config SERIAL_8250_PCI ++ tristate "8250/16550 PCI device support" if EXPERT ++ depends on SERIAL_8250 && PCI ++ default SERIAL_8250 ++ help ++ This builds standard PCI serial support. You may be able to ++ disable this feature if you only need legacy serial support. ++ Saves about 9K. ++ ++config SERIAL_8250_PNP ++ tristate "8250/16550 PNP device support" if EXPERT ++ depends on SERIAL_8250 && PNP ++ default SERIAL_8250 ++ help ++ This builds standard PNP serial support. You may be able to ++ disable this feature if you only need legacy serial support. ++ ++config SERIAL_8250_HP300 ++ tristate ++ depends on SERIAL_8250 && HP300 ++ default SERIAL_8250 ++ ++config SERIAL_8250_CS ++ tristate "8250/16550 PCMCIA device support" ++ depends on PCMCIA && SERIAL_8250 ++ ---help--- ++ Say Y here to enable support for 16-bit PCMCIA serial devices, ++ including serial port cards, modems, and the modem functions of ++ multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are ++ credit-card size devices often used with laptops.) ++ ++ To compile this driver as a module, choose M here: the ++ module will be called serial_cs. ++ ++ If unsure, say N. ++ ++config SERIAL_8250_NR_UARTS ++ int "Maximum number of 8250/16550 serial ports" ++ depends on SERIAL_8250 ++ default "4" ++ help ++ Set this to the number of serial ports you want the driver ++ to support. This includes any ports discovered via ACPI or ++ PCI enumeration and any ports that may be added at run-time ++ via hot-plug, or any ISA multi-port serial cards. ++ ++config SERIAL_8250_RUNTIME_UARTS ++ int "Number of 8250/16550 serial ports to register at runtime" ++ depends on SERIAL_8250 ++ range 0 SERIAL_8250_NR_UARTS ++ default "4" ++ help ++ Set this to the maximum number of serial ports you want ++ the kernel to register at boot time. This can be overridden ++ with the module parameter "nr_uarts", or boot-time parameter ++ 8250.nr_uarts ++ ++config SERIAL_8250_EXTENDED ++ bool "Extended 8250/16550 serial driver options" ++ depends on SERIAL_8250 ++ help ++ If you wish to use any non-standard features of the standard "dumb" ++ driver, say Y here. This includes HUB6 support, shared serial ++ interrupts, special multiport support, support for more than the ++ four COM 1/2/3/4 boards, etc. ++ ++ Note that the answer to this question won't directly affect the ++ kernel: saying N will just cause the configurator to skip all ++ the questions about serial driver options. If unsure, say N. ++ ++config SERIAL_8250_MANY_PORTS ++ bool "Support more than 4 legacy serial ports" ++ depends on SERIAL_8250_EXTENDED && !IA64 ++ help ++ Say Y here if you have dumb serial boards other than the four ++ standard COM 1/2/3/4 ports. This may happen if you have an AST ++ FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available ++ from <http://www.tldp.org/docs.html#howto>), or other custom ++ serial port hardware which acts similar to standard serial port ++ hardware. If you only use the standard COM 1/2/3/4 ports, you can ++ say N here to save some memory. You can also say Y if you have an ++ "intelligent" multiport card such as Cyclades, Digiboards, etc. ++ ++# ++# Multi-port serial cards ++# ++ ++config SERIAL_8250_FOURPORT ++ tristate "Support Fourport cards" ++ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS ++ help ++ Say Y here if you have an AST FourPort serial board. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_fourport. ++ ++config SERIAL_8250_ACCENT ++ tristate "Support Accent cards" ++ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS ++ help ++ Say Y here if you have an Accent Async serial board. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_accent. ++ ++config SERIAL_8250_BOCA ++ tristate "Support Boca cards" ++ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS ++ help ++ Say Y here if you have a Boca serial board. Please read the Boca ++ mini-HOWTO, available from <http://www.tldp.org/docs.html#howto> ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_boca. ++ ++config SERIAL_8250_EXAR_ST16C554 ++ tristate "Support Exar ST16C554/554D Quad UART" ++ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS ++ help ++ The Uplogix Envoy TU301 uses this Exar Quad UART. If you are ++ tinkering with your Envoy TU301, or have a machine with this UART, ++ say Y here. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_exar_st16c554. ++ ++config SERIAL_8250_HUB6 ++ tristate "Support Hub6 cards" ++ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS ++ help ++ Say Y here if you have a HUB6 serial board. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_hub6. ++ ++# ++# Misc. options/drivers. ++# ++ ++config SERIAL_8250_SHARE_IRQ ++ bool "Support for sharing serial interrupts" ++ depends on SERIAL_8250_EXTENDED ++ help ++ Some serial boards have hardware support which allows multiple dumb ++ serial ports on the same board to share a single IRQ. To enable ++ support for this in the serial driver, say Y here. ++ ++config SERIAL_8250_DETECT_IRQ ++ bool "Autodetect IRQ on standard ports (unsafe)" ++ depends on SERIAL_8250_EXTENDED ++ help ++ Say Y here if you want the kernel to try to guess which IRQ ++ to use for your serial port. ++ ++ This is considered unsafe; it is far better to configure the IRQ in ++ a boot script using the setserial command. ++ ++ If unsure, say N. ++ ++config SERIAL_8250_RSA ++ bool "Support RSA serial ports" ++ depends on SERIAL_8250_EXTENDED ++ help ++ ::: To be written ::: ++ ++config SERIAL_8250_MCA ++ tristate "Support 8250-type ports on MCA buses" ++ depends on SERIAL_8250 != n && MCA ++ help ++ Say Y here if you have a MCA serial ports. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_mca. ++ ++config SERIAL_8250_ACORN ++ tristate "Acorn expansion card serial port support" ++ depends on ARCH_ACORN && SERIAL_8250 ++ help ++ If you have an Atomwide Serial card or Serial Port card for an Acorn ++ system, say Y to this option. The driver can handle 1, 2, or 3 port ++ cards. If unsure, say N. ++ ++config SERIAL_8250_RM9K ++ bool "Support for MIPS RM9xxx integrated serial port" ++ depends on SERIAL_8250 != n && SERIAL_RM9000 ++ select SERIAL_8250_SHARE_IRQ ++ help ++ Selecting this option will add support for the integrated serial ++ port hardware found on MIPS RM9122 and similar processors. ++ If unsure, say N. +diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile +new file mode 100644 +index 0000000..c0d0c29 +--- /dev/null ++++ b/drivers/tty/serial/8250/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the 8250 serial device drivers. ++# ++ ++obj-$(CONFIG_SERIAL_8250) += 8250.o ++obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o ++obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o ++obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o ++obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o ++obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o ++obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o ++obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o ++obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o ++obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o ++obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o ++obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o ++obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o ++obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o +diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/8250/m32r_sio.c +similarity index 100% +rename from drivers/tty/serial/m32r_sio.c +rename to drivers/tty/serial/8250/m32r_sio.c +diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/8250/m32r_sio.h +similarity index 100% +rename from drivers/tty/serial/m32r_sio.h +rename to drivers/tty/serial/8250/m32r_sio.h +diff --git a/drivers/tty/serial/m32r_sio_reg.h b/drivers/tty/serial/8250/m32r_sio_reg.h +similarity index 100% +rename from drivers/tty/serial/m32r_sio_reg.h +rename to drivers/tty/serial/8250/m32r_sio_reg.h +diff --git a/drivers/tty/serial/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c +similarity index 100% +rename from drivers/tty/serial/serial_cs.c +rename to drivers/tty/serial/8250/serial_cs.c +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 9789293..69349bf 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -5,267 +5,7 @@ + menu "Serial drivers" + depends on HAS_IOMEM + +-# +-# The new 8250/16550 serial drivers +-config SERIAL_8250 +- tristate "8250/16550 and compatible serial support" +- select SERIAL_CORE +- ---help--- +- This selects whether you want to include the driver for the standard +- serial ports. The standard answer is Y. People who might say N +- here are those that are setting up dedicated Ethernet WWW/FTP +- servers, or users that have one of the various bus mice instead of a +- serial mouse and don't intend to use their machine's standard serial +- port for anything. (Note that the Cyclades and Stallion multi +- serial port drivers do not need this driver built in for them to +- work.) +- +- To compile this driver as a module, choose M here: the +- module will be called 8250. +- [WARNING: Do not compile this driver as a module if you are using +- non-standard serial ports, since the configuration information will +- be lost when the driver is unloaded. This limitation may be lifted +- in the future.] +- +- BTW1: If you have a mouseman serial mouse which is not recognized by +- the X window system, try running gpm first. +- +- BTW2: If you intend to use a software modem (also called Winmodem) +- under Linux, forget it. These modems are crippled and require +- proprietary drivers which are only available under Windows. +- +- Most people will say Y or M here, so that they can use serial mice, +- modems and similar devices connecting to the standard serial ports. +- +-config SERIAL_8250_CONSOLE +- bool "Console on 8250/16550 and compatible serial port" +- depends on SERIAL_8250=y +- select SERIAL_CORE_CONSOLE +- ---help--- +- If you say Y here, it will be possible to use a serial port as the +- system console (the system console is the device which receives all +- kernel messages and warnings and which allows logins in single user +- mode). This could be useful if some terminal or printer is connected +- to that serial port. +- +- Even if you say Y here, the currently visible virtual console +- (/dev/tty0) will still be used as the system console by default, but +- you can alter that using a kernel command line option such as +- "console=ttyS1". (Try "man bootparam" or see the documentation of +- your boot loader (grub or lilo or loadlin) about how to pass options +- to the kernel at boot time.) +- +- If you don't have a VGA card installed and you say Y here, the +- kernel will automatically use the first serial line, /dev/ttyS0, as +- system console. +- +- You can set that using a kernel command line option such as +- "console=uart8250,io,0x3f8,9600n8" +- "console=uart8250,mmio,0xff5e0000,115200n8". +- and it will switch to normal serial console when the corresponding +- port is ready. +- "earlycon=uart8250,io,0x3f8,9600n8" +- "earlycon=uart8250,mmio,0xff5e0000,115200n8". +- it will not only setup early console. +- +- If unsure, say N. +- +-config FIX_EARLYCON_MEM +- bool +- depends on X86 +- default y +- +-config SERIAL_8250_GSC +- tristate +- depends on SERIAL_8250 && GSC +- default SERIAL_8250 +- +-config SERIAL_8250_PCI +- tristate "8250/16550 PCI device support" if EXPERT +- depends on SERIAL_8250 && PCI +- default SERIAL_8250 +- help +- This builds standard PCI serial support. You may be able to +- disable this feature if you only need legacy serial support. +- Saves about 9K. +- +-config SERIAL_8250_PNP +- tristate "8250/16550 PNP device support" if EXPERT +- depends on SERIAL_8250 && PNP +- default SERIAL_8250 +- help +- This builds standard PNP serial support. You may be able to +- disable this feature if you only need legacy serial support. +- +-config SERIAL_8250_HP300 +- tristate +- depends on SERIAL_8250 && HP300 +- default SERIAL_8250 +- +-config SERIAL_8250_CS +- tristate "8250/16550 PCMCIA device support" +- depends on PCMCIA && SERIAL_8250 +- ---help--- +- Say Y here to enable support for 16-bit PCMCIA serial devices, +- including serial port cards, modems, and the modem functions of +- multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are +- credit-card size devices often used with laptops.) +- +- To compile this driver as a module, choose M here: the +- module will be called serial_cs. +- +- If unsure, say N. +- +-config SERIAL_8250_NR_UARTS +- int "Maximum number of 8250/16550 serial ports" +- depends on SERIAL_8250 +- default "4" +- help +- Set this to the number of serial ports you want the driver +- to support. This includes any ports discovered via ACPI or +- PCI enumeration and any ports that may be added at run-time +- via hot-plug, or any ISA multi-port serial cards. +- +-config SERIAL_8250_RUNTIME_UARTS +- int "Number of 8250/16550 serial ports to register at runtime" +- depends on SERIAL_8250 +- range 0 SERIAL_8250_NR_UARTS +- default "4" +- help +- Set this to the maximum number of serial ports you want +- the kernel to register at boot time. This can be overridden +- with the module parameter "nr_uarts", or boot-time parameter +- 8250.nr_uarts +- +-config SERIAL_8250_EXTENDED +- bool "Extended 8250/16550 serial driver options" +- depends on SERIAL_8250 +- help +- If you wish to use any non-standard features of the standard "dumb" +- driver, say Y here. This includes HUB6 support, shared serial +- interrupts, special multiport support, support for more than the +- four COM 1/2/3/4 boards, etc. +- +- Note that the answer to this question won't directly affect the +- kernel: saying N will just cause the configurator to skip all +- the questions about serial driver options. If unsure, say N. +- +-config SERIAL_8250_MANY_PORTS +- bool "Support more than 4 legacy serial ports" +- depends on SERIAL_8250_EXTENDED && !IA64 +- help +- Say Y here if you have dumb serial boards other than the four +- standard COM 1/2/3/4 ports. This may happen if you have an AST +- FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available +- from <http://www.tldp.org/docs.html#howto>), or other custom +- serial port hardware which acts similar to standard serial port +- hardware. If you only use the standard COM 1/2/3/4 ports, you can +- say N here to save some memory. You can also say Y if you have an +- "intelligent" multiport card such as Cyclades, Digiboards, etc. +- +-# +-# Multi-port serial cards +-# +- +-config SERIAL_8250_FOURPORT +- tristate "Support Fourport cards" +- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS +- help +- Say Y here if you have an AST FourPort serial board. +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_fourport. +- +-config SERIAL_8250_ACCENT +- tristate "Support Accent cards" +- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS +- help +- Say Y here if you have an Accent Async serial board. +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_accent. +- +-config SERIAL_8250_BOCA +- tristate "Support Boca cards" +- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS +- help +- Say Y here if you have a Boca serial board. Please read the Boca +- mini-HOWTO, available from <http://www.tldp.org/docs.html#howto> +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_boca. +- +-config SERIAL_8250_EXAR_ST16C554 +- tristate "Support Exar ST16C554/554D Quad UART" +- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS +- help +- The Uplogix Envoy TU301 uses this Exar Quad UART. If you are +- tinkering with your Envoy TU301, or have a machine with this UART, +- say Y here. +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_exar_st16c554. +- +-config SERIAL_8250_HUB6 +- tristate "Support Hub6 cards" +- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS +- help +- Say Y here if you have a HUB6 serial board. +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_hub6. +- +-config SERIAL_8250_SHARE_IRQ +- bool "Support for sharing serial interrupts" +- depends on SERIAL_8250_EXTENDED +- help +- Some serial boards have hardware support which allows multiple dumb +- serial ports on the same board to share a single IRQ. To enable +- support for this in the serial driver, say Y here. +- +-config SERIAL_8250_DETECT_IRQ +- bool "Autodetect IRQ on standard ports (unsafe)" +- depends on SERIAL_8250_EXTENDED +- help +- Say Y here if you want the kernel to try to guess which IRQ +- to use for your serial port. +- +- This is considered unsafe; it is far better to configure the IRQ in +- a boot script using the setserial command. +- +- If unsure, say N. +- +-config SERIAL_8250_RSA +- bool "Support RSA serial ports" +- depends on SERIAL_8250_EXTENDED +- help +- ::: To be written ::: +- +-config SERIAL_8250_MCA +- tristate "Support 8250-type ports on MCA buses" +- depends on SERIAL_8250 != n && MCA +- help +- Say Y here if you have a MCA serial ports. +- +- To compile this driver as a module, choose M here: the module +- will be called 8250_mca. +- +-config SERIAL_8250_ACORN +- tristate "Acorn expansion card serial port support" +- depends on ARCH_ACORN && SERIAL_8250 +- help +- If you have an Atomwide Serial card or Serial Port card for an Acorn +- system, say Y to this option. The driver can handle 1, 2, or 3 port +- cards. If unsure, say N. +- +-config SERIAL_8250_RM9K +- bool "Support for MIPS RM9xxx integrated serial port" +- depends on SERIAL_8250 != n && SERIAL_RM9000 +- select SERIAL_8250_SHARE_IRQ +- help +- Selecting this option will add support for the integrated serial +- port hardware found on MIPS RM9122 and similar processors. +- If unsure, say N. ++source "drivers/tty/serial/8250/Kconfig" + + comment "Non-8250 serial port support" + +diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile +index cb2628f..b74267d 100644 +--- a/drivers/tty/serial/Makefile ++++ b/drivers/tty/serial/Makefile +@@ -14,20 +14,9 @@ obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o + obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o + obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o + +-obj-$(CONFIG_SERIAL_8250) += 8250.o +-obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +-obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o +-obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o +-obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o +-obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o +-obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o +-obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o +-obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o +-obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o +-obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o +-obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o +-obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o +-obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o ++# Now bring in any enabled 8250/16450/16550 type drivers. ++obj-$(CONFIG_SERIAL_8250) += 8250/ ++ + obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o + obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o + obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0018-serial-Kill-off-NO_IRQ.patch b/patches.kzm9g/0018-serial-Kill-off-NO_IRQ.patch new file mode 100644 index 00000000000000..20a2b724db0863 --- /dev/null +++ b/patches.kzm9g/0018-serial-Kill-off-NO_IRQ.patch @@ -0,0 +1,361 @@ +From f2a0fc4b05410441cf28a4894bb7f1e1983a77bb Mon Sep 17 00:00:00 2001 +From: Alan Cox <alan@linux.intel.com> +Date: Thu, 26 Jan 2012 17:44:09 +0000 +Subject: serial: Kill off NO_IRQ + +We transform the offenders into a test of irq <= 0 which will be ok while +the ARM people get their platform sorted. Once that is done (or in a while +if they don't do it anyway) then we will change them all to !irq checks. + +For arch specific drivers that are already using NO_IRQ = 0 we just test +against zero so we don't need to re-review them later. + +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +(cherry picked from commit d4e33fac2408d37f7b52e80ca2a89f9fb482914f) + +Conflicts: + + drivers/tty/serial/m32r_sio.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/hvc/hvc_beat.c | 2 +- + drivers/tty/hvc/hvc_rtas.c | 2 +- + drivers/tty/hvc/hvc_udbg.c | 2 +- + drivers/tty/hvc/hvc_xen.c | 2 +- + drivers/tty/hvc/hvcs.c | 4 ++-- + drivers/tty/hvc/hvsi.c | 2 +- + drivers/tty/serial/21285.c | 4 ++-- + drivers/tty/serial/8250/8250.c | 21 +++++++-------------- + drivers/tty/serial/mpc52xx_uart.c | 4 ++-- + drivers/tty/serial/mux.c | 2 +- + drivers/tty/serial/pmac_zilog.c | 2 +- + drivers/tty/serial/sunzilog.c | 10 +++++----- + drivers/tty/serial/ucc_uart.c | 2 +- + drivers/tty/serial/vr41xx_siu.c | 4 ++-- + 14 files changed, 28 insertions(+), 35 deletions(-) + +diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c +index 5fe4631..1560d23 100644 +--- a/drivers/tty/hvc/hvc_beat.c ++++ b/drivers/tty/hvc/hvc_beat.c +@@ -113,7 +113,7 @@ static int __init hvc_beat_init(void) + if (!firmware_has_feature(FW_FEATURE_BEAT)) + return -ENODEV; + +- hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); ++ hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + hvc_beat_dev = hp; +diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c +index 61c4a61..0069bb8 100644 +--- a/drivers/tty/hvc/hvc_rtas.c ++++ b/drivers/tty/hvc/hvc_rtas.c +@@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void) + + /* Allocate an hvc_struct for the console device we instantiated + * earlier. Save off hp so that we can return it on exit */ +- hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); ++ hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + +diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c +index b0957e6..4c9b13e 100644 +--- a/drivers/tty/hvc/hvc_udbg.c ++++ b/drivers/tty/hvc/hvc_udbg.c +@@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void) + + BUG_ON(hvc_udbg_dev); + +- hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); ++ hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + +diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c +index 52fdf60..a1b0a75 100644 +--- a/drivers/tty/hvc/hvc_xen.c ++++ b/drivers/tty/hvc/hvc_xen.c +@@ -176,7 +176,7 @@ static int __init xen_hvc_init(void) + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + } + if (xencons_irq < 0) +- xencons_irq = 0; /* NO_IRQ */ ++ xencons_irq = 0; + else + irq_set_noprobe(xencons_irq); + +diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c +index 4c8b665..cb0bf44 100644 +--- a/drivers/tty/hvc/hvcs.c ++++ b/drivers/tty/hvc/hvcs.c +@@ -1203,7 +1203,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) + { + struct hvcs_struct *hvcsd; + unsigned long flags; +- int irq = NO_IRQ; ++ int irq; + + /* + * Is someone trying to close the file associated with this device after +@@ -1264,7 +1264,7 @@ static void hvcs_hangup(struct tty_struct * tty) + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; + int temp_open_count; +- int irq = NO_IRQ; ++ int irq; + + spin_lock_irqsave(&hvcsd->lock, flags); + /* Preserve this so that we know how many kref refs to put */ +diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c +index 8a8d637..8e1fbd3 100644 +--- a/drivers/tty/hvc/hvsi.c ++++ b/drivers/tty/hvc/hvsi.c +@@ -1298,7 +1298,7 @@ static int __init hvsi_console_init(void) + hp->state = HVSI_CLOSED; + hp->vtermno = *vtermno; + hp->virq = irq_create_mapping(NULL, irq[0]); +- if (hp->virq == NO_IRQ) { ++ if (hp->virq == 0) { + printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", + __func__, irq[0]); + continue; +diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c +index 1b37626..f899996 100644 +--- a/drivers/tty/serial/21285.c ++++ b/drivers/tty/serial/21285.c +@@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) + ret = -EINVAL; +- if (ser->irq != NO_IRQ) ++ if (ser->irq <= 0) + ret = -EINVAL; + if (ser->baud_base != port->uartclk / 16) + ret = -EINVAL; +@@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = { + static struct uart_port serial21285_port = { + .mapbase = 0x42000160, + .iotype = UPIO_MEM, +- .irq = NO_IRQ, ++ .irq = 0, + .fifosize = 16, + .ops = &serial21285_ops, + .flags = UPF_BOOT_AUTOCONF, +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 047221d..e7c1304 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -86,13 +86,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ + #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + + +-/* +- * We default to IRQ0 for the "no irq" hack. Some +- * machine types want others as well - they're free +- * to redefine this in their header file. +- */ +-#define is_real_interrupt(irq) ((irq) != 0) +- + #ifdef CONFIG_SERIAL_8250_DETECT_IRQ + #define CONFIG_SERIAL_DETECT_IRQ 1 + #endif +@@ -1748,7 +1741,7 @@ static void serial8250_backup_timeout(unsigned long data) + * Must disable interrupts or else we risk racing with the interrupt + * based handler. + */ +- if (is_real_interrupt(up->port.irq)) { ++ if (up->port.irq) { + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + } +@@ -1773,7 +1766,7 @@ static void serial8250_backup_timeout(unsigned long data) + if (!(iir & UART_IIR_NO_INT)) + serial8250_tx_chars(up); + +- if (is_real_interrupt(up->port.irq)) ++ if (up->port.irq) + serial_out(up, UART_IER, ier); + + spin_unlock_irqrestore(&up->port.lock, flags); +@@ -2026,7 +2019,7 @@ static int serial8250_startup(struct uart_port *port) + serial_outp(up, UART_LCR, 0); + } + +- if (is_real_interrupt(up->port.irq)) { ++ if (up->port.irq) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the +@@ -2081,7 +2074,7 @@ static int serial8250_startup(struct uart_port *port) + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ +- if (!is_real_interrupt(up->port.irq)) { ++ if (!up->port.irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else { +@@ -2097,13 +2090,13 @@ static int serial8250_startup(struct uart_port *port) + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { +- if (!is_real_interrupt(up->port.irq)) ++ if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ +- if (is_real_interrupt(up->port.irq)) ++ if (up->port.irq) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(&up->port, up->port.mctrl); +@@ -2221,7 +2214,7 @@ static void serial8250_shutdown(struct uart_port *port) + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; +- if (is_real_interrupt(up->port.irq)) ++ if (up->port.irq) + serial_unlink_irq_chain(up); + } + +diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c +index a0bcd8a..0d0d859 100644 +--- a/drivers/tty/serial/mpc52xx_uart.c ++++ b/drivers/tty/serial/mpc52xx_uart.c +@@ -506,7 +506,7 @@ static int __init mpc512x_psc_fifoc_init(void) + + psc_fifoc_irq = irq_of_parse_and_map(np, 0); + of_node_put(np); +- if (psc_fifoc_irq == NO_IRQ) { ++ if (psc_fifoc_irq == 0) { + pr_err("%s: Can't get FIFOC irq\n", __func__); + iounmap(psc_fifoc); + return -ENODEV; +@@ -1353,7 +1353,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op) + } + + psc_ops->get_irq(port, op->dev.of_node); +- if (port->irq == NO_IRQ) { ++ if (port->irq == 0) { + dev_dbg(&op->dev, "Could not get irq\n"); + return -EINVAL; + } +diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c +index 9711e06..3605c79 100644 +--- a/drivers/tty/serial/mux.c ++++ b/drivers/tty/serial/mux.c +@@ -497,7 +497,7 @@ static int __init mux_probe(struct parisc_device *dev) + port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); + port->iotype = UPIO_MEM; + port->type = PORT_MUX; +- port->irq = NO_IRQ; ++ port->irq = 0; + port->uartclk = 0; + port->fifosize = MUX_FIFO_SIZE; + port->ops = &mux_pops; +diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c +index 5acd24a..22ef6b2 100644 +--- a/drivers/tty/serial/pmac_zilog.c ++++ b/drivers/tty/serial/pmac_zilog.c +@@ -1565,7 +1565,7 @@ no_dma: + * fixed up interrupt info, but we use the device-tree directly + * here due to early probing so we need the fixup too. + */ +- if (uap->port.irq == NO_IRQ && ++ if (uap->port.irq == 0 && + np->parent && np->parent->parent && + of_device_is_compatible(np->parent->parent, "gatwick")) { + /* IRQs on gatwick are offset by 64 */ +diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c +index 8e916e7..5a47d1b 100644 +--- a/drivers/tty/serial/sunzilog.c ++++ b/drivers/tty/serial/sunzilog.c +@@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) + #endif + } + +-static int zilog_irq = -1; ++static int zilog_irq; + + static int __devinit zs_probe(struct platform_device *op) + { +@@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op) + + rp = sunzilog_chip_regs[inst]; + +- if (zilog_irq == -1) ++ if (!zilog_irq) + zilog_irq = op->archdata.irqs[0]; + + up = &sunzilog_port_table[inst * 2]; +@@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void) + if (err) + goto out_unregister_uart; + +- if (zilog_irq != -1) { ++ if (!zilog_irq) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, + "zs", sunzilog_irq_chain); +@@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void) + { + platform_driver_unregister(&zs_driver); + +- if (zilog_irq != -1) { ++ if (!zilog_irq) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + + /* Disable Interrupts */ +@@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void) + } + + free_irq(zilog_irq, sunzilog_irq_chain); +- zilog_irq = -1; ++ zilog_irq = 0; + } + + if (sunzilog_reg.nr) { +diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c +index c327218..d5b8e7e 100644 +--- a/drivers/tty/serial/ucc_uart.c ++++ b/drivers/tty/serial/ucc_uart.c +@@ -1355,7 +1355,7 @@ static int ucc_uart_probe(struct platform_device *ofdev) + } + + qe_port->port.irq = irq_of_parse_and_map(np, 0); +- if (qe_port->port.irq == NO_IRQ) { ++ if (qe_port->port.irq == 0) { + dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", + qe_port->ucc_num + 1); + ret = -EINVAL; +diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c +index 3beb6ab..15be73d 100644 +--- a/drivers/tty/serial/vr41xx_siu.c ++++ b/drivers/tty/serial/vr41xx_siu.c +@@ -61,7 +61,7 @@ + static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { + [0 ... SIU_PORTS_MAX-1] = { + .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), +- .irq = -1, ++ .irq = 0, + }, + }; + +@@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port) + { + if (port->line == 0) + return PORT_VR41XX_SIU; +- if (port->line == 1 && port->irq != -1) ++ if (port->line == 1 && port->irq) + return PORT_VR41XX_DSIU; + + return PORT_UNKNOWN; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0019-tty-fix-a-build-failure-on-sparc.patch b/patches.kzm9g/0019-tty-fix-a-build-failure-on-sparc.patch new file mode 100644 index 00000000000000..35a49625e5f4f7 --- /dev/null +++ b/patches.kzm9g/0019-tty-fix-a-build-failure-on-sparc.patch @@ -0,0 +1,42 @@ +From 571708bcbfb19bb1d4916d2bbc4c5cc23b4a701a Mon Sep 17 00:00:00 2001 +From: Cong Wang <xiyou.wangcong@gmail.com> +Date: Fri, 3 Feb 2012 13:22:10 +0800 +Subject: tty: fix a build failure on sparc + +On sparc, there is a build failure: + +drivers/tty/serial/8250/8250.c:48:21: error: suncore.h: No such file or directory +drivers/tty/serial/8250/8250.c:3275: error: implicit declaration of function 'sunserial_register_minors' +drivers/tty/serial/8250/8250.c:3305: error: implicit declaration of function 'sunserial_unregister_minors' + +this is due to commit 9bef3d4197379a995fa80f81950bbbf8d32e9e8b +(serial: group all the 8250 related code together) moved these files +into 8250/ subdirectory, but forgot to change the reference +to drivers/tty/serial/suncore.h. + +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Signed-off-by: WANG Cong <xiyou.wangcong@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit e7c9bba7999a8e55efb96d4279c025ca587c5ecd) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index e7c1304..a154ba2 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -45,7 +45,7 @@ + #include "8250.h" + + #ifdef CONFIG_SPARC +-#include "suncore.h" ++#include "../suncore.h" + #endif + + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0020-tty-sparc-rename-drivers-tty-serial-suncore.h-includ.patch b/patches.kzm9g/0020-tty-sparc-rename-drivers-tty-serial-suncore.h-includ.patch new file mode 100644 index 00000000000000..073454477bb0df --- /dev/null +++ b/patches.kzm9g/0020-tty-sparc-rename-drivers-tty-serial-suncore.h-includ.patch @@ -0,0 +1,199 @@ +From 7242a5c3b6dae31b7d9fc687ece21d96aa27bead Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 9 Feb 2012 18:48:19 -0500 +Subject: tty: sparc: rename drivers/tty/serial/suncore.h -> + include/linux/sunserialcore.h + +There are multiple users of this file from different source +paths now, and rather than have ../ paths in include statements, +just move the file to the linux header dir. + +Suggested-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 6816383a09b5be8d35f14f4c25dedb64498e4959) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + MAINTAINERS | 2 +- + drivers/tty/serial/8250/8250.c | 7 +++---- + drivers/tty/serial/suncore.c | 2 +- + drivers/tty/serial/suncore.h | 33 --------------------------------- + drivers/tty/serial/sunhv.c | 3 +-- + drivers/tty/serial/sunsab.c | 2 +- + drivers/tty/serial/sunsu.c | 3 +-- + drivers/tty/serial/sunzilog.c | 2 +- + include/linux/sunserialcore.h | 33 +++++++++++++++++++++++++++++++++ + 9 files changed, 42 insertions(+), 45 deletions(-) + rename drivers/tty/serial/suncore.h => include/linux/sunserialcore.h (98%) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -5958,8 +5958,8 @@ L: sparclinux@vger.kernel.org + T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git + T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git + S: Maintained ++F: include/linux/sunserialcore.h + F: drivers/tty/serial/suncore.c +-F: drivers/tty/serial/suncore.h + F: drivers/tty/serial/sunhv.c + F: drivers/tty/serial/sunsab.c + F: drivers/tty/serial/sunsab.h +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -38,16 +38,15 @@ + #include <linux/nmi.h> + #include <linux/mutex.h> + #include <linux/slab.h> ++#ifdef CONFIG_SPARC ++#include <linux/sunserialcore.h> ++#endif + + #include <asm/io.h> + #include <asm/irq.h> + + #include "8250.h" + +-#ifdef CONFIG_SPARC +-#include "../suncore.h" +-#endif +- + /* + * Configuration: + * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option +--- a/drivers/tty/serial/suncore.c ++++ b/drivers/tty/serial/suncore.c +@@ -17,11 +17,11 @@ + #include <linux/errno.h> + #include <linux/string.h> + #include <linux/serial_core.h> ++#include <linux/sunserialcore.h> + #include <linux/init.h> + + #include <asm/prom.h> + +-#include "suncore.h" + + static int sunserial_current_minor = 64; + +--- a/drivers/tty/serial/suncore.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* suncore.h +- * +- * Generic SUN serial/kbd/ms layer. Based entirely +- * upon drivers/sbus/char/sunserial.h which is: +- * +- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) +- * +- * Port to new UART layer is: +- * +- * Copyright (C) 2002 David S. Miller (davem@redhat.com) +- */ +- +-#ifndef _SERIAL_SUN_H +-#define _SERIAL_SUN_H +- +-/* Serial keyboard defines for L1-A processing... */ +-#define SUNKBD_RESET 0xff +-#define SUNKBD_L1 0x01 +-#define SUNKBD_UP 0x80 +-#define SUNKBD_A 0x4d +- +-extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); +-extern int suncore_mouse_baud_detection(unsigned char, int); +- +-extern int sunserial_register_minors(struct uart_driver *, int); +-extern void sunserial_unregister_minors(struct uart_driver *, int); +- +-extern int sunserial_console_match(struct console *, struct device_node *, +- struct uart_driver *, int, bool); +-extern void sunserial_console_termios(struct console *, +- struct device_node *); +- +-#endif /* !(_SERIAL_SUN_H) */ +--- a/drivers/tty/serial/sunhv.c ++++ b/drivers/tty/serial/sunhv.c +@@ -29,8 +29,7 @@ + #endif + + #include <linux/serial_core.h> +- +-#include "suncore.h" ++#include <linux/sunserialcore.h> + + #define CON_BREAK ((long)-1) + #define CON_HUP ((long)-2) +--- a/drivers/tty/serial/sunsab.c ++++ b/drivers/tty/serial/sunsab.c +@@ -43,8 +43,8 @@ + #endif + + #include <linux/serial_core.h> ++#include <linux/sunserialcore.h> + +-#include "suncore.h" + #include "sunsab.h" + + struct uart_sunsab_port { +--- a/drivers/tty/serial/sunsu.c ++++ b/drivers/tty/serial/sunsu.c +@@ -47,8 +47,7 @@ + #endif + + #include <linux/serial_core.h> +- +-#include "suncore.h" ++#include <linux/sunserialcore.h> + + /* We are on a NS PC87303 clocked with 24.0 MHz, which results + * in a UART clock of 1.8462 MHz. +--- a/drivers/tty/serial/sunzilog.c ++++ b/drivers/tty/serial/sunzilog.c +@@ -43,8 +43,8 @@ + #endif + + #include <linux/serial_core.h> ++#include <linux/sunserialcore.h> + +-#include "suncore.h" + #include "sunzilog.h" + + /* On 32-bit sparcs we need to delay after register accesses +--- /dev/null ++++ b/include/linux/sunserialcore.h +@@ -0,0 +1,33 @@ ++/* sunserialcore.h ++ * ++ * Generic SUN serial/kbd/ms layer. Based entirely ++ * upon drivers/sbus/char/sunserial.h which is: ++ * ++ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) ++ * ++ * Port to new UART layer is: ++ * ++ * Copyright (C) 2002 David S. Miller (davem@redhat.com) ++ */ ++ ++#ifndef _SERIAL_SUN_H ++#define _SERIAL_SUN_H ++ ++/* Serial keyboard defines for L1-A processing... */ ++#define SUNKBD_RESET 0xff ++#define SUNKBD_L1 0x01 ++#define SUNKBD_UP 0x80 ++#define SUNKBD_A 0x4d ++ ++extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); ++extern int suncore_mouse_baud_detection(unsigned char, int); ++ ++extern int sunserial_register_minors(struct uart_driver *, int); ++extern void sunserial_unregister_minors(struct uart_driver *, int); ++ ++extern int sunserial_console_match(struct console *, struct device_node *, ++ struct uart_driver *, int, bool); ++extern void sunserial_console_termios(struct console *, ++ struct device_node *); ++ ++#endif /* !(_SERIAL_SUN_H) */ diff --git a/patches.kzm9g/0021-serial-delete-last-unused-traces-of-pausing-I-O-in-8.patch b/patches.kzm9g/0021-serial-delete-last-unused-traces-of-pausing-I-O-in-8.patch new file mode 100644 index 00000000000000..5356b24616bf68 --- /dev/null +++ b/patches.kzm9g/0021-serial-delete-last-unused-traces-of-pausing-I-O-in-8.patch @@ -0,0 +1,732 @@ +From 6312e447e5cfbc4a17af35d1c1bb0b12df671ad2 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:08 -0500 +Subject: serial: delete last unused traces of pausing I/O in 8250 + +This is the last traces of pausing I/O that we had back some +twenty years ago. Probably was only required for 8MHz ISA +cards running "on the edge" at 12MHz. Anyway it hasn't been +in use for years, so lets just bury it for good. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 0acf519f3f22450ae8f90cdb0f77b046fc731624) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 308 +++++++++++++++++++--------------------- + 1 file changed, 150 insertions(+), 158 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 9e2e282..fe75134 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -486,26 +486,18 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) + (up->port.serial_in(&(up)->port, (offset))) + #define serial_out(up, offset, value) \ + (up->port.serial_out(&(up)->port, (offset), (value))) +-/* +- * We used to support using pause I/O for certain machines. We +- * haven't supported this for a while, but just in case it's badly +- * needed for certain old 386 machines, I've left these #define's +- * in.... +- */ +-#define serial_inp(up, offset) serial_in(up, offset) +-#define serial_outp(up, offset, value) serial_out(up, offset, value) + + /* Uart divisor latch read */ + static inline int _serial_dl_read(struct uart_8250_port *up) + { +- return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; ++ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; + } + + /* Uart divisor latch write */ + static inline void _serial_dl_write(struct uart_8250_port *up, int value) + { +- serial_outp(up, UART_DLL, value & 0xff); +- serial_outp(up, UART_DLM, value >> 8 & 0xff); ++ serial_out(up, UART_DLL, value & 0xff); ++ serial_out(up, UART_DLM, value >> 8 & 0xff); + } + + #if defined(CONFIG_MIPS_ALCHEMY) +@@ -575,10 +567,10 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) + static void serial8250_clear_fifos(struct uart_8250_port *p) + { + if (p->capabilities & UART_CAP_FIFO) { +- serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); +- serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | ++ serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); +- serial_outp(p, UART_FCR, 0); ++ serial_out(p, UART_FCR, 0); + } + } + +@@ -591,15 +583,15 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + { + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { +- serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(p, UART_EFR, UART_EFR_ECB); +- serial_outp(p, UART_LCR, 0); ++ serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(p, UART_EFR, UART_EFR_ECB); ++ serial_out(p, UART_LCR, 0); + } +- serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); ++ serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { +- serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(p, UART_EFR, 0); +- serial_outp(p, UART_LCR, 0); ++ serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(p, UART_EFR, 0); ++ serial_out(p, UART_LCR, 0); + } + } + } +@@ -614,12 +606,12 @@ static int __enable_rsa(struct uart_8250_port *up) + unsigned char mode; + int result; + +- mode = serial_inp(up, UART_RSA_MSR); ++ mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { +- serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); +- mode = serial_inp(up, UART_RSA_MSR); ++ serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); ++ mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + +@@ -638,7 +630,7 @@ static void enable_rsa(struct uart_8250_port *up) + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) +- serial_outp(up, UART_RSA_FRR, 0); ++ serial_out(up, UART_RSA_FRR, 0); + } + } + +@@ -657,12 +649,12 @@ static void disable_rsa(struct uart_8250_port *up) + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + +- mode = serial_inp(up, UART_RSA_MSR); ++ mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { +- serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); +- mode = serial_inp(up, UART_RSA_MSR); ++ serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); ++ mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + +@@ -683,28 +675,28 @@ static int size_fifo(struct uart_8250_port *up) + unsigned short old_dl; + int count; + +- old_lcr = serial_inp(up, UART_LCR); +- serial_outp(up, UART_LCR, 0); +- old_fcr = serial_inp(up, UART_FCR); +- old_mcr = serial_inp(up, UART_MCR); +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | ++ old_lcr = serial_in(up, UART_LCR); ++ serial_out(up, UART_LCR, 0); ++ old_fcr = serial_in(up, UART_FCR); ++ old_mcr = serial_in(up, UART_MCR); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); +- serial_outp(up, UART_MCR, UART_MCR_LOOP); +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); ++ serial_out(up, UART_MCR, UART_MCR_LOOP); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); +- serial_outp(up, UART_LCR, 0x03); ++ serial_out(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) +- serial_outp(up, UART_TX, count); ++ serial_out(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ +- for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && ++ for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) +- serial_inp(up, UART_RX); +- serial_outp(up, UART_FCR, old_fcr); +- serial_outp(up, UART_MCR, old_mcr); +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); ++ serial_in(up, UART_RX); ++ serial_out(up, UART_FCR, old_fcr); ++ serial_out(up, UART_MCR, old_mcr); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_dl_write(up, old_dl); +- serial_outp(up, UART_LCR, old_lcr); ++ serial_out(up, UART_LCR, old_lcr); + + return count; + } +@@ -719,20 +711,20 @@ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + +- old_lcr = serial_inp(p, UART_LCR); +- serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A); ++ old_lcr = serial_in(p, UART_LCR); ++ serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + +- old_dll = serial_inp(p, UART_DLL); +- old_dlm = serial_inp(p, UART_DLM); ++ old_dll = serial_in(p, UART_DLL); ++ old_dlm = serial_in(p, UART_DLM); + +- serial_outp(p, UART_DLL, 0); +- serial_outp(p, UART_DLM, 0); ++ serial_out(p, UART_DLL, 0); ++ serial_out(p, UART_DLM, 0); + +- id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8; ++ id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; + +- serial_outp(p, UART_DLL, old_dll); +- serial_outp(p, UART_DLM, old_dlm); +- serial_outp(p, UART_LCR, old_lcr); ++ serial_out(p, UART_DLL, old_dll); ++ serial_out(p, UART_DLM, old_dlm); ++ serial_out(p, UART_LCR, old_lcr); + + return id; + } +@@ -842,11 +834,11 @@ static void autoconfig_8250(struct uart_8250_port *up) + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); +- serial_outp(up, UART_SCR, 0xa5); ++ serial_out(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); +- serial_outp(up, UART_SCR, 0x5a); ++ serial_out(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); +- serial_outp(up, UART_SCR, scratch); ++ serial_out(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +@@ -877,7 +869,7 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) + } else { + status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ +- serial_outp(up, 0x04, status); ++ serial_out(up, 0x04, status); + } + return 1; + } +@@ -900,9 +892,9 @@ static void autoconfig_16550a(struct uart_8250_port *up) + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + if (serial_in(up, UART_EFR) == 0) { +- serial_outp(up, UART_EFR, 0xA8); ++ serial_out(up, UART_EFR, 0xA8); + if (serial_in(up, UART_EFR) != 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; +@@ -910,7 +902,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) + } else { + DEBUG_AUTOCONF("Motorola 8xxx DUART "); + } +- serial_outp(up, UART_EFR, 0); ++ serial_out(up, UART_EFR, 0); + return; + } + +@@ -918,7 +910,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); +@@ -932,23 +924,23 @@ static void autoconfig_16550a(struct uart_8250_port *up) + * switch back to bank 2, read it from EXCR1 again and check + * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 + */ +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, 0); + status1 = serial_in(up, UART_MCR); +- serial_outp(up, UART_LCR, 0xE0); ++ serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + + if (!((status2 ^ status1) & UART_MCR_LOOP)) { +- serial_outp(up, UART_LCR, 0); +- serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP); +- serial_outp(up, UART_LCR, 0xE0); ++ serial_out(up, UART_LCR, 0); ++ serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); ++ serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ +- serial_outp(up, UART_LCR, 0); +- serial_outp(up, UART_MCR, status1); ++ serial_out(up, UART_LCR, 0); ++ serial_out(up, UART_MCR, status1); + + if ((status2 ^ status1) & UART_MCR_LOOP) { + unsigned short quot; + +- serial_outp(up, UART_LCR, 0xE0); ++ serial_out(up, UART_LCR, 0xE0); + + quot = serial_dl_read(up); + quot <<= 3; +@@ -956,7 +948,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) + if (ns16550a_goto_highspeed(up)) + serial_dl_write(up, quot); + +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, 0); + + up->port.uartclk = 921600*16; + up->port.type = PORT_NS16550A; +@@ -971,15 +963,15 @@ static void autoconfig_16550a(struct uart_8250_port *up) + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ +- serial_outp(up, UART_LCR, 0); +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); ++ serial_out(up, UART_LCR, 0); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_LCR, 0); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + +@@ -998,13 +990,13 @@ static void autoconfig_16550a(struct uart_8250_port *up) + * already a 1 and maybe locked there before we even start start. + */ + iersave = serial_in(up, UART_IER); +- serial_outp(up, UART_IER, iersave & ~UART_IER_UUE); ++ serial_out(up, UART_IER, iersave & ~UART_IER_UUE); + if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ +- serial_outp(up, UART_IER, iersave | UART_IER_UUE); ++ serial_out(up, UART_IER, iersave | UART_IER_UUE); + if (serial_in(up, UART_IER) & UART_IER_UUE) { + /* + * It's an Xscale. +@@ -1022,7 +1014,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) + */ + DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); + } +- serial_outp(up, UART_IER, iersave); ++ serial_out(up, UART_IER, iersave); + + /* + * Exar uarts have EFR in a weird location +@@ -1084,8 +1076,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. + */ +- scratch = serial_inp(up, UART_IER); +- serial_outp(up, UART_IER, 0); ++ scratch = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, 0); + #ifdef __i386__ + outb(0xff, 0x080); + #endif +@@ -1093,13 +1085,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ +- scratch2 = serial_inp(up, UART_IER) & 0x0f; +- serial_outp(up, UART_IER, 0x0F); ++ scratch2 = serial_in(up, UART_IER) & 0x0f; ++ serial_out(up, UART_IER, 0x0F); + #ifdef __i386__ + outb(0, 0x080); + #endif +- scratch3 = serial_inp(up, UART_IER) & 0x0f; +- serial_outp(up, UART_IER, scratch); ++ scratch3 = serial_in(up, UART_IER) & 0x0f; ++ serial_out(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here +@@ -1123,9 +1115,9 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + * that conflicts with COM 1-4 --- we hope! + */ + if (!(up->port.flags & UPF_SKIP_TEST)) { +- serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); +- status1 = serial_inp(up, UART_MSR) & 0xF0; +- serial_outp(up, UART_MCR, save_mcr); ++ serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); ++ status1 = serial_in(up, UART_MSR) & 0xF0; ++ serial_out(up, UART_MCR, save_mcr); + if (status1 != 0x90) { + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); +@@ -1142,11 +1134,11 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(up, UART_EFR, 0); +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_EFR, 0); ++ serial_out(up, UART_LCR, 0); + +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + + DEBUG_AUTOCONF("iir=%d ", scratch); +@@ -1183,7 +1175,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + } + #endif + +- serial_outp(up, UART_LCR, save_lcr); ++ serial_out(up, UART_LCR, save_lcr); + + if (up->capabilities != uart_config[up->port.type].flags) { + printk(KERN_WARNING +@@ -1204,15 +1196,15 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + */ + #ifdef CONFIG_SERIAL_8250_RSA + if (up->port.type == PORT_RSA) +- serial_outp(up, UART_RSA_FRR, 0); ++ serial_out(up, UART_RSA_FRR, 0); + #endif +- serial_outp(up, UART_MCR, save_mcr); ++ serial_out(up, UART_MCR, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + if (up->capabilities & UART_CAP_UUE) +- serial_outp(up, UART_IER, UART_IER_UUE); ++ serial_out(up, UART_IER, UART_IER_UUE); + else +- serial_outp(up, UART_IER, 0); ++ serial_out(up, UART_IER, 0); + + out: + spin_unlock_irqrestore(&up->port.lock, flags); +@@ -1236,31 +1228,31 @@ static void autoconfig_irq(struct uart_8250_port *up) + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); +- save_mcr = serial_inp(up, UART_MCR); +- save_ier = serial_inp(up, UART_IER); +- serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); ++ save_mcr = serial_in(up, UART_MCR); ++ save_ier = serial_in(up, UART_IER); ++ serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); +- serial_outp(up, UART_MCR, 0); ++ serial_out(up, UART_MCR, 0); + udelay(10); + if (up->port.flags & UPF_FOURPORT) { +- serial_outp(up, UART_MCR, ++ serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { +- serial_outp(up, UART_MCR, ++ serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } +- serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ +- (void)serial_inp(up, UART_LSR); +- (void)serial_inp(up, UART_RX); +- (void)serial_inp(up, UART_IIR); +- (void)serial_inp(up, UART_MSR); +- serial_outp(up, UART_TX, 0xFF); ++ serial_out(up, UART_IER, 0x0f); /* enable all intrs */ ++ (void)serial_in(up, UART_LSR); ++ (void)serial_in(up, UART_RX); ++ (void)serial_in(up, UART_IIR); ++ (void)serial_in(up, UART_MSR); ++ serial_out(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); + +- serial_outp(up, UART_MCR, save_mcr); +- serial_outp(up, UART_IER, save_ier); ++ serial_out(up, UART_MCR, save_mcr); ++ serial_out(up, UART_IER, save_ier); + + if (up->port.flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); +@@ -1380,7 +1372,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + + do { + if (likely(lsr & UART_LSR_DR)) +- ch = serial_inp(up, UART_RX); ++ ch = serial_in(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will +@@ -1445,7 +1437,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + + ignore_char: +- lsr = serial_inp(up, UART_LSR); ++ lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); + spin_unlock(&up->port.lock); + tty_flip_buffer_push(tty); +@@ -1460,7 +1452,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) + int count; + + if (up->port.x_char) { +- serial_outp(up, UART_TX, up->port.x_char); ++ serial_out(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; +@@ -1532,7 +1524,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + + spin_lock_irqsave(&up->port.lock, flags); + +- status = serial_inp(up, UART_LSR); ++ status = serial_in(up, UART_LSR); + + DEBUG_INTR("status = %x...", status); + +@@ -1892,12 +1884,12 @@ static int serial8250_get_poll_char(struct uart_port *port) + { + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); +- unsigned char lsr = serial_inp(up, UART_LSR); ++ unsigned char lsr = serial_in(up, UART_LSR); + + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; + +- return serial_inp(up, UART_RX); ++ return serial_in(up, UART_RX); + } + + +@@ -1957,14 +1949,14 @@ static int serial8250_startup(struct uart_port *port) + if (up->port.type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(up, UART_EFR, UART_EFR_ECB); +- serial_outp(up, UART_IER, 0); +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_EFR, UART_EFR_ECB); ++ serial_out(up, UART_IER, 0); ++ serial_out(up, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_outp(up, UART_EFR, UART_EFR_ECB); +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_EFR, UART_EFR_ECB); ++ serial_out(up, UART_LCR, 0); + } + + #ifdef CONFIG_SERIAL_8250_RSA +@@ -1984,10 +1976,10 @@ static int serial8250_startup(struct uart_port *port) + /* + * Clear the interrupt registers. + */ +- (void) serial_inp(up, UART_LSR); +- (void) serial_inp(up, UART_RX); +- (void) serial_inp(up, UART_IIR); +- (void) serial_inp(up, UART_MSR); ++ (void) serial_in(up, UART_LSR); ++ (void) serial_in(up, UART_RX); ++ (void) serial_in(up, UART_IIR); ++ (void) serial_in(up, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; +@@ -1995,7 +1987,7 @@ static int serial8250_startup(struct uart_port *port) + * here. + */ + if (!(up->port.flags & UPF_BUGGY_UART) && +- (serial_inp(up, UART_LSR) == 0xff)) { ++ (serial_in(up, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(&up->port)); + return -ENODEV; +@@ -2007,15 +1999,15 @@ static int serial8250_startup(struct uart_port *port) + if (up->port.type == PORT_16850) { + unsigned char fctr; + +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + +- fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); +- serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); +- serial_outp(up, UART_TRG, UART_TRG_96); +- serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); +- serial_outp(up, UART_TRG, UART_TRG_96); ++ fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); ++ serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); ++ serial_out(up, UART_TRG, UART_TRG_96); ++ serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); ++ serial_out(up, UART_TRG, UART_TRG_96); + +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, 0); + } + + if (up->port.irq) { +@@ -2085,7 +2077,7 @@ static int serial8250_startup(struct uart_port *port) + /* + * Now, initialize the UART + */ +- serial_outp(up, UART_LCR, UART_LCR_WLEN8); ++ serial_out(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { +@@ -2118,10 +2110,10 @@ static int serial8250_startup(struct uart_port *port) + * Do a quick test to see if we receive an + * interrupt when we enable the TX irq. + */ +- serial_outp(up, UART_IER, UART_IER_THRI); ++ serial_out(up, UART_IER, UART_IER_THRI); + lsr = serial_in(up, UART_LSR); + iir = serial_in(up, UART_IIR); +- serial_outp(up, UART_IER, 0); ++ serial_out(up, UART_IER, 0); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { +@@ -2141,10 +2133,10 @@ dont_test_tx_en: + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ +- serial_inp(up, UART_LSR); +- serial_inp(up, UART_RX); +- serial_inp(up, UART_IIR); +- serial_inp(up, UART_MSR); ++ serial_in(up, UART_LSR); ++ serial_in(up, UART_RX); ++ serial_in(up, UART_IIR); ++ serial_in(up, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + +@@ -2154,7 +2146,7 @@ dont_test_tx_en: + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; +- serial_outp(up, UART_IER, up->ier); ++ serial_out(up, UART_IER, up->ier); + + if (up->port.flags & UPF_FOURPORT) { + unsigned int icp; +@@ -2179,7 +2171,7 @@ static void serial8250_shutdown(struct uart_port *port) + * Disable interrupts from this port + */ + up->ier = 0; +- serial_outp(up, UART_IER, 0); ++ serial_out(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { +@@ -2195,7 +2187,7 @@ static void serial8250_shutdown(struct uart_port *port) + /* + * Disable break condition and FIFOs + */ +- serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); ++ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + + #ifdef CONFIG_SERIAL_8250_RSA +@@ -2372,11 +2364,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + +- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (up->port.flags & UPF_EXAR_EFR) +- serial_outp(up, UART_XR_EFR, efr); ++ serial_out(up, UART_XR_EFR, efr); + else +- serial_outp(up, UART_EFR, efr); ++ serial_out(up, UART_EFR, efr); + } + + #ifdef CONFIG_ARCH_OMAP +@@ -2392,9 +2384,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + + if (up->capabilities & UART_NATSEMI) { + /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ +- serial_outp(up, UART_LCR, 0xe0); ++ serial_out(up, UART_LCR, 0xe0); + } else { +- serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ ++ serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + } + + serial_dl_write(up, quot); +@@ -2404,16 +2396,16 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * is written without DLAB set, this mode will be disabled. + */ + if (up->port.type == PORT_16750) +- serial_outp(up, UART_FCR, fcr); ++ serial_out(up, UART_FCR, fcr); + +- serial_outp(up, UART_LCR, cval); /* reset DLAB */ ++ serial_out(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (up->port.type != PORT_16750) { + if (fcr & UART_FCR_ENABLE_FIFO) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ +- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } +- serial_outp(up, UART_FCR, fcr); /* set fcr */ ++ serial_out(up, UART_FCR, fcr); /* set fcr */ + } + serial8250_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); +@@ -2995,11 +2987,11 @@ void serial8250_resume_port(int line) + + if (up->capabilities & UART_NATSEMI) { + /* Ensure it's still in high speed mode */ +- serial_outp(up, UART_LCR, 0xE0); ++ serial_out(up, UART_LCR, 0xE0); + + ns16550a_goto_highspeed(up); + +- serial_outp(up, UART_LCR, 0); ++ serial_out(up, UART_LCR, 0); + up->port.uartclk = 921600*16; + } + uart_resume_port(&serial8250_reg, &up->port); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0022-serial-make-8250-s-serial_in-shareable-to-other-driv.patch b/patches.kzm9g/0022-serial-make-8250-s-serial_in-shareable-to-other-driv.patch new file mode 100644 index 00000000000000..5492bd40e93e39 --- /dev/null +++ b/patches.kzm9g/0022-serial-make-8250-s-serial_in-shareable-to-other-driv.patch @@ -0,0 +1,73 @@ +From aa16319bc84ef2b1c48898c340accb81575be000 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:09 -0500 +Subject: serial: make 8250's serial_in shareable to other drivers. + +Currently 8250.c has serial_in and serial_out as shortcuts +to doing the port I/O. They are implemented as macros a +ways down in the file. This isn't by accident, but is +implicitly required, so cpp doesn't mangle other instances +of the common string "serial_in", as it exists as a field +in the port struct itself. + +The above mangling avoidance violates the principle of least +surprise, and it also prevents the shortcuts from being +relocated up to the top of file, or into 8250.h -- either +being a better location than the current one. + +Move them to 8250.h so other 8250-like drivers can also use +the shortcuts, and in the process, make the conflicting +names go away by using static inlines instead of macros. +The object file size remains unchanged with this modification. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 3f0ab32753b49ae7afc5b69e3f23152d92aa1f85) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 5 ----- + drivers/tty/serial/8250/8250.h | 10 ++++++++++ + 2 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index fe75134..06e17d5 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -482,11 +482,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) + } + } + +-#define serial_in(up, offset) \ +- (up->port.serial_in(&(up)->port, (offset))) +-#define serial_out(up, offset, value) \ +- (up->port.serial_out(&(up)->port, (offset), (value))) +- + /* Uart divisor latch read */ + static inline int _serial_dl_read(struct uart_8250_port *up) + { +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index ae027be..2868a1d 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -86,6 +86,16 @@ struct serial8250_config { + #define SERIAL8250_SHARE_IRQS 0 + #endif + ++static inline int serial_in(struct uart_8250_port *up, int offset) ++{ ++ return up->port.serial_in(&up->port, offset); ++} ++ ++static inline void serial_out(struct uart_8250_port *up, int offset, int value) ++{ ++ up->port.serial_out(&up->port, offset, value); ++} ++ + #if defined(__alpha__) && !defined(CONFIG_PCI) + /* + * Digital did something really horribly wrong with the OUT1 and OUT2 +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0023-serial-delete-useless-void-casts-in-8250.c.patch b/patches.kzm9g/0023-serial-delete-useless-void-casts-in-8250.c.patch new file mode 100644 index 00000000000000..ee3eaff5a34de7 --- /dev/null +++ b/patches.kzm9g/0023-serial-delete-useless-void-casts-in-8250.c.patch @@ -0,0 +1,84 @@ +From e5d5cfab51ec956d809d5951e2ec3b7d7fe7819c Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:10 -0500 +Subject: serial: delete useless void casts in 8250.c + +These might have worked some magic with an ancient gcc back in +1992, but "objdump --disassemble" on gcc 4.6 on x86-64 shows +identical output before and after this commit. Send the casts +and their hysterical rasins to the bitbucket. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 0d263a264c4b8376ccf33248f6fac873310e5e05) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 06e17d5..5da9f99 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -1218,7 +1218,7 @@ static void autoconfig_irq(struct uart_8250_port *up) + ICP = (up->port.iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); +- (void) inb_p(ICP); ++ inb_p(ICP); + } + + /* forget possible initially masked and pending IRQ */ +@@ -1238,10 +1238,10 @@ static void autoconfig_irq(struct uart_8250_port *up) + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_out(up, UART_IER, 0x0f); /* enable all intrs */ +- (void)serial_in(up, UART_LSR); +- (void)serial_in(up, UART_RX); +- (void)serial_in(up, UART_IIR); +- (void)serial_in(up, UART_MSR); ++ serial_in(up, UART_LSR); ++ serial_in(up, UART_RX); ++ serial_in(up, UART_IIR); ++ serial_in(up, UART_MSR); + serial_out(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); +@@ -1971,10 +1971,10 @@ static int serial8250_startup(struct uart_port *port) + /* + * Clear the interrupt registers. + */ +- (void) serial_in(up, UART_LSR); +- (void) serial_in(up, UART_RX); +- (void) serial_in(up, UART_IIR); +- (void) serial_in(up, UART_MSR); ++ serial_in(up, UART_LSR); ++ serial_in(up, UART_RX); ++ serial_in(up, UART_IIR); ++ serial_in(up, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; +@@ -2150,7 +2150,7 @@ dont_test_tx_en: + */ + icp = (up->port.iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); +- (void) inb_p(icp); ++ inb_p(icp); + } + + return 0; +@@ -2196,7 +2196,7 @@ static void serial8250_shutdown(struct uart_port *port) + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ +- (void) serial_in(up, UART_RX); ++ serial_in(up, UART_RX); + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0024-serial-reduce-number-of-indirections-in-8250-code.patch b/patches.kzm9g/0024-serial-reduce-number-of-indirections-in-8250-code.patch new file mode 100644 index 00000000000000..f729a5591f1fc3 --- /dev/null +++ b/patches.kzm9g/0024-serial-reduce-number-of-indirections-in-8250-code.patch @@ -0,0 +1,958 @@ +From 83c841cec4163679900da8fa7845ef51fd8d9486 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:11 -0500 +Subject: serial: reduce number of indirections in 8250 code + +The serial_8250_port struct contains within a serial_port struct +and many times one or the other, or both are in scope within +functions via a passed in arg, or via container_of. + +However there are a lot of cases where we have access directly +to the port pointer, but yet go through the parent 8250_port +structure instead to get it. These should just use the port +struct directly. + +Similarly there are cases where it makes sense (from a code +cleanliness point of view) to declare a local for the port +struct, so we aren't going through the parent 8250_port struct +repeatedly to get to it. + +We get a small reduction in text size, but it appears that +gcc was smart enough to internally be doing most of this +already, so the readability improvement is the larger gain. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit dfe42443ea1d30c98db59b7b1f914bc147d31336) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 322 +++++++++++++++++++++------------------- + 1 file changed, 167 insertions(+), 155 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 5da9f99..9ffb3cf 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -1040,24 +1040,25 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + { + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; ++ struct uart_port *port = &up->port; + unsigned long flags; + +- if (!up->port.iobase && !up->port.mapbase && !up->port.membase) ++ if (!port->iobase && !port->mapbase && !port->membase) + return; + + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", +- serial_index(&up->port), up->port.iobase, up->port.membase); ++ serial_index(port), port->iobase, port->membase); + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + + up->capabilities = 0; + up->bugs = 0; + +- if (!(up->port.flags & UPF_BUGGY_UART)) { ++ if (!(port->flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. +@@ -1109,7 +1110,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ +- if (!(up->port.flags & UPF_SKIP_TEST)) { ++ if (!(port->flags & UPF_SKIP_TEST)) { + serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_in(up, UART_MSR) & 0xF0; + serial_out(up, UART_MCR, save_mcr); +@@ -1143,10 +1144,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + autoconfig_8250(up); + break; + case 1: +- up->port.type = PORT_UNKNOWN; ++ port->type = PORT_UNKNOWN; + break; + case 2: +- up->port.type = PORT_16550; ++ port->type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); +@@ -1157,13 +1158,12 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + /* + * Only probe for RSA ports if we got the region. + */ +- if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { ++ if (port->type == PORT_16550A && probeflags & PROBE_RSA) { + int i; + + for (i = 0 ; i < probe_rsa_count; ++i) { +- if (probe_rsa[i] == up->port.iobase && +- __enable_rsa(up)) { +- up->port.type = PORT_RSA; ++ if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { ++ port->type = PORT_RSA; + break; + } + } +@@ -1172,25 +1172,25 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + + serial_out(up, UART_LCR, save_lcr); + +- if (up->capabilities != uart_config[up->port.type].flags) { ++ if (up->capabilities != uart_config[port->type].flags) { + printk(KERN_WARNING + "ttyS%d: detected caps %08x should be %08x\n", +- serial_index(&up->port), up->capabilities, +- uart_config[up->port.type].flags); ++ serial_index(port), up->capabilities, ++ uart_config[port->type].flags); + } + +- up->port.fifosize = uart_config[up->port.type].fifo_size; +- up->capabilities = uart_config[up->port.type].flags; +- up->tx_loadsz = uart_config[up->port.type].tx_loadsz; ++ port->fifosize = uart_config[up->port.type].fifo_size; ++ up->capabilities = uart_config[port->type].flags; ++ up->tx_loadsz = uart_config[port->type].tx_loadsz; + +- if (up->port.type == PORT_UNKNOWN) ++ if (port->type == PORT_UNKNOWN) + goto out; + + /* + * Reset the UART. + */ + #ifdef CONFIG_SERIAL_8250_RSA +- if (up->port.type == PORT_RSA) ++ if (port->type == PORT_RSA) + serial_out(up, UART_RSA_FRR, 0); + #endif + serial_out(up, UART_MCR, save_mcr); +@@ -1202,20 +1202,21 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) + serial_out(up, UART_IER, 0); + + out: +- spin_unlock_irqrestore(&up->port.lock, flags); +- DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); ++ spin_unlock_irqrestore(&port->lock, flags); ++ DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); + } + + static void autoconfig_irq(struct uart_8250_port *up) + { ++ struct uart_port *port = &up->port; + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + +- if (up->port.flags & UPF_FOURPORT) { +- ICP = (up->port.iobase & 0xfe0) | 0x1f; ++ if (port->flags & UPF_FOURPORT) { ++ ICP = (port->iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + inb_p(ICP); +@@ -1230,7 +1231,7 @@ static void autoconfig_irq(struct uart_8250_port *up) + irqs = probe_irq_on(); + serial_out(up, UART_MCR, 0); + udelay(10); +- if (up->port.flags & UPF_FOURPORT) { ++ if (port->flags & UPF_FOURPORT) { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { +@@ -1249,10 +1250,10 @@ static void autoconfig_irq(struct uart_8250_port *up) + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_IER, save_ier); + +- if (up->port.flags & UPF_FOURPORT) ++ if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + +- up->port.irq = (irq > 0) ? irq : 0; ++ port->irq = (irq > 0) ? irq : 0; + } + + static inline void __stop_tx(struct uart_8250_port *p) +@@ -1273,7 +1274,7 @@ static void serial8250_stop_tx(struct uart_port *port) + /* + * We really want to stop the transmitter from sending. + */ +- if (up->port.type == PORT_16C950) { ++ if (port->type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +@@ -1292,7 +1293,7 @@ static void serial8250_start_tx(struct uart_port *port) + unsigned char lsr; + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; +- if ((up->port.type == PORT_RM9000) ? ++ if ((port->type == PORT_RM9000) ? + (lsr & UART_LSR_THRE) : + (lsr & UART_LSR_TEMT)) + serial8250_tx_chars(up); +@@ -1302,7 +1303,7 @@ static void serial8250_start_tx(struct uart_port *port) + /* + * Re-enable the transmitter if we disabled it. + */ +- if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { ++ if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +@@ -1360,7 +1361,8 @@ static void clear_rx_fifo(struct uart_8250_port *up) + unsigned char + serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + { +- struct tty_struct *tty = up->port.state->port.tty; ++ struct uart_port *port = &up->port; ++ struct tty_struct *tty = port->state->port.tty; + unsigned char ch; + int max_count = 256; + char flag; +@@ -1379,7 +1381,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + ch = 0; + + flag = TTY_NORMAL; +- up->port.icount.rx++; ++ port->icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; +@@ -1390,12 +1392,12 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + */ + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); +- up->port.icount.brk++; ++ port->icount.brk++; + /* + * If tegra port then clear the rx fifo to + * accept another break/character. + */ +- if (up->port.type == PORT_TEGRA) ++ if (port->type == PORT_TEGRA) + clear_rx_fifo(up); + + /* +@@ -1404,19 +1406,19 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + * may get masked by ignore_status_mask + * or read_status_mask. + */ +- if (uart_handle_break(&up->port)) ++ if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) +- up->port.icount.parity++; ++ port->icount.parity++; + else if (lsr & UART_LSR_FE) +- up->port.icount.frame++; ++ port->icount.frame++; + if (lsr & UART_LSR_OE) +- up->port.icount.overrun++; ++ port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ +- lsr &= up->port.read_status_mask; ++ lsr &= port->read_status_mask; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); +@@ -1426,34 +1428,35 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } +- if (uart_handle_sysrq_char(&up->port, ch)) ++ if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + +- uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); ++ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); + + ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); +- spin_unlock(&up->port.lock); ++ spin_unlock(&port->lock); + tty_flip_buffer_push(tty); +- spin_lock(&up->port.lock); ++ spin_lock(&port->lock); + return lsr; + } + EXPORT_SYMBOL_GPL(serial8250_rx_chars); + + void serial8250_tx_chars(struct uart_8250_port *up) + { +- struct circ_buf *xmit = &up->port.state->xmit; ++ struct uart_port *port = &up->port; ++ struct circ_buf *xmit = &port->state->xmit; + int count; + +- if (up->port.x_char) { +- serial_out(up, UART_TX, up->port.x_char); +- up->port.icount.tx++; +- up->port.x_char = 0; ++ if (port->x_char) { ++ serial_out(up, UART_TX, port->x_char); ++ port->icount.tx++; ++ port->x_char = 0; + return; + } +- if (uart_tx_stopped(&up->port)) { +- serial8250_stop_tx(&up->port); ++ if (uart_tx_stopped(port)) { ++ serial8250_stop_tx(port); + return; + } + if (uart_circ_empty(xmit)) { +@@ -1465,13 +1468,13 @@ void serial8250_tx_chars(struct uart_8250_port *up) + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +- up->port.icount.tx++; ++ port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) +- uart_write_wakeup(&up->port); ++ uart_write_wakeup(port); + + DEBUG_INTR("THRE..."); + +@@ -1482,22 +1485,23 @@ EXPORT_SYMBOL_GPL(serial8250_tx_chars); + + unsigned int serial8250_modem_status(struct uart_8250_port *up) + { ++ struct uart_port *port = &up->port; + unsigned int status = serial_in(up, UART_MSR); + + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && +- up->port.state != NULL) { ++ port->state != NULL) { + if (status & UART_MSR_TERI) +- up->port.icount.rng++; ++ port->icount.rng++; + if (status & UART_MSR_DDSR) +- up->port.icount.dsr++; ++ port->icount.dsr++; + if (status & UART_MSR_DDCD) +- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); ++ uart_handle_dcd_change(port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) +- uart_handle_cts_change(&up->port, status & UART_MSR_CTS); ++ uart_handle_cts_change(port, status & UART_MSR_CTS); + +- wake_up_interruptible(&up->port.state->port.delta_msr_wait); ++ wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + return status; +@@ -1517,7 +1521,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + if (iir & UART_IIR_NO_INT) + return 0; + +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + + status = serial_in(up, UART_LSR); + +@@ -1529,7 +1533,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + if (status & UART_LSR_THRE) + serial8250_tx_chars(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + return 1; + } + EXPORT_SYMBOL_GPL(serial8250_handle_irq); +@@ -1769,10 +1773,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int lsr; + +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; +- spin_unlock_irqrestore(&up->port.lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; + } +@@ -1826,13 +1830,13 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) + container_of(port, struct uart_8250_port, port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + /* +@@ -1933,15 +1937,15 @@ static int serial8250_startup(struct uart_port *port) + unsigned char lsr, iir; + int retval; + +- up->port.fifosize = uart_config[up->port.type].fifo_size; ++ port->fifosize = uart_config[up->port.type].fifo_size; + up->tx_loadsz = uart_config[up->port.type].tx_loadsz; + up->capabilities = uart_config[up->port.type].flags; + up->mcr = 0; + +- if (up->port.iotype != up->cur_iotype) ++ if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + +- if (up->port.type == PORT_16C950) { ++ if (port->type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); +@@ -1981,17 +1985,17 @@ static int serial8250_startup(struct uart_port *port) + * if it is, then bail out, because there's likely no UART + * here. + */ +- if (!(up->port.flags & UPF_BUGGY_UART) && ++ if (!(port->flags & UPF_BUGGY_UART) && + (serial_in(up, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", +- serial_index(&up->port)); ++ serial_index(port)); + return -ENODEV; + } + + /* + * For a XR16C850, we need to set the trigger levels + */ +- if (up->port.type == PORT_16850) { ++ if (port->type == PORT_16850) { + unsigned char fctr; + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); +@@ -2005,7 +2009,7 @@ static int serial8250_startup(struct uart_port *port) + serial_out(up, UART_LCR, 0); + } + +- if (up->port.irq) { ++ if (port->irq) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the +@@ -2015,9 +2019,9 @@ static int serial8250_startup(struct uart_port *port) + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + if (up->port.irqflags & IRQF_SHARED) +- disable_irq_nosync(up->port.irq); ++ disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_out_sync(up, UART_IER, UART_IER_THRI); +@@ -2029,9 +2033,9 @@ static int serial8250_startup(struct uart_port *port) + iir = serial_in(up, UART_IIR); + serial_out(up, UART_IER, 0); + +- if (up->port.irqflags & IRQF_SHARED) +- enable_irq(up->port.irq); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ if (port->irqflags & IRQF_SHARED) ++ enable_irq(port->irq); ++ spin_unlock_irqrestore(&port->lock, flags); + + /* + * If the interrupt is not reasserted, setup a timer to +@@ -2060,7 +2064,7 @@ static int serial8250_startup(struct uart_port *port) + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ +- if (!up->port.irq) { ++ if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else { +@@ -2074,7 +2078,7 @@ static int serial8250_startup(struct uart_port *port) + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + if (up->port.flags & UPF_FOURPORT) { + if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; +@@ -2082,10 +2086,10 @@ static int serial8250_startup(struct uart_port *port) + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ +- if (up->port.irq) ++ if (port->irq) + up->port.mctrl |= TIOCM_OUT2; + +- serial8250_set_mctrl(&up->port, up->port.mctrl); ++ serial8250_set_mctrl(port, port->mctrl); + + /* Serial over Lan (SoL) hack: + Intel 8257x Gigabit ethernet chips have a +@@ -2121,7 +2125,7 @@ static int serial8250_startup(struct uart_port *port) + } + + dont_test_tx_en: +- spin_unlock_irqrestore(&up->port.lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + + /* + * Clear the interrupt registers again for luck, and clear the +@@ -2143,12 +2147,12 @@ dont_test_tx_en: + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + +- if (up->port.flags & UPF_FOURPORT) { ++ if (port->flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ +- icp = (up->port.iobase & 0xfe0) | 0x01f; ++ icp = (port->iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + inb_p(icp); + } +@@ -2168,16 +2172,16 @@ static void serial8250_shutdown(struct uart_port *port) + up->ier = 0; + serial_out(up, UART_IER, 0); + +- spin_lock_irqsave(&up->port.lock, flags); +- if (up->port.flags & UPF_FOURPORT) { ++ spin_lock_irqsave(&port->lock, flags); ++ if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ +- inb((up->port.iobase & 0xfe0) | 0x1f); +- up->port.mctrl |= TIOCM_OUT1; ++ inb((port->iobase & 0xfe0) | 0x1f); ++ port->mctrl |= TIOCM_OUT1; + } else +- up->port.mctrl &= ~TIOCM_OUT2; ++ port->mctrl &= ~TIOCM_OUT2; + +- serial8250_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ serial8250_set_mctrl(port, port->mctrl); ++ spin_unlock_irqrestore(&port->lock, flags); + + /* + * Disable break condition and FIFOs +@@ -2200,7 +2204,7 @@ static void serial8250_shutdown(struct uart_port *port) + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; +- if (up->port.irq) ++ if (port->irq) + serial_unlink_irq_chain(up); + } + +@@ -2275,11 +2279,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) + quot++; + +- if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { ++ if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { + if (baud < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else +- fcr = uart_config[up->port.type].fcr; ++ fcr = uart_config[port->type].fcr; + } + + /* +@@ -2290,7 +2294,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * have sufficient FIFO entries for the latency of the remote + * UART to respond. IOW, at least 32 bytes of FIFO. + */ +- if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { ++ if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; +@@ -2300,40 +2304,40 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + +- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; ++ port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) +- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; ++ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) +- up->port.read_status_mask |= UART_LSR_BI; ++ port->read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ +- up->port.ignore_status_mask = 0; ++ port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) +- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; ++ port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { +- up->port.ignore_status_mask |= UART_LSR_BI; ++ port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) +- up->port.ignore_status_mask |= UART_LSR_OE; ++ port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) +- up->port.ignore_status_mask |= UART_LSR_DR; ++ port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts +@@ -2360,7 +2364,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + efr |= UART_EFR_CTS; + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); +- if (up->port.flags & UPF_EXAR_EFR) ++ if (port->flags & UPF_EXAR_EFR) + serial_out(up, UART_XR_EFR, efr); + else + serial_out(up, UART_EFR, efr); +@@ -2390,20 +2394,20 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR + * is written without DLAB set, this mode will be disabled. + */ +- if (up->port.type == PORT_16750) ++ if (port->type == PORT_16750) + serial_out(up, UART_FCR, fcr); + + serial_out(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ +- if (up->port.type != PORT_16750) { ++ if (port->type != PORT_16750) { + if (fcr & UART_FCR_ENABLE_FIFO) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_out(up, UART_FCR, fcr); /* set fcr */ + } +- serial8250_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ serial8250_set_mctrl(port, port->mctrl); ++ spin_unlock_irqrestore(&port->lock, flags); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +@@ -2468,26 +2472,26 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) + static int serial8250_request_std_resource(struct uart_8250_port *up) + { + unsigned int size = serial8250_port_size(up); ++ struct uart_port *port = &up->port; + int ret = 0; + +- switch (up->port.iotype) { ++ switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: +- if (!up->port.mapbase) ++ if (!port->mapbase) + break; + +- if (!request_mem_region(up->port.mapbase, size, "serial")) { ++ if (!request_mem_region(port->mapbase, size, "serial")) { + ret = -EBUSY; + break; + } + +- if (up->port.flags & UPF_IOREMAP) { +- up->port.membase = ioremap_nocache(up->port.mapbase, +- size); +- if (!up->port.membase) { +- release_mem_region(up->port.mapbase, size); ++ if (port->flags & UPF_IOREMAP) { ++ port->membase = ioremap_nocache(port->mapbase, size); ++ if (!port->membase) { ++ release_mem_region(port->mapbase, size); + ret = -ENOMEM; + } + } +@@ -2495,7 +2499,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) + + case UPIO_HUB6: + case UPIO_PORT: +- if (!request_region(up->port.iobase, size, "serial")) ++ if (!request_region(port->iobase, size, "serial")) + ret = -EBUSY; + break; + } +@@ -2505,26 +2509,27 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) + static void serial8250_release_std_resource(struct uart_8250_port *up) + { + unsigned int size = serial8250_port_size(up); ++ struct uart_port *port = &up->port; + +- switch (up->port.iotype) { ++ switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: +- if (!up->port.mapbase) ++ if (!port->mapbase) + break; + +- if (up->port.flags & UPF_IOREMAP) { +- iounmap(up->port.membase); +- up->port.membase = NULL; ++ if (port->flags & UPF_IOREMAP) { ++ iounmap(port->membase); ++ port->membase = NULL; + } + +- release_mem_region(up->port.mapbase, size); ++ release_mem_region(port->mapbase, size); + break; + + case UPIO_HUB6: + case UPIO_PORT: +- release_region(up->port.iobase, size); ++ release_region(port->iobase, size); + break; + } + } +@@ -2533,12 +2538,13 @@ static int serial8250_request_rsa_resource(struct uart_8250_port *up) + { + unsigned long start = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; ++ struct uart_port *port = &up->port; + int ret = -EINVAL; + +- switch (up->port.iotype) { ++ switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: +- start += up->port.iobase; ++ start += port->iobase; + if (request_region(start, size, "serial-rsa")) + ret = 0; + else +@@ -2553,11 +2559,12 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) + { + unsigned long offset = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; ++ struct uart_port *port = &up->port; + +- switch (up->port.iotype) { ++ switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: +- release_region(up->port.iobase + offset, size); ++ release_region(port->iobase + offset, size); + break; + } + } +@@ -2568,7 +2575,7 @@ static void serial8250_release_port(struct uart_port *port) + container_of(port, struct uart_8250_port, port); + + serial8250_release_std_resource(up); +- if (up->port.type == PORT_RSA) ++ if (port->type == PORT_RSA) + serial8250_release_rsa_resource(up); + } + +@@ -2579,7 +2586,7 @@ static int serial8250_request_port(struct uart_port *port) + int ret = 0; + + ret = serial8250_request_std_resource(up); +- if (ret == 0 && up->port.type == PORT_RSA) { ++ if (ret == 0 && port->type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + serial8250_release_std_resource(up); +@@ -2607,22 +2614,22 @@ static void serial8250_config_port(struct uart_port *port, int flags) + if (ret < 0) + probeflags &= ~PROBE_RSA; + +- if (up->port.iotype != up->cur_iotype) ++ if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + if (flags & UART_CONFIG_TYPE) + autoconfig(up, probeflags); + + /* if access method is AU, it is a 16550 with a quirk */ +- if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) ++ if (port->type == PORT_16550A && port->iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; + +- if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) ++ if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + +- if (up->port.type != PORT_RSA && probeflags & PROBE_RSA) ++ if (port->type != PORT_RSA && probeflags & PROBE_RSA) + serial8250_release_rsa_resource(up); +- if (up->port.type == PORT_UNKNOWN) ++ if (port->type == PORT_UNKNOWN) + serial8250_release_std_resource(up); + } + +@@ -2696,9 +2703,10 @@ static void __init serial8250_isa_init_ports(void) + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; ++ struct uart_port *port = &up->port; + +- up->port.line = i; +- spin_lock_init(&up->port.lock); ++ port->line = i; ++ spin_lock_init(&port->lock); + + init_timer(&up->timer); + up->timer.function = serial8250_timeout; +@@ -2709,7 +2717,7 @@ static void __init serial8250_isa_init_ports(void) + up->mcr_mask = ~ALPHA_KLUDGE_MCR; + up->mcr_force = ALPHA_KLUDGE_MCR; + +- up->port.ops = &serial8250_pops; ++ port->ops = &serial8250_pops; + } + + if (share_irqs) +@@ -2718,17 +2726,19 @@ static void __init serial8250_isa_init_ports(void) + for (i = 0, up = serial8250_ports; + i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; + i++, up++) { +- up->port.iobase = old_serial_port[i].port; +- up->port.irq = irq_canonicalize(old_serial_port[i].irq); +- up->port.irqflags = old_serial_port[i].irqflags; +- up->port.uartclk = old_serial_port[i].baud_base * 16; +- up->port.flags = old_serial_port[i].flags; +- up->port.hub6 = old_serial_port[i].hub6; +- up->port.membase = old_serial_port[i].iomem_base; +- up->port.iotype = old_serial_port[i].io_type; +- up->port.regshift = old_serial_port[i].iomem_reg_shift; +- set_io_from_upio(&up->port); +- up->port.irqflags |= irqflag; ++ struct uart_port *port = &up->port; ++ ++ port->iobase = old_serial_port[i].port; ++ port->irq = irq_canonicalize(old_serial_port[i].irq); ++ port->irqflags = old_serial_port[i].irqflags; ++ port->uartclk = old_serial_port[i].baud_base * 16; ++ port->flags = old_serial_port[i].flags; ++ port->hub6 = old_serial_port[i].hub6; ++ port->membase = old_serial_port[i].iomem_base; ++ port->iotype = old_serial_port[i].io_type; ++ port->regshift = old_serial_port[i].iomem_reg_shift; ++ set_io_from_upio(port); ++ port->irqflags |= irqflag; + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + +@@ -2789,6 +2799,7 @@ static void + serial8250_console_write(struct console *co, const char *s, unsigned int count) + { + struct uart_8250_port *up = &serial8250_ports[co->index]; ++ struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier; + int locked = 1; +@@ -2796,13 +2807,13 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + touch_nmi_watchdog(); + + local_irq_save(flags); +- if (up->port.sysrq) { ++ if (port->sysrq) { + /* serial8250_handle_irq() already took the lock */ + locked = 0; + } else if (oops_in_progress) { +- locked = spin_trylock(&up->port.lock); ++ locked = spin_trylock(&port->lock); + } else +- spin_lock(&up->port.lock); ++ spin_lock(&port->lock); + + /* + * First save the IER then disable the interrupts +@@ -2814,7 +2825,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + else + serial_out(up, UART_IER, 0); + +- uart_console_write(&up->port, s, count, serial8250_console_putchar); ++ uart_console_write(port, s, count, serial8250_console_putchar); + + /* + * Finally, wait for transmitter to become empty +@@ -2834,7 +2845,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + serial8250_modem_status(up); + + if (locked) +- spin_unlock(&up->port.lock); ++ spin_unlock(&port->lock); + local_irq_restore(flags); + } + +@@ -2979,6 +2990,7 @@ void serial8250_suspend_port(int line) + void serial8250_resume_port(int line) + { + struct uart_8250_port *up = &serial8250_ports[line]; ++ struct uart_port *port = &up->port; + + if (up->capabilities & UART_NATSEMI) { + /* Ensure it's still in high speed mode */ +@@ -2987,9 +2999,9 @@ void serial8250_resume_port(int line) + ns16550a_goto_highspeed(up); + + serial_out(up, UART_LCR, 0); +- up->port.uartclk = 921600*16; ++ port->uartclk = 921600*16; + } +- uart_resume_port(&serial8250_reg, &up->port); ++ uart_resume_port(&serial8250_reg, port); + } + + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0025-serial-use-serial_port_in-out-vs-serial_in-out-in-82.patch b/patches.kzm9g/0025-serial-use-serial_port_in-out-vs-serial_in-out-in-82.patch new file mode 100644 index 00000000000000..249a4282220bec --- /dev/null +++ b/patches.kzm9g/0025-serial-use-serial_port_in-out-vs-serial_in-out-in-82.patch @@ -0,0 +1,455 @@ +From 291546c8ba381a8579bdcfc2a1dee3971c3ac9b9 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:13 -0500 +Subject: serial: use serial_port_in/out vs serial_in/out in 8250 + +The serial_in and serial_out helpers are expecting to operate +on an 8250_port struct. These in turn go after the contained +normal port struct which actually has the actual in/out accessors. + +But what is happening in some cases, is that a function is passed +in a port struct, and it runs container_of to get the 8250_port +struct, and then it uses serial_in/out helpers on that. But when +you do, it goes full circle, since it jumps back inside the 8250_port +to find the contained port struct (which we already knew!). + +So, if we are operating in a scope where we know the struct port, +then use the serial_port_in/out helpers and avoid the bouncing +around. If we don't have the struct port handy, and it isn't +worth making a local for it, then just leave things as-is which +uses the serial_in/out helpers that will resolve the 8250_port +onto the struct port. + +Mostly, gcc figures this out on its own -- so this doesn't bring to +the table any revolutionary runtime delta. However, it is somewhat +misleading to always hammer away on 8250 structs, when the actual +underlying property isn't at all 8250 specific -- and this change +makes that clear. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 4fd996a14660f56a6fd92ce7c8fb167d262c994f) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 160 ++++++++++++++++++++-------------------- + 1 file changed, 80 insertions(+), 80 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 9ffb3cf..cb45a29 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -1287,7 +1287,7 @@ static void serial8250_start_tx(struct uart_port *port) + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; +- serial_out(up, UART_IER, up->ier); ++ serial_port_out(port, UART_IER, up->ier); + + if (up->bugs & UART_BUG_TXEN) { + unsigned char lsr; +@@ -1316,7 +1316,7 @@ static void serial8250_stop_rx(struct uart_port *port) + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; +- serial_out(up, UART_IER, up->ier); ++ serial_port_out(port, UART_IER, up->ier); + } + + static void serial8250_enable_ms(struct uart_port *port) +@@ -1329,7 +1329,7 @@ static void serial8250_enable_ms(struct uart_port *port) + return; + + up->ier |= UART_IER_MSI; +- serial_out(up, UART_IER, up->ier); ++ serial_port_out(port, UART_IER, up->ier); + } + + /* +@@ -1523,7 +1523,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + + spin_lock_irqsave(&port->lock, flags); + +- status = serial_in(up, UART_LSR); ++ status = serial_port_in(port, UART_LSR); + + DEBUG_INTR("status = %x...", status); + +@@ -1540,9 +1540,7 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq); + + static int serial8250_default_handle_irq(struct uart_port *port) + { +- struct uart_8250_port *up = +- container_of(port, struct uart_8250_port, port); +- unsigned int iir = serial_in(up, UART_IIR); ++ unsigned int iir = serial_port_in(port, UART_IIR); + + return serial8250_handle_irq(port, iir); + } +@@ -1774,7 +1772,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) + unsigned int lsr; + + spin_lock_irqsave(&port->lock, flags); +- lsr = serial_in(up, UART_LSR); ++ lsr = serial_port_in(port, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&port->lock, flags); + +@@ -1821,7 +1819,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) + + mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + +- serial_out(up, UART_MCR, mcr); ++ serial_port_out(port, UART_MCR, mcr); + } + + static void serial8250_break_ctl(struct uart_port *port, int break_state) +@@ -1835,7 +1833,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; +- serial_out(up, UART_LCR, up->lcr); ++ serial_port_out(port, UART_LCR, up->lcr); + spin_unlock_irqrestore(&port->lock, flags); + } + +@@ -1881,14 +1879,12 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) + + static int serial8250_get_poll_char(struct uart_port *port) + { +- struct uart_8250_port *up = +- container_of(port, struct uart_8250_port, port); +- unsigned char lsr = serial_in(up, UART_LSR); ++ unsigned char lsr = serial_port_in(port, UART_LSR); + + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; + +- return serial_in(up, UART_RX); ++ return serial_port_in(port, UART_RX); + } + + +@@ -1902,21 +1898,21 @@ static void serial8250_put_poll_char(struct uart_port *port, + /* + * First save the IER then disable the interrupts + */ +- ier = serial_in(up, UART_IER); ++ ier = serial_port_in(port, UART_IER); + if (up->capabilities & UART_CAP_UUE) +- serial_out(up, UART_IER, UART_IER_UUE); ++ serial_port_out(port, UART_IER, UART_IER_UUE); + else +- serial_out(up, UART_IER, 0); ++ serial_port_out(port, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + * If a LF, also do CR... + */ +- serial_out(up, UART_TX, c); ++ serial_port_out(port, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up, BOTH_EMPTY); +- serial_out(up, UART_TX, 13); ++ serial_port_out(port, UART_TX, 13); + } + + /* +@@ -1924,7 +1920,7 @@ static void serial8250_put_poll_char(struct uart_port *port, + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); +- serial_out(up, UART_IER, ier); ++ serial_port_out(port, UART_IER, ier); + } + + #endif /* CONFIG_CONSOLE_POLL */ +@@ -1948,14 +1944,14 @@ static int serial8250_startup(struct uart_port *port) + if (port->type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; +- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_out(up, UART_EFR, UART_EFR_ECB); +- serial_out(up, UART_IER, 0); +- serial_out(up, UART_LCR, 0); ++ serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_port_out(port, UART_EFR, UART_EFR_ECB); ++ serial_port_out(port, UART_IER, 0); ++ serial_port_out(port, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ +- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); +- serial_out(up, UART_EFR, UART_EFR_ECB); +- serial_out(up, UART_LCR, 0); ++ serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_port_out(port, UART_EFR, UART_EFR_ECB); ++ serial_port_out(port, UART_LCR, 0); + } + + #ifdef CONFIG_SERIAL_8250_RSA +@@ -1975,10 +1971,10 @@ static int serial8250_startup(struct uart_port *port) + /* + * Clear the interrupt registers. + */ +- serial_in(up, UART_LSR); +- serial_in(up, UART_RX); +- serial_in(up, UART_IIR); +- serial_in(up, UART_MSR); ++ serial_port_in(port, UART_LSR); ++ serial_port_in(port, UART_RX); ++ serial_port_in(port, UART_IIR); ++ serial_port_in(port, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; +@@ -1986,7 +1982,7 @@ static int serial8250_startup(struct uart_port *port) + * here. + */ + if (!(port->flags & UPF_BUGGY_UART) && +- (serial_in(up, UART_LSR) == 0xff)) { ++ (serial_port_in(port, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(port)); + return -ENODEV; +@@ -2001,12 +1997,14 @@ static int serial8250_startup(struct uart_port *port) + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); +- serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); +- serial_out(up, UART_TRG, UART_TRG_96); +- serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); +- serial_out(up, UART_TRG, UART_TRG_96); ++ serial_port_out(port, UART_FCTR, ++ fctr | UART_FCTR_TRGD | UART_FCTR_RX); ++ serial_port_out(port, UART_TRG, UART_TRG_96); ++ serial_port_out(port, UART_FCTR, ++ fctr | UART_FCTR_TRGD | UART_FCTR_TX); ++ serial_port_out(port, UART_TRG, UART_TRG_96); + +- serial_out(up, UART_LCR, 0); ++ serial_port_out(port, UART_LCR, 0); + } + + if (port->irq) { +@@ -2026,12 +2024,12 @@ static int serial8250_startup(struct uart_port *port) + wait_for_xmitr(up, UART_LSR_THRE); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ +- iir1 = serial_in(up, UART_IIR); +- serial_out(up, UART_IER, 0); ++ iir1 = serial_port_in(port, UART_IIR); ++ serial_port_out(port, UART_IER, 0); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ +- iir = serial_in(up, UART_IIR); +- serial_out(up, UART_IER, 0); ++ iir = serial_port_in(port, UART_IIR); ++ serial_port_out(port, UART_IER, 0); + + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); +@@ -2076,7 +2074,7 @@ static int serial8250_startup(struct uart_port *port) + /* + * Now, initialize the UART + */ +- serial_out(up, UART_LCR, UART_LCR_WLEN8); ++ serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&port->lock, flags); + if (up->port.flags & UPF_FOURPORT) { +@@ -2109,10 +2107,10 @@ static int serial8250_startup(struct uart_port *port) + * Do a quick test to see if we receive an + * interrupt when we enable the TX irq. + */ +- serial_out(up, UART_IER, UART_IER_THRI); +- lsr = serial_in(up, UART_LSR); +- iir = serial_in(up, UART_IIR); +- serial_out(up, UART_IER, 0); ++ serial_port_out(port, UART_IER, UART_IER_THRI); ++ lsr = serial_port_in(port, UART_LSR); ++ iir = serial_port_in(port, UART_IIR); ++ serial_port_out(port, UART_IER, 0); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { +@@ -2132,10 +2130,10 @@ dont_test_tx_en: + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ +- serial_in(up, UART_LSR); +- serial_in(up, UART_RX); +- serial_in(up, UART_IIR); +- serial_in(up, UART_MSR); ++ serial_port_in(port, UART_LSR); ++ serial_port_in(port, UART_RX); ++ serial_port_in(port, UART_IIR); ++ serial_port_in(port, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + +@@ -2145,7 +2143,7 @@ dont_test_tx_en: + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; +- serial_out(up, UART_IER, up->ier); ++ serial_port_out(port, UART_IER, up->ier); + + if (port->flags & UPF_FOURPORT) { + unsigned int icp; +@@ -2170,7 +2168,7 @@ static void serial8250_shutdown(struct uart_port *port) + * Disable interrupts from this port + */ + up->ier = 0; +- serial_out(up, UART_IER, 0); ++ serial_port_out(port, UART_IER, 0); + + spin_lock_irqsave(&port->lock, flags); + if (port->flags & UPF_FOURPORT) { +@@ -2186,7 +2184,8 @@ static void serial8250_shutdown(struct uart_port *port) + /* + * Disable break condition and FIFOs + */ +- serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); ++ serial_port_out(port, UART_LCR, ++ serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + + #ifdef CONFIG_SERIAL_8250_RSA +@@ -2200,7 +2199,7 @@ static void serial8250_shutdown(struct uart_port *port) + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ +- serial_in(up, UART_RX); ++ serial_port_in(port, UART_RX); + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; +@@ -2351,7 +2350,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + +- serial_out(up, UART_IER, up->ier); ++ serial_port_out(port, UART_IER, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; +@@ -2363,11 +2362,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + +- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ++ serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + if (port->flags & UPF_EXAR_EFR) +- serial_out(up, UART_XR_EFR, efr); ++ serial_port_out(port, UART_XR_EFR, efr); + else +- serial_out(up, UART_EFR, efr); ++ serial_port_out(port, UART_EFR, efr); + } + + #ifdef CONFIG_ARCH_OMAP +@@ -2375,18 +2374,20 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (cpu_is_omap1510() && is_omap_port(up)) { + if (baud == 115200) { + quot = 1; +- serial_out(up, UART_OMAP_OSC_12M_SEL, 1); ++ serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); + } else +- serial_out(up, UART_OMAP_OSC_12M_SEL, 0); ++ serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); + } + #endif + +- if (up->capabilities & UART_NATSEMI) { +- /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ +- serial_out(up, UART_LCR, 0xe0); +- } else { +- serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ +- } ++ /* ++ * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, ++ * otherwise just set DLAB ++ */ ++ if (up->capabilities & UART_NATSEMI) ++ serial_port_out(port, UART_LCR, 0xe0); ++ else ++ serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB); + + serial_dl_write(up, quot); + +@@ -2395,16 +2396,15 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * is written without DLAB set, this mode will be disabled. + */ + if (port->type == PORT_16750) +- serial_out(up, UART_FCR, fcr); ++ serial_port_out(port, UART_FCR, fcr); + +- serial_out(up, UART_LCR, cval); /* reset DLAB */ ++ serial_port_out(port, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (port->type != PORT_16750) { +- if (fcr & UART_FCR_ENABLE_FIFO) { +- /* emulated UARTs (Lucent Venus 167x) need two steps */ +- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); +- } +- serial_out(up, UART_FCR, fcr); /* set fcr */ ++ /* emulated UARTs (Lucent Venus 167x) need two steps */ ++ if (fcr & UART_FCR_ENABLE_FIFO) ++ serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_port_out(port, UART_FCR, fcr); /* set fcr */ + } + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); +@@ -2786,7 +2786,7 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) + container_of(port, struct uart_8250_port, port); + + wait_for_xmitr(up, UART_LSR_THRE); +- serial_out(up, UART_TX, ch); ++ serial_port_out(port, UART_TX, ch); + } + + /* +@@ -2818,12 +2818,12 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + /* + * First save the IER then disable the interrupts + */ +- ier = serial_in(up, UART_IER); ++ ier = serial_port_in(port, UART_IER); + + if (up->capabilities & UART_CAP_UUE) +- serial_out(up, UART_IER, UART_IER_UUE); ++ serial_port_out(port, UART_IER, UART_IER_UUE); + else +- serial_out(up, UART_IER, 0); ++ serial_port_out(port, UART_IER, 0); + + uart_console_write(port, s, count, serial8250_console_putchar); + +@@ -2832,7 +2832,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); +- serial_out(up, UART_IER, ier); ++ serial_port_out(port, UART_IER, ier); + + /* + * The receive handling will happen properly because the +@@ -2994,11 +2994,11 @@ void serial8250_resume_port(int line) + + if (up->capabilities & UART_NATSEMI) { + /* Ensure it's still in high speed mode */ +- serial_out(up, UART_LCR, 0xE0); ++ serial_port_out(port, UART_LCR, 0xE0); + + ns16550a_goto_highspeed(up); + +- serial_out(up, UART_LCR, 0); ++ serial_port_out(port, UART_LCR, 0); + port->uartclk = 921600*16; + } + uart_resume_port(&serial8250_reg, port); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0026-serial-remove-back-and-forth-conversions-in-serial_o.patch b/patches.kzm9g/0026-serial-remove-back-and-forth-conversions-in-serial_o.patch new file mode 100644 index 00000000000000..efe8300234a695 --- /dev/null +++ b/patches.kzm9g/0026-serial-remove-back-and-forth-conversions-in-serial_o.patch @@ -0,0 +1,56 @@ +From 51a2897e38814dc21408888a8d3ddd364e7686e2 Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Thu, 8 Mar 2012 19:12:14 -0500 +Subject: serial: remove back and forth conversions in serial_out_sync + +The two callers to serial_out_sync() have a struct port right +there in scope, but then pass in a struct 8250_port which then +is locally resolved back to a struct port. + +Delete the needless back and forth and just pass in the struct +port directly. Rename the function to have "_port" in its +name, so the name <--> args relationship is consistent with the +other serial_in/out vs serial_port_in/out function classes. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 55e4016dd055e262e4b078b81c80b55386ead0f4) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index cb45a29..56492d2 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -467,9 +467,8 @@ static void set_io_from_upio(struct uart_port *p) + } + + static void +-serial_out_sync(struct uart_8250_port *up, int offset, int value) ++serial_port_out_sync(struct uart_port *p, int offset, int value) + { +- struct uart_port *p = &up->port; + switch (p->iotype) { + case UPIO_MEM: + case UPIO_MEM32: +@@ -2022,11 +2021,11 @@ static int serial8250_startup(struct uart_port *port) + disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); +- serial_out_sync(up, UART_IER, UART_IER_THRI); ++ serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir1 = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); +- serial_out_sync(up, UART_IER, UART_IER_THRI); ++ serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0027-serial-8250_pci-add-a-force-background-timer-flag-an.patch b/patches.kzm9g/0027-serial-8250_pci-add-a-force-background-timer-flag-an.patch new file mode 100644 index 00000000000000..95b07cdfa19be1 --- /dev/null +++ b/patches.kzm9g/0027-serial-8250_pci-add-a-force-background-timer-flag-an.patch @@ -0,0 +1,118 @@ +From b503e9756dc79ffaf2b3160b79c1bf2aed842547 Mon Sep 17 00:00:00 2001 +From: Dan Williams <dan.j.williams@intel.com> +Date: Fri, 6 Apr 2012 11:49:50 -0700 +Subject: serial/8250_pci: add a "force background timer" flag and use it for + the "kt" serial port + +Workaround dropped notifications in the iir register. Register reads +coincident with new interrupt notifications sometimes result in this +device clearing the interrupt event without reporting it in the read +data. + +The serial core already has a heuristic for determining when a device +has an untrustworthy iir register. In this case when we apriori know +that the iir is faulty use a flag (UPF_BUG_THRE) to bypass the test and +force usage of the background timer. + +[stable: 3.3.x] +Acked-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@vger.kernel.org> +Reported-by: Nhan H Mai <nhan.h.mai@intel.com> +Reported-by: Sudhakar Mamillapalli <sudhakar@fb.com> +Tested-by: Nhan H Mai <nhan.h.mai@intel.com> +Tested-by: Sudhakar Mamillapalli <sudhakar@fb.com> +Signed-off-by: Dan Williams <dan.j.williams@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit bc02d15a3452fdf9276e8fb89c5e504a88df888a) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 8 +++++--- + drivers/tty/serial/8250/8250_pci.c | 17 ++++++++++++++++- + include/linux/serial_core.h | 1 + + 3 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 56492d2..5c27f7e 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -2035,10 +2035,12 @@ static int serial8250_startup(struct uart_port *port) + spin_unlock_irqrestore(&port->lock, flags); + + /* +- * If the interrupt is not reasserted, setup a timer to +- * kick the UART on a regular basis. ++ * If the interrupt is not reasserted, or we otherwise ++ * don't trust the iir, setup a timer to kick the UART ++ * on a regular basis. + */ +- if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { ++ 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)); +diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c +index a213f38..107eff0 100644 +--- a/drivers/tty/serial/8250/8250_pci.c ++++ b/drivers/tty/serial/8250/8250_pci.c +@@ -994,6 +994,14 @@ static int skip_tx_en_setup(struct serial_private *priv, + return pci_default_setup(priv, board, port, idx); + } + ++static int kt_serial_setup(struct serial_private *priv, ++ const struct pciserial_board *board, ++ struct uart_port *port, int idx) ++{ ++ port->flags |= UPF_BUG_THRE; ++ return skip_tx_en_setup(priv, board, port, idx); ++} ++ + static int pci_eg20t_init(struct pci_dev *dev) + { + #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) +@@ -1012,7 +1020,6 @@ pci_xr17c154_setup(struct serial_private *priv, + return pci_default_setup(priv, board, port, idx); + } + +-/* This should be in linux/pci_ids.h */ + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B + #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B + #define PCI_DEVICE_ID_OCTPRO 0x0001 +@@ -1038,6 +1045,7 @@ pci_xr17c154_setup(struct serial_private *priv, + #define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 + #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 + #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 ++#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d + + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ + #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 +@@ -1122,6 +1130,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { + .subdevice = PCI_ANY_ID, + .setup = ce4100_serial_setup, + }, ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .setup = kt_serial_setup, ++ }, + /* + * ITE + */ +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index d611ca0..724fde0 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -351,6 +351,7 @@ struct uart_port { + #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) + #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) + #define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) ++#define UPF_BUG_THRE ((__force upf_t) (1 << 26)) + /* The exact UART type is known and should not be probed. */ + #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) + #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0028-8250.c-less-than-2400-baud-fix.patch b/patches.kzm9g/0028-8250.c-less-than-2400-baud-fix.patch new file mode 100644 index 00000000000000..44791ce2d1d895 --- /dev/null +++ b/patches.kzm9g/0028-8250.c-less-than-2400-baud-fix.patch @@ -0,0 +1,51 @@ +From 5fbfa3c9a23c95bb26065fb7a6ee3d6256d2a410 Mon Sep 17 00:00:00 2001 +From: Christian Melki <christian.melki@ericsson.se> +Date: Mon, 30 Apr 2012 11:21:26 +0200 +Subject: 8250.c: less than 2400 baud fix. + +We noticed that we were loosing data at speed less than 2400 baud. +It turned out our (TI16750 compatible) uart with 64 byte outgoing fifo +was truncated to 16 byte (bit 5 sets fifo len) when modifying the fcr +reg. +The input code still fills the buffer with 64 bytes if I remember +correctly and thus data is lost. +Our fix was to remove whiping of the fcr content and just add the +TRIGGER_1 which we want for latency. +I can't see why this would not work on less than 2400 always, for all +uarts ... +Otherwise one would have to make sure the filling of the fifo re-checks +the current state of available fifo size (urrk). + +Signed-off-by: Christian Melki <christian.melki@ericsson.se> +Cc: stable <stable@vger.kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit f9a9111b540fd67db5dab332f4b83d86c90e27b1) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 5c27f7e..d537431 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -2280,10 +2280,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + quot++; + + if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { +- if (baud < 2400) +- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; +- else +- fcr = uart_config[port->type].fcr; ++ fcr = uart_config[port->type].fcr; ++ if (baud < 2400) { ++ fcr &= ~UART_FCR_TRIGGER_MASK; ++ fcr |= UART_FCR_TRIGGER_1; ++ } + } + + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0029-serial8250-Add-dl_read-dl_write-callbacks.patch b/patches.kzm9g/0029-serial8250-Add-dl_read-dl_write-callbacks.patch new file mode 100644 index 00000000000000..b1eb8440605ba8 --- /dev/null +++ b/patches.kzm9g/0029-serial8250-Add-dl_read-dl_write-callbacks.patch @@ -0,0 +1,203 @@ +From c7fbe0d5b21bad7ee177f745bfd423f0ed57243d Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 2 May 2012 21:46:51 +0900 +Subject: serial8250: Add dl_read()/dl_write() callbacks + +Convert serial_dl_read() and serial_dl_write() from macro +to 8250 specific callbacks. This change makes it easier to +support 8250 hardware with non-standard DLL and DLM register +configurations such as Alchemy, RM9K and upcoming Emma Mobile +UART hardware. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit cc419fa0d38c425e4ea7bffeed931b07b0a3e461) + +Conflicts: + drivers/tty/serial/8250/8250.h + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 117 ++++++++++++++++++++++------------------ + drivers/tty/serial/8250/8250.h | 14 +++++ + 2 files changed, 78 insertions(+), 53 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index d537431..7a31149 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -284,6 +284,66 @@ static const struct serial8250_config uart_config[] = { + }, + }; + ++/* Uart divisor latch read */ ++static int default_dl_read(struct uart_8250_port *up) ++{ ++ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; ++} ++ ++/* Uart divisor latch write */ ++static void default_dl_write(struct uart_8250_port *up, int value) ++{ ++ serial_out(up, UART_DLL, value & 0xff); ++ serial_out(up, UART_DLM, value >> 8 & 0xff); ++} ++ ++#if defined(CONFIG_MIPS_ALCHEMY) ++/* Au1x00 haven't got a standard divisor latch */ ++static int _serial_dl_read(struct uart_8250_port *up) ++{ ++ if (up->port.iotype == UPIO_AU) ++ return __raw_readl(up->port.membase + 0x28); ++ else ++ return default_dl_read(up); ++} ++ ++static void _serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ if (up->port.iotype == UPIO_AU) ++ __raw_writel(value, up->port.membase + 0x28); ++ else ++ default_dl_write(up, value); ++} ++#elif defined(CONFIG_SERIAL_8250_RM9K) ++static int _serial_dl_read(struct uart_8250_port *up) ++{ ++ return (up->port.iotype == UPIO_RM9000) ? ++ (((__raw_readl(up->port.membase + 0x10) << 8) | ++ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : ++ default_dl_read(up); ++} ++ ++static void _serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ if (up->port.iotype == UPIO_RM9000) { ++ __raw_writel(value, up->port.membase + 0x08); ++ __raw_writel(value >> 8, up->port.membase + 0x10); ++ } else { ++ default_dl_write(up, value); ++ } ++} ++#else ++static int _serial_dl_read(struct uart_8250_port *up) ++{ ++ return default_dl_read(up); ++} ++ ++static void _serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ default_dl_write(up, value); ++} ++#endif ++ + #if defined(CONFIG_MIPS_ALCHEMY) + + /* Au1x00 UART hardware has a weird register layout */ +@@ -434,6 +494,10 @@ static void set_io_from_upio(struct uart_port *p) + { + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); ++ ++ up->dl_read = _serial_dl_read; ++ up->dl_write = _serial_dl_write; ++ + switch (p->iotype) { + case UPIO_HUB6: + p->serial_in = hub6_serial_in; +@@ -481,59 +545,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) + } + } + +-/* Uart divisor latch read */ +-static inline int _serial_dl_read(struct uart_8250_port *up) +-{ +- return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +-} +- +-/* Uart divisor latch write */ +-static inline void _serial_dl_write(struct uart_8250_port *up, int value) +-{ +- serial_out(up, UART_DLL, value & 0xff); +- serial_out(up, UART_DLM, value >> 8 & 0xff); +-} +- +-#if defined(CONFIG_MIPS_ALCHEMY) +-/* Au1x00 haven't got a standard divisor latch */ +-static int serial_dl_read(struct uart_8250_port *up) +-{ +- if (up->port.iotype == UPIO_AU) +- return __raw_readl(up->port.membase + 0x28); +- else +- return _serial_dl_read(up); +-} +- +-static void serial_dl_write(struct uart_8250_port *up, int value) +-{ +- if (up->port.iotype == UPIO_AU) +- __raw_writel(value, up->port.membase + 0x28); +- else +- _serial_dl_write(up, value); +-} +-#elif defined(CONFIG_SERIAL_8250_RM9K) +-static int serial_dl_read(struct uart_8250_port *up) +-{ +- return (up->port.iotype == UPIO_RM9000) ? +- (((__raw_readl(up->port.membase + 0x10) << 8) | +- (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : +- _serial_dl_read(up); +-} +- +-static void serial_dl_write(struct uart_8250_port *up, int value) +-{ +- if (up->port.iotype == UPIO_RM9000) { +- __raw_writel(value, up->port.membase + 0x08); +- __raw_writel(value >> 8, up->port.membase + 0x10); +- } else { +- _serial_dl_write(up, value); +- } +-} +-#else +-#define serial_dl_read(up) _serial_dl_read(up) +-#define serial_dl_write(up, value) _serial_dl_write(up, value) +-#endif +- + /* + * For the 16C950 + */ +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index 2868a1d..bafe034 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -37,6 +37,10 @@ struct uart_8250_port { + unsigned char lsr_saved_flags; + #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA + unsigned char msr_saved_flags; ++ ++ /* 8250 specific callbacks */ ++ int (*dl_read)(struct uart_8250_port *); ++ void (*dl_write)(struct uart_8250_port *, int); + }; + + struct old_serial_port { +@@ -96,6 +100,16 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) + up->port.serial_out(&up->port, offset, value); + } + ++static inline int serial_dl_read(struct uart_8250_port *up) ++{ ++ return up->dl_read(up); ++} ++ ++static inline void serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ up->dl_write(up, value); ++} ++ + #if defined(__alpha__) && !defined(CONFIG_PCI) + /* + * Digital did something really horribly wrong with the OUT1 and OUT2 +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0030-serial8250-Use-dl_read-dl_write-on-Alchemy.patch b/patches.kzm9g/0030-serial8250-Use-dl_read-dl_write-on-Alchemy.patch new file mode 100644 index 00000000000000..d543de7ec41cc8 --- /dev/null +++ b/patches.kzm9g/0030-serial8250-Use-dl_read-dl_write-on-Alchemy.patch @@ -0,0 +1,138 @@ +From c5c260031fff81671154c36017619be60bd9db4d Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 2 May 2012 21:47:00 +0900 +Subject: serial8250: Use dl_read()/dl_write() on Alchemy + +Convert the 8250 Alchemy support code to make +use of the new dl_read()/dl_write() callbacks. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 6b4160313c239d61c3907b2aaaeeec156911c9d1) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 67 ++++++++++++++++------------------------ + 1 file changed, 26 insertions(+), 41 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 7a31149..ce7717c 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -297,24 +297,7 @@ static void default_dl_write(struct uart_8250_port *up, int value) + serial_out(up, UART_DLM, value >> 8 & 0xff); + } + +-#if defined(CONFIG_MIPS_ALCHEMY) +-/* Au1x00 haven't got a standard divisor latch */ +-static int _serial_dl_read(struct uart_8250_port *up) +-{ +- if (up->port.iotype == UPIO_AU) +- return __raw_readl(up->port.membase + 0x28); +- else +- return default_dl_read(up); +-} +- +-static void _serial_dl_write(struct uart_8250_port *up, int value) +-{ +- if (up->port.iotype == UPIO_AU) +- __raw_writel(value, up->port.membase + 0x28); +- else +- default_dl_write(up, value); +-} +-#elif defined(CONFIG_SERIAL_8250_RM9K) ++#if defined(CONFIG_SERIAL_8250_RM9K) + static int _serial_dl_read(struct uart_8250_port *up) + { + return (up->port.iotype == UPIO_RM9000) ? +@@ -344,7 +327,7 @@ static void _serial_dl_write(struct uart_8250_port *up, int value) + } + #endif + +-#if defined(CONFIG_MIPS_ALCHEMY) ++#ifdef CONFIG_MIPS_ALCHEMY + + /* Au1x00 UART hardware has a weird register layout */ + static const u8 au_io_in_map[] = { +@@ -365,22 +348,32 @@ static const u8 au_io_out_map[] = { + [UART_MCR] = 6, + }; + +-/* sane hardware needs no mapping */ +-static inline int map_8250_in_reg(struct uart_port *p, int offset) ++static unsigned int au_serial_in(struct uart_port *p, int offset) + { +- if (p->iotype != UPIO_AU) +- return offset; +- return au_io_in_map[offset]; ++ offset = au_io_in_map[offset] << p->regshift; ++ return __raw_readl(p->membase + offset); + } + +-static inline int map_8250_out_reg(struct uart_port *p, int offset) ++static void au_serial_out(struct uart_port *p, int offset, int value) + { +- if (p->iotype != UPIO_AU) +- return offset; +- return au_io_out_map[offset]; ++ offset = au_io_out_map[offset] << p->regshift; ++ __raw_writel(value, p->membase + offset); ++} ++ ++/* Au1x00 haven't got a standard divisor latch */ ++static int au_serial_dl_read(struct uart_8250_port *up) ++{ ++ return __raw_readl(up->port.membase + 0x28); + } + +-#elif defined(CONFIG_SERIAL_8250_RM9K) ++static void au_serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ __raw_writel(value, up->port.membase + 0x28); ++} ++ ++#endif ++ ++#if defined(CONFIG_SERIAL_8250_RM9K) + + static const u8 + regmap_in[8] = { +@@ -464,18 +457,6 @@ static unsigned int mem32_serial_in(struct uart_port *p, int offset) + return readl(p->membase + offset); + } + +-static unsigned int au_serial_in(struct uart_port *p, int offset) +-{ +- offset = map_8250_in_reg(p, offset) << p->regshift; +- return __raw_readl(p->membase + offset); +-} +- +-static void au_serial_out(struct uart_port *p, int offset, int value) +-{ +- offset = map_8250_out_reg(p, offset) << p->regshift; +- __raw_writel(value, p->membase + offset); +-} +- + static unsigned int io_serial_in(struct uart_port *p, int offset) + { + offset = map_8250_in_reg(p, offset) << p->regshift; +@@ -515,10 +496,14 @@ static void set_io_from_upio(struct uart_port *p) + p->serial_out = mem32_serial_out; + break; + ++#ifdef CONFIG_MIPS_ALCHEMY + case UPIO_AU: + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; ++ up->dl_read = au_serial_dl_read; ++ up->dl_write = au_serial_dl_write; + break; ++#endif + + default: + p->serial_in = io_serial_in; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0031-serial8250-Use-dl_read-dl_write-on-RM9K.patch b/patches.kzm9g/0031-serial8250-Use-dl_read-dl_write-on-RM9K.patch new file mode 100644 index 00000000000000..11c12350a223cd --- /dev/null +++ b/patches.kzm9g/0031-serial8250-Use-dl_read-dl_write-on-RM9K.patch @@ -0,0 +1,139 @@ +From b2a0b1532958cbf0ef8e7078c78558b2e78bb524 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 2 May 2012 21:47:09 +0900 +Subject: serial8250: Use dl_read()/dl_write() on RM9K + +Convert the 8250 RM9K support code to make +use of the new dl_read()/dl_write() callbacks. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 28bf4cf22dcd936f93dd6063696b1accdc1d5207) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 62 +++++++++++++++++++--------------------- + 1 file changed, 29 insertions(+), 33 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index ce7717c..36ce1e2 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -297,25 +297,6 @@ static void default_dl_write(struct uart_8250_port *up, int value) + serial_out(up, UART_DLM, value >> 8 & 0xff); + } + +-#if defined(CONFIG_SERIAL_8250_RM9K) +-static int _serial_dl_read(struct uart_8250_port *up) +-{ +- return (up->port.iotype == UPIO_RM9000) ? +- (((__raw_readl(up->port.membase + 0x10) << 8) | +- (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : +- default_dl_read(up); +-} +- +-static void _serial_dl_write(struct uart_8250_port *up, int value) +-{ +- if (up->port.iotype == UPIO_RM9000) { +- __raw_writel(value, up->port.membase + 0x08); +- __raw_writel(value >> 8, up->port.membase + 0x10); +- } else { +- default_dl_write(up, value); +- } +-} +-#else + static int _serial_dl_read(struct uart_8250_port *up) + { + return default_dl_read(up); +@@ -325,7 +306,6 @@ static void _serial_dl_write(struct uart_8250_port *up, int value) + { + default_dl_write(up, value); + } +-#endif + + #ifdef CONFIG_MIPS_ALCHEMY + +@@ -373,7 +353,7 @@ static void au_serial_dl_write(struct uart_8250_port *up, int value) + + #endif + +-#if defined(CONFIG_SERIAL_8250_RM9K) ++#ifdef CONFIG_SERIAL_8250_RM9K + + static const u8 + regmap_in[8] = { +@@ -397,28 +377,36 @@ static const u8 + [UART_SCR] = 0x2c + }; + +-static inline int map_8250_in_reg(struct uart_port *p, int offset) ++static unsigned int rm9k_serial_in(struct uart_port *p, int offset) + { +- if (p->iotype != UPIO_RM9000) +- return offset; +- return regmap_in[offset]; ++ offset = regmap_in[offset] << p->regshift; ++ return readl(p->membase + offset); + } + +-static inline int map_8250_out_reg(struct uart_port *p, int offset) ++static void rm9k_serial_out(struct uart_port *p, int offset, int value) + { +- if (p->iotype != UPIO_RM9000) +- return offset; +- return regmap_out[offset]; ++ offset = regmap_out[offset] << p->regshift; ++ writel(value, p->membase + offset); + } + +-#else ++static int rm9k_serial_dl_read(struct uart_8250_port *up) ++{ ++ return ((__raw_readl(up->port.membase + 0x10) << 8) | ++ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff; ++} ++ ++static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ __raw_writel(value, up->port.membase + 0x08); ++ __raw_writel(value >> 8, up->port.membase + 0x10); ++} ++ ++#endif + + /* sane hardware needs no mapping */ + #define map_8250_in_reg(up, offset) (offset) + #define map_8250_out_reg(up, offset) (offset) + +-#endif +- + static unsigned int hub6_serial_in(struct uart_port *p, int offset) + { + offset = map_8250_in_reg(p, offset) << p->regshift; +@@ -490,12 +478,20 @@ static void set_io_from_upio(struct uart_port *p) + p->serial_out = mem_serial_out; + break; + +- case UPIO_RM9000: + case UPIO_MEM32: + p->serial_in = mem32_serial_in; + p->serial_out = mem32_serial_out; + break; + ++#ifdef CONFIG_SERIAL_8250_RM9K ++ case UPIO_RM9000: ++ p->serial_in = rm9k_serial_in; ++ p->serial_out = rm9k_serial_out; ++ up->dl_read = rm9k_serial_dl_read; ++ up->dl_write = rm9k_serial_dl_write; ++ break; ++#endif ++ + #ifdef CONFIG_MIPS_ALCHEMY + case UPIO_AU: + p->serial_in = au_serial_in; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0032-serial8250-Clean-up-default-map-and-dl-code.patch b/patches.kzm9g/0032-serial8250-Clean-up-default-map-and-dl-code.patch new file mode 100644 index 00000000000000..5ebaebd7ba7583 --- /dev/null +++ b/patches.kzm9g/0032-serial8250-Clean-up-default-map-and-dl-code.patch @@ -0,0 +1,134 @@ +From 2c6855bab06ff3e78cdcafd00a9ab5b6fd4c3ef3 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 2 May 2012 21:47:18 +0900 +Subject: serial8250: Clean up default map and dl code + +Get rid of unused functions and macros now when +Alchemy and RM9K are converted over to callbacks. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit e8155629ff19e05722ba057d1521baec270d780e) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 38 ++++++++++++-------------------------- + 1 file changed, 12 insertions(+), 26 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 36ce1e2..3445a27 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -285,28 +285,18 @@ static const struct serial8250_config uart_config[] = { + }; + + /* Uart divisor latch read */ +-static int default_dl_read(struct uart_8250_port *up) ++static int default_serial_dl_read(struct uart_8250_port *up) + { + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; + } + + /* Uart divisor latch write */ +-static void default_dl_write(struct uart_8250_port *up, int value) ++static void default_serial_dl_write(struct uart_8250_port *up, int value) + { + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); + } + +-static int _serial_dl_read(struct uart_8250_port *up) +-{ +- return default_dl_read(up); +-} +- +-static void _serial_dl_write(struct uart_8250_port *up, int value) +-{ +- default_dl_write(up, value); +-} +- + #ifdef CONFIG_MIPS_ALCHEMY + + /* Au1x00 UART hardware has a weird register layout */ +@@ -403,57 +393,53 @@ static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) + + #endif + +-/* sane hardware needs no mapping */ +-#define map_8250_in_reg(up, offset) (offset) +-#define map_8250_out_reg(up, offset) (offset) +- + static unsigned int hub6_serial_in(struct uart_port *p, int offset) + { +- offset = map_8250_in_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + return inb(p->iobase + 1); + } + + static void hub6_serial_out(struct uart_port *p, int offset, int value) + { +- offset = map_8250_out_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + outb(value, p->iobase + 1); + } + + static unsigned int mem_serial_in(struct uart_port *p, int offset) + { +- offset = map_8250_in_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + return readb(p->membase + offset); + } + + static void mem_serial_out(struct uart_port *p, int offset, int value) + { +- offset = map_8250_out_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + writeb(value, p->membase + offset); + } + + static void mem32_serial_out(struct uart_port *p, int offset, int value) + { +- offset = map_8250_out_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + writel(value, p->membase + offset); + } + + static unsigned int mem32_serial_in(struct uart_port *p, int offset) + { +- offset = map_8250_in_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + return readl(p->membase + offset); + } + + static unsigned int io_serial_in(struct uart_port *p, int offset) + { +- offset = map_8250_in_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + return inb(p->iobase + offset); + } + + static void io_serial_out(struct uart_port *p, int offset, int value) + { +- offset = map_8250_out_reg(p, offset) << p->regshift; ++ offset = offset << p->regshift; + outb(value, p->iobase + offset); + } + +@@ -464,8 +450,8 @@ static void set_io_from_upio(struct uart_port *p) + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + +- up->dl_read = _serial_dl_read; +- up->dl_write = _serial_dl_write; ++ up->dl_read = default_serial_dl_read; ++ up->dl_write = default_serial_dl_write; + + switch (p->iotype) { + case UPIO_HUB6: +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0033-serial8250-Introduce-serial8250_register_8250_port.patch b/patches.kzm9g/0033-serial8250-Introduce-serial8250_register_8250_port.patch new file mode 100644 index 00000000000000..f01d7ee280adfa --- /dev/null +++ b/patches.kzm9g/0033-serial8250-Introduce-serial8250_register_8250_port.patch @@ -0,0 +1,169 @@ +From 4d5e00ec9374ddf1ec0995e10380e2e044eb8154 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 2 May 2012 21:47:27 +0900 +Subject: serial8250: Introduce serial8250_register_8250_port() + +Introduce yet another 8250 registration function. +This time it is serial8250_register_8250_port() and it +allows us to register 8250 hardware instances using struct +uart_8250_port. The new function makes it possible to +register 8250 hardware that makes use of 8250 specific +callbacks such as ->dl_read() and ->dl_write(). + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit f73fa05b90eb8c0dd3230c364cf1107f4f8f3848) + +Conflicts: + drivers/tty/serial/8250/8250.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250.c | 87 ++++++++++++++++++++++++++-------------- + include/linux/serial_8250.h | 1 + + 2 files changed, 58 insertions(+), 30 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index 3445a27..8de9a39 100644 +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c +@@ -3132,7 +3132,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * + } + + /** +- * serial8250_register_port - register a serial port ++ * serial8250_register_8250_port - register a serial port + * @port: serial port template + * + * Configure the serial port specified by the request. If the +@@ -3144,50 +3144,54 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * + * + * On success the port is ready to use and the line number is returned. + */ +-int serial8250_register_port(struct uart_port *port) ++int serial8250_register_8250_port(struct uart_8250_port *up) + { + struct uart_8250_port *uart; + int ret = -ENOSPC; + +- if (port->uartclk == 0) ++ if (up->port.uartclk == 0) + return -EINVAL; + + mutex_lock(&serial_mutex); + +- uart = serial8250_find_match_or_unused(port); ++ uart = serial8250_find_match_or_unused(&up->port); + if (uart) { + uart_remove_one_port(&serial8250_reg, &uart->port); + +- uart->port.iobase = port->iobase; +- uart->port.membase = port->membase; +- uart->port.irq = port->irq; +- uart->port.irqflags = port->irqflags; +- uart->port.uartclk = port->uartclk; +- uart->port.fifosize = port->fifosize; +- uart->port.regshift = port->regshift; +- uart->port.iotype = port->iotype; +- uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; +- uart->port.mapbase = port->mapbase; +- uart->port.private_data = port->private_data; +- if (port->dev) +- uart->port.dev = port->dev; +- +- if (port->flags & UPF_FIXED_TYPE) +- serial8250_init_fixed_type_port(uart, port->type); ++ uart->port.iobase = up->port.iobase; ++ uart->port.membase = up->port.membase; ++ uart->port.irq = up->port.irq; ++ uart->port.irqflags = up->port.irqflags; ++ uart->port.uartclk = up->port.uartclk; ++ uart->port.fifosize = up->port.fifosize; ++ uart->port.regshift = up->port.regshift; ++ uart->port.iotype = up->port.iotype; ++ uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; ++ uart->port.mapbase = up->port.mapbase; ++ uart->port.private_data = up->port.private_data; ++ if (up->port.dev) ++ uart->port.dev = up->port.dev; ++ ++ if (up->port.flags & UPF_FIXED_TYPE) ++ serial8250_init_fixed_type_port(uart, up->port.type); + + set_io_from_upio(&uart->port); + /* Possibly override default I/O functions. */ +- if (port->serial_in) +- uart->port.serial_in = port->serial_in; +- if (port->serial_out) +- uart->port.serial_out = port->serial_out; +- if (port->handle_irq) +- uart->port.handle_irq = port->handle_irq; ++ if (up->port.serial_in) ++ uart->port.serial_in = up->port.serial_in; ++ if (up->port.serial_out) ++ uart->port.serial_out = up->port.serial_out; ++ if (up->port.handle_irq) ++ uart->port.handle_irq = up->port.handle_irq; + /* Possibly override set_termios call */ +- if (port->set_termios) +- uart->port.set_termios = port->set_termios; +- if (port->pm) +- uart->port.pm = port->pm; ++ if (up->port.set_termios) ++ uart->port.set_termios = up->port.set_termios; ++ if (up->port.pm) ++ uart->port.pm = up->port.pm; ++ if (up->dl_read) ++ uart->dl_read = up->dl_read; ++ if (up->dl_write) ++ uart->dl_write = up->dl_write; + + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, +@@ -3201,6 +3205,29 @@ int serial8250_register_port(struct uart_port *port) + + return ret; + } ++EXPORT_SYMBOL(serial8250_register_8250_port); ++ ++/** ++ * serial8250_register_port - register a serial port ++ * @port: serial port template ++ * ++ * Configure the serial port specified by the request. If the ++ * port exists and is in use, it is hung up and unregistered ++ * first. ++ * ++ * The port is then probed and if necessary the IRQ is autodetected ++ * If this fails an error is returned. ++ * ++ * On success the port is ready to use and the line number is returned. ++ */ ++int serial8250_register_port(struct uart_port *port) ++{ ++ struct uart_8250_port up; ++ ++ memset(&up, 0, sizeof(up)); ++ memcpy(&up.port, port, sizeof(*port)); ++ return serial8250_register_8250_port(&up); ++} + EXPORT_SYMBOL(serial8250_register_port); + + /** +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index b44034e..d7f286e 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -68,6 +68,7 @@ enum { + struct uart_port; + struct uart_8250_port; + ++int serial8250_register_8250_port(struct uart_8250_port *); + int serial8250_register_port(struct uart_port *); + void serial8250_unregister_port(int line); + void serial8250_suspend_port(int line); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0034-serial8250-em-Emma-Mobile-UART-driver-V2.patch b/patches.kzm9g/0034-serial8250-em-Emma-Mobile-UART-driver-V2.patch new file mode 100644 index 00000000000000..d20eea6d874744 --- /dev/null +++ b/patches.kzm9g/0034-serial8250-em-Emma-Mobile-UART-driver-V2.patch @@ -0,0 +1,254 @@ +From 851dd6ac01a254a7c6e14a75c0cd0c8aec2d542b Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Thu, 3 May 2012 21:13:09 +0900 +Subject: serial8250-em: Emma Mobile UART driver V2 + +This is V2 of the Emma Mobile 8250 platform driver. + +The hardware itself has according to the data sheet +up to 64 byte FIFOs but at this point we only make +use of the 16550 compatible mode. + +To support this piece of hardware the common UART +registers need to be remapped, and the access size +differences need to be handled. + +The DLL and DLM registers can due to offset collision +not be remapped easily, and because of that this +driver makes use of ->dl_read() and ->dl_write() +callbacks. This in turn requires a registration +function that takes 8250-specific paramenters. + +Future potential enhancements include DT support, +early platform driver console and fine grained PM. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Acked-by: Alan Cox <alan@linux.intel.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 22886ee96895b7a9f9d06da4dc9420b61b4ef1f7) + +Conflicts: + drivers/tty/serial/8250/Kconfig + drivers/tty/serial/8250/Makefile + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250_em.c | 178 +++++++++++++++++++++++++++++++++++++ + drivers/tty/serial/8250/Kconfig | 8 ++ + drivers/tty/serial/8250/Makefile | 1 + + 3 files changed, 187 insertions(+) + create mode 100644 drivers/tty/serial/8250/8250_em.c + +diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c +new file mode 100644 +index 0000000..ff42542 +--- /dev/null ++++ b/drivers/tty/serial/8250/8250_em.c +@@ -0,0 +1,178 @@ ++/* ++ * Renesas Emma Mobile 8250 driver ++ * ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/device.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/serial_8250.h> ++#include <linux/serial_core.h> ++#include <linux/serial_reg.h> ++#include <linux/platform_device.h> ++#include <linux/clk.h> ++#include <linux/slab.h> ++ ++#include "8250.h" ++ ++#define UART_DLL_EM 9 ++#define UART_DLM_EM 10 ++ ++struct serial8250_em_priv { ++ struct clk *sclk; ++ int line; ++}; ++ ++static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) ++{ ++ switch (offset) { ++ case UART_TX: /* TX @ 0x00 */ ++ writeb(value, p->membase); ++ break; ++ case UART_FCR: /* FCR @ 0x0c (+1) */ ++ case UART_LCR: /* LCR @ 0x10 (+1) */ ++ case UART_MCR: /* MCR @ 0x14 (+1) */ ++ case UART_SCR: /* SCR @ 0x20 (+1) */ ++ writel(value, p->membase + ((offset + 1) << 2)); ++ break; ++ case UART_IER: /* IER @ 0x04 */ ++ value &= 0x0f; /* only 4 valid bits - not Xscale */ ++ /* fall-through */ ++ case UART_DLL_EM: /* DLL @ 0x24 (+9) */ ++ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ ++ writel(value, p->membase + (offset << 2)); ++ } ++} ++ ++static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset) ++{ ++ switch (offset) { ++ case UART_RX: /* RX @ 0x00 */ ++ return readb(p->membase); ++ case UART_MCR: /* MCR @ 0x14 (+1) */ ++ case UART_LSR: /* LSR @ 0x18 (+1) */ ++ case UART_MSR: /* MSR @ 0x1c (+1) */ ++ case UART_SCR: /* SCR @ 0x20 (+1) */ ++ return readl(p->membase + ((offset + 1) << 2)); ++ case UART_IER: /* IER @ 0x04 */ ++ case UART_IIR: /* IIR @ 0x08 */ ++ case UART_DLL_EM: /* DLL @ 0x24 (+9) */ ++ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ ++ return readl(p->membase + (offset << 2)); ++ } ++ return 0; ++} ++ ++static int serial8250_em_serial_dl_read(struct uart_8250_port *up) ++{ ++ return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8; ++} ++ ++static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) ++{ ++ serial_out(up, UART_DLL_EM, value & 0xff); ++ serial_out(up, UART_DLM_EM, value >> 8 & 0xff); ++} ++ ++static int __devinit serial8250_em_probe(struct platform_device *pdev) ++{ ++ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ struct serial8250_em_priv *priv; ++ struct uart_8250_port up; ++ int ret = -EINVAL; ++ ++ if (!regs || !irq) { ++ dev_err(&pdev->dev, "missing registers or irq\n"); ++ goto err0; ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&pdev->dev, "unable to allocate private data\n"); ++ ret = -ENOMEM; ++ goto err0; ++ } ++ ++ priv->sclk = clk_get(&pdev->dev, "sclk"); ++ if (!priv->sclk) { ++ dev_err(&pdev->dev, "unable to get clock\n"); ++ goto err1; ++ } ++ ++ memset(&up, 0, sizeof(up)); ++ up.port.mapbase = regs->start; ++ up.port.irq = irq->start; ++ up.port.type = PORT_UNKNOWN; ++ up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; ++ up.port.dev = &pdev->dev; ++ up.port.private_data = priv; ++ ++ clk_enable(priv->sclk); ++ up.port.uartclk = clk_get_rate(priv->sclk); ++ ++ up.port.iotype = UPIO_MEM32; ++ up.port.serial_in = serial8250_em_serial_in; ++ up.port.serial_out = serial8250_em_serial_out; ++ up.dl_read = serial8250_em_serial_dl_read; ++ up.dl_write = serial8250_em_serial_dl_write; ++ ++ ret = serial8250_register_8250_port(&up); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "unable to register 8250 port\n"); ++ goto err2; ++ } ++ ++ priv->line = ret; ++ platform_set_drvdata(pdev, priv); ++ return 0; ++ ++ err2: ++ clk_disable(priv->sclk); ++ clk_put(priv->sclk); ++ err1: ++ kfree(priv); ++ err0: ++ return ret; ++} ++ ++static int __devexit serial8250_em_remove(struct platform_device *pdev) ++{ ++ struct serial8250_em_priv *priv = platform_get_drvdata(pdev); ++ ++ serial8250_unregister_port(priv->line); ++ clk_disable(priv->sclk); ++ clk_put(priv->sclk); ++ kfree(priv); ++ return 0; ++} ++ ++static struct platform_driver serial8250_em_platform_driver = { ++ .driver = { ++ .name = "serial8250-em", ++ .owner = THIS_MODULE, ++ }, ++ .probe = serial8250_em_probe, ++ .remove = __devexit_p(serial8250_em_remove), ++}; ++ ++module_platform_driver(serial8250_em_platform_driver); ++ ++MODULE_AUTHOR("Magnus Damm"); ++MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +index b1bb251..7aa3b6c 100644 +--- a/drivers/tty/serial/8250/Kconfig ++++ b/drivers/tty/serial/8250/Kconfig +@@ -266,3 +266,11 @@ config SERIAL_8250_RM9K + Selecting this option will add support for the integrated serial + port hardware found on MIPS RM9122 and similar processors. + If unsure, say N. ++ ++config SERIAL_8250_EM ++ tristate "Support for Emma Mobile intergrated serial port" ++ depends on SERIAL_8250 && ARM && HAVE_CLK ++ help ++ Selecting this option will add support for the integrated serial ++ port hardware found on the Emma Mobile line of processors. ++ If unsure, say N. +diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile +index c0d0c29..6a70704 100644 +--- a/drivers/tty/serial/8250/Makefile ++++ b/drivers/tty/serial/8250/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o + obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o + obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o + obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o ++obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0035-serial8250-em-clk_get-IS_ERR-error-handling-fix.patch b/patches.kzm9g/0035-serial8250-em-clk_get-IS_ERR-error-handling-fix.patch new file mode 100644 index 00000000000000..f0dbf2bf2bd6ed --- /dev/null +++ b/patches.kzm9g/0035-serial8250-em-clk_get-IS_ERR-error-handling-fix.patch @@ -0,0 +1,38 @@ +From 7ff1614653a079059c1d017d4d95376a616649ab Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 9 May 2012 15:49:57 +0900 +Subject: serial8250-em: clk_get() IS_ERR() error handling fix + +Update the 8250_em driver to correctly handle the case +where no clock is associated with the device. + +The return value of clk_get() needs to be checked with +IS_ERR() to avoid NULL pointer referencing. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +(cherry picked from commit 94e792ab66d696aad2e52c91bae4cfbeefe4c9f6) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/tty/serial/8250/8250_em.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c +index ff42542..be6c289 100644 +--- a/drivers/tty/serial/8250/8250_em.c ++++ b/drivers/tty/serial/8250/8250_em.c +@@ -110,8 +110,9 @@ static int __devinit serial8250_em_probe(struct platform_device *pdev) + } + + priv->sclk = clk_get(&pdev->dev, "sclk"); +- if (!priv->sclk) { ++ if (IS_ERR(priv->sclk)) { + dev_err(&pdev->dev, "unable to get clock\n"); ++ ret = PTR_ERR(priv->sclk); + goto err1; + } + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0036-cpuidle-create-bootparam-cpuidle.off-1.patch b/patches.kzm9g/0036-cpuidle-create-bootparam-cpuidle.off-1.patch new file mode 100644 index 00000000000000..d0cef7b7014acd --- /dev/null +++ b/patches.kzm9g/0036-cpuidle-create-bootparam-cpuidle.off-1.patch @@ -0,0 +1,116 @@ +From 9c84f8943b8bb242d3eab46ab23bc6daeaa7a02f Mon Sep 17 00:00:00 2001 +From: Len Brown <len.brown@intel.com> +Date: Fri, 1 Apr 2011 18:13:10 -0400 +Subject: cpuidle: create bootparam "cpuidle.off=1" + +useful for disabling cpuidle to fall back +to architecture-default idle loop + +cpuidle drivers and governors will fail to register. +on x86 they'll say so: + +intel_idle: intel_idle yielding to (null) +ACPI: acpi_idle yielding to (null) + +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit 62027aea23fcd14478abdddd3b74a4e0f5fb2984) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + Documentation/kernel-parameters.txt | 3 +++ + drivers/cpuidle/cpuidle.c | 10 ++++++++++ + drivers/cpuidle/cpuidle.h | 1 + + drivers/cpuidle/driver.c | 3 +++ + drivers/cpuidle/governor.c | 3 +++ + 5 files changed, 20 insertions(+) + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index 400b7be..79cef3c 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -546,6 +546,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. + /proc/<pid>/coredump_filter. + See also Documentation/filesystems/proc.txt. + ++ cpuidle.off=1 [CPU_IDLE] ++ disable the cpuidle sub-system ++ + cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver + Format: + <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index eed4c47..4487396 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -28,6 +28,12 @@ LIST_HEAD(cpuidle_detected_devices); + static void (*pm_idle_old)(void); + + static int enabled_devices; ++static int off __read_mostly; ++ ++int cpuidle_disabled(void) ++{ ++ return off; ++} + + #if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) + static void cpuidle_kick_cpus(void) +@@ -427,6 +433,9 @@ static int __init cpuidle_init(void) + { + int ret; + ++ if (cpuidle_disabled()) ++ return -ENODEV; ++ + pm_idle_old = pm_idle; + + ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); +@@ -438,4 +447,5 @@ static int __init cpuidle_init(void) + return 0; + } + ++module_param(off, int, 0444); + core_initcall(cpuidle_init); +diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h +index 33e50d5..38c3fd8 100644 +--- a/drivers/cpuidle/cpuidle.h ++++ b/drivers/cpuidle/cpuidle.h +@@ -13,6 +13,7 @@ extern struct list_head cpuidle_governors; + extern struct list_head cpuidle_detected_devices; + extern struct mutex cpuidle_lock; + extern spinlock_t cpuidle_driver_lock; ++extern int cpuidle_disabled(void); + + /* idle loop */ + extern void cpuidle_install_idle_handler(void); +diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c +index fd1601e..3f7e3ce 100644 +--- a/drivers/cpuidle/driver.c ++++ b/drivers/cpuidle/driver.c +@@ -26,6 +26,9 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) + if (!drv) + return -EINVAL; + ++ if (cpuidle_disabled()) ++ return -ENODEV; ++ + spin_lock(&cpuidle_driver_lock); + if (cpuidle_curr_driver) { + spin_unlock(&cpuidle_driver_lock); +diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c +index 724c164..ea2f8e7 100644 +--- a/drivers/cpuidle/governor.c ++++ b/drivers/cpuidle/governor.c +@@ -81,6 +81,9 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) + if (!gov || !gov->select) + return -EINVAL; + ++ if (cpuidle_disabled()) ++ return -ENODEV; ++ + mutex_lock(&cpuidle_lock); + if (__cpuidle_find_governor(gov->name) == NULL) { + ret = 0; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0037-cpuidle-replace-xen-access-to-x86-pm_idle-and-defaul.patch b/patches.kzm9g/0037-cpuidle-replace-xen-access-to-x86-pm_idle-and-defaul.patch new file mode 100644 index 00000000000000..3ae71b0e25c0c6 --- /dev/null +++ b/patches.kzm9g/0037-cpuidle-replace-xen-access-to-x86-pm_idle-and-defaul.patch @@ -0,0 +1,85 @@ +From 761a5d96c87fccab8a53f8c8c3240d8dcdb1bb19 Mon Sep 17 00:00:00 2001 +From: Len Brown <len.brown@intel.com> +Date: Fri, 1 Apr 2011 18:28:35 -0400 +Subject: cpuidle: replace xen access to x86 pm_idle and default_idle + +When a Xen Dom0 kernel boots on a hypervisor, it gets access +to the raw-hardware ACPI tables. While it parses the idle tables +for the hypervisor's beneift, it uses HLT for its own idle. + +Rather than have xen scribble on pm_idle and access default_idle, +have it simply disable_cpuidle() so acpi_idle will not load and +architecture default HLT will be used. + +cc: xen-devel@lists.xensource.com +Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> +Acked-by: H. Peter Anvin <hpa@linux.intel.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit d91ee5863b71e8c90eaf6035bff3078a85e2e7b5) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/x86/xen/setup.c | 3 ++- + drivers/cpuidle/cpuidle.c | 4 ++++ + include/linux/cpuidle.h | 2 ++ + 3 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index f8dcda4..e16a4ca 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -9,6 +9,7 @@ + #include <linux/mm.h> + #include <linux/pm.h> + #include <linux/memblock.h> ++#include <linux/cpuidle.h> + + #include <asm/elf.h> + #include <asm/vdso.h> +@@ -459,7 +460,7 @@ void __init xen_arch_setup(void) + #ifdef CONFIG_X86_32 + boot_cpu_data.hlt_works_ok = 1; + #endif +- pm_idle = default_idle; ++ disable_cpuidle(); + boot_option_idle_override = IDLE_HALT; + + fiddle_vdso(); +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index 4487396..cd1c19c 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -34,6 +34,10 @@ int cpuidle_disabled(void) + { + return off; + } ++void disable_cpuidle(void) ++{ ++ off = 1; ++} + + #if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) + static void cpuidle_kick_cpus(void) +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index 36719ea..b89f67d 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -122,6 +122,7 @@ struct cpuidle_driver { + }; + + #ifdef CONFIG_CPU_IDLE ++extern void disable_cpuidle(void); + + extern int cpuidle_register_driver(struct cpuidle_driver *drv); + struct cpuidle_driver *cpuidle_get_driver(void); +@@ -135,6 +136,7 @@ extern int cpuidle_enable_device(struct cpuidle_device *dev); + extern void cpuidle_disable_device(struct cpuidle_device *dev); + + #else ++static inline void disable_cpuidle(void) { } + + static inline int cpuidle_register_driver(struct cpuidle_driver *drv) + {return -ENODEV; } +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0038-cpuidle-stop-depending-on-pm_idle.patch b/patches.kzm9g/0038-cpuidle-stop-depending-on-pm_idle.patch new file mode 100644 index 00000000000000..276df0975f753b --- /dev/null +++ b/patches.kzm9g/0038-cpuidle-stop-depending-on-pm_idle.patch @@ -0,0 +1,254 @@ +From be5500b643f8d3d104e64d9096a5c8d86afadd92 Mon Sep 17 00:00:00 2001 +From: Len Brown <len.brown@intel.com> +Date: Fri, 1 Apr 2011 19:34:59 -0400 +Subject: cpuidle: stop depending on pm_idle + +cpuidle users should call cpuidle_call_idle() directly +rather than via (pm_idle)() function pointer. + +Architecture may choose to continue using (pm_idle)(), +but cpuidle need not depend on it: + + my_arch_cpu_idle() + ... + if(cpuidle_call_idle()) + pm_idle(); + +cc: Kevin Hilman <khilman@deeprootsystems.com> +cc: Paul Mundt <lethal@linux-sh.org> +cc: x86@kernel.org +Acked-by: H. Peter Anvin <hpa@linux.intel.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit a0bfa1373859e9d11dc92561a8667588803e42d8) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/kernel/process.c | 4 +++- + arch/sh/kernel/idle.c | 6 ++++-- + arch/x86/kernel/process_32.c | 4 +++- + arch/x86/kernel/process_64.c | 4 +++- + drivers/cpuidle/cpuidle.c | 38 ++++++++++++++++++-------------------- + include/linux/cpuidle.h | 2 ++ + 6 files changed, 33 insertions(+), 25 deletions(-) + +diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c +index 74ae833..5affc61 100644 +--- a/arch/arm/kernel/process.c ++++ b/arch/arm/kernel/process.c +@@ -30,6 +30,7 @@ + #include <linux/uaccess.h> + #include <linux/random.h> + #include <linux/hw_breakpoint.h> ++#include <linux/cpuidle.h> + + #include <asm/cacheflush.h> + #include <asm/leds.h> +@@ -199,7 +200,8 @@ void cpu_idle(void) + cpu_relax(); + } else { + stop_critical_timings(); +- pm_idle(); ++ if (cpuidle_call_idle()) ++ pm_idle(); + start_critical_timings(); + /* + * This will eventually be removed - pm_idle +diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c +index 425d604..9c7099e 100644 +--- a/arch/sh/kernel/idle.c ++++ b/arch/sh/kernel/idle.c +@@ -16,12 +16,13 @@ + #include <linux/thread_info.h> + #include <linux/irqflags.h> + #include <linux/smp.h> ++#include <linux/cpuidle.h> + #include <asm/pgalloc.h> + #include <asm/system.h> + #include <asm/atomic.h> + #include <asm/smp.h> + +-void (*pm_idle)(void) = NULL; ++static void (*pm_idle)(void); + + static int hlt_counter; + +@@ -100,7 +101,8 @@ void cpu_idle(void) + local_irq_disable(); + /* Don't trace irqs off for idle */ + stop_critical_timings(); +- pm_idle(); ++ if (cpuidle_call_idle()) ++ pm_idle(); + /* + * Sanity check to ensure that pm_idle() returns + * with IRQs enabled +diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c +index fcdb1b3..ca71e9a 100644 +--- a/arch/x86/kernel/process_32.c ++++ b/arch/x86/kernel/process_32.c +@@ -38,6 +38,7 @@ + #include <linux/uaccess.h> + #include <linux/io.h> + #include <linux/kdebug.h> ++#include <linux/cpuidle.h> + + #include <asm/pgtable.h> + #include <asm/system.h> +@@ -109,7 +110,8 @@ void cpu_idle(void) + local_irq_disable(); + /* Don't trace irqs off for idle */ + stop_critical_timings(); +- pm_idle(); ++ if (cpuidle_idle_call()) ++ pm_idle(); + start_critical_timings(); + } + tick_nohz_restart_sched_tick(); +diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c +index b01898d..ca8df6a 100644 +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -37,6 +37,7 @@ + #include <linux/uaccess.h> + #include <linux/io.h> + #include <linux/ftrace.h> ++#include <linux/cpuidle.h> + + #include <asm/pgtable.h> + #include <asm/system.h> +@@ -136,7 +137,8 @@ void cpu_idle(void) + enter_idle(); + /* Don't trace irqs off for idle */ + stop_critical_timings(); +- pm_idle(); ++ if (cpuidle_idle_call()) ++ pm_idle(); + start_critical_timings(); + + /* In many cases the interrupt that ended idle +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index cd1c19c..0df0141 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -25,10 +25,10 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); + + DEFINE_MUTEX(cpuidle_lock); + LIST_HEAD(cpuidle_detected_devices); +-static void (*pm_idle_old)(void); + + static int enabled_devices; + static int off __read_mostly; ++static int initialized __read_mostly; + + int cpuidle_disabled(void) + { +@@ -56,25 +56,23 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); + * cpuidle_idle_call - the main idle loop + * + * NOTE: no locks or semaphores should be used here ++ * return non-zero on failure + */ +-static void cpuidle_idle_call(void) ++int cpuidle_idle_call(void) + { + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_state *target_state; + int next_state; + ++ if (off) ++ return -ENODEV; ++ ++ if (!initialized) ++ return -ENODEV; ++ + /* check if the device is ready */ +- if (!dev || !dev->enabled) { +- if (pm_idle_old) +- pm_idle_old(); +- else +-#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE) +- default_idle(); +-#else +- local_irq_enable(); +-#endif +- return; +- } ++ if (!dev || !dev->enabled) ++ return -EBUSY; + + #if 0 + /* shows regressions, re-enable for 2.6.29 */ +@@ -99,7 +97,7 @@ static void cpuidle_idle_call(void) + next_state = cpuidle_curr_governor->select(dev); + if (need_resched()) { + local_irq_enable(); +- return; ++ return 0; + } + + target_state = &dev->states[next_state]; +@@ -124,6 +122,8 @@ static void cpuidle_idle_call(void) + /* give the governor an opportunity to reflect on the outcome */ + if (cpuidle_curr_governor->reflect) + cpuidle_curr_governor->reflect(dev); ++ ++ return 0; + } + + /** +@@ -131,10 +131,10 @@ static void cpuidle_idle_call(void) + */ + void cpuidle_install_idle_handler(void) + { +- if (enabled_devices && (pm_idle != cpuidle_idle_call)) { ++ if (enabled_devices) { + /* Make sure all changes finished before we switch to new idle */ + smp_wmb(); +- pm_idle = cpuidle_idle_call; ++ initialized = 1; + } + } + +@@ -143,8 +143,8 @@ void cpuidle_install_idle_handler(void) + */ + void cpuidle_uninstall_idle_handler(void) + { +- if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { +- pm_idle = pm_idle_old; ++ if (enabled_devices) { ++ initialized = 0; + cpuidle_kick_cpus(); + } + } +@@ -440,8 +440,6 @@ static int __init cpuidle_init(void) + if (cpuidle_disabled()) + return -ENODEV; + +- pm_idle_old = pm_idle; +- + ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); + if (ret) + return ret; +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index b89f67d..b51629e 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -123,6 +123,7 @@ struct cpuidle_driver { + + #ifdef CONFIG_CPU_IDLE + extern void disable_cpuidle(void); ++extern int cpuidle_idle_call(void); + + extern int cpuidle_register_driver(struct cpuidle_driver *drv); + struct cpuidle_driver *cpuidle_get_driver(void); +@@ -137,6 +138,7 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev); + + #else + static inline void disable_cpuidle(void) { } ++static inline int cpuidle_idle_call(void) { return -ENODEV; } + + static inline int cpuidle_register_driver(struct cpuidle_driver *drv) + {return -ENODEV; } +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0039-cpuidle-Consistent-spelling-of-cpuidle_idle_call.patch b/patches.kzm9g/0039-cpuidle-Consistent-spelling-of-cpuidle_idle_call.patch new file mode 100644 index 00000000000000..495c66f5cd66dc --- /dev/null +++ b/patches.kzm9g/0039-cpuidle-Consistent-spelling-of-cpuidle_idle_call.patch @@ -0,0 +1,53 @@ +From 8fb27384a7f934ae0f01e86b41a8cdc22bf57ca7 Mon Sep 17 00:00:00 2001 +From: David Brown <davidb@codeaurora.org> +Date: Thu, 4 Aug 2011 09:24:31 -0700 +Subject: cpuidle: Consistent spelling of cpuidle_idle_call() + +Commit a0bfa1373859e9d11dc92561a8667588803e42d8 mispells +cpuidle_idle_call() on ARM and SH code. Fix this to be consistent. + +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Paul Mundt <lethal@linux-sh.org> +Cc: x86@kernel.org +Cc: Len Brown <len.brown@intel.com> +Signed-off-by: David Brown <davidb@codeaurora.org> +[ Also done by Mark Brown - th ebug has been around forever, and was + noticed in -next, but the idle tree never picked it up. Bad bad bad ] +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +(cherry picked from commit cbc158d6bfa1990f7869717bb5270867c66068d1) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/kernel/process.c | 2 +- + arch/sh/kernel/idle.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c +index 5affc61..c9d11ea 100644 +--- a/arch/arm/kernel/process.c ++++ b/arch/arm/kernel/process.c +@@ -200,7 +200,7 @@ void cpu_idle(void) + cpu_relax(); + } else { + stop_critical_timings(); +- if (cpuidle_call_idle()) ++ if (cpuidle_idle_call()) + pm_idle(); + start_critical_timings(); + /* +diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c +index 9c7099e..1db1968 100644 +--- a/arch/sh/kernel/idle.c ++++ b/arch/sh/kernel/idle.c +@@ -101,7 +101,7 @@ void cpu_idle(void) + local_irq_disable(); + /* Don't trace irqs off for idle */ + stop_critical_timings(); +- if (cpuidle_call_idle()) ++ if (cpuidle_idle_call()) + pm_idle(); + /* + * Sanity check to ensure that pm_idle() returns +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0040-sh-Fix-up-fallout-from-cpuidle-changes.patch b/patches.kzm9g/0040-sh-Fix-up-fallout-from-cpuidle-changes.patch new file mode 100644 index 00000000000000..e39f543f6d5345 --- /dev/null +++ b/patches.kzm9g/0040-sh-Fix-up-fallout-from-cpuidle-changes.patch @@ -0,0 +1,32 @@ +From ff5ca09e2aa7d364357133e228c8f47ceccaa8a0 Mon Sep 17 00:00:00 2001 +From: Paul Mundt <lethal@linux-sh.org> +Date: Mon, 8 Aug 2011 16:30:11 +0900 +Subject: sh: Fix up fallout from cpuidle changes. + +Fixes up the pm_idle redefinition that was introduced with the earlier +cpuidle changes. + +Signed-off-by: Paul Mundt <lethal@linux-sh.org> +(cherry picked from commit c66d3fcbf306af3c0c4b6f4e0d81467f89c67702) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/sh/kernel/idle.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c +index 1db1968..169767f 100644 +--- a/arch/sh/kernel/idle.c ++++ b/arch/sh/kernel/idle.c +@@ -22,7 +22,7 @@ + #include <asm/atomic.h> + #include <asm/smp.h> + +-static void (*pm_idle)(void); ++void (*pm_idle)(void); + + static int hlt_counter; + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0041-cpuidle-Add-module.h-to-drivers-cpuidle-files-as-req.patch b/patches.kzm9g/0041-cpuidle-Add-module.h-to-drivers-cpuidle-files-as-req.patch new file mode 100644 index 00000000000000..4a4ecdd8a534a1 --- /dev/null +++ b/patches.kzm9g/0041-cpuidle-Add-module.h-to-drivers-cpuidle-files-as-req.patch @@ -0,0 +1,41 @@ +From e642a0935f0ebf4599766c1005b6995f79a0cfcd Mon Sep 17 00:00:00 2001 +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Mon, 29 Aug 2011 17:52:39 -0400 +Subject: cpuidle: Add module.h to drivers/cpuidle files as required. + +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +(cherry picked from commit 884b17e109d61e95ee4c652cf6873341bf1dca63) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/cpuidle/cpuidle.c | 1 + + drivers/cpuidle/governors/menu.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index 0df0141..becd6d9 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -17,6 +17,7 @@ + #include <linux/cpuidle.h> + #include <linux/ktime.h> + #include <linux/hrtimer.h> ++#include <linux/module.h> + #include <trace/events/power.h> + + #include "cpuidle.h" +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 3600f19..0027524 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -19,6 +19,7 @@ + #include <linux/tick.h> + #include <linux/sched.h> + #include <linux/math64.h> ++#include <linux/module.h> + + #define BUCKETS 12 + #define INTERVALS 8 +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0042-cpuidle-Move-dev-last_residency-update-to-driver-ent.patch b/patches.kzm9g/0042-cpuidle-Move-dev-last_residency-update-to-driver-ent.patch new file mode 100644 index 00000000000000..fb997a6fcea315 --- /dev/null +++ b/patches.kzm9g/0042-cpuidle-Move-dev-last_residency-update-to-driver-ent.patch @@ -0,0 +1,868 @@ +From a2bea6713199f518d94d1bcc5acbe8b7523d4b7e Mon Sep 17 00:00:00 2001 +From: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Date: Fri, 28 Oct 2011 16:20:09 +0530 +Subject: cpuidle: Move dev->last_residency update to driver enter routine; + remove dev->last_state + +Cpuidle governor only suggests the state to enter using the +governor->select() interface, but allows the low level driver to +override the recommended state. The actual entered state +may be different because of software or hardware demotion. Software +demotion is done by the back-end cpuidle driver and can be accounted +correctly. Current cpuidle code uses last_state field to capture the +actual state entered and based on that updates the statistics for the +state entered. + +Ideally the driver enter routine should update the counters, +and it should return the state actually entered rather than the time +spent there. The generic cpuidle code should simply handle where +the counters live in the sysfs namespace, not updating the counters. + +Reference: +https://lkml.org/lkml/2011/3/25/52 + +Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> +Tested-by: Jean Pihet <j-pihet@ti.com> +Reviewed-by: Kevin Hilman <khilman@ti.com> +Acked-by: Arjan van de Ven <arjan@linux.intel.com> +Acked-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit e978aa7d7d57d04eb5f88a7507c4fb98577def77) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-at91/cpuidle.c | 10 +++-- + arch/arm/mach-davinci/cpuidle.c | 9 ++-- + arch/arm/mach-exynos4/cpuidle.c | 7 +-- + arch/arm/mach-kirkwood/cpuidle.c | 12 ++++-- + arch/arm/mach-omap2/cpuidle34xx.c | 67 +++++++++++++++++------------ + arch/sh/kernel/cpu/shmobile/cpuidle.c | 12 +++--- + drivers/acpi/processor_idle.c | 75 +++++++++++++++++++++------------ + drivers/cpuidle/cpuidle.c | 32 +++++++------- + drivers/cpuidle/governors/ladder.c | 13 ++++++ + drivers/cpuidle/governors/menu.c | 7 ++- + drivers/idle/intel_idle.c | 12 ++++-- + include/linux/cpuidle.h | 7 ++- + 12 files changed, 164 insertions(+), 99 deletions(-) + +diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c +index f474272..d76a600 100644 +--- a/arch/arm/mach-at91/cpuidle.c ++++ b/arch/arm/mach-at91/cpuidle.c +@@ -34,7 +34,7 @@ static struct cpuidle_driver at91_idle_driver = { + + /* Actual code that puts the SoC in different idle states */ + static int at91_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + struct timeval before, after; + int idle_time; +@@ -42,10 +42,10 @@ static int at91_enter_idle(struct cpuidle_device *dev, + + local_irq_disable(); + do_gettimeofday(&before); +- if (state == &dev->states[0]) ++ if (index == 0) + /* Wait for interrupt state */ + cpu_do_idle(); +- else if (state == &dev->states[1]) { ++ else if (index == 1) { + asm("b 1f; .align 5; 1:"); + asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ + saved_lpr = sdram_selfrefresh_enable(); +@@ -56,7 +56,9 @@ static int at91_enter_idle(struct cpuidle_device *dev, + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); +- return idle_time; ++ ++ dev->last_residency = idle_time; ++ return index; + } + + /* Initialize CPU idle by registering the idle states */ +diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c +index 85cc399..ab9a9e4 100644 +--- a/arch/arm/mach-davinci/cpuidle.c ++++ b/arch/arm/mach-davinci/cpuidle.c +@@ -79,9 +79,9 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { + + /* Actual code that puts the SoC in different idle states */ + static int davinci_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { +- struct davinci_ops *ops = cpuidle_get_statedata(state); ++ struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]); + struct timeval before, after; + int idle_time; + +@@ -99,7 +99,10 @@ static int davinci_enter_idle(struct cpuidle_device *dev, + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); +- return idle_time; ++ ++ dev->last_residency = idle_time; ++ ++ return index; + } + + static int __init davinci_cpuidle_probe(struct platform_device *pdev) +diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c +index bf7e96f..ea026e7 100644 +--- a/arch/arm/mach-exynos4/cpuidle.c ++++ b/arch/arm/mach-exynos4/cpuidle.c +@@ -16,7 +16,7 @@ + #include <asm/proc-fns.h> + + static int exynos4_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state); ++ int index); + + static struct cpuidle_state exynos4_cpuidle_set[] = { + [0] = { +@@ -37,7 +37,7 @@ static struct cpuidle_driver exynos4_idle_driver = { + }; + + static int exynos4_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + struct timeval before, after; + int idle_time; +@@ -52,7 +52,8 @@ static int exynos4_enter_idle(struct cpuidle_device *dev, + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + +- return idle_time; ++ dev->last_residency = idle_time; ++ return index; + } + + static int __init exynos4_init_cpuidle(void) +diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c +index 864e569..53d6049 100644 +--- a/arch/arm/mach-kirkwood/cpuidle.c ++++ b/arch/arm/mach-kirkwood/cpuidle.c +@@ -33,17 +33,17 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); + + /* Actual code that puts the SoC in different idle states */ + static int kirkwood_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + struct timeval before, after; + int idle_time; + + local_irq_disable(); + do_gettimeofday(&before); +- if (state == &dev->states[0]) ++ if (index == 0) + /* Wait for interrupt state */ + cpu_do_idle(); +- else if (state == &dev->states[1]) { ++ else if (index == 1) { + /* + * Following write will put DDR in self refresh. + * Note that we have 256 cycles before DDR puts it +@@ -58,7 +58,11 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); +- return idle_time; ++ ++ /* Update last residency */ ++ dev->last_residency = idle_time; ++ ++ return index; + } + + /* Initialize CPU idle by registering the idle states */ +diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c +index 4bf6e6e..58425c7 100644 +--- a/arch/arm/mach-omap2/cpuidle34xx.c ++++ b/arch/arm/mach-omap2/cpuidle34xx.c +@@ -88,17 +88,19 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, + /** + * omap3_enter_idle - Programs OMAP3 to enter the specified state + * @dev: cpuidle device +- * @state: The target state to be programmed ++ * @index: the index of state to be entered + * + * Called from the CPUidle framework to program the device to the + * specified target state selected by the governor. + */ + static int omap3_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { +- struct omap3_idle_statedata *cx = cpuidle_get_statedata(state); ++ struct omap3_idle_statedata *cx = ++ cpuidle_get_statedata(&dev->states[index]); + struct timespec ts_preidle, ts_postidle, ts_idle; + u32 mpu_state = cx->mpu_state, core_state = cx->core_state; ++ int idle_time; + + /* Used to keep track of the total time in idle */ + getnstimeofday(&ts_preidle); +@@ -113,7 +115,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, + goto return_sleep_time; + + /* Deny idle for C1 */ +- if (state == &dev->states[0]) { ++ if (index == 0) { + pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); + pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); + } +@@ -122,7 +124,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, + omap_sram_idle(); + + /* Re-allow idle for C1 */ +- if (state == &dev->states[0]) { ++ if (index == 0) { + pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); + pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); + } +@@ -134,28 +136,35 @@ return_sleep_time: + local_irq_enable(); + local_fiq_enable(); + +- return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; ++ idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \ ++ USEC_PER_SEC; ++ ++ /* Update cpuidle counters */ ++ dev->last_residency = idle_time; ++ ++ return index; + } + + /** + * next_valid_state - Find next valid C-state + * @dev: cpuidle device +- * @state: Currently selected C-state ++ * @index: Index of currently selected c-state + * +- * If the current state is valid, it is returned back to the caller. +- * Else, this function searches for a lower c-state which is still +- * valid. ++ * If the state corresponding to index is valid, index is returned back ++ * to the caller. Else, this function searches for a lower c-state which is ++ * still valid (as defined in omap3_power_states[]) and returns its index. + * + * A state is valid if the 'valid' field is enabled and + * if it satisfies the enable_off_mode condition. + */ +-static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, +- struct cpuidle_state *curr) ++static int next_valid_state(struct cpuidle_device *dev, ++ int index) + { +- struct cpuidle_state *next = NULL; ++ struct cpuidle_state *curr = &dev->states[index]; + struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); + u32 mpu_deepest_state = PWRDM_POWER_RET; + u32 core_deepest_state = PWRDM_POWER_RET; ++ int next_index = -1; + + if (enable_off_mode) { + mpu_deepest_state = PWRDM_POWER_OFF; +@@ -172,20 +181,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, + if ((cx->valid) && + (cx->mpu_state >= mpu_deepest_state) && + (cx->core_state >= core_deepest_state)) { +- return curr; ++ return index; + } else { + int idx = OMAP3_NUM_STATES - 1; + + /* Reach the current state starting at highest C-state */ + for (; idx >= 0; idx--) { + if (&dev->states[idx] == curr) { +- next = &dev->states[idx]; ++ next_index = idx; + break; + } + } + + /* Should never hit this condition */ +- WARN_ON(next == NULL); ++ WARN_ON(next_index == -1); + + /* + * Drop to next valid state. +@@ -197,37 +206,39 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, + if ((cx->valid) && + (cx->mpu_state >= mpu_deepest_state) && + (cx->core_state >= core_deepest_state)) { +- next = &dev->states[idx]; ++ next_index = idx; + break; + } + } + /* + * C1 is always valid. +- * So, no need to check for 'next==NULL' outside this loop. ++ * So, no need to check for 'next_index == -1' outside ++ * this loop. + */ + } + +- return next; ++ return next_index; + } + + /** + * omap3_enter_idle_bm - Checks for any bus activity + * @dev: cpuidle device +- * @state: The target state to be programmed ++ * @index: array index of target state to be programmed + * + * This function checks for any pending activity and then programs + * the device to the specified or a safer state. + */ + static int omap3_enter_idle_bm(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { +- struct cpuidle_state *new_state; ++ struct cpuidle_state *state = &dev->states[index]; ++ int new_state_idx; + u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; + struct omap3_idle_statedata *cx; + int ret; + + if (!omap3_can_sleep()) { +- new_state = dev->safe_state; ++ new_state_idx = dev->safe_state_index; + goto select_state; + } + +@@ -237,7 +248,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + */ + cam_state = pwrdm_read_pwrst(cam_pd); + if (cam_state == PWRDM_POWER_ON) { +- new_state = dev->safe_state; ++ new_state_idx = dev->safe_state_index; + goto select_state; + } + +@@ -264,11 +275,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + if (per_next_state != per_saved_state) + pwrdm_set_next_pwrst(per_pd, per_next_state); + +- new_state = next_valid_state(dev, state); ++ new_state_idx = next_valid_state(dev, index); + + select_state: +- dev->last_state = new_state; +- ret = omap3_enter_idle(dev, new_state); ++ ret = omap3_enter_idle(dev, new_state_idx); + + /* Restore original PER state if it was modified */ + if (per_next_state != per_saved_state) +@@ -339,11 +349,12 @@ int __init omap3_idle_init(void) + + cpuidle_register_driver(&omap3_idle_driver); + dev = &per_cpu(omap3_idle_dev, smp_processor_id()); ++ dev->safe_state_index = -1; + + /* C1 . MPU WFI + Core active */ + cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); + (&dev->states[0])->enter = omap3_enter_idle; +- dev->safe_state = &dev->states[0]; ++ dev->safe_state_index = 0; + cx->valid = 1; /* C1 is always valid */ + cx->mpu_state = PWRDM_POWER_ON; + cx->core_state = PWRDM_POWER_ON; +diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c +index e4469e72..7be50d4c 100644 +--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c ++++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c +@@ -25,11 +25,11 @@ static unsigned long cpuidle_mode[] = { + }; + + static int cpuidle_sleep_enter(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + unsigned long allowed_mode = arch_hwblk_sleep_mode(); + ktime_t before, after; +- int requested_state = state - &dev->states[0]; ++ int requested_state = index; + int allowed_state; + int k; + +@@ -46,11 +46,13 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, + */ + k = min_t(int, allowed_state, requested_state); + +- dev->last_state = &dev->states[k]; + before = ktime_get(); + sh_mobile_call_standby(cpuidle_mode[k]); + after = ktime_get(); +- return ktime_to_ns(ktime_sub(after, before)) >> 10; ++ ++ dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10; ++ ++ return k; + } + + static struct cpuidle_device cpuidle_dev; +@@ -84,7 +86,7 @@ void sh_mobile_setup_cpuidle(void) + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = cpuidle_sleep_enter; + +- dev->safe_state = state; ++ dev->safe_state_index = i-1; + + if (sh_mobile_sleep_supported & SUSP_SH_SF) { + state = &dev->states[i++]; +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 2e69e09..6be70bf 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -741,22 +741,24 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) + /** + * acpi_idle_enter_c1 - enters an ACPI C1 state-type + * @dev: the target CPU +- * @state: the state data ++ * @index: index of target state + * + * This is equivalent to the HALT instruction. + */ + static int acpi_idle_enter_c1(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + ktime_t kt1, kt2; + s64 idle_time; + struct acpi_processor *pr; ++ struct cpuidle_state *state = &dev->states[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + + pr = __this_cpu_read(processors); ++ dev->last_residency = 0; + + if (unlikely(!pr)) +- return 0; ++ return -EINVAL; + + local_irq_disable(); + +@@ -764,7 +766,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, + if (acpi_idle_suspend) { + local_irq_enable(); + cpu_relax(); +- return 0; ++ return -EINVAL; + } + + lapic_timer_state_broadcast(pr, cx, 1); +@@ -773,37 +775,46 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, + kt2 = ktime_get_real(); + idle_time = ktime_to_us(ktime_sub(kt2, kt1)); + ++ /* Update device last_residency*/ ++ dev->last_residency = (int)idle_time; ++ + local_irq_enable(); + cx->usage++; + lapic_timer_state_broadcast(pr, cx, 0); + +- return idle_time; ++ return index; + } + + /** + * acpi_idle_enter_simple - enters an ACPI state without BM handling + * @dev: the target CPU +- * @state: the state data ++ * @index: the index of suggested state + */ + static int acpi_idle_enter_simple(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + struct acpi_processor *pr; ++ struct cpuidle_state *state = &dev->states[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + ktime_t kt1, kt2; + s64 idle_time_ns; + s64 idle_time; + + pr = __this_cpu_read(processors); ++ dev->last_residency = 0; + + if (unlikely(!pr)) +- return 0; +- +- if (acpi_idle_suspend) +- return(acpi_idle_enter_c1(dev, state)); ++ return -EINVAL; + + local_irq_disable(); + ++ if (acpi_idle_suspend) { ++ local_irq_enable(); ++ cpu_relax(); ++ return -EINVAL; ++ } ++ ++ + if (cx->entry_method != ACPI_CSTATE_FFH) { + current_thread_info()->status &= ~TS_POLLING; + /* +@@ -815,7 +826,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, + if (unlikely(need_resched())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); +- return 0; ++ return -EINVAL; + } + } + +@@ -837,6 +848,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, + idle_time = idle_time_ns; + do_div(idle_time, NSEC_PER_USEC); + ++ /* Update device last_residency*/ ++ dev->last_residency = (int)idle_time; ++ + /* Tell the scheduler how much we idled: */ + sched_clock_idle_wakeup_event(idle_time_ns); + +@@ -848,7 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, + + lapic_timer_state_broadcast(pr, cx, 0); + cx->time += idle_time; +- return idle_time; ++ return index; + } + + static int c3_cpu_count; +@@ -857,14 +871,15 @@ static DEFINE_SPINLOCK(c3_lock); + /** + * acpi_idle_enter_bm - enters C3 with proper BM handling + * @dev: the target CPU +- * @state: the state data ++ * @index: the index of suggested state + * + * If BM is detected, the deepest non-C3 idle state is entered instead. + */ + static int acpi_idle_enter_bm(struct cpuidle_device *dev, +- struct cpuidle_state *state) ++ int index) + { + struct acpi_processor *pr; ++ struct cpuidle_state *state = &dev->states[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + ktime_t kt1, kt2; + s64 idle_time_ns; +@@ -872,22 +887,26 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, + + + pr = __this_cpu_read(processors); ++ dev->last_residency = 0; + + if (unlikely(!pr)) +- return 0; ++ return -EINVAL; + +- if (acpi_idle_suspend) +- return(acpi_idle_enter_c1(dev, state)); ++ ++ if (acpi_idle_suspend) { ++ cpu_relax(); ++ return -EINVAL; ++ } + + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { +- if (dev->safe_state) { +- dev->last_state = dev->safe_state; +- return dev->safe_state->enter(dev, dev->safe_state); ++ if (dev->safe_state_index >= 0) { ++ return dev->states[dev->safe_state_index].enter(dev, ++ dev->safe_state_index); + } else { + local_irq_disable(); + acpi_safe_halt(); + local_irq_enable(); +- return 0; ++ return -EINVAL; + } + } + +@@ -904,7 +923,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, + if (unlikely(need_resched())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); +- return 0; ++ return -EINVAL; + } + } + +@@ -954,6 +973,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, + idle_time = idle_time_ns; + do_div(idle_time, NSEC_PER_USEC); + ++ /* Update device last_residency*/ ++ dev->last_residency = (int)idle_time; ++ + /* Tell the scheduler how much we idled: */ + sched_clock_idle_wakeup_event(idle_time_ns); + +@@ -965,7 +987,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, + + lapic_timer_state_broadcast(pr, cx, 0); + cx->time += idle_time; +- return idle_time; ++ return index; + } + + struct cpuidle_driver acpi_idle_driver = { +@@ -992,6 +1014,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + } + + dev->cpu = pr->id; ++ dev->safe_state_index = -1; + for (i = 0; i < CPUIDLE_STATE_MAX; i++) { + dev->states[i].name[0] = '\0'; + dev->states[i].desc[0] = '\0'; +@@ -1027,13 +1050,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + state->flags |= CPUIDLE_FLAG_TIME_VALID; + + state->enter = acpi_idle_enter_c1; +- dev->safe_state = state; ++ dev->safe_state_index = count; + break; + + case ACPI_STATE_C2: + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = acpi_idle_enter_simple; +- dev->safe_state = state; ++ dev->safe_state_index = count; + break; + + case ACPI_STATE_C3: +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index becd6d9..c0f1a3a 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -63,7 +63,7 @@ int cpuidle_idle_call(void) + { + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_state *target_state; +- int next_state; ++ int next_state, entered_state; + + if (off) + return -ENODEV; +@@ -103,26 +103,27 @@ int cpuidle_idle_call(void) + + target_state = &dev->states[next_state]; + +- /* enter the state and update stats */ +- dev->last_state = target_state; +- + trace_power_start(POWER_CSTATE, next_state, dev->cpu); + trace_cpu_idle(next_state, dev->cpu); + +- dev->last_residency = target_state->enter(dev, target_state); ++ entered_state = target_state->enter(dev, next_state); + + trace_power_end(dev->cpu); + trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); + +- if (dev->last_state) +- target_state = dev->last_state; +- +- target_state->time += (unsigned long long)dev->last_residency; +- target_state->usage++; ++ if (entered_state >= 0) { ++ /* Update cpuidle counters */ ++ /* This can be moved to within driver enter routine ++ * but that results in multiple copies of same code. ++ */ ++ dev->states[entered_state].time += ++ (unsigned long long)dev->last_residency; ++ dev->states[entered_state].usage++; ++ } + + /* give the governor an opportunity to reflect on the outcome */ + if (cpuidle_curr_governor->reflect) +- cpuidle_curr_governor->reflect(dev); ++ cpuidle_curr_governor->reflect(dev, entered_state); + + return 0; + } +@@ -173,11 +174,10 @@ void cpuidle_resume_and_unlock(void) + EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); + + #ifdef CONFIG_ARCH_HAS_CPU_RELAX +-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) ++static int poll_idle(struct cpuidle_device *dev, int index) + { + ktime_t t1, t2; + s64 diff; +- int ret; + + t1 = ktime_get(); + local_irq_enable(); +@@ -189,8 +189,9 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) + if (diff > INT_MAX) + diff = INT_MAX; + +- ret = (int) diff; +- return ret; ++ dev->last_residency = (int) diff; ++ ++ return index; + } + + static void poll_idle_init(struct cpuidle_device *dev) +@@ -249,7 +250,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) + dev->states[i].time = 0; + } + dev->last_residency = 0; +- dev->last_state = NULL; + + smp_wmb(); + +diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c +index f62fde2..78b06d2 100644 +--- a/drivers/cpuidle/governors/ladder.c ++++ b/drivers/cpuidle/governors/ladder.c +@@ -153,11 +153,24 @@ static int ladder_enable_device(struct cpuidle_device *dev) + return 0; + } + ++/** ++ * ladder_reflect - update the correct last_state_idx ++ * @dev: the CPU ++ * @index: the index of actual state entered ++ */ ++static void ladder_reflect(struct cpuidle_device *dev, int index) ++{ ++ struct ladder_device *ldev = &__get_cpu_var(ladder_devices); ++ if (index > 0) ++ ldev->last_state_idx = index; ++} ++ + static struct cpuidle_governor ladder_governor = { + .name = "ladder", + .rating = 10, + .enable = ladder_enable_device, + .select = ladder_select_state, ++ .reflect = ladder_reflect, + .owner = THIS_MODULE, + }; + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 0027524..e27a2af 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -311,14 +311,17 @@ static int menu_select(struct cpuidle_device *dev) + /** + * menu_reflect - records that data structures need update + * @dev: the CPU ++ * @index: the index of actual entered state + * + * NOTE: it's important to be fast here because this operation will add to + * the overall exit latency. + */ +-static void menu_reflect(struct cpuidle_device *dev) ++static void menu_reflect(struct cpuidle_device *dev, int index) + { + struct menu_device *data = &__get_cpu_var(menu_devices); +- data->needs_update = 1; ++ data->last_state_idx = index; ++ if (index >= 0) ++ data->needs_update = 1; + } + + /** +diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c +index 026f9aa..8f056e1 100644 +--- a/drivers/idle/intel_idle.c ++++ b/drivers/idle/intel_idle.c +@@ -81,7 +81,7 @@ static unsigned int mwait_substates; + static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ + + static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; +-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); ++static int intel_idle(struct cpuidle_device *dev, int index); + + static struct cpuidle_state *cpuidle_state_table; + +@@ -209,12 +209,13 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { + /** + * intel_idle + * @dev: cpuidle_device +- * @state: cpuidle state ++ * @index: index of cpuidle state + * + */ +-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) ++static int intel_idle(struct cpuidle_device *dev, int index) + { + unsigned long ecx = 1; /* break on interrupt flag */ ++ struct cpuidle_state *state = &dev->states[index]; + unsigned long eax = (unsigned long)cpuidle_get_statedata(state); + unsigned int cstate; + ktime_t kt_before, kt_after; +@@ -256,7 +257,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) + if (!(lapic_timer_reliable_states & (1 << (cstate)))) + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); + +- return usec_delta; ++ /* Update cpuidle counters */ ++ dev->last_residency = (int)usec_delta; ++ ++ return index; + } + + static void __setup_broadcast_timer(void *arg) +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index b51629e..8da811b 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -42,7 +42,7 @@ struct cpuidle_state { + unsigned long long time; /* in US */ + + int (*enter) (struct cpuidle_device *dev, +- struct cpuidle_state *state); ++ int index); + }; + + /* Idle State Flags */ +@@ -87,13 +87,12 @@ struct cpuidle_device { + int state_count; + struct cpuidle_state states[CPUIDLE_STATE_MAX]; + struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; +- struct cpuidle_state *last_state; + + struct list_head device_list; + struct kobject kobj; + struct completion kobj_unregister; + void *governor_data; +- struct cpuidle_state *safe_state; ++ int safe_state_index; + + int (*prepare) (struct cpuidle_device *dev); + }; +@@ -169,7 +168,7 @@ struct cpuidle_governor { + void (*disable) (struct cpuidle_device *dev); + + int (*select) (struct cpuidle_device *dev); +- void (*reflect) (struct cpuidle_device *dev); ++ void (*reflect) (struct cpuidle_device *dev, int index); + + struct module *owner; + }; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0043-cpuidle-Remove-CPUIDLE_FLAG_IGNORE-and-dev-prepare.patch b/patches.kzm9g/0043-cpuidle-Remove-CPUIDLE_FLAG_IGNORE-and-dev-prepare.patch new file mode 100644 index 00000000000000..549d142a86ca94 --- /dev/null +++ b/patches.kzm9g/0043-cpuidle-Remove-CPUIDLE_FLAG_IGNORE-and-dev-prepare.patch @@ -0,0 +1,89 @@ +From bdf8107f9e58c5563946d7cb46e1bed307ce2653 Mon Sep 17 00:00:00 2001 +From: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Date: Fri, 28 Oct 2011 16:20:24 +0530 +Subject: cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare() + +The cpuidle_device->prepare() mechanism causes updates to the +cpuidle_state[].flags, setting and clearing CPUIDLE_FLAG_IGNORE +to tell the governor not to chose a state on a per-cpu basis at +run-time. State demotion is now handled by the driver and it returns +the actual state entered. Hence, this mechanism is not required. +Also this removes per-cpu flags from cpuidle_state enabling +it to be made global. + +Reference: +https://lkml.org/lkml/2011/3/25/52 + +Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm> +Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> +Tested-by: Jean Pihet <j-pihet@ti.com> +Acked-by: Arjan van de Ven <arjan@linux.intel.com> +Reviewed-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit b25edc42bfb9602f0503474b2c94701d5536ce60) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/cpuidle/cpuidle.c | 10 ---------- + drivers/cpuidle/governors/menu.c | 2 -- + include/linux/cpuidle.h | 3 --- + 3 files changed, 15 deletions(-) + +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index c0f1a3a..70350d2 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -84,16 +84,6 @@ int cpuidle_idle_call(void) + hrtimer_peek_ahead_timers(); + #endif + +- /* +- * Call the device's prepare function before calling the +- * governor's select function. ->prepare gives the device's +- * cpuidle driver a chance to update any dynamic information +- * of its cpuidle states for the current idle period, e.g. +- * state availability, latencies, residencies, etc. +- */ +- if (dev->prepare) +- dev->prepare(dev); +- + /* ask the governor for the next state */ + next_state = cpuidle_curr_governor->select(dev); + if (need_resched()) { +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index e27a2af..2072aeb 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -289,8 +289,6 @@ static int menu_select(struct cpuidle_device *dev) + for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { + struct cpuidle_state *s = &dev->states[i]; + +- if (s->flags & CPUIDLE_FLAG_IGNORE) +- continue; + if (s->target_residency > data->predicted_us) + continue; + if (s->exit_latency > latency_req) +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index 8da811b..c6d85cf 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -47,7 +47,6 @@ struct cpuidle_state { + + /* Idle State Flags */ + #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ +-#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */ + + #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) + +@@ -93,8 +92,6 @@ struct cpuidle_device { + struct completion kobj_unregister; + void *governor_data; + int safe_state_index; +- +- int (*prepare) (struct cpuidle_device *dev); + }; + + DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0044-cpuidle-Split-cpuidle_state-structure-and-move-per-c.patch b/patches.kzm9g/0044-cpuidle-Split-cpuidle_state-structure-and-move-per-c.patch new file mode 100644 index 00000000000000..d41a55c17819b7 --- /dev/null +++ b/patches.kzm9g/0044-cpuidle-Split-cpuidle_state-structure-and-move-per-c.patch @@ -0,0 +1,531 @@ +From f3127a05382f54ff79a80cddcabc22ffdfb510e0 Mon Sep 17 00:00:00 2001 +From: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Date: Fri, 28 Oct 2011 16:20:33 +0530 +Subject: cpuidle: Split cpuidle_state structure and move per-cpu statistics + fields + +This is the first step towards global registration of cpuidle +states. The statistics used primarily by the governor are per-cpu +and have to be split from rest of the fields inside cpuidle_state, +which would be made global i.e. single copy. The driver_data field +is also per-cpu and moved. + +Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> +Tested-by: Jean Pihet <j-pihet@ti.com> +Reviewed-by: Kevin Hilman <khilman@ti.com> +Acked-by: Arjan van de Ven <arjan@linux.intel.com> +Acked-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit 4202735e8ab6ecfb0381631a0d0b58fefe0bd4e2) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-davinci/cpuidle.c | 5 ++-- + arch/arm/mach-omap2/cpuidle34xx.c | 13 ++++++----- + drivers/acpi/processor_idle.c | 25 ++++++++++---------- + drivers/cpuidle/cpuidle.c | 11 +++++---- + drivers/cpuidle/sysfs.c | 19 ++++++++++----- + drivers/idle/intel_idle.c | 46 +++++++++++++++++++++++++++---------- + include/linux/cpuidle.h | 25 ++++++++++++-------- + 7 files changed, 90 insertions(+), 54 deletions(-) + +diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c +index ab9a9e4..dda6d2f 100644 +--- a/arch/arm/mach-davinci/cpuidle.c ++++ b/arch/arm/mach-davinci/cpuidle.c +@@ -81,7 +81,8 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { + static int davinci_enter_idle(struct cpuidle_device *dev, + int index) + { +- struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]); ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; ++ struct davinci_ops *ops = cpuidle_get_statedata(state_usage); + struct timeval before, after; + int idle_time; + +@@ -143,7 +144,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) + strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); + if (pdata->ddr2_pdown) + davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; +- cpuidle_set_statedata(&device->states[1], &davinci_states[1]); ++ cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]); + + device->state_count = DAVINCI_CPUIDLE_MAX_STATES; + +diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c +index 58425c7..d3fce7b 100644 +--- a/arch/arm/mach-omap2/cpuidle34xx.c ++++ b/arch/arm/mach-omap2/cpuidle34xx.c +@@ -97,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, + int index) + { + struct omap3_idle_statedata *cx = +- cpuidle_get_statedata(&dev->states[index]); ++ cpuidle_get_statedata(&dev->states_usage[index]); + struct timespec ts_preidle, ts_postidle, ts_idle; + u32 mpu_state = cx->mpu_state, core_state = cx->core_state; + int idle_time; +@@ -160,8 +160,9 @@ return_sleep_time: + static int next_valid_state(struct cpuidle_device *dev, + int index) + { ++ struct cpuidle_state_usage *curr_usage = &dev->states_usage[index]; + struct cpuidle_state *curr = &dev->states[index]; +- struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); ++ struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage); + u32 mpu_deepest_state = PWRDM_POWER_RET; + u32 core_deepest_state = PWRDM_POWER_RET; + int next_index = -1; +@@ -202,7 +203,7 @@ static int next_valid_state(struct cpuidle_device *dev, + */ + idx--; + for (; idx >= 0; idx--) { +- cx = cpuidle_get_statedata(&dev->states[idx]); ++ cx = cpuidle_get_statedata(&dev->states_usage[idx]); + if ((cx->valid) && + (cx->mpu_state >= mpu_deepest_state) && + (cx->core_state >= core_deepest_state)) { +@@ -231,7 +232,6 @@ static int next_valid_state(struct cpuidle_device *dev, + static int omap3_enter_idle_bm(struct cpuidle_device *dev, + int index) + { +- struct cpuidle_state *state = &dev->states[index]; + int new_state_idx; + u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; + struct omap3_idle_statedata *cx; +@@ -264,7 +264,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + * Prevent PER off if CORE is not in retention or off as this + * would disable PER wakeups completely. + */ +- cx = cpuidle_get_statedata(state); ++ cx = cpuidle_get_statedata(&dev->states_usage[index]); + core_next_state = cx->core_state; + per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); + if ((per_next_state == PWRDM_POWER_OFF) && +@@ -318,6 +318,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( + { + struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; + struct cpuidle_state *state = &dev->states[idx]; ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; + + state->exit_latency = cpuidle_params_table[idx].exit_latency; + state->target_residency = cpuidle_params_table[idx].target_residency; +@@ -326,7 +327,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( + cx->valid = cpuidle_params_table[idx].valid; + sprintf(state->name, "C%d", idx + 1); + strncpy(state->desc, descr, CPUIDLE_DESC_LEN); +- cpuidle_set_statedata(state, cx); ++ cpuidle_set_statedata(state_usage, cx); + + return cx; + } +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 6be70bf..c7b89f0 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -745,14 +745,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) + * + * This is equivalent to the HALT instruction. + */ +-static int acpi_idle_enter_c1(struct cpuidle_device *dev, +- int index) ++static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) + { + ktime_t kt1, kt2; + s64 idle_time; + struct acpi_processor *pr; +- struct cpuidle_state *state = &dev->states[index]; +- struct acpi_processor_cx *cx = cpuidle_get_statedata(state); ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; ++ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); + + pr = __this_cpu_read(processors); + dev->last_residency = 0; +@@ -790,12 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, + * @dev: the target CPU + * @index: the index of suggested state + */ +-static int acpi_idle_enter_simple(struct cpuidle_device *dev, +- int index) ++static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index) + { + struct acpi_processor *pr; +- struct cpuidle_state *state = &dev->states[index]; +- struct acpi_processor_cx *cx = cpuidle_get_statedata(state); ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; ++ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); + ktime_t kt1, kt2; + s64 idle_time_ns; + s64 idle_time; +@@ -875,12 +873,11 @@ static DEFINE_SPINLOCK(c3_lock); + * + * If BM is detected, the deepest non-C3 idle state is entered instead. + */ +-static int acpi_idle_enter_bm(struct cpuidle_device *dev, +- int index) ++static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) + { + struct acpi_processor *pr; +- struct cpuidle_state *state = &dev->states[index]; +- struct acpi_processor_cx *cx = cpuidle_get_statedata(state); ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; ++ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); + ktime_t kt1, kt2; + s64 idle_time_ns; + s64 idle_time; +@@ -1004,6 +1001,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + int i, count = CPUIDLE_DRIVER_STATE_START; + struct acpi_processor_cx *cx; + struct cpuidle_state *state; ++ struct cpuidle_state_usage *state_usage; + struct cpuidle_device *dev = &pr->power.dev; + + if (!pr->flags.power_setup_done) +@@ -1026,6 +1024,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; + state = &dev->states[count]; ++ state_usage = &dev->states_usage[count]; + + if (!cx->valid) + continue; +@@ -1036,7 +1035,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; + #endif +- cpuidle_set_statedata(state, cx); ++ cpuidle_set_statedata(state_usage, cx); + + snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); + strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index 70350d2..219a757 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -106,9 +106,9 @@ int cpuidle_idle_call(void) + /* This can be moved to within driver enter routine + * but that results in multiple copies of same code. + */ +- dev->states[entered_state].time += ++ dev->states_usage[entered_state].time += + (unsigned long long)dev->last_residency; +- dev->states[entered_state].usage++; ++ dev->states_usage[entered_state].usage++; + } + + /* give the governor an opportunity to reflect on the outcome */ +@@ -187,8 +187,9 @@ static int poll_idle(struct cpuidle_device *dev, int index) + static void poll_idle_init(struct cpuidle_device *dev) + { + struct cpuidle_state *state = &dev->states[0]; ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[0]; + +- cpuidle_set_statedata(state, NULL); ++ cpuidle_set_statedata(state_usage, NULL); + + snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); + snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); +@@ -236,8 +237,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev) + goto fail_sysfs; + + for (i = 0; i < dev->state_count; i++) { +- dev->states[i].usage = 0; +- dev->states[i].time = 0; ++ dev->states_usage[i].usage = 0; ++ dev->states_usage[i].time = 0; + } + dev->last_residency = 0; + +diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c +index be7917ec..8a1ace1 100644 +--- a/drivers/cpuidle/sysfs.c ++++ b/drivers/cpuidle/sysfs.c +@@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = { + + struct cpuidle_state_attr { + struct attribute attr; +- ssize_t (*show)(struct cpuidle_state *, char *); ++ ssize_t (*show)(struct cpuidle_state *, \ ++ struct cpuidle_state_usage *, char *); + ssize_t (*store)(struct cpuidle_state *, const char *, size_t); + }; + +@@ -224,19 +225,22 @@ struct cpuidle_state_attr { + static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) + + #define define_show_state_function(_name) \ +-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ ++static ssize_t show_state_##_name(struct cpuidle_state *state, \ ++ struct cpuidle_state_usage *state_usage, char *buf) \ + { \ + return sprintf(buf, "%u\n", state->_name);\ + } + + #define define_show_state_ull_function(_name) \ +-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ ++static ssize_t show_state_##_name(struct cpuidle_state *state, \ ++ struct cpuidle_state_usage *state_usage, char *buf) \ + { \ +- return sprintf(buf, "%llu\n", state->_name);\ ++ return sprintf(buf, "%llu\n", state_usage->_name);\ + } + + #define define_show_state_str_function(_name) \ +-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ ++static ssize_t show_state_##_name(struct cpuidle_state *state, \ ++ struct cpuidle_state_usage *state_usage, char *buf) \ + { \ + if (state->_name[0] == '\0')\ + return sprintf(buf, "<null>\n");\ +@@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = { + + #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) + #define kobj_to_state(k) (kobj_to_state_obj(k)->state) ++#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) + #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) + static ssize_t cpuidle_state_show(struct kobject * kobj, + struct attribute * attr ,char * buf) + { + int ret = -EIO; + struct cpuidle_state *state = kobj_to_state(kobj); ++ struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); + struct cpuidle_state_attr * cattr = attr_to_stateattr(attr); + + if (cattr->show) +- ret = cattr->show(state, buf); ++ ret = cattr->show(state, state_usage, buf); + + return ret; + } +@@ -323,6 +329,7 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) + if (!kobj) + goto error_state; + kobj->state = &device->states[i]; ++ kobj->state_usage = &device->states_usage[i]; + init_completion(&kobj->kobj_unregister); + + ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, +diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c +index 8f056e1..b0c63e9 100644 +--- a/drivers/idle/intel_idle.c ++++ b/drivers/idle/intel_idle.c +@@ -109,7 +109,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C1 */ + .name = "C1-NHM", + .desc = "MWAIT 0x00", +- .driver_data = (void *) 0x00, + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 3, + .target_residency = 6, +@@ -117,7 +116,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C2 */ + .name = "C3-NHM", + .desc = "MWAIT 0x10", +- .driver_data = (void *) 0x10, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 20, + .target_residency = 80, +@@ -125,7 +123,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C3 */ + .name = "C6-NHM", + .desc = "MWAIT 0x20", +- .driver_data = (void *) 0x20, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 200, + .target_residency = 800, +@@ -137,7 +134,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C1 */ + .name = "C1-SNB", + .desc = "MWAIT 0x00", +- .driver_data = (void *) 0x00, + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 1, +@@ -145,7 +141,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C2 */ + .name = "C3-SNB", + .desc = "MWAIT 0x10", +- .driver_data = (void *) 0x10, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 80, + .target_residency = 211, +@@ -153,7 +148,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C3 */ + .name = "C6-SNB", + .desc = "MWAIT 0x20", +- .driver_data = (void *) 0x20, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 104, + .target_residency = 345, +@@ -161,7 +155,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C4 */ + .name = "C7-SNB", + .desc = "MWAIT 0x30", +- .driver_data = (void *) 0x30, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 109, + .target_residency = 345, +@@ -173,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C1 */ + .name = "C1-ATM", + .desc = "MWAIT 0x00", +- .driver_data = (void *) 0x00, + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 4, +@@ -181,7 +173,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C2 */ + .name = "C2-ATM", + .desc = "MWAIT 0x10", +- .driver_data = (void *) 0x10, + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 20, + .target_residency = 80, +@@ -190,7 +181,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C4 */ + .name = "C4-ATM", + .desc = "MWAIT 0x30", +- .driver_data = (void *) 0x30, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 100, + .target_residency = 400, +@@ -199,13 +189,41 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { + { /* MWAIT C6 */ + .name = "C6-ATM", + .desc = "MWAIT 0x52", +- .driver_data = (void *) 0x52, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 140, + .target_residency = 560, + .enter = &intel_idle }, + }; + ++static int get_driver_data(int cstate) ++{ ++ int driver_data; ++ switch (cstate) { ++ ++ case 1: /* MWAIT C1 */ ++ driver_data = 0x00; ++ break; ++ case 2: /* MWAIT C2 */ ++ driver_data = 0x10; ++ break; ++ case 3: /* MWAIT C3 */ ++ driver_data = 0x20; ++ break; ++ case 4: /* MWAIT C4 */ ++ driver_data = 0x30; ++ break; ++ case 5: /* MWAIT C5 */ ++ driver_data = 0x40; ++ break; ++ case 6: /* MWAIT C6 */ ++ driver_data = 0x52; ++ break; ++ default: ++ driver_data = 0x00; ++ } ++ return driver_data; ++} ++ + /** + * intel_idle + * @dev: cpuidle_device +@@ -216,7 +234,8 @@ static int intel_idle(struct cpuidle_device *dev, int index) + { + unsigned long ecx = 1; /* break on interrupt flag */ + struct cpuidle_state *state = &dev->states[index]; +- unsigned long eax = (unsigned long)cpuidle_get_statedata(state); ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; ++ unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); + unsigned int cstate; + ktime_t kt_before, kt_after; + s64 usec_delta; +@@ -452,6 +471,9 @@ static int intel_idle_cpuidle_devices_init(void) + dev->states[dev->state_count] = /* structure copy */ + cpuidle_state_table[cstate]; + ++ dev->states_usage[dev->state_count].driver_data = ++ (void *)get_driver_data(cstate); ++ + dev->state_count += 1; + } + +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index c6d85cf..0156540 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -28,19 +28,22 @@ struct cpuidle_device; + * CPUIDLE DEVICE INTERFACE * + ****************************/ + ++struct cpuidle_state_usage { ++ void *driver_data; ++ ++ unsigned long long usage; ++ unsigned long long time; /* in US */ ++}; ++ + struct cpuidle_state { + char name[CPUIDLE_NAME_LEN]; + char desc[CPUIDLE_DESC_LEN]; +- void *driver_data; + + unsigned int flags; + unsigned int exit_latency; /* in US */ + unsigned int power_usage; /* in mW */ + unsigned int target_residency; /* in US */ + +- unsigned long long usage; +- unsigned long long time; /* in US */ +- + int (*enter) (struct cpuidle_device *dev, + int index); + }; +@@ -52,26 +55,27 @@ struct cpuidle_state { + + /** + * cpuidle_get_statedata - retrieves private driver state data +- * @state: the state ++ * @st_usage: the state usage statistics + */ +-static inline void * cpuidle_get_statedata(struct cpuidle_state *state) ++static inline void *cpuidle_get_statedata(struct cpuidle_state_usage *st_usage) + { +- return state->driver_data; ++ return st_usage->driver_data; + } + + /** + * cpuidle_set_statedata - stores private driver state data +- * @state: the state ++ * @st_usage: the state usage statistics + * @data: the private data + */ + static inline void +-cpuidle_set_statedata(struct cpuidle_state *state, void *data) ++cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data) + { +- state->driver_data = data; ++ st_usage->driver_data = data; + } + + struct cpuidle_state_kobj { + struct cpuidle_state *state; ++ struct cpuidle_state_usage *state_usage; + struct completion kobj_unregister; + struct kobject kobj; + }; +@@ -85,6 +89,7 @@ struct cpuidle_device { + int last_residency; + int state_count; + struct cpuidle_state states[CPUIDLE_STATE_MAX]; ++ struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; + struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; + + struct list_head device_list; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0045-cpuidle-Single-Global-registration-of-idle-states.patch b/patches.kzm9g/0045-cpuidle-Single-Global-registration-of-idle-states.patch new file mode 100644 index 00000000000000..b6aa221bd0d115 --- /dev/null +++ b/patches.kzm9g/0045-cpuidle-Single-Global-registration-of-idle-states.patch @@ -0,0 +1,1520 @@ +From a50a3085d47712f6a11024570ffc8bf6b90fb126 Mon Sep 17 00:00:00 2001 +From: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Date: Fri, 28 Oct 2011 16:20:42 +0530 +Subject: cpuidle: Single/Global registration of idle states + +This patch makes the cpuidle_states structure global (single copy) +instead of per-cpu. The statistics needed on per-cpu basis +by the governor are kept per-cpu. This simplifies the cpuidle +subsystem as state registration is done by single cpu only. +Having single copy of cpuidle_states saves memory. Rare case +of asymmetric C-states can be handled within the cpuidle driver +and architectures such as POWER do not have asymmetric C-states. + +Having single/global registration of all the idle states, +dynamic C-state transitions on x86 are handled by +the boot cpu. Here, the boot cpu would disable all the devices, +re-populate the states and later enable all the devices, +irrespective of the cpu that would receive the notification first. + +Reference: +https://lkml.org/lkml/2011/4/25/83 + +Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> +Tested-by: Jean Pihet <j-pihet@ti.com> +Reviewed-by: Kevin Hilman <khilman@ti.com> +Acked-by: Arjan van de Ven <arjan@linux.intel.com> +Acked-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit 46bcfad7a819bd17ac4e831b04405152d59784ab) + +Conflicts: + + drivers/idle/intel_idle.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-at91/cpuidle.c | 31 +++--- + arch/arm/mach-davinci/cpuidle.c | 39 +++---- + arch/arm/mach-exynos4/cpuidle.c | 23 ++-- + arch/arm/mach-kirkwood/cpuidle.c | 30 +++--- + arch/arm/mach-omap2/cpuidle34xx.c | 73 ++++++++----- + arch/sh/kernel/cpu/shmobile/cpuidle.c | 18 ++-- + drivers/acpi/processor_driver.c | 20 +--- + drivers/acpi/processor_idle.c | 191 ++++++++++++++++++++++++++++----- + drivers/cpuidle/cpuidle.c | 45 +++----- + drivers/cpuidle/driver.c | 25 +++++ + drivers/cpuidle/governors/ladder.c | 28 +++-- + drivers/cpuidle/governors/menu.c | 20 ++-- + drivers/cpuidle/sysfs.c | 3 +- + drivers/idle/intel_idle.c | 80 ++++++++++---- + include/acpi/processor.h | 1 + + include/linux/cpuidle.h | 19 ++-- + 16 files changed, 439 insertions(+), 207 deletions(-) + +diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c +index d76a600..a851e6c 100644 +--- a/arch/arm/mach-at91/cpuidle.c ++++ b/arch/arm/mach-at91/cpuidle.c +@@ -34,6 +34,7 @@ static struct cpuidle_driver at91_idle_driver = { + + /* Actual code that puts the SoC in different idle states */ + static int at91_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct timeval before, after; +@@ -65,27 +66,29 @@ static int at91_enter_idle(struct cpuidle_device *dev, + static int at91_init_cpuidle(void) + { + struct cpuidle_device *device; +- +- cpuidle_register_driver(&at91_idle_driver); ++ struct cpuidle_driver *driver = &at91_idle_driver; + + device = &per_cpu(at91_cpuidle_device, smp_processor_id()); + device->state_count = AT91_MAX_STATES; ++ driver->state_count = AT91_MAX_STATES; + + /* Wait for interrupt state */ +- device->states[0].enter = at91_enter_idle; +- device->states[0].exit_latency = 1; +- device->states[0].target_residency = 10000; +- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[0].name, "WFI"); +- strcpy(device->states[0].desc, "Wait for interrupt"); ++ driver->states[0].enter = at91_enter_idle; ++ driver->states[0].exit_latency = 1; ++ driver->states[0].target_residency = 10000; ++ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[0].name, "WFI"); ++ strcpy(driver->states[0].desc, "Wait for interrupt"); + + /* Wait for interrupt and RAM self refresh state */ +- device->states[1].enter = at91_enter_idle; +- device->states[1].exit_latency = 10; +- device->states[1].target_residency = 10000; +- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[1].name, "RAM_SR"); +- strcpy(device->states[1].desc, "WFI and RAM Self Refresh"); ++ driver->states[1].enter = at91_enter_idle; ++ driver->states[1].exit_latency = 10; ++ driver->states[1].target_residency = 10000; ++ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[1].name, "RAM_SR"); ++ strcpy(driver->states[1].desc, "WFI and RAM Self Refresh"); ++ ++ cpuidle_register_driver(&at91_idle_driver); + + if (cpuidle_register_device(device)) { + printk(KERN_ERR "at91_init_cpuidle: Failed registering\n"); +diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c +index dda6d2f..ed7fb95 100644 +--- a/arch/arm/mach-davinci/cpuidle.c ++++ b/arch/arm/mach-davinci/cpuidle.c +@@ -79,6 +79,7 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { + + /* Actual code that puts the SoC in different idle states */ + static int davinci_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; +@@ -110,6 +111,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) + { + int ret; + struct cpuidle_device *device; ++ struct cpuidle_driver *driver = &davinci_idle_driver; + struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; + + device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); +@@ -121,32 +123,33 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) + + ddr2_reg_base = pdata->ddr2_ctlr_base; + +- ret = cpuidle_register_driver(&davinci_idle_driver); +- if (ret) { +- dev_err(&pdev->dev, "failed to register driver\n"); +- return ret; +- } +- + /* Wait for interrupt state */ +- device->states[0].enter = davinci_enter_idle; +- device->states[0].exit_latency = 1; +- device->states[0].target_residency = 10000; +- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[0].name, "WFI"); +- strcpy(device->states[0].desc, "Wait for interrupt"); ++ driver->states[0].enter = davinci_enter_idle; ++ driver->states[0].exit_latency = 1; ++ driver->states[0].target_residency = 10000; ++ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[0].name, "WFI"); ++ strcpy(driver->states[0].desc, "Wait for interrupt"); + + /* Wait for interrupt and DDR self refresh state */ +- device->states[1].enter = davinci_enter_idle; +- device->states[1].exit_latency = 10; +- device->states[1].target_residency = 10000; +- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[1].name, "DDR SR"); +- strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); ++ driver->states[1].enter = davinci_enter_idle; ++ driver->states[1].exit_latency = 10; ++ driver->states[1].target_residency = 10000; ++ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[1].name, "DDR SR"); ++ strcpy(driver->states[1].desc, "WFI and DDR Self Refresh"); + if (pdata->ddr2_pdown) + davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; + cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]); + + device->state_count = DAVINCI_CPUIDLE_MAX_STATES; ++ driver->state_count = DAVINCI_CPUIDLE_MAX_STATES; ++ ++ ret = cpuidle_register_driver(&davinci_idle_driver); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register driver\n"); ++ return ret; ++ } + + ret = cpuidle_register_device(device); + if (ret) { +diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c +index ea026e7..35f6502 100644 +--- a/arch/arm/mach-exynos4/cpuidle.c ++++ b/arch/arm/mach-exynos4/cpuidle.c +@@ -16,6 +16,7 @@ + #include <asm/proc-fns.h> + + static int exynos4_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index); + + static struct cpuidle_state exynos4_cpuidle_set[] = { +@@ -37,6 +38,7 @@ static struct cpuidle_driver exynos4_idle_driver = { + }; + + static int exynos4_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct timeval before, after; +@@ -60,22 +62,23 @@ static int __init exynos4_init_cpuidle(void) + { + int i, max_cpuidle_state, cpu_id; + struct cpuidle_device *device; +- ++ struct cpuidle_driver *drv = &exynos4_idle_driver; ++ ++ /* Setup cpuidle driver */ ++ drv->state_count = (sizeof(exynos4_cpuidle_set) / ++ sizeof(struct cpuidle_state)); ++ max_cpuidle_state = drv->state_count; ++ for (i = 0; i < max_cpuidle_state; i++) { ++ memcpy(&drv->states[i], &exynos4_cpuidle_set[i], ++ sizeof(struct cpuidle_state)); ++ } + cpuidle_register_driver(&exynos4_idle_driver); + + for_each_cpu(cpu_id, cpu_online_mask) { + device = &per_cpu(exynos4_cpuidle_device, cpu_id); + device->cpu = cpu_id; + +- device->state_count = (sizeof(exynos4_cpuidle_set) / +- sizeof(struct cpuidle_state)); +- +- max_cpuidle_state = device->state_count; +- +- for (i = 0; i < max_cpuidle_state; i++) { +- memcpy(&device->states[i], &exynos4_cpuidle_set[i], +- sizeof(struct cpuidle_state)); +- } ++ device->state_count = drv->state_count; + + if (cpuidle_register_device(device)) { + printk(KERN_ERR "CPUidle register device failed\n,"); +diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c +index 53d6049..7088180 100644 +--- a/arch/arm/mach-kirkwood/cpuidle.c ++++ b/arch/arm/mach-kirkwood/cpuidle.c +@@ -33,6 +33,7 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); + + /* Actual code that puts the SoC in different idle states */ + static int kirkwood_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct timeval before, after; +@@ -69,28 +70,29 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, + static int kirkwood_init_cpuidle(void) + { + struct cpuidle_device *device; +- +- cpuidle_register_driver(&kirkwood_idle_driver); ++ struct cpuidle_driver *driver = &kirkwood_idle_driver; + + device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); + device->state_count = KIRKWOOD_MAX_STATES; ++ driver->state_count = KIRKWOOD_MAX_STATES; + + /* Wait for interrupt state */ +- device->states[0].enter = kirkwood_enter_idle; +- device->states[0].exit_latency = 1; +- device->states[0].target_residency = 10000; +- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[0].name, "WFI"); +- strcpy(device->states[0].desc, "Wait for interrupt"); ++ driver->states[0].enter = kirkwood_enter_idle; ++ driver->states[0].exit_latency = 1; ++ driver->states[0].target_residency = 10000; ++ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[0].name, "WFI"); ++ strcpy(driver->states[0].desc, "Wait for interrupt"); + + /* Wait for interrupt and DDR self refresh state */ +- device->states[1].enter = kirkwood_enter_idle; +- device->states[1].exit_latency = 10; +- device->states[1].target_residency = 10000; +- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; +- strcpy(device->states[1].name, "DDR SR"); +- strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); ++ driver->states[1].enter = kirkwood_enter_idle; ++ driver->states[1].exit_latency = 10; ++ driver->states[1].target_residency = 10000; ++ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; ++ strcpy(driver->states[1].name, "DDR SR"); ++ strcpy(driver->states[1].desc, "WFI and DDR Self Refresh"); + ++ cpuidle_register_driver(&kirkwood_idle_driver); + if (cpuidle_register_device(device)) { + printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n"); + return -EIO; +diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c +index d3fce7b..1fe35c2 100644 +--- a/arch/arm/mach-omap2/cpuidle34xx.c ++++ b/arch/arm/mach-omap2/cpuidle34xx.c +@@ -88,12 +88,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, + /** + * omap3_enter_idle - Programs OMAP3 to enter the specified state + * @dev: cpuidle device ++ * @drv: cpuidle driver + * @index: the index of state to be entered + * + * Called from the CPUidle framework to program the device to the + * specified target state selected by the governor. + */ + static int omap3_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct omap3_idle_statedata *cx = +@@ -148,6 +150,7 @@ return_sleep_time: + /** + * next_valid_state - Find next valid C-state + * @dev: cpuidle device ++ * @drv: cpuidle driver + * @index: Index of currently selected c-state + * + * If the state corresponding to index is valid, index is returned back +@@ -158,10 +161,11 @@ return_sleep_time: + * if it satisfies the enable_off_mode condition. + */ + static int next_valid_state(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + struct cpuidle_state_usage *curr_usage = &dev->states_usage[index]; +- struct cpuidle_state *curr = &dev->states[index]; ++ struct cpuidle_state *curr = &drv->states[index]; + struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage); + u32 mpu_deepest_state = PWRDM_POWER_RET; + u32 core_deepest_state = PWRDM_POWER_RET; +@@ -188,7 +192,7 @@ static int next_valid_state(struct cpuidle_device *dev, + + /* Reach the current state starting at highest C-state */ + for (; idx >= 0; idx--) { +- if (&dev->states[idx] == curr) { ++ if (&drv->states[idx] == curr) { + next_index = idx; + break; + } +@@ -224,12 +228,14 @@ static int next_valid_state(struct cpuidle_device *dev, + /** + * omap3_enter_idle_bm - Checks for any bus activity + * @dev: cpuidle device ++ * @drv: cpuidle driver + * @index: array index of target state to be programmed + * + * This function checks for any pending activity and then programs + * the device to the specified or a safer state. + */ + static int omap3_enter_idle_bm(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + int new_state_idx; +@@ -238,7 +244,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + int ret; + + if (!omap3_can_sleep()) { +- new_state_idx = dev->safe_state_index; ++ new_state_idx = drv->safe_state_index; + goto select_state; + } + +@@ -248,7 +254,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + */ + cam_state = pwrdm_read_pwrst(cam_pd); + if (cam_state == PWRDM_POWER_ON) { +- new_state_idx = dev->safe_state_index; ++ new_state_idx = drv->safe_state_index; + goto select_state; + } + +@@ -275,10 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + if (per_next_state != per_saved_state) + pwrdm_set_next_pwrst(per_pd, per_next_state); + +- new_state_idx = next_valid_state(dev, index); ++ new_state_idx = next_valid_state(dev, drv, index); + + select_state: +- ret = omap3_enter_idle(dev, new_state_idx); ++ ret = omap3_enter_idle(dev, drv, new_state_idx); + + /* Restore original PER state if it was modified */ + if (per_next_state != per_saved_state) +@@ -311,22 +317,30 @@ struct cpuidle_driver omap3_idle_driver = { + .owner = THIS_MODULE, + }; + +-/* Helper to fill the C-state common data and register the driver_data */ +-static inline struct omap3_idle_statedata *_fill_cstate( +- struct cpuidle_device *dev, ++/* Helper to fill the C-state common data*/ ++static inline void _fill_cstate(struct cpuidle_driver *drv, + int idx, const char *descr) + { +- struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; +- struct cpuidle_state *state = &dev->states[idx]; +- struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; ++ struct cpuidle_state *state = &drv->states[idx]; + + state->exit_latency = cpuidle_params_table[idx].exit_latency; + state->target_residency = cpuidle_params_table[idx].target_residency; + state->flags = CPUIDLE_FLAG_TIME_VALID; + state->enter = omap3_enter_idle_bm; +- cx->valid = cpuidle_params_table[idx].valid; + sprintf(state->name, "C%d", idx + 1); + strncpy(state->desc, descr, CPUIDLE_DESC_LEN); ++ ++} ++ ++/* Helper to register the driver_data */ ++static inline struct omap3_idle_statedata *_fill_cstate_usage( ++ struct cpuidle_device *dev, ++ int idx) ++{ ++ struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; ++ struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; ++ ++ cx->valid = cpuidle_params_table[idx].valid; + cpuidle_set_statedata(state_usage, cx); + + return cx; +@@ -341,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( + int __init omap3_idle_init(void) + { + struct cpuidle_device *dev; ++ struct cpuidle_driver *drv = &omap3_idle_driver; + struct omap3_idle_statedata *cx; + + mpu_pd = pwrdm_lookup("mpu_pwrdm"); +@@ -348,45 +363,52 @@ int __init omap3_idle_init(void) + per_pd = pwrdm_lookup("per_pwrdm"); + cam_pd = pwrdm_lookup("cam_pwrdm"); + +- cpuidle_register_driver(&omap3_idle_driver); ++ ++ drv->safe_state_index = -1; + dev = &per_cpu(omap3_idle_dev, smp_processor_id()); +- dev->safe_state_index = -1; + + /* C1 . MPU WFI + Core active */ +- cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); +- (&dev->states[0])->enter = omap3_enter_idle; +- dev->safe_state_index = 0; ++ _fill_cstate(drv, 0, "MPU ON + CORE ON"); ++ (&drv->states[0])->enter = omap3_enter_idle; ++ drv->safe_state_index = 0; ++ cx = _fill_cstate_usage(dev, 0); + cx->valid = 1; /* C1 is always valid */ + cx->mpu_state = PWRDM_POWER_ON; + cx->core_state = PWRDM_POWER_ON; + + /* C2 . MPU WFI + Core inactive */ +- cx = _fill_cstate(dev, 1, "MPU ON + CORE ON"); ++ _fill_cstate(drv, 1, "MPU ON + CORE ON"); ++ cx = _fill_cstate_usage(dev, 1); + cx->mpu_state = PWRDM_POWER_ON; + cx->core_state = PWRDM_POWER_ON; + + /* C3 . MPU CSWR + Core inactive */ +- cx = _fill_cstate(dev, 2, "MPU RET + CORE ON"); ++ _fill_cstate(drv, 2, "MPU RET + CORE ON"); ++ cx = _fill_cstate_usage(dev, 2); + cx->mpu_state = PWRDM_POWER_RET; + cx->core_state = PWRDM_POWER_ON; + + /* C4 . MPU OFF + Core inactive */ +- cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON"); ++ _fill_cstate(drv, 3, "MPU OFF + CORE ON"); ++ cx = _fill_cstate_usage(dev, 3); + cx->mpu_state = PWRDM_POWER_OFF; + cx->core_state = PWRDM_POWER_ON; + + /* C5 . MPU RET + Core RET */ +- cx = _fill_cstate(dev, 4, "MPU RET + CORE RET"); ++ _fill_cstate(drv, 4, "MPU RET + CORE RET"); ++ cx = _fill_cstate_usage(dev, 4); + cx->mpu_state = PWRDM_POWER_RET; + cx->core_state = PWRDM_POWER_RET; + + /* C6 . MPU OFF + Core RET */ +- cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET"); ++ _fill_cstate(drv, 5, "MPU OFF + CORE RET"); ++ cx = _fill_cstate_usage(dev, 5); + cx->mpu_state = PWRDM_POWER_OFF; + cx->core_state = PWRDM_POWER_RET; + + /* C7 . MPU OFF + Core OFF */ +- cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF"); ++ _fill_cstate(drv, 6, "MPU OFF + CORE OFF"); ++ cx = _fill_cstate_usage(dev, 6); + /* + * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot + * enable OFF mode in a stable form for previous revisions. +@@ -400,6 +422,9 @@ int __init omap3_idle_init(void) + cx->mpu_state = PWRDM_POWER_OFF; + cx->core_state = PWRDM_POWER_OFF; + ++ drv->state_count = OMAP3_NUM_STATES; ++ cpuidle_register_driver(&omap3_idle_driver); ++ + dev->state_count = OMAP3_NUM_STATES; + if (cpuidle_register_device(dev)) { + printk(KERN_ERR "%s: CPUidle register device failed\n", +diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c +index 7be50d4c..ad1012a 100644 +--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c ++++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c +@@ -25,6 +25,7 @@ static unsigned long cpuidle_mode[] = { + }; + + static int cpuidle_sleep_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index) + { + unsigned long allowed_mode = arch_hwblk_sleep_mode(); +@@ -64,19 +65,19 @@ static struct cpuidle_driver cpuidle_driver = { + void sh_mobile_setup_cpuidle(void) + { + struct cpuidle_device *dev = &cpuidle_dev; ++ struct cpuidle_driver *drv = &cpuidle_driver; + struct cpuidle_state *state; + int i; + +- cpuidle_register_driver(&cpuidle_driver); + + for (i = 0; i < CPUIDLE_STATE_MAX; i++) { +- dev->states[i].name[0] = '\0'; +- dev->states[i].desc[0] = '\0'; ++ drv->states[i].name[0] = '\0'; ++ drv->states[i].desc[0] = '\0'; + } + + i = CPUIDLE_DRIVER_STATE_START; + +- state = &dev->states[i++]; ++ state = &drv->states[i++]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); + strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); + state->exit_latency = 1; +@@ -86,10 +87,10 @@ void sh_mobile_setup_cpuidle(void) + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = cpuidle_sleep_enter; + +- dev->safe_state_index = i-1; ++ drv->safe_state_index = i-1; + + if (sh_mobile_sleep_supported & SUSP_SH_SF) { +- state = &dev->states[i++]; ++ state = &drv->states[i++]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); + strncpy(state->desc, "SuperH Sleep Mode [SF]", + CPUIDLE_DESC_LEN); +@@ -102,7 +103,7 @@ void sh_mobile_setup_cpuidle(void) + } + + if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { +- state = &dev->states[i++]; ++ state = &drv->states[i++]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C3"); + strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", + CPUIDLE_DESC_LEN); +@@ -114,7 +115,10 @@ void sh_mobile_setup_cpuidle(void) + state->enter = cpuidle_sleep_enter; + } + ++ drv->state_count = i; + dev->state_count = i; + ++ cpuidle_register_driver(&cpuidle_driver); ++ + cpuidle_register_device(dev); + } +diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c +index a4e0f1b..9d7bc9f 100644 +--- a/drivers/acpi/processor_driver.c ++++ b/drivers/acpi/processor_driver.c +@@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, + + if (action == CPU_ONLINE && pr) { + acpi_processor_ppc_has_changed(pr, 0); +- acpi_processor_cst_has_changed(pr); ++ acpi_processor_hotplug(pr); + acpi_processor_reevaluate_tstate(pr, action); + acpi_processor_tstate_has_changed(pr); + } +@@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) + acpi_processor_get_throttling_info(pr); + acpi_processor_get_limit_info(pr); + +- +- if (cpuidle_get_driver() == &acpi_idle_driver) ++ if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr, device); + + pr->cdev = thermal_cooling_device_register("Processor", device, +@@ -800,17 +799,9 @@ static int __init acpi_processor_init(void) + + memset(&errata, 0, sizeof(errata)); + +- if (!cpuidle_register_driver(&acpi_idle_driver)) { +- printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", +- acpi_idle_driver.name); +- } else { +- printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n", +- cpuidle_get_driver()->name); +- } +- + result = acpi_bus_register_driver(&acpi_processor_driver); + if (result < 0) +- goto out_cpuidle; ++ return result; + + acpi_processor_install_hotplug_notify(); + +@@ -821,11 +812,6 @@ static int __init acpi_processor_init(void) + acpi_processor_throttling_init(); + + return 0; +- +-out_cpuidle: +- cpuidle_unregister_driver(&acpi_idle_driver); +- +- return result; + } + + static void __exit acpi_processor_exit(void) +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index c7b89f0..da70c26 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -741,11 +741,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) + /** + * acpi_idle_enter_c1 - enters an ACPI C1 state-type + * @dev: the target CPU ++ * @drv: cpuidle driver containing cpuidle state info + * @index: index of target state + * + * This is equivalent to the HALT instruction. + */ +-static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) ++static int acpi_idle_enter_c1(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { + ktime_t kt1, kt2; + s64 idle_time; +@@ -787,9 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) + /** + * acpi_idle_enter_simple - enters an ACPI state without BM handling + * @dev: the target CPU ++ * @drv: cpuidle driver with cpuidle state information + * @index: the index of suggested state + */ +-static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index) ++static int acpi_idle_enter_simple(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { + struct acpi_processor *pr; + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; +@@ -869,11 +873,13 @@ static DEFINE_SPINLOCK(c3_lock); + /** + * acpi_idle_enter_bm - enters C3 with proper BM handling + * @dev: the target CPU ++ * @drv: cpuidle driver containing state data + * @index: the index of suggested state + * + * If BM is detected, the deepest non-C3 idle state is entered instead. + */ +-static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) ++static int acpi_idle_enter_bm(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { + struct acpi_processor *pr; + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; +@@ -896,9 +902,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) + } + + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { +- if (dev->safe_state_index >= 0) { +- return dev->states[dev->safe_state_index].enter(dev, +- dev->safe_state_index); ++ if (drv->safe_state_index >= 0) { ++ return drv->states[drv->safe_state_index].enter(dev, ++ drv, drv->safe_state_index); + } else { + local_irq_disable(); + acpi_safe_halt(); +@@ -993,14 +999,15 @@ struct cpuidle_driver acpi_idle_driver = { + }; + + /** +- * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE ++ * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE ++ * device i.e. per-cpu data ++ * + * @pr: the ACPI processor + */ +-static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) ++static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) + { + int i, count = CPUIDLE_DRIVER_STATE_START; + struct acpi_processor_cx *cx; +- struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; + struct cpuidle_device *dev = &pr->power.dev; + +@@ -1012,18 +1019,12 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + } + + dev->cpu = pr->id; +- dev->safe_state_index = -1; +- for (i = 0; i < CPUIDLE_STATE_MAX; i++) { +- dev->states[i].name[0] = '\0'; +- dev->states[i].desc[0] = '\0'; +- } + + if (max_cstate == 0) + max_cstate = 1; + + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; +- state = &dev->states[count]; + state_usage = &dev->states_usage[count]; + + if (!cx->valid) +@@ -1035,8 +1036,64 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; + #endif ++ + cpuidle_set_statedata(state_usage, cx); + ++ count++; ++ if (count == CPUIDLE_STATE_MAX) ++ break; ++ } ++ ++ dev->state_count = count; ++ ++ if (!count) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/** ++ * acpi_processor_setup_cpuidle states- prepares and configures cpuidle ++ * global state data i.e. idle routines ++ * ++ * @pr: the ACPI processor ++ */ ++static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) ++{ ++ int i, count = CPUIDLE_DRIVER_STATE_START; ++ struct acpi_processor_cx *cx; ++ struct cpuidle_state *state; ++ struct cpuidle_driver *drv = &acpi_idle_driver; ++ ++ if (!pr->flags.power_setup_done) ++ return -EINVAL; ++ ++ if (pr->flags.power == 0) ++ return -EINVAL; ++ ++ drv->safe_state_index = -1; ++ for (i = 0; i < CPUIDLE_STATE_MAX; i++) { ++ drv->states[i].name[0] = '\0'; ++ drv->states[i].desc[0] = '\0'; ++ } ++ ++ if (max_cstate == 0) ++ max_cstate = 1; ++ ++ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { ++ cx = &pr->power.states[i]; ++ ++ if (!cx->valid) ++ continue; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && ++ !pr->flags.has_cst && ++ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) ++ continue; ++#endif ++ ++ state = &drv->states[count]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); + strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); + state->exit_latency = cx->latency; +@@ -1049,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + state->flags |= CPUIDLE_FLAG_TIME_VALID; + + state->enter = acpi_idle_enter_c1; +- dev->safe_state_index = count; ++ drv->safe_state_index = count; + break; + + case ACPI_STATE_C2: + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = acpi_idle_enter_simple; +- dev->safe_state_index = count; ++ drv->safe_state_index = count; + break; + + case ACPI_STATE_C3: +@@ -1071,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + break; + } + +- dev->state_count = count; ++ drv->state_count = count; + + if (!count) + return -EINVAL; +@@ -1079,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) + return 0; + } + +-int acpi_processor_cst_has_changed(struct acpi_processor *pr) ++int acpi_processor_hotplug(struct acpi_processor *pr) + { + int ret = 0; + +@@ -1100,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) + cpuidle_disable_device(&pr->power.dev); + acpi_processor_get_power_info(pr); + if (pr->flags.power) { +- acpi_processor_setup_cpuidle(pr); ++ acpi_processor_setup_cpuidle_cx(pr); + ret = cpuidle_enable_device(&pr->power.dev); + } + cpuidle_resume_and_unlock(); +@@ -1108,10 +1165,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) + return ret; + } + ++int acpi_processor_cst_has_changed(struct acpi_processor *pr) ++{ ++ int cpu; ++ struct acpi_processor *_pr; ++ ++ if (disabled_by_idle_boot_param()) ++ return 0; ++ ++ if (!pr) ++ return -EINVAL; ++ ++ if (nocst) ++ return -ENODEV; ++ ++ if (!pr->flags.power_setup_done) ++ return -ENODEV; ++ ++ /* ++ * FIXME: Design the ACPI notification to make it once per ++ * system instead of once per-cpu. This condition is a hack ++ * to make the code that updates C-States be called once. ++ */ ++ ++ if (smp_processor_id() == 0 && ++ cpuidle_get_driver() == &acpi_idle_driver) { ++ ++ cpuidle_pause_and_lock(); ++ /* Protect against cpu-hotplug */ ++ get_online_cpus(); ++ ++ /* Disable all cpuidle devices */ ++ for_each_online_cpu(cpu) { ++ _pr = per_cpu(processors, cpu); ++ if (!_pr || !_pr->flags.power_setup_done) ++ continue; ++ cpuidle_disable_device(&_pr->power.dev); ++ } ++ ++ /* Populate Updated C-state information */ ++ acpi_processor_setup_cpuidle_states(pr); ++ ++ /* Enable all cpuidle devices */ ++ for_each_online_cpu(cpu) { ++ _pr = per_cpu(processors, cpu); ++ if (!_pr || !_pr->flags.power_setup_done) ++ continue; ++ acpi_processor_get_power_info(_pr); ++ if (_pr->flags.power) { ++ acpi_processor_setup_cpuidle_cx(_pr); ++ cpuidle_enable_device(&_pr->power.dev); ++ } ++ } ++ put_online_cpus(); ++ cpuidle_resume_and_unlock(); ++ } ++ ++ return 0; ++} ++ ++static int acpi_processor_registered; ++ + int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, + struct acpi_device *device) + { + acpi_status status = 0; ++ int retval; + static int first_run; + + if (disabled_by_idle_boot_param()) +@@ -1148,9 +1267,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, + * platforms that only support C1. + */ + if (pr->flags.power) { +- acpi_processor_setup_cpuidle(pr); +- if (cpuidle_register_device(&pr->power.dev)) +- return -EIO; ++ /* Register acpi_idle_driver if not already registered */ ++ if (!acpi_processor_registered) { ++ acpi_processor_setup_cpuidle_states(pr); ++ retval = cpuidle_register_driver(&acpi_idle_driver); ++ if (retval) ++ return retval; ++ printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", ++ acpi_idle_driver.name); ++ } ++ /* Register per-cpu cpuidle_device. Cpuidle driver ++ * must already be registered before registering device ++ */ ++ acpi_processor_setup_cpuidle_cx(pr); ++ retval = cpuidle_register_device(&pr->power.dev); ++ if (retval) { ++ if (acpi_processor_registered == 0) ++ cpuidle_unregister_driver(&acpi_idle_driver); ++ return retval; ++ } ++ acpi_processor_registered++; + } + return 0; + } +@@ -1161,8 +1297,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr, + if (disabled_by_idle_boot_param()) + return 0; + +- cpuidle_unregister_device(&pr->power.dev); +- pr->flags.power_setup_done = 0; ++ if (pr->flags.power) { ++ cpuidle_unregister_device(&pr->power.dev); ++ acpi_processor_registered--; ++ if (acpi_processor_registered == 0) ++ cpuidle_unregister_driver(&acpi_idle_driver); ++ } + ++ pr->flags.power_setup_done = 0; + return 0; + } +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index 219a757..06ce268 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -62,6 +62,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); + int cpuidle_idle_call(void) + { + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); ++ struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_state *target_state; + int next_state, entered_state; + +@@ -85,18 +86,18 @@ int cpuidle_idle_call(void) + #endif + + /* ask the governor for the next state */ +- next_state = cpuidle_curr_governor->select(dev); ++ next_state = cpuidle_curr_governor->select(drv, dev); + if (need_resched()) { + local_irq_enable(); + return 0; + } + +- target_state = &dev->states[next_state]; ++ target_state = &drv->states[next_state]; + + trace_power_start(POWER_CSTATE, next_state, dev->cpu); + trace_cpu_idle(next_state, dev->cpu); + +- entered_state = target_state->enter(dev, next_state); ++ entered_state = target_state->enter(dev, drv, next_state); + + trace_power_end(dev->cpu); + trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); +@@ -164,7 +165,8 @@ void cpuidle_resume_and_unlock(void) + EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); + + #ifdef CONFIG_ARCH_HAS_CPU_RELAX +-static int poll_idle(struct cpuidle_device *dev, int index) ++static int poll_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { + ktime_t t1, t2; + s64 diff; +@@ -184,12 +186,9 @@ static int poll_idle(struct cpuidle_device *dev, int index) + return index; + } + +-static void poll_idle_init(struct cpuidle_device *dev) ++static void poll_idle_init(struct cpuidle_driver *drv) + { +- struct cpuidle_state *state = &dev->states[0]; +- struct cpuidle_state_usage *state_usage = &dev->states_usage[0]; +- +- cpuidle_set_statedata(state_usage, NULL); ++ struct cpuidle_state *state = &drv->states[0]; + + snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); + snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); +@@ -200,7 +199,7 @@ static void poll_idle_init(struct cpuidle_device *dev) + state->enter = poll_idle; + } + #else +-static void poll_idle_init(struct cpuidle_device *dev) {} ++static void poll_idle_init(struct cpuidle_driver *drv) {} + #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ + + /** +@@ -227,13 +226,13 @@ int cpuidle_enable_device(struct cpuidle_device *dev) + return ret; + } + +- poll_idle_init(dev); ++ poll_idle_init(cpuidle_get_driver()); + + if ((ret = cpuidle_add_state_sysfs(dev))) + return ret; + + if (cpuidle_curr_governor->enable && +- (ret = cpuidle_curr_governor->enable(dev))) ++ (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) + goto fail_sysfs; + + for (i = 0; i < dev->state_count; i++) { +@@ -274,7 +273,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev) + dev->enabled = 0; + + if (cpuidle_curr_governor->disable) +- cpuidle_curr_governor->disable(dev); ++ cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); + + cpuidle_remove_state_sysfs(dev); + enabled_devices--; +@@ -302,26 +301,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) + + init_completion(&dev->kobj_unregister); + +- /* +- * cpuidle driver should set the dev->power_specified bit +- * before registering the device if the driver provides +- * power_usage numbers. +- * +- * For those devices whose ->power_specified is not set, +- * we fill in power_usage with decreasing values as the +- * cpuidle code has an implicit assumption that state Cn +- * uses less power than C(n-1). +- * +- * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned +- * an power value of -1. So we use -2, -3, etc, for other +- * c-states. +- */ +- if (!dev->power_specified) { +- int i; +- for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) +- dev->states[i].power_usage = -1 - i; +- } +- + per_cpu(cpuidle_devices, dev->cpu) = dev; + list_add(&dev->device_list, &cpuidle_detected_devices); + if ((ret = cpuidle_add_sysfs(sys_dev))) { +diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c +index 3f7e3ce..284d7af 100644 +--- a/drivers/cpuidle/driver.c ++++ b/drivers/cpuidle/driver.c +@@ -17,6 +17,30 @@ + static struct cpuidle_driver *cpuidle_curr_driver; + DEFINE_SPINLOCK(cpuidle_driver_lock); + ++static void __cpuidle_register_driver(struct cpuidle_driver *drv) ++{ ++ int i; ++ /* ++ * cpuidle driver should set the drv->power_specified bit ++ * before registering if the driver provides ++ * power_usage numbers. ++ * ++ * If power_specified is not set, ++ * we fill in power_usage with decreasing values as the ++ * cpuidle code has an implicit assumption that state Cn ++ * uses less power than C(n-1). ++ * ++ * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned ++ * an power value of -1. So we use -2, -3, etc, for other ++ * c-states. ++ */ ++ if (!drv->power_specified) { ++ for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) ++ drv->states[i].power_usage = -1 - i; ++ } ++} ++ ++ + /** + * cpuidle_register_driver - registers a driver + * @drv: the driver +@@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) + spin_unlock(&cpuidle_driver_lock); + return -EBUSY; + } ++ __cpuidle_register_driver(drv); + cpuidle_curr_driver = drv; + spin_unlock(&cpuidle_driver_lock); + +diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c +index 78b06d2..261e57a 100644 +--- a/drivers/cpuidle/governors/ladder.c ++++ b/drivers/cpuidle/governors/ladder.c +@@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev, + + /** + * ladder_select_state - selects the next state to enter ++ * @drv: cpuidle driver + * @dev: the CPU + */ +-static int ladder_select_state(struct cpuidle_device *dev) ++static int ladder_select_state(struct cpuidle_driver *drv, ++ struct cpuidle_device *dev) + { + struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + struct ladder_device_state *last_state; +@@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev) + + last_state = &ldev->states[last_idx]; + +- if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) +- last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency; ++ if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) { ++ last_residency = cpuidle_get_last_residency(dev) - \ ++ drv->states[last_idx].exit_latency; ++ } + else + last_residency = last_state->threshold.promotion_time + 1; + + /* consider promotion */ +- if (last_idx < dev->state_count - 1 && ++ if (last_idx < drv->state_count - 1 && + last_residency > last_state->threshold.promotion_time && +- dev->states[last_idx + 1].exit_latency <= latency_req) { ++ drv->states[last_idx + 1].exit_latency <= latency_req) { + last_state->stats.promotion_count++; + last_state->stats.demotion_count = 0; + if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { +@@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev) + + /* consider demotion */ + if (last_idx > CPUIDLE_DRIVER_STATE_START && +- dev->states[last_idx].exit_latency > latency_req) { ++ drv->states[last_idx].exit_latency > latency_req) { + int i; + + for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { +- if (dev->states[i].exit_latency <= latency_req) ++ if (drv->states[i].exit_latency <= latency_req) + break; + } + ladder_do_selection(ldev, last_idx, i); +@@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev) + + /** + * ladder_enable_device - setup for the governor ++ * @drv: cpuidle driver + * @dev: the CPU + */ +-static int ladder_enable_device(struct cpuidle_device *dev) ++static int ladder_enable_device(struct cpuidle_driver *drv, ++ struct cpuidle_device *dev) + { + int i; + struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu); +@@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev) + + ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START; + +- for (i = 0; i < dev->state_count; i++) { +- state = &dev->states[i]; ++ for (i = 0; i < drv->state_count; i++) { ++ state = &drv->states[i]; + lstate = &ldev->states[i]; + + lstate->stats.promotion_count = 0; +@@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev) + lstate->threshold.promotion_count = PROMOTION_COUNT; + lstate->threshold.demotion_count = DEMOTION_COUNT; + +- if (i < dev->state_count - 1) ++ if (i < drv->state_count - 1) + lstate->threshold.promotion_time = state->exit_latency; + if (i > 0) + lstate->threshold.demotion_time = state->exit_latency; +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 2072aeb..ad09526 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -183,7 +183,7 @@ static inline int performance_multiplier(void) + + static DEFINE_PER_CPU(struct menu_device, menu_devices); + +-static void menu_update(struct cpuidle_device *dev); ++static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); + + /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ + static u64 div_round64(u64 dividend, u32 divisor) +@@ -229,9 +229,10 @@ static void detect_repeating_patterns(struct menu_device *data) + + /** + * menu_select - selects the next idle state to enter ++ * @drv: cpuidle driver containing state data + * @dev: the CPU + */ +-static int menu_select(struct cpuidle_device *dev) ++static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) + { + struct menu_device *data = &__get_cpu_var(menu_devices); + int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); +@@ -241,7 +242,7 @@ static int menu_select(struct cpuidle_device *dev) + struct timespec t; + + if (data->needs_update) { +- menu_update(dev); ++ menu_update(drv, dev); + data->needs_update = 0; + } + +@@ -286,8 +287,8 @@ static int menu_select(struct cpuidle_device *dev) + * Find the idle state with the lowest power while satisfying + * our constraints. + */ +- for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { +- struct cpuidle_state *s = &dev->states[i]; ++ for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { ++ struct cpuidle_state *s = &drv->states[i]; + + if (s->target_residency > data->predicted_us) + continue; +@@ -324,14 +325,15 @@ static void menu_reflect(struct cpuidle_device *dev, int index) + + /** + * menu_update - attempts to guess what happened after entry ++ * @drv: cpuidle driver containing state data + * @dev: the CPU + */ +-static void menu_update(struct cpuidle_device *dev) ++static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) + { + struct menu_device *data = &__get_cpu_var(menu_devices); + int last_idx = data->last_state_idx; + unsigned int last_idle_us = cpuidle_get_last_residency(dev); +- struct cpuidle_state *target = &dev->states[last_idx]; ++ struct cpuidle_state *target = &drv->states[last_idx]; + unsigned int measured_us; + u64 new_factor; + +@@ -385,9 +387,11 @@ static void menu_update(struct cpuidle_device *dev) + + /** + * menu_enable_device - scans a CPU's states and does setup ++ * @drv: cpuidle driver + * @dev: the CPU + */ +-static int menu_enable_device(struct cpuidle_device *dev) ++static int menu_enable_device(struct cpuidle_driver *drv, ++ struct cpuidle_device *dev) + { + struct menu_device *data = &per_cpu(menu_devices, dev->cpu); + +diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c +index 8a1ace1..1e756e1 100644 +--- a/drivers/cpuidle/sysfs.c ++++ b/drivers/cpuidle/sysfs.c +@@ -322,13 +322,14 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) + { + int i, ret = -ENOMEM; + struct cpuidle_state_kobj *kobj; ++ struct cpuidle_driver *drv = cpuidle_get_driver(); + + /* state statistics */ + for (i = 0; i < device->state_count; i++) { + kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); + if (!kobj) + goto error_state; +- kobj->state = &device->states[i]; ++ kobj->state = &drv->states[i]; + kobj->state_usage = &device->states_usage[i]; + init_completion(&kobj->kobj_unregister); + +diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c +index b0c63e9..1f122c6 100644 +--- a/drivers/idle/intel_idle.c ++++ b/drivers/idle/intel_idle.c +@@ -81,7 +81,8 @@ static unsigned int mwait_substates; + static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ + + static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; +-static int intel_idle(struct cpuidle_device *dev, int index); ++static int intel_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index); + + static struct cpuidle_state *cpuidle_state_table; + +@@ -227,13 +228,15 @@ static int get_driver_data(int cstate) + /** + * intel_idle + * @dev: cpuidle_device ++ * @drv: cpuidle driver + * @index: index of cpuidle state + * + */ +-static int intel_idle(struct cpuidle_device *dev, int index) ++static int intel_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { + unsigned long ecx = 1; /* break on interrupt flag */ +- struct cpuidle_state *state = &dev->states[index]; ++ struct cpuidle_state *state = &drv->states[index]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); + unsigned int cstate; +@@ -421,6 +424,60 @@ static void intel_idle_cpuidle_devices_uninit(void) + return; + } + /* ++ * intel_idle_cpuidle_driver_init() ++ * allocate, initialize cpuidle_states ++ */ ++static int intel_idle_cpuidle_driver_init(void) ++{ ++ int cstate; ++ struct cpuidle_driver *drv = &intel_idle_driver; ++ ++ drv->state_count = 1; ++ ++ for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { ++ int num_substates; ++ ++ if (cstate > max_cstate) { ++ printk(PREFIX "max_cstate %d reached\n", ++ max_cstate); ++ break; ++ } ++ ++ /* does the state exist in CPUID.MWAIT? */ ++ num_substates = (mwait_substates >> ((cstate) * 4)) ++ & MWAIT_SUBSTATE_MASK; ++ if (num_substates == 0) ++ continue; ++ /* is the state not enabled? */ ++ if (cpuidle_state_table[cstate].enter == NULL) { ++ /* does the driver not know about the state? */ ++ if (*cpuidle_state_table[cstate].name == '\0') ++ pr_debug(PREFIX "unaware of model 0x%x" ++ " MWAIT %d please" ++ " contact lenb@kernel.org", ++ boot_cpu_data.x86_model, cstate); ++ continue; ++ } ++ ++ if ((cstate > 2) && ++ !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) ++ mark_tsc_unstable("TSC halts in idle" ++ " states deeper than C2"); ++ ++ drv->states[drv->state_count] = /* structure copy */ ++ cpuidle_state_table[cstate]; ++ ++ drv->state_count += 1; ++ } ++ ++ if (auto_demotion_disable_flags) ++ smp_call_function(auto_demotion_disable, NULL, 1); ++ ++ return 0; ++} ++ ++ ++/* + * intel_idle_cpuidle_devices_init() + * allocate, initialize, register cpuidle_devices + */ +@@ -454,23 +511,9 @@ static int intel_idle_cpuidle_devices_init(void) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) { +- /* does the driver not know about the state? */ +- if (*cpuidle_state_table[cstate].name == '\0') +- pr_debug(PREFIX "unaware of model 0x%x" +- " MWAIT %d please" +- " contact lenb@kernel.org", +- boot_cpu_data.x86_model, cstate); + continue; + } + +- if ((cstate > 2) && +- !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) +- mark_tsc_unstable("TSC halts in idle" +- " states deeper than C2"); +- +- dev->states[dev->state_count] = /* structure copy */ +- cpuidle_state_table[cstate]; +- + dev->states_usage[dev->state_count].driver_data = + (void *)get_driver_data(cstate); + +@@ -485,8 +528,6 @@ static int intel_idle_cpuidle_devices_init(void) + return -EIO; + } + } +- if (auto_demotion_disable_flags) +- on_each_cpu(auto_demotion_disable, NULL, 1); + + return 0; + } +@@ -504,6 +545,7 @@ static int __init intel_idle_init(void) + if (retval) + return retval; + ++ intel_idle_cpuidle_driver_init(); + retval = cpuidle_register_driver(&intel_idle_driver); + if (retval) { + printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", +diff --git a/include/acpi/processor.h b/include/acpi/processor.h +index ba4928c..716e97b 100644 +--- a/include/acpi/processor.h ++++ b/include/acpi/processor.h +@@ -329,6 +329,7 @@ extern void acpi_processor_throttling_init(void); + int acpi_processor_power_init(struct acpi_processor *pr, + struct acpi_device *device); + int acpi_processor_cst_has_changed(struct acpi_processor *pr); ++int acpi_processor_hotplug(struct acpi_processor *pr); + int acpi_processor_power_exit(struct acpi_processor *pr, + struct acpi_device *device); + int acpi_processor_suspend(struct acpi_device * device, pm_message_t state); +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index 0156540..c904188 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -22,6 +22,7 @@ + #define CPUIDLE_DESC_LEN 32 + + struct cpuidle_device; ++struct cpuidle_driver; + + + /**************************** +@@ -45,6 +46,7 @@ struct cpuidle_state { + unsigned int target_residency; /* in US */ + + int (*enter) (struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, + int index); + }; + +@@ -83,12 +85,10 @@ struct cpuidle_state_kobj { + struct cpuidle_device { + unsigned int registered:1; + unsigned int enabled:1; +- unsigned int power_specified:1; + unsigned int cpu; + + int last_residency; + int state_count; +- struct cpuidle_state states[CPUIDLE_STATE_MAX]; + struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; + struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; + +@@ -96,7 +96,6 @@ struct cpuidle_device { + struct kobject kobj; + struct completion kobj_unregister; + void *governor_data; +- int safe_state_index; + }; + + DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); +@@ -120,6 +119,11 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev) + struct cpuidle_driver { + char name[CPUIDLE_NAME_LEN]; + struct module *owner; ++ ++ unsigned int power_specified:1; ++ struct cpuidle_state states[CPUIDLE_STATE_MAX]; ++ int state_count; ++ int safe_state_index; + }; + + #ifdef CONFIG_CPU_IDLE +@@ -166,10 +170,13 @@ struct cpuidle_governor { + struct list_head governor_list; + unsigned int rating; + +- int (*enable) (struct cpuidle_device *dev); +- void (*disable) (struct cpuidle_device *dev); ++ int (*enable) (struct cpuidle_driver *drv, ++ struct cpuidle_device *dev); ++ void (*disable) (struct cpuidle_driver *drv, ++ struct cpuidle_device *dev); + +- int (*select) (struct cpuidle_device *dev); ++ int (*select) (struct cpuidle_driver *drv, ++ struct cpuidle_device *dev); + void (*reflect) (struct cpuidle_device *dev, int index); + + struct module *owner; +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0046-cpuidle-Add-common-time-keeping-and-irq-enabling.patch b/patches.kzm9g/0046-cpuidle-Add-common-time-keeping-and-irq-enabling.patch new file mode 100644 index 00000000000000..6e6e73f5646766 --- /dev/null +++ b/patches.kzm9g/0046-cpuidle-Add-common-time-keeping-and-irq-enabling.patch @@ -0,0 +1,285 @@ +From 578cf9ddd7dd3eee538113c2824ddfe3ca0b9857 Mon Sep 17 00:00:00 2001 +From: Robert Lee <rob.lee@linaro.org> +Date: Tue, 20 Mar 2012 15:22:42 -0500 +Subject: cpuidle: Add common time keeping and irq enabling + +Make necessary changes to implement time keeping and irq enabling +in the core cpuidle code. This will allow the removal of these +functionalities from various platform cpuidle implementations whose +timekeeping and irq enabling follows the form in this common code. + +Signed-off-by: Robert Lee <rob.lee@linaro.org> +Tested-by: Jean Pihet <j-pihet@ti.com> +Tested-by: Amit Daniel <amit.kachhap@linaro.org> +Tested-by: Robert Lee <rob.lee@linaro.org> +Reviewed-by: Kevin Hilman <khilman@ti.com> +Reviewed-by: Daniel Lezcano <daniel.lezcano@linaro.org> +Reviewed-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> +Acked-by: Jean Pihet <j-pihet@ti.com> +Signed-off-by: Len Brown <len.brown@intel.com> +(cherry picked from commit e1689795a784a7c41ac4cf9032794986b095a133) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/include/asm/cpuidle.h | 29 ++++++++++++++++++ + arch/arm/kernel/Makefile | 2 +- + arch/arm/kernel/cpuidle.c | 21 +++++++++++++ + drivers/cpuidle/cpuidle.c | 66 +++++++++++++++++++++++++++++++++++----- + include/linux/cpuidle.h | 13 +++++++- + 5 files changed, 122 insertions(+), 9 deletions(-) + create mode 100644 arch/arm/include/asm/cpuidle.h + create mode 100644 arch/arm/kernel/cpuidle.c + +diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h +new file mode 100644 +index 0000000..2fca60a +--- /dev/null ++++ b/arch/arm/include/asm/cpuidle.h +@@ -0,0 +1,29 @@ ++#ifndef __ASM_ARM_CPUIDLE_H ++#define __ASM_ARM_CPUIDLE_H ++ ++#ifdef CONFIG_CPU_IDLE ++extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index); ++#else ++static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) { return -ENODEV; } ++#endif ++ ++/* Common ARM WFI state */ ++#define ARM_CPUIDLE_WFI_STATE_PWR(p) {\ ++ .enter = arm_cpuidle_simple_enter,\ ++ .exit_latency = 1,\ ++ .target_residency = 1,\ ++ .power_usage = p,\ ++ .flags = CPUIDLE_FLAG_TIME_VALID,\ ++ .name = "WFI",\ ++ .desc = "ARM WFI",\ ++} ++ ++/* ++ * in case power_specified == 1, give a default WFI power value needed ++ * by some governors ++ */ ++#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX) ++ ++#endif +diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile +index 816a481..086fe97 100644 +--- a/arch/arm/kernel/Makefile ++++ b/arch/arm/kernel/Makefile +@@ -21,7 +21,7 @@ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o + + obj-$(CONFIG_LEDS) += leds.o + obj-$(CONFIG_OC_ETM) += etm.o +- ++obj-$(CONFIG_CPU_IDLE) += cpuidle.o + obj-$(CONFIG_ISA_DMA_API) += dma.o + obj-$(CONFIG_ARCH_ACORN) += ecard.o + obj-$(CONFIG_FIQ) += fiq.o fiqasm.o +diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c +new file mode 100644 +index 0000000..89545f6 +--- /dev/null ++++ b/arch/arm/kernel/cpuidle.c +@@ -0,0 +1,21 @@ ++/* ++ * Copyright 2012 Linaro Ltd. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include <linux/cpuidle.h> ++#include <asm/proc-fns.h> ++ ++int arm_cpuidle_simple_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ cpu_do_idle(); ++ ++ return index; ++} +diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c +index 06ce268..3d3bd98 100644 +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {} + + static int __cpuidle_register_device(struct cpuidle_device *dev); + ++static inline int cpuidle_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ struct cpuidle_state *target_state = &drv->states[index]; ++ return target_state->enter(dev, drv, index); ++} ++ ++static inline int cpuidle_enter_tk(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter); ++} ++ ++typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index); ++ ++static cpuidle_enter_t cpuidle_enter_ops; ++ + /** + * cpuidle_idle_call - the main idle loop + * +@@ -63,7 +81,6 @@ int cpuidle_idle_call(void) + { + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_driver *drv = cpuidle_get_driver(); +- struct cpuidle_state *target_state; + int next_state, entered_state; + + if (off) +@@ -92,12 +109,10 @@ int cpuidle_idle_call(void) + return 0; + } + +- target_state = &drv->states[next_state]; +- + trace_power_start(POWER_CSTATE, next_state, dev->cpu); + trace_cpu_idle(next_state, dev->cpu); + +- entered_state = target_state->enter(dev, drv, next_state); ++ entered_state = cpuidle_enter_ops(dev, drv, next_state); + + trace_power_end(dev->cpu); + trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); +@@ -110,6 +125,8 @@ int cpuidle_idle_call(void) + dev->states_usage[entered_state].time += + (unsigned long long)dev->last_residency; + dev->states_usage[entered_state].usage++; ++ } else { ++ dev->last_residency = 0; + } + + /* give the governor an opportunity to reflect on the outcome */ +@@ -164,6 +181,37 @@ void cpuidle_resume_and_unlock(void) + + EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); + ++/** ++ * cpuidle_wrap_enter - performs timekeeping and irqen around enter function ++ * @dev: pointer to a valid cpuidle_device object ++ * @drv: pointer to a valid cpuidle_driver object ++ * @index: index of the target cpuidle state. ++ */ ++int cpuidle_wrap_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index, ++ int (*enter)(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index)) ++{ ++ ktime_t time_start, time_end; ++ s64 diff; ++ ++ time_start = ktime_get(); ++ ++ index = enter(dev, drv, index); ++ ++ time_end = ktime_get(); ++ ++ local_irq_enable(); ++ ++ diff = ktime_to_us(ktime_sub(time_end, time_start)); ++ if (diff > INT_MAX) ++ diff = INT_MAX; ++ ++ dev->last_residency = (int) diff; ++ ++ return index; ++} ++ + #ifdef CONFIG_ARCH_HAS_CPU_RELAX + static int poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +@@ -212,10 +260,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} + int cpuidle_enable_device(struct cpuidle_device *dev) + { + int ret, i; ++ struct cpuidle_driver *drv = cpuidle_get_driver(); + + if (dev->enabled) + return 0; +- if (!cpuidle_get_driver() || !cpuidle_curr_governor) ++ if (!drv || !cpuidle_curr_governor) + return -EIO; + if (!dev->state_count) + return -EINVAL; +@@ -226,13 +275,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev) + return ret; + } + +- poll_idle_init(cpuidle_get_driver()); ++ cpuidle_enter_ops = drv->en_core_tk_irqen ? ++ cpuidle_enter_tk : cpuidle_enter; ++ ++ poll_idle_init(drv); + + if ((ret = cpuidle_add_state_sysfs(dev))) + return ret; + + if (cpuidle_curr_governor->enable && +- (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) ++ (ret = cpuidle_curr_governor->enable(drv, dev))) + goto fail_sysfs; + + for (i = 0; i < dev->state_count; i++) { +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index c904188..fd11aa0 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -16,6 +16,7 @@ + #include <linux/module.h> + #include <linux/kobject.h> + #include <linux/completion.h> ++#include <linux/hrtimer.h> + + #define CPUIDLE_STATE_MAX 8 + #define CPUIDLE_NAME_LEN 16 +@@ -121,6 +122,8 @@ struct cpuidle_driver { + struct module *owner; + + unsigned int power_specified:1; ++ /* set to 1 to use the core cpuidle time keeping (for all states). */ ++ unsigned int en_core_tk_irqen:1; + struct cpuidle_state states[CPUIDLE_STATE_MAX]; + int state_count; + int safe_state_index; +@@ -140,7 +143,10 @@ extern void cpuidle_pause_and_lock(void); + extern void cpuidle_resume_and_unlock(void); + extern int cpuidle_enable_device(struct cpuidle_device *dev); + extern void cpuidle_disable_device(struct cpuidle_device *dev); +- ++extern int cpuidle_wrap_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index, ++ int (*enter)(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index)); + #else + static inline void disable_cpuidle(void) { } + static inline int cpuidle_idle_call(void) { return -ENODEV; } +@@ -158,6 +164,11 @@ static inline void cpuidle_resume_and_unlock(void) { } + static inline int cpuidle_enable_device(struct cpuidle_device *dev) + {return -ENODEV; } + static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } ++static inline int cpuidle_wrap_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index, ++ int (*enter)(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index)) ++{ return -ENODEV; } + + #endif + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0047-mm-add-vm_area_add_early.patch b/patches.kzm9g/0047-mm-add-vm_area_add_early.patch new file mode 100644 index 00000000000000..6e00e80e95e5ae --- /dev/null +++ b/patches.kzm9g/0047-mm-add-vm_area_add_early.patch @@ -0,0 +1,92 @@ +From faf323f0f552c0523cce81cf62b87a87b3eb0020 Mon Sep 17 00:00:00 2001 +From: Nicolas Pitre <nicolas.pitre@linaro.org> +Date: Thu, 25 Aug 2011 00:24:21 -0400 +Subject: mm: add vm_area_add_early() + +The existing vm_area_register_early() allows for early vmalloc space +allocation. However upcoming cleanups in the ARM architecture require +that some fixed locations in the vmalloc area be reserved also very early. + +The name "vm_area_register_early" would have been a good name for the +reservation part without the allocation. Since it is already in use with +different semantics, let's create vm_area_add_early() instead. + +Both vm_area_register_early() and vm_area_add_early() can be used together +meaning that the former is now implemented using the later where it is +ensured that no conflicting areas are added, but no attempt is made to +make the allocation scheme in vm_area_register_early() more sophisticated. +After all, you must know what you're doing when using those functions. + +Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> +Acked-by: Andrew Morton <akpm@linux-foundation.org> +Cc: linux-mm@kvack.org +(cherry picked from commit be9b7335e70696bee731c152429b1737e42fe163) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + include/linux/vmalloc.h | 1 + + mm/vmalloc.c | 29 +++++++++++++++++++++++++++-- + 2 files changed, 28 insertions(+), 2 deletions(-) + +diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h +index 687fb11..4115d6a 100644 +--- a/include/linux/vmalloc.h ++++ b/include/linux/vmalloc.h +@@ -131,6 +131,7 @@ extern long vwrite(char *buf, char *addr, unsigned long count); + */ + extern rwlock_t vmlist_lock; + extern struct vm_struct *vmlist; ++extern __init void vm_area_add_early(struct vm_struct *vm); + extern __init void vm_area_register_early(struct vm_struct *vm, size_t align); + + #ifdef CONFIG_SMP +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 43b44db..fb0d354 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -1132,6 +1132,32 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro + EXPORT_SYMBOL(vm_map_ram); + + /** ++ * vm_area_add_early - add vmap area early during boot ++ * @vm: vm_struct to add ++ * ++ * This function is used to add fixed kernel vm area to vmlist before ++ * vmalloc_init() is called. @vm->addr, @vm->size, and @vm->flags ++ * should contain proper values and the other fields should be zero. ++ * ++ * DO NOT USE THIS FUNCTION UNLESS YOU KNOW WHAT YOU'RE DOING. ++ */ ++void __init vm_area_add_early(struct vm_struct *vm) ++{ ++ struct vm_struct *tmp, **p; ++ ++ BUG_ON(vmap_initialized); ++ for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) { ++ if (tmp->addr >= vm->addr) { ++ BUG_ON(tmp->addr < vm->addr + vm->size); ++ break; ++ } else ++ BUG_ON(tmp->addr + tmp->size > vm->addr); ++ } ++ vm->next = *p; ++ *p = vm; ++} ++ ++/** + * vm_area_register_early - register vmap area early during boot + * @vm: vm_struct to register + * @align: requested alignment +@@ -1153,8 +1179,7 @@ void __init vm_area_register_early(struct vm_struct *vm, size_t align) + + vm->addr = (void *)addr; + +- vm->next = vmlist; +- vmlist = vm; ++ vm_area_add_early(vm); + } + + void __init vmalloc_init(void) +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0048-clockevents-Make-clockevents_config-a-global-symbol.patch b/patches.kzm9g/0048-clockevents-Make-clockevents_config-a-global-symbol.patch new file mode 100644 index 00000000000000..c276f9f29d3b24 --- /dev/null +++ b/patches.kzm9g/0048-clockevents-Make-clockevents_config-a-global-symbol.patch @@ -0,0 +1,46 @@ +From fff14be80697fd2ad8584769e60a24f97ba0a704 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 9 May 2012 23:39:34 +0900 +Subject: clockevents: Make clockevents_config() a global symbol + +Make clockevents_config() into a global symbol to allow it +to be used by compiled-in clockevent drivers. This is needed +by drivers that want to update the timer frequency after +registration time. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + include/linux/clockchips.h | 1 + + kernel/time/clockevents.c | 3 +-- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h +index d6733e2..91d1b67 100644 +--- a/include/linux/clockchips.h ++++ b/include/linux/clockchips.h +@@ -128,6 +128,7 @@ extern u64 clockevent_delta2ns(unsigned long latch, + struct clock_event_device *evt); + extern void clockevents_register_device(struct clock_event_device *dev); + ++extern void clockevents_config(struct clock_event_device *dev, u32 freq); + extern void clockevents_config_and_register(struct clock_event_device *dev, + u32 freq, unsigned long min_delta, + unsigned long max_delta); +diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c +index e4c699d..1029cbc 100644 +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -197,8 +197,7 @@ void clockevents_register_device(struct clock_event_device *dev) + } + EXPORT_SYMBOL_GPL(clockevents_register_device); + +-static void clockevents_config(struct clock_event_device *dev, +- u32 freq) ++void clockevents_config(struct clock_event_device *dev, u32 freq) + { + u64 sec; + +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0049-clocksource-em_sti-Emma-Mobile-STI-driver-V2.patch b/patches.kzm9g/0049-clocksource-em_sti-Emma-Mobile-STI-driver-V2.patch new file mode 100644 index 00000000000000..826ec8002d1011 --- /dev/null +++ b/patches.kzm9g/0049-clocksource-em_sti-Emma-Mobile-STI-driver-V2.patch @@ -0,0 +1,484 @@ +From c97faaf620983062ebff15fd4db3f341a8e224b2 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 9 May 2012 23:39:42 +0900 +Subject: clocksource: em_sti: Emma Mobile STI driver V2 + +This is V2 of the Emma Mobile STI timer driver. + +The STI hardware is based on a single 48-bit 32kHz +counter that together with two individual compare +registers can generate interrupts. There are no +timer operating modes selectable which means that +the timer can not clear on match. + +This driver is providing clocksource support for the +48-bit counter. Clockevents are also supported using +the same timer in periodic or oneshot modes. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Simon Horman <horms@verge.net.au> + +Conflicts: + drivers/clocksource/Makefile +--- + arch/arm/mach-shmobile/Kconfig | 6 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/em_sti.c | 418 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 425 insertions(+) + create mode 100644 drivers/clocksource/em_sti.c + +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index 9020c1b..1e7656a 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -147,6 +147,12 @@ config SH_TIMER_TMU + help + This enables build of the TMU timer driver. + ++config EM_TIMER_STI ++ bool "STI timer driver" ++ default y ++ help ++ This enables build of the STI timer driver. ++ + endmenu + + config SH_CLK_CPG +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index b995942..59eb37d 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -6,5 +6,6 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o + obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o + obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o + obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o ++obj-$(CONFIG_EM_TIMER_STI) += em_sti.o + obj-$(CONFIG_CLKSRC_I8253) += i8253.o + obj-$(CONFIG_CLKSRC_MMIO) += mmio.o +diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c +new file mode 100644 +index 0000000..e8fc46d +--- /dev/null ++++ b/drivers/clocksource/em_sti.c +@@ -0,0 +1,418 @@ ++/* ++ * Emma Mobile Timer Support - STI ++ * ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/irq.h> ++#include <linux/err.h> ++#include <linux/delay.h> ++#include <linux/clocksource.h> ++#include <linux/clockchips.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++ ++enum { USER_CLOCKSOURCE, USER_CLOCKEVENT, USER_NR }; ++ ++struct em_sti_priv { ++ void __iomem *base; ++ struct clk *clk; ++ struct platform_device *pdev; ++ unsigned int active[USER_NR]; ++ unsigned long rate; ++ unsigned long delta; ++ cycle_t next; ++ spinlock_t lock; ++ struct clock_event_device ced; ++ struct clocksource cs; ++}; ++ ++#define STI_CONTROL 0x00 ++#define STI_COMPA_H 0x10 ++#define STI_COMPA_L 0x14 ++#define STI_COMPB_H 0x18 ++#define STI_COMPB_L 0x1c ++#define STI_COUNT_H 0x20 ++#define STI_COUNT_L 0x24 ++#define STI_COUNT_RAW_H 0x28 ++#define STI_COUNT_RAW_L 0x2c ++#define STI_SET_H 0x30 ++#define STI_SET_L 0x34 ++#define STI_INTSTATUS 0x40 ++#define STI_INTRAWSTATUS 0x44 ++#define STI_INTENSET 0x48 ++#define STI_INTENCLR 0x4c ++#define STI_INTFFCLR 0x50 ++ ++static inline unsigned long em_sti_read(struct em_sti_priv *p, int offs) ++{ ++ return ioread32(p->base + offs); ++} ++ ++static inline void em_sti_write(struct em_sti_priv *p, int offs, ++ unsigned long value) ++{ ++ iowrite32(value, p->base + offs); ++} ++ ++static int em_sti_enable(struct em_sti_priv *p) ++{ ++ int ret; ++ ++ /* enable clock */ ++ ret = clk_enable(p->clk); ++ if (ret) { ++ dev_err(&p->pdev->dev, "cannot enable clock\n"); ++ return ret; ++ } ++ ++ /* configure channel, periodic mode and maximum timeout */ ++ p->rate = clk_get_rate(p->clk); ++ ++ /* reset the counter */ ++ em_sti_write(p, STI_SET_H, 0x40000000); ++ em_sti_write(p, STI_SET_L, 0x00000000); ++ ++ /* mask and clear pending interrupts */ ++ em_sti_write(p, STI_INTENCLR, 3); ++ em_sti_write(p, STI_INTFFCLR, 3); ++ ++ /* enable updates of counter registers */ ++ em_sti_write(p, STI_CONTROL, 1); ++ ++ return 0; ++} ++ ++static void em_sti_disable(struct em_sti_priv *p) ++{ ++ /* mask interrupts */ ++ em_sti_write(p, STI_INTENCLR, 3); ++ ++ /* stop clock */ ++ clk_disable(p->clk); ++} ++ ++static cycle_t em_sti_count(struct em_sti_priv *p) ++{ ++ cycle_t ticks; ++ unsigned long flags; ++ ++ /* the STI hardware buffers the 48-bit count, but to ++ * break it out into two 32-bit access the registers ++ * must be accessed in a certain order. ++ * Always read STI_COUNT_H before STI_COUNT_L. ++ */ ++ spin_lock_irqsave(&p->lock, flags); ++ ticks = (cycle_t)(em_sti_read(p, STI_COUNT_H) & 0xffff) << 32; ++ ticks |= em_sti_read(p, STI_COUNT_L); ++ spin_unlock_irqrestore(&p->lock, flags); ++ ++ return ticks; ++} ++ ++static void em_sti_update(struct em_sti_priv *p) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p->lock, flags); ++ ++ /* update our cached counter */ ++ p->next += p->delta; ++ ++ /* mask compare A interrupt */ ++ em_sti_write(p, STI_INTENCLR, 1); ++ ++ /* update compare A value */ ++ em_sti_write(p, STI_COMPA_H, p->next >> 32); ++ em_sti_write(p, STI_COMPA_L, p->next & 0xffffffff); ++ ++ /* clear compare A interrupt source */ ++ em_sti_write(p, STI_INTFFCLR, 1); ++ ++ /* unmask compare A interrupt */ ++ em_sti_write(p, STI_INTENSET, 1); ++ ++ spin_unlock_irqrestore(&p->lock, flags); ++} ++ ++static irqreturn_t em_sti_interrupt(int irq, void *dev_id) ++{ ++ struct em_sti_priv *p = dev_id; ++ ++ /* Always regprogram timer compare A */ ++ if (p->ced.mode == CLOCK_EVT_MODE_PERIODIC) ++ em_sti_update(p); ++ ++ p->ced.event_handler(&p->ced); ++ return IRQ_HANDLED; ++} ++ ++static int em_sti_start(struct em_sti_priv *p, unsigned int user) ++{ ++ unsigned long flags; ++ int used_before; ++ int ret = 0; ++ ++ spin_lock_irqsave(&p->lock, flags); ++ used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; ++ if (!used_before) ++ ret = em_sti_enable(p); ++ ++ if (!ret) ++ p->active[user] = 1; ++ spin_unlock_irqrestore(&p->lock, flags); ++ ++ return ret; ++} ++ ++static void em_sti_stop(struct em_sti_priv *p, unsigned int user) ++{ ++ unsigned long flags; ++ int used_before, used_after; ++ ++ spin_lock_irqsave(&p->lock, flags); ++ used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; ++ p->active[user] = 0; ++ used_after = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; ++ ++ if (used_before && !used_after) ++ em_sti_disable(p); ++ spin_unlock_irqrestore(&p->lock, flags); ++} ++ ++static struct em_sti_priv *cs_to_em_sti(struct clocksource *cs) ++{ ++ return container_of(cs, struct em_sti_priv, cs); ++} ++ ++static cycle_t em_sti_clocksource_read(struct clocksource *cs) ++{ ++ return em_sti_count(cs_to_em_sti(cs)); ++} ++ ++static int em_sti_clocksource_enable(struct clocksource *cs) ++{ ++ int ret; ++ struct em_sti_priv *p = cs_to_em_sti(cs); ++ ++ ret = em_sti_start(p, USER_CLOCKSOURCE); ++ if (!ret) ++ __clocksource_updatefreq_hz(cs, p->rate); ++ return ret; ++} ++ ++static void em_sti_clocksource_disable(struct clocksource *cs) ++{ ++ em_sti_stop(cs_to_em_sti(cs), USER_CLOCKSOURCE); ++} ++ ++static void em_sti_clocksource_resume(struct clocksource *cs) ++{ ++ em_sti_clocksource_enable(cs); ++} ++ ++static int em_sti_register_clocksource(struct em_sti_priv *p) ++{ ++ struct clocksource *cs = &p->cs; ++ ++ memset(cs, 0, sizeof(*cs)); ++ cs->name = dev_name(&p->pdev->dev); ++ cs->rating = 200; ++ cs->read = em_sti_clocksource_read; ++ cs->enable = em_sti_clocksource_enable; ++ cs->disable = em_sti_clocksource_disable; ++ cs->suspend = em_sti_clocksource_disable; ++ cs->resume = em_sti_clocksource_resume; ++ cs->mask = CLOCKSOURCE_MASK(48); ++ cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; ++ ++ dev_info(&p->pdev->dev, "used as clock source\n"); ++ ++ /* Register with dummy 1 Hz value, gets updated in ->enable() */ ++ clocksource_register_hz(cs, 1); ++ return 0; ++} ++ ++static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) ++{ ++ return container_of(ced, struct em_sti_priv, ced); ++} ++ ++static void em_sti_clock_event_mode(enum clock_event_mode mode, ++ struct clock_event_device *ced) ++{ ++ struct em_sti_priv *p = ced_to_em_sti(ced); ++ ++ /* deal with old setting first */ ++ switch (ced->mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ case CLOCK_EVT_MODE_ONESHOT: ++ em_sti_stop(p, USER_CLOCKEVENT); ++ break; ++ default: ++ break; ++ } ++ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ dev_info(&p->pdev->dev, "used for periodic clock events\n"); ++ em_sti_start(p, USER_CLOCKEVENT); ++ clockevents_config(&p->ced, p->rate); ++ p->delta = (p->rate + HZ/2) / HZ; ++ p->next = em_sti_count(p); ++ em_sti_update(p); ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ dev_info(&p->pdev->dev, "used for oneshot clock events\n"); ++ em_sti_start(p, USER_CLOCKEVENT); ++ clockevents_config(&p->ced, p->rate); ++ break; ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ case CLOCK_EVT_MODE_UNUSED: ++ em_sti_stop(p, USER_CLOCKEVENT); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int em_sti_clock_event_next(unsigned long delta, ++ struct clock_event_device *ced) ++{ ++ struct em_sti_priv *p = ced_to_em_sti(ced); ++ int safe; ++ ++ p->delta = delta; ++ p->next = em_sti_count(p); ++ em_sti_update(p); ++ ++ safe = em_sti_count(p) < (p->next - 1); ++ ++ return !safe; ++} ++ ++static void em_sti_register_clockevent(struct em_sti_priv *p) ++{ ++ struct clock_event_device *ced = &p->ced; ++ ++ memset(ced, 0, sizeof(*ced)); ++ ced->name = dev_name(&p->pdev->dev); ++ ced->features = CLOCK_EVT_FEAT_PERIODIC; ++ ced->features |= CLOCK_EVT_FEAT_ONESHOT; ++ ced->rating = 200; ++ ced->cpumask = cpumask_of(0); ++ ced->set_next_event = em_sti_clock_event_next; ++ ced->set_mode = em_sti_clock_event_mode; ++ ++ dev_info(&p->pdev->dev, "used for clock events\n"); ++ ++ /* Register with dummy 1 Hz value, gets updated in ->set_mode() */ ++ clockevents_config_and_register(ced, 1, 2, 0xffffffff); ++} ++ ++static int __devinit em_sti_probe(struct platform_device *pdev) ++{ ++ struct em_sti_priv *p; ++ struct resource *res; ++ int irq, ret; ++ ++ p = kzalloc(sizeof(*p), GFP_KERNEL); ++ if (p == NULL) { ++ dev_err(&pdev->dev, "failed to allocate driver data\n"); ++ ret = -ENOMEM; ++ goto err0; ++ } ++ ++ p->pdev = pdev; ++ platform_set_drvdata(pdev, p); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ ret = -EINVAL; ++ goto err0; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ ret = -EINVAL; ++ goto err0; ++ } ++ ++ /* map memory, let base point to the STI instance */ ++ p->base = ioremap_nocache(res->start, resource_size(res)); ++ if (p->base == NULL) { ++ dev_err(&pdev->dev, "failed to remap I/O memory\n"); ++ ret = -ENXIO; ++ goto err0; ++ } ++ ++ /* get hold of clock */ ++ p->clk = clk_get(&pdev->dev, "sclk"); ++ if (IS_ERR(p->clk)) { ++ dev_err(&pdev->dev, "cannot get clock\n"); ++ ret = PTR_ERR(p->clk); ++ goto err1; ++ } ++ ++ if (request_irq(irq, em_sti_interrupt, ++ IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, ++ dev_name(&pdev->dev), p)) { ++ dev_err(&pdev->dev, "failed to request low IRQ\n"); ++ ret = -ENOENT; ++ goto err2; ++ } ++ ++ spin_lock_init(&p->lock); ++ em_sti_register_clockevent(p); ++ em_sti_register_clocksource(p); ++ return 0; ++ ++err2: ++ clk_put(p->clk); ++err1: ++ iounmap(p->base); ++err0: ++ kfree(p); ++ return ret; ++} ++ ++static int __devexit em_sti_remove(struct platform_device *pdev) ++{ ++ return -EBUSY; /* cannot unregister clockevent and clocksource */ ++} ++ ++static struct platform_driver em_sti_device_driver = { ++ .probe = em_sti_probe, ++ .remove = __devexit_p(em_sti_remove), ++ .driver = { ++ .name = "em_sti", ++ } ++}; ++ ++module_platform_driver(em_sti_device_driver); ++ ++MODULE_AUTHOR("Magnus Damm"); ++MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); ++MODULE_LICENSE("GPL v2"); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0050-ARM-move-initialization-of-the-high_memory-variable-.patch b/patches.kzm9g/0050-ARM-move-initialization-of-the-high_memory-variable-.patch new file mode 100644 index 00000000000000..995ac0d9c826bd --- /dev/null +++ b/patches.kzm9g/0050-ARM-move-initialization-of-the-high_memory-variable-.patch @@ -0,0 +1,63 @@ +From 778219539dbd4ac7a63ab82fdba8b529e61f1aeb Mon Sep 17 00:00:00 2001 +From: Nicolas Pitre <nicolas.pitre@linaro.org> +Date: Sun, 18 Sep 2011 22:40:00 -0400 +Subject: ARM: move initialization of the high_memory variable earlier + +Some upcoming changes must know the VMALLOC_START value, which is based +on high_memory, before bootmem_init() is called. + +The best location to set it is in sanity_check_meminfo() where the needed +computation is already done, and in the non MMU case it is trivial to do +now that the meminfo array is already sorted at that point. + +Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> +(cherry picked from commit 55a8173cfe1c6b489f8f5705282c762aed2e265e) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mm/init.c | 2 -- + arch/arm/mm/mmu.c | 1 + + arch/arm/mm/nommu.c | 2 ++ + 3 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c +index db04a3e5..0530019 100644 +--- a/arch/arm/mm/init.c ++++ b/arch/arm/mm/init.c +@@ -391,8 +391,6 @@ void __init bootmem_init(void) + */ + arm_bootmem_free(min, max_low, max_high); + +- high_memory = __va(((phys_addr_t)max_low << PAGE_SHIFT) - 1) + 1; +- + /* + * This doesn't seem to be used by the Linux memory manager any + * more, but is used by ll_rw_block. If we can get rid of it, we +diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c +index 594d677..eefb8ed 100644 +--- a/arch/arm/mm/mmu.c ++++ b/arch/arm/mm/mmu.c +@@ -852,6 +852,7 @@ void __init sanity_check_meminfo(void) + } + #endif + meminfo.nr_banks = j; ++ high_memory = __va(lowmem_limit - 1) + 1; + memblock_set_current_limit(lowmem_limit); + } + +diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c +index 941a98c..9348730 100644 +--- a/arch/arm/mm/nommu.c ++++ b/arch/arm/mm/nommu.c +@@ -29,6 +29,8 @@ void __init arm_mm_memblock_reserve(void) + + void __init sanity_check_meminfo(void) + { ++ phys_addr_t end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]); ++ high_memory = __va(end - 1) + 1; + } + + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0051-ARM-move-iotable-mappings-within-the-vmalloc-region.patch b/patches.kzm9g/0051-ARM-move-iotable-mappings-within-the-vmalloc-region.patch new file mode 100644 index 00000000000000..720421b0e5fa32 --- /dev/null +++ b/patches.kzm9g/0051-ARM-move-iotable-mappings-within-the-vmalloc-region.patch @@ -0,0 +1,207 @@ +From dbc2d5048de20169fff5e5c5032e89a4129cfc3b Mon Sep 17 00:00:00 2001 +From: Nicolas Pitre <nicolas.pitre@linaro.org> +Date: Thu, 25 Aug 2011 00:35:59 -0400 +Subject: ARM: move iotable mappings within the vmalloc region + +In order to remove the build time variation between different SOCs with +regards to VMALLOC_END, the iotable mappings are now allocated inside +the vmalloc region. This allows for VMALLOC_END to be identical across +all machines. + +The value for VMALLOC_END is now set to 0xff000000 which is right where +the consistent DMA area starts. + +To accommodate all static mappings on machines with possible highmem usage, +the default vmalloc area size is changed to 240 MB so that VMALLOC_START +is no higher than 0xf0000000 by default. + +Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> +Tested-by: Stephen Warren <swarren@nvidia.com> +Tested-by: Kevin Hilman <khilman@ti.com> +Tested-by: Jamie Iles <jamie@jamieiles.com> +(cherry picked from commit 0536bdf33faff4d940ac094c77998cfac368cfff) + +Conflicts: + arch/arm/mm/mmu.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + Documentation/arm/memory.txt | 11 ++++----- + arch/arm/include/asm/pgtable.h | 8 +------ + arch/arm/mm/mmu.c | 49 ++++++++++++++++++++++++++++------------ + 3 files changed, 41 insertions(+), 27 deletions(-) + +diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt +index 771d48d..208a2d4 100644 +--- a/Documentation/arm/memory.txt ++++ b/Documentation/arm/memory.txt +@@ -51,15 +51,14 @@ ffc00000 ffefffff DMA memory mapping region. Memory returned + ff000000 ffbfffff Reserved for future expansion of DMA + mapping region. + +-VMALLOC_END feffffff Free for platform use, recommended. +- VMALLOC_END must be aligned to a 2MB +- boundary. +- + VMALLOC_START VMALLOC_END-1 vmalloc() / ioremap() space. + Memory returned by vmalloc/ioremap will + be dynamically placed in this region. +- VMALLOC_START may be based upon the value +- of the high_memory variable. ++ Machine specific static mappings are also ++ located here through iotable_init(). ++ VMALLOC_START is based upon the value ++ of the high_memory variable, and VMALLOC_END ++ is equal to 0xff000000. + + PAGE_OFFSET high_memory-1 Kernel direct-mapped RAM region. + This maps the platforms RAM, and typically +diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h +index 5750704..950dee3 100644 +--- a/arch/arm/include/asm/pgtable.h ++++ b/arch/arm/include/asm/pgtable.h +@@ -21,7 +21,6 @@ + #else + + #include <asm/memory.h> +-#include <mach/vmalloc.h> + #include <asm/pgtable-hwdef.h> + + /* +@@ -31,15 +30,10 @@ + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) +- * +- * Note that platforms may override VMALLOC_START, but they must provide +- * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space, +- * which may not overlap IO space. + */ +-#ifndef VMALLOC_START + #define VMALLOC_OFFSET (8*1024*1024) + #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +-#endif ++#define VMALLOC_END 0xff000000UL + + /* + * Hardware-wise, we have a two level page table structure, where the first +diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c +index eefb8ed..6a98c4a 100644 +--- a/arch/arm/mm/mmu.c ++++ b/arch/arm/mm/mmu.c +@@ -15,6 +15,7 @@ + #include <linux/nodemask.h> + #include <linux/memblock.h> + #include <linux/fs.h> ++#include <linux/vmalloc.h> + + #include <asm/cputype.h> + #include <asm/sections.h> +@@ -521,13 +522,18 @@ EXPORT_SYMBOL(phys_mem_access_prot); + + #define vectors_base() (vectors_high() ? 0xffff0000 : 0) + +-static void __init *early_alloc(unsigned long sz) ++static void __init *early_alloc_aligned(unsigned long sz, unsigned long align) + { +- void *ptr = __va(memblock_alloc(sz, sz)); ++ void *ptr = __va(memblock_alloc(sz, align)); + memset(ptr, 0, sz); + return ptr; + } + ++static void __init *early_alloc(unsigned long sz) ++{ ++ return early_alloc_aligned(sz, sz); ++} ++ + static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot) + { + if (pmd_none(*pmd)) { +@@ -677,9 +683,10 @@ static void __init create_mapping(struct map_desc *md) + } + + if ((md->type == MT_DEVICE || md->type == MT_ROM) && +- md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { ++ md->virtual >= PAGE_OFFSET && ++ (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) { + printk(KERN_WARNING "BUG: mapping for 0x%08llx" +- " at 0x%08lx overlaps vmalloc space\n", ++ " at 0x%08lx out of vmalloc space\n", + (long long)__pfn_to_phys((u64)md->pfn), md->virtual); + } + +@@ -721,18 +728,32 @@ static void __init create_mapping(struct map_desc *md) + */ + void __init iotable_init(struct map_desc *io_desc, int nr) + { +- int i; ++ struct map_desc *md; ++ struct vm_struct *vm; ++ ++ if (!nr) ++ return; + +- for (i = 0; i < nr; i++) +- create_mapping(io_desc + i); ++ vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm)); ++ ++ for (md = io_desc; nr; md++, nr--) { ++ create_mapping(md); ++ vm->addr = (void *)(md->virtual & PAGE_MASK); ++ vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); ++ vm->phys_addr = __pfn_to_phys(md->pfn); ++ vm->flags = VM_IOREMAP; ++ vm->caller = iotable_init; ++ vm_area_add_early(vm++); ++ } + } + +-static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M); ++static void * __initdata vmalloc_min = ++ (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET); + + /* + * vmalloc=size forces the vmalloc area to be exactly 'size' + * bytes. This can be used to increase (or decrease) the vmalloc +- * area - the default is 128m. ++ * area - the default is 240m. + */ + static int __init early_vmalloc(char *arg) + { +@@ -883,10 +904,10 @@ static inline void prepare_page_table(void) + + /* + * Clear out all the kernel space mappings, except for the first +- * memory bank, up to the end of the vmalloc region. ++ * memory bank, up to the vmalloc region. + */ + for (addr = __phys_to_virt(end); +- addr < VMALLOC_END; addr += PGDIR_SIZE) ++ addr < VMALLOC_START; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + } + +@@ -911,8 +932,8 @@ void __init arm_mm_memblock_reserve(void) + } + + /* +- * Set up device the mappings. Since we clear out the page tables for all +- * mappings above VMALLOC_END, we will remove any debug device mappings. ++ * Set up the device mappings. Since we clear out the page tables for all ++ * mappings above VMALLOC_START, we will remove any debug device mappings. + * This means you have to be careful how you debug this function, or any + * called function. This means you can't use any function or debugging + * method which may touch any device, otherwise the kernel _will_ crash. +@@ -927,7 +948,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) + */ + vectors_page = early_alloc(PAGE_SIZE); + +- for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) ++ for (addr = VMALLOC_START; addr; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0052-ARM-simplify-__iounmap-when-dealing-with-section-bas.patch b/patches.kzm9g/0052-ARM-simplify-__iounmap-when-dealing-with-section-bas.patch new file mode 100644 index 00000000000000..85b4c27b1b4d48 --- /dev/null +++ b/patches.kzm9g/0052-ARM-simplify-__iounmap-when-dealing-with-section-bas.patch @@ -0,0 +1,66 @@ +From 9c711a650671536e915cea3661fc7caa2a4ab487 Mon Sep 17 00:00:00 2001 +From: Nicolas Pitre <nicolas.pitre@linaro.org> +Date: Thu, 15 Sep 2011 22:12:19 -0400 +Subject: ARM: simplify __iounmap() when dealing with section based mapping + +Firstly, there is no need to have a double pointer here as we're only +walking the vmlist and not modifying it. + +Secondly, for the same reason, we don't need a write lock but only a +read lock here, since the lock only protects the coherency of the list +nothing else. + +Lastly, the reason for holding a lock is not what the comment says, so +let's remove that misleading piece of information. + +Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> +(cherry picked from commit 6ee723a6570a897208b76ab3e9a495e9106b2f8c) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mm/ioremap.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c +index ab50627..1ddcd8a 100644 +--- a/arch/arm/mm/ioremap.c ++++ b/arch/arm/mm/ioremap.c +@@ -293,26 +293,24 @@ void __iounmap(volatile void __iomem *io_addr) + { + void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); + #ifndef CONFIG_SMP +- struct vm_struct **p, *tmp; ++ struct vm_struct *vm; + + /* + * If this is a section based mapping we need to handle it + * specially as the VM subsystem does not know how to handle +- * such a beast. We need the lock here b/c we need to clear +- * all the mappings before the area can be reclaimed +- * by someone else. ++ * such a beast. + */ +- write_lock(&vmlist_lock); +- for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) { +- if ((tmp->flags & VM_IOREMAP) && (tmp->addr == addr)) { +- if (tmp->flags & VM_ARM_SECTION_MAPPING) { +- unmap_area_sections((unsigned long)tmp->addr, +- tmp->size); ++ read_lock(&vmlist_lock); ++ for (vm = vmlist; vm; vm = vm->next) { ++ if ((vm->flags & VM_IOREMAP) && (vm->addr == addr)) { ++ if (vm->flags & VM_ARM_SECTION_MAPPING) { ++ unmap_area_sections((unsigned long)vm->addr, ++ vm->size); + } + break; + } + } +- write_unlock(&vmlist_lock); ++ read_unlock(&vmlist_lock); + #endif + + vunmap(addr); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0053-ARM-add-generic-ioremap-optimization-by-reusing-stat.patch b/patches.kzm9g/0053-ARM-add-generic-ioremap-optimization-by-reusing-stat.patch new file mode 100644 index 00000000000000..1ecd497ee2d9bd --- /dev/null +++ b/patches.kzm9g/0053-ARM-add-generic-ioremap-optimization-by-reusing-stat.patch @@ -0,0 +1,177 @@ +From 5be0e66269ddfd8ca3dee6512e573b1f461a6faf Mon Sep 17 00:00:00 2001 +From: Nicolas Pitre <nicolas.pitre@linaro.org> +Date: Fri, 16 Sep 2011 01:14:23 -0400 +Subject: ARM: add generic ioremap optimization by reusing static mappings + +Now that we have all the static mappings from iotable_init() located +in the vmalloc area, it is trivial to optimize ioremap by reusing those +static mappings when the requested physical area fits in one of them, +and so in a generic way for all platforms. + +Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> +Tested-by: Stephen Warren <swarren@nvidia.com> +Tested-by: Kevin Hilman <khilman@ti.com> +Tested-by: Jamie Iles <jamie@jamieiles.com> +(cherry picked from commit 576d2f2525612ecb5af029a76f21f22a3b82563d) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mm/ioremap.c | 72 ++++++++++++++++++++++++++++++++----------------- + arch/arm/mm/mm.h | 14 ++++++++++ + arch/arm/mm/mmu.c | 3 ++- + 3 files changed, 64 insertions(+), 25 deletions(-) + +diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c +index 1ddcd8a..b5900f2 100644 +--- a/arch/arm/mm/ioremap.c ++++ b/arch/arm/mm/ioremap.c +@@ -36,12 +36,6 @@ + #include <asm/mach/map.h> + #include "mm.h" + +-/* +- * Used by ioremap() and iounmap() code to mark (super)section-mapped +- * I/O regions in vm_struct->flags field. +- */ +-#define VM_ARM_SECTION_MAPPING 0x80000000 +- + int ioremap_page(unsigned long virt, unsigned long phys, + const struct mem_type *mtype) + { +@@ -201,12 +195,6 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, + if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK)) + return NULL; + +- /* +- * Don't allow RAM to be mapped - this causes problems with ARMv6+ +- */ +- if (WARN_ON(pfn_valid(pfn))) +- return NULL; +- + type = get_mem_type(mtype); + if (!type) + return NULL; +@@ -216,6 +204,34 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, + */ + size = PAGE_ALIGN(offset + size); + ++ /* ++ * Try to reuse one of the static mapping whenever possible. ++ */ ++ read_lock(&vmlist_lock); ++ for (area = vmlist; area; area = area->next) { ++ if (!size || (sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) ++ break; ++ if (!(area->flags & VM_ARM_STATIC_MAPPING)) ++ continue; ++ if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype)) ++ continue; ++ if (__phys_to_pfn(area->phys_addr) > pfn || ++ __pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1) ++ continue; ++ /* we can drop the lock here as we know *area is static */ ++ read_unlock(&vmlist_lock); ++ addr = (unsigned long)area->addr; ++ addr += __pfn_to_phys(pfn) - area->phys_addr; ++ return (void __iomem *) (offset + addr); ++ } ++ read_unlock(&vmlist_lock); ++ ++ /* ++ * Don't allow RAM to be mapped - this causes problems with ARMv6+ ++ */ ++ if (WARN_ON(pfn_valid(pfn))) ++ return NULL; ++ + area = get_vm_area_caller(size, VM_IOREMAP, caller); + if (!area) + return NULL; +@@ -292,26 +308,34 @@ EXPORT_SYMBOL(__arm_ioremap); + void __iounmap(volatile void __iomem *io_addr) + { + void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); +-#ifndef CONFIG_SMP + struct vm_struct *vm; + +- /* +- * If this is a section based mapping we need to handle it +- * specially as the VM subsystem does not know how to handle +- * such a beast. +- */ + read_lock(&vmlist_lock); + for (vm = vmlist; vm; vm = vm->next) { +- if ((vm->flags & VM_IOREMAP) && (vm->addr == addr)) { +- if (vm->flags & VM_ARM_SECTION_MAPPING) { +- unmap_area_sections((unsigned long)vm->addr, +- vm->size); +- } ++ if (vm->addr > addr) + break; ++ if (!(vm->flags & VM_IOREMAP)) ++ continue; ++ /* If this is a static mapping we must leave it alone */ ++ if ((vm->flags & VM_ARM_STATIC_MAPPING) && ++ (vm->addr <= addr) && (vm->addr + vm->size > addr)) { ++ read_unlock(&vmlist_lock); ++ return; + } ++#ifndef CONFIG_SMP ++ /* ++ * If this is a section based mapping we need to handle it ++ * specially as the VM subsystem does not know how to handle ++ * such a beast. ++ */ ++ if ((vm->addr == addr) && ++ (vm->flags & VM_ARM_SECTION_MAPPING)) { ++ unmap_area_sections((unsigned long)vm->addr, vm->size); ++ break; ++ } ++#endif + } + read_unlock(&vmlist_lock); +-#endif + + vunmap(addr); + } +diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h +index 5b3d7d5..26f3a2c 100644 +--- a/arch/arm/mm/mm.h ++++ b/arch/arm/mm/mm.h +@@ -21,6 +21,20 @@ const struct mem_type *get_mem_type(unsigned int type); + + extern void __flush_dcache_page(struct address_space *mapping, struct page *page); + ++/* ++ * ARM specific vm_struct->flags bits. ++ */ ++ ++/* (super)section-mapped I/O regions used by ioremap()/iounmap() */ ++#define VM_ARM_SECTION_MAPPING 0x80000000 ++ ++/* permanent static mappings from iotable_init() */ ++#define VM_ARM_STATIC_MAPPING 0x40000000 ++ ++/* mapping type (attributes) for permanent static mappings */ ++#define VM_ARM_MTYPE(mt) ((mt) << 20) ++#define VM_ARM_MTYPE_MASK (0x1f << 20) ++ + #endif + + void __init bootmem_init(void); +diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c +index 6a98c4a..ce0e427 100644 +--- a/arch/arm/mm/mmu.c ++++ b/arch/arm/mm/mmu.c +@@ -741,7 +741,8 @@ void __init iotable_init(struct map_desc *io_desc, int nr) + vm->addr = (void *)(md->virtual & PAGE_MASK); + vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); + vm->phys_addr = __pfn_to_phys(md->pfn); +- vm->flags = VM_IOREMAP; ++ vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; ++ vm->flags |= VM_ARM_MTYPE(md->type); + vm->caller = iotable_init; + vm_area_add_early(vm++); + } +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0054-ARM-mach-shmobile-Introduce-shmobile_setup_delay.patch b/patches.kzm9g/0054-ARM-mach-shmobile-Introduce-shmobile_setup_delay.patch new file mode 100644 index 00000000000000..df4fe7b07a5135 --- /dev/null +++ b/patches.kzm9g/0054-ARM-mach-shmobile-Introduce-shmobile_setup_delay.patch @@ -0,0 +1,72 @@ +From 4db83a8c2af822cc5ae76ea212c7a77b20a637b5 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 28 Mar 2012 19:22:30 +0900 +Subject: ARM: mach-shmobile: Introduce shmobile_setup_delay() + +Add the function shmobile_setup_delay() to let platforms +configure their maximum loops per jiffy delay. With this +jiffies calculation done the dependency on early timer +is removed. + +In the future this allows us to assign timers +using the regular driver model via the device tree. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit 0f2c9f20e4e339de30cfd5613dfa9505e7b9c58b) + +Conflicts: + arch/arm/mach-shmobile/include/mach/common.h + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/include/mach/common.h | 2 ++ + arch/arm/mach-shmobile/timer.c | 17 +++++++++++++++++ + 2 files changed, 19 insertions(+) + +diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h +index c77b3a1..bc3aa3e 100644 +--- a/arch/arm/mach-shmobile/include/mach/common.h ++++ b/arch/arm/mach-shmobile/include/mach/common.h +@@ -3,6 +3,8 @@ + + extern void shmobile_earlytimer_init(void); + extern struct sys_timer shmobile_timer; ++extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, ++ unsigned int mult, unsigned int div); + extern void shmobile_setup_console(void); + extern void shmobile_secondary_vector(void); + struct clk; +diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c +index be1ad70..b323e3c 100644 +--- a/arch/arm/mach-shmobile/timer.c ++++ b/arch/arm/mach-shmobile/timer.c +@@ -19,8 +19,25 @@ + * + */ + #include <linux/platform_device.h> ++#include <linux/delay.h> + #include <asm/mach/time.h> + ++void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, ++ unsigned int mult, unsigned int div) ++{ ++ /* calculate a worst-case loops-per-jiffy value ++ * based on maximum cpu core mhz setting and the ++ * __delay() implementation in arch/arm/lib/delay.S ++ * ++ * this will result in a longer delay than expected ++ * when the cpu core runs on lower frequencies. ++ */ ++ ++ unsigned int value = (1000000 * mult) / (HZ * div); ++ ++ lpj_fine = max_cpu_core_mhz * value; ++} ++ + static void __init shmobile_late_time_init(void) + { + /* +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0055-ARM-mach-shmobile-Allow-SoC-specific-CPU-kill-code.patch b/patches.kzm9g/0055-ARM-mach-shmobile-Allow-SoC-specific-CPU-kill-code.patch new file mode 100644 index 00000000000000..4c08f8fffb2b53 --- /dev/null +++ b/patches.kzm9g/0055-ARM-mach-shmobile-Allow-SoC-specific-CPU-kill-code.patch @@ -0,0 +1,67 @@ +From 05f453548b4b9fdf0ab8e36a15c9ef74b21f27e2 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 28 Dec 2011 16:47:16 +0900 +Subject: ARM: mach-shmobile: Allow SoC specific CPU kill code + +Add the function shmobile_platform_kill_cpu() to allow +SoC specific code to tie in their CPU shutdown code. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Paul Mundt <lethal@linux-sh.org> +(cherry picked from commit 8b306796995609c281f6d32b3cbaa814551ad5ac) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/hotplug.c | 3 ++- + arch/arm/mach-shmobile/include/mach/common.h | 1 + + arch/arm/mach-shmobile/platsmp.c | 5 +++++ + 3 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c +index 238a0d9..aee3a10 100644 +--- a/arch/arm/mach-shmobile/hotplug.c ++++ b/arch/arm/mach-shmobile/hotplug.c +@@ -12,10 +12,11 @@ + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/smp.h> ++#include <mach/common.h> + + int platform_cpu_kill(unsigned int cpu) + { +- return 1; ++ return shmobile_platform_cpu_kill(cpu); + } + + void platform_cpu_die(unsigned int cpu) +diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h +index bc3aa3e..8b88b80 100644 +--- a/arch/arm/mach-shmobile/include/mach/common.h ++++ b/arch/arm/mach-shmobile/include/mach/common.h +@@ -7,6 +7,7 @@ extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, + unsigned int mult, unsigned int div); + extern void shmobile_setup_console(void); + extern void shmobile_secondary_vector(void); ++extern int shmobile_platform_cpu_kill(unsigned int cpu); + struct clk; + extern int shmobile_clk_init(void); + extern void shmobile_handle_irq_intc(struct pt_regs *); +diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c +index 2cc8930..1103ce5 100644 +--- a/arch/arm/mach-shmobile/platsmp.c ++++ b/arch/arm/mach-shmobile/platsmp.c +@@ -37,6 +37,11 @@ static void __init shmobile_smp_prepare_cpus(void) + sh73a0_smp_prepare_cpus(); + } + ++int shmobile_platform_cpu_kill(unsigned int cpu) ++{ ++ return 1; ++} ++ + void __cpuinit platform_secondary_init(unsigned int cpu) + { + trace_hardirqs_off(); +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0056-ARM-mach-shmobile-Use-preset_lpj-with-calibrate_dela.patch b/patches.kzm9g/0056-ARM-mach-shmobile-Use-preset_lpj-with-calibrate_dela.patch new file mode 100644 index 00000000000000..3b83af24fe5af5 --- /dev/null +++ b/patches.kzm9g/0056-ARM-mach-shmobile-Use-preset_lpj-with-calibrate_dela.patch @@ -0,0 +1,46 @@ +From 0d710173dcca9b9e7c5ec0ddf109e9bbaa6d4a79 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Thu, 10 May 2012 00:37:48 +0200 +Subject: ARM / mach-shmobile: Use preset_lpj with calibrate_delay() + +Update the mach-shmobile shared delay calibration code for late +timers. All existing in-tree non-DT socs are however using early +timers today and they are unaffected by this change. + +The patch modifies shmobile_setup_delay() from using lpj_fine +to preset_lpj. This change allows us to preset the worst case +loops-per-jiffy value to all CPU cores on the system. + +The old code which made use of lpj_fine did not affect the +secondary CPU cores which made it impossible to boot on SMP +without early timers. + +Needed for SMP SoCs using late timers like EMEV2 or any other +mach-shmobile SMP SoC that makes use of late timers via DT. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit 173bf69a7af142e0325fa514954f6eeb2d20cc1d) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/timer.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c +index b323e3c..a169cea 100644 +--- a/arch/arm/mach-shmobile/timer.c ++++ b/arch/arm/mach-shmobile/timer.c +@@ -35,7 +35,8 @@ void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, + + unsigned int value = (1000000 * mult) / (HZ * div); + +- lpj_fine = max_cpu_core_mhz * value; ++ if (!preset_lpj) ++ preset_lpj = max_cpu_core_mhz * value; + } + + static void __init shmobile_late_time_init(void) +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0057-ARM-Undelete-KZM9D-mach-type.patch b/patches.kzm9g/0057-ARM-Undelete-KZM9D-mach-type.patch new file mode 100644 index 00000000000000..5e93acec0931ad --- /dev/null +++ b/patches.kzm9g/0057-ARM-Undelete-KZM9D-mach-type.patch @@ -0,0 +1,32 @@ +From cc8618aa381c26c3aaeb40ac9617adeaac14dbfc Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Mon, 14 May 2012 19:54:51 +0900 +Subject: ARM: Undelete KZM9D mach-type + +Undelete the KZM9D mach-type to allow build of board +for EMEV2 SoC support. + +Signed-off-by: Magnus Damm <damm@opensource.se> + +N.B: Not present upstream + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/tools/mach-types | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types +index 2997e56..e2e0d3f 100644 +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -462,6 +462,7 @@ msm7x27_surf MACH_MSM7X27_SURF MSM7X27_SURF 2705 + msm7x27_ffa MACH_MSM7X27_FFA MSM7X27_FFA 2706 + msm7x30_ffa MACH_MSM7X30_FFA MSM7X30_FFA 2707 + qsd8x50_surf MACH_QSD8X50_SURF QSD8X50_SURF 2708 ++kzm9d MACH_KZM9D KZM9D 3246 + mx53_evk MACH_MX53_EVK MX53_EVK 2716 + igep0030 MACH_IGEP0030 IGEP0030 2717 + sbc3530 MACH_SBC3530 SBC3530 2722 +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0058-gpio-Emma-Mobile-GPIO-driver.patch b/patches.kzm9g/0058-gpio-Emma-Mobile-GPIO-driver.patch new file mode 100644 index 00000000000000..fd825b1f193902 --- /dev/null +++ b/patches.kzm9g/0058-gpio-Emma-Mobile-GPIO-driver.patch @@ -0,0 +1,481 @@ +From 1ed76280e95d4cba220d465a58caec2ba5c20632 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Fri, 11 May 2012 18:41:03 +0900 +Subject: gpio: Emma Mobile GPIO driver + +This patch adds a GPIO driver for the Emma Mobile line +of SoCs. The driver is designed to be reusable between +multiple SoCs that share the same basic building block, +but so far it has only been used on Emma Mobile EV2. + +Each driver instance handles 32 GPIOs with individually +maskable IRQs. The driver operates on two I/O memory +ranges and the 32 GPIOs are hooked up to two interrupts. + +In the case of Emma Mobile EV2 this GPIO building block +is used as main external interrupt controller hooking up +159 GPIOS as 159 interrupts via 5 driver instances and +10 interrupts to the GIC and the Cortex-A9 Dual. + +This version of the driver gets all configuration via +struct resource and platform data, but DT bindings are +currently in development and such support will be sent +as a individual feature patch in the near future. + +Signed-off-by: Magnus Damm <damm@opensource.se> + +N.B: This driver has been merged upsteram +as commit a07e103ef08c6907d695a06467d7ee950796fccf. +However, this code is an earlier version of +the driver that doesn't make use of infrastructure +that isn't present in Linux 3.0. + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + drivers/gpio/Kconfig | 6 + + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-em.c | 385 +++++++++++++++++++++++++++++++++ + include/linux/platform_data/gpio-em.h | 10 + + 4 files changed, 402 insertions(+) + create mode 100644 drivers/gpio/gpio-em.c + create mode 100644 include/linux/platform_data/gpio-em.h + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 2967002..6450431 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -86,6 +86,12 @@ config GPIO_IT8761E + help + Say yes here to support GPIO functionality of IT8761E super I/O chip. + ++config GPIO_EM ++ tristate "Emma Mobile GPIO" ++ depends on ARM ++ help ++ Say yes here to support GPIO on Renesas Emma Mobile SoCs. ++ + config GPIO_EXYNOS4 + def_bool y + depends on CPU_EXYNOS4210 +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index b605f8e..d5ae36e 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o + obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o + obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o + obj-$(CONFIG_GPIO_CS5535) += cs5535-gpio.o ++obj-$(CONFIG_GPIO_EM) += gpio-em.o + obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o + obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o + obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o +diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c +new file mode 100644 +index 0000000..8873429 +--- /dev/null ++++ b/drivers/gpio/gpio-em.c +@@ -0,0 +1,385 @@ ++/* ++ * Emma Mobile GPIO Support - GIO ++ * ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/err.h> ++#include <linux/gpio.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/platform_data/gpio-em.h> ++ ++struct em_gio_priv { ++ void __iomem *base0; ++ void __iomem *base1; ++ unsigned int irq_base; ++ spinlock_t sense_lock; ++ struct gpio_chip gpio_chip; ++ struct irq_chip irq_chip; ++}; ++ ++#define GIO_E1 0x00 ++#define GIO_E0 0x04 ++#define GIO_EM 0x04 ++#define GIO_OL 0x08 ++#define GIO_OH 0x0c ++#define GIO_I 0x10 ++#define GIO_IIA 0x14 ++#define GIO_IEN 0x18 ++#define GIO_IDS 0x1c ++#define GIO_IIM 0x1c ++#define GIO_RAW 0x20 ++#define GIO_MST 0x24 ++#define GIO_IIR 0x28 ++ ++#define GIO_IDT0 0x40 ++#define GIO_IDT1 0x44 ++#define GIO_IDT2 0x48 ++#define GIO_IDT3 0x4c ++#define GIO_RAWBL 0x50 ++#define GIO_RAWBH 0x54 ++#define GIO_IRBL 0x58 ++#define GIO_IRBH 0x5c ++ ++#define GIO_IDT(n) GIO_IDT0 + ((n) * 4) ++ ++static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs) ++{ ++ if (offs < GIO_IDT0) ++ return ioread32(p->base0 + offs); ++ else ++ return ioread32(p->base1 + (offs - GIO_IDT0)); ++} ++ ++static inline void em_gio_write(struct em_gio_priv *p, int offs, ++ unsigned long value) ++{ ++ if (offs < GIO_IDT0) ++ iowrite32(value, p->base0 + offs); ++ else ++ iowrite32(value, p->base1 + (offs - GIO_IDT0)); ++} ++ ++static struct em_gio_priv *irq_to_priv(unsigned int irq) ++{ ++ struct irq_chip *chip = irq_get_chip(irq); ++ return container_of(chip, struct em_gio_priv, irq_chip); ++} ++ ++static void em_gio_irq_disable(struct irq_data *data) ++{ ++ struct em_gio_priv *p = irq_to_priv(data->irq); ++ int offset = data->irq - p->irq_base; ++ ++ em_gio_write(p, GIO_IDS, 1 << offset); ++} ++ ++static void em_gio_irq_enable(struct irq_data *data) ++{ ++ struct em_gio_priv *p = irq_to_priv(data->irq); ++ int offset = data->irq - p->irq_base; ++ ++ em_gio_write(p, GIO_IEN, 1 << offset); ++} ++ ++#define GIO_ASYNC(x) (x + 8) ++ ++static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { ++ [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00), ++ [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01), ++ [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02), ++ [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03), ++ [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04), ++}; ++ ++static int em_gio_irq_set_type(struct irq_data *data, unsigned int type) ++{ ++ unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK]; ++ struct em_gio_priv *p = irq_to_priv(data->irq); ++ unsigned int reg, offset, shift; ++ unsigned long flags; ++ unsigned long tmp; ++ ++ if (!value) ++ return -EINVAL; ++ ++ offset = data->irq - p->irq_base; ++ ++ pr_debug("gio: sense irq = %d, irq = %d, mode = %d, sw base = %d\n", ++ offset, data->irq, value, p->irq_base); ++ ++ /* 8 x 4 bit fields in 4 IDT registers */ ++ reg = GIO_IDT(offset >> 3); ++ shift = (offset & 0x07) << 4; ++ ++ spin_lock_irqsave(&p->sense_lock, flags); ++ ++ /* disable the interrupt in IIA */ ++ tmp = em_gio_read(p, GIO_IIA); ++ tmp &= ~(1 << offset); ++ em_gio_write(p, GIO_IIA, tmp); ++ ++ /* change the sense setting in IDT */ ++ tmp = em_gio_read(p, reg); ++ tmp &= ~(0xf << shift); ++ tmp |= value << shift; ++ em_gio_write(p, reg, tmp); ++ ++ /* clear pending interrupts */ ++ em_gio_write(p, GIO_IIR, 1 << offset); ++ ++ /* enable the interrupt in IIA */ ++ tmp = em_gio_read(p, GIO_IIA); ++ tmp |= 1 << offset; ++ em_gio_write(p, GIO_IIA, tmp); ++ ++ spin_unlock_irqrestore(&p->sense_lock, flags); ++ ++ return 0; ++} ++ ++static irqreturn_t em_gio_irq_handler(int irq, void *dev_id) ++{ ++ struct em_gio_priv *p = dev_id; ++ unsigned long tmp, status; ++ unsigned int offset; ++ ++ status = tmp = em_gio_read(p, GIO_MST); ++ if (!status) ++ return IRQ_NONE; ++ ++ while (status) { ++ offset = __ffs(status); ++ generic_handle_irq(p->irq_base + offset); ++ status &= ~(1 << offset); ++ } ++ ++ em_gio_write(p, GIO_IIR, tmp); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip) ++{ ++ return container_of(chip, struct em_gio_priv, gpio_chip); ++} ++ ++static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset) ++{ ++ em_gio_write(gpio_to_priv(chip), GIO_E0, 1 << offset); ++ return 0; ++} ++ ++static int em_gio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & (1 << offset)); ++} ++ ++static void __em_gio_set(struct gpio_chip *chip, unsigned int reg, ++ unsigned shift, int value) ++{ ++ /* upper 16 bits contains mask and lower 16 actual value */ ++ em_gio_write(gpio_to_priv(chip), reg, ++ (1 << (shift + 16)) | (value << shift)); ++} ++ ++static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ /* output is split into two registers */ ++ if (offset < 16) ++ __em_gio_set(chip, GIO_OL, offset, value); ++ else ++ __em_gio_set(chip, GIO_OH, offset - 16, value); ++} ++ ++static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ /* write GPIO value to output before selecting output mode of pin */ ++ em_gio_set(chip, offset, value); ++ em_gio_write(gpio_to_priv(chip), GIO_E1, 1 << offset); ++ return 0; ++} ++ ++static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) ++{ ++ return gpio_to_priv(chip)->irq_base + offset; ++} ++ ++static int __devinit em_gio_probe(struct platform_device *pdev) ++{ ++ struct gpio_em_config *pdata = pdev->dev.platform_data; ++ struct em_gio_priv *p; ++ struct resource *io[2], *irq[2]; ++ struct gpio_chip *gpio_chip; ++ struct irq_chip *irq_chip; ++ const char *name = dev_name(&pdev->dev); ++ int k, ret; ++ ++ p = kzalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) { ++ dev_err(&pdev->dev, "failed to allocate driver data\n"); ++ ret = -ENOMEM; ++ goto err0; ++ } ++ ++ gpio_chip = &p->gpio_chip; ++ irq_chip = &p->irq_chip; ++ platform_set_drvdata(pdev, p); ++ spin_lock_init(&p->sense_lock); ++ ++ io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); ++ ++ if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) { ++ dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n"); ++ ret = -EINVAL; ++ goto err1; ++ } ++ ++ p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0])); ++ if (!p->base0) { ++ dev_err(&pdev->dev, "failed to remap low I/O memory\n"); ++ ret = -ENXIO; ++ goto err1; ++ } ++ ++ p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1])); ++ if (!p->base1) { ++ dev_err(&pdev->dev, "failed to remap high I/O memory\n"); ++ ret = -ENXIO; ++ goto err2; ++ } ++ ++ p->irq_base = irq_alloc_descs(pdata->irq_base, 0, ++ pdata->number_of_pins, numa_node_id()); ++ if (IS_ERR_VALUE(p->irq_base)) { ++ dev_err(&pdev->dev, "cannot get irq_desc\n"); ++ ret = -ENXIO; ++ goto err3; ++ } ++ ++ pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", ++ pdata->gpio_base, pdata->number_of_pins, p->irq_base); ++ ++ irq_chip->name = name; ++ irq_chip->irq_mask = em_gio_irq_disable; ++ irq_chip->irq_unmask = em_gio_irq_enable; ++ irq_chip->irq_enable = em_gio_irq_enable; ++ irq_chip->irq_disable = em_gio_irq_disable; ++ irq_chip->irq_set_type = em_gio_irq_set_type; ++ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; ++ ++ for (k = p->irq_base; k < (p->irq_base + pdata->number_of_pins); k++) { ++ irq_set_chip_and_handler_name(k, irq_chip, handle_level_irq, ++ "level"); ++ set_irq_flags(k, IRQF_VALID); /* kill me now */ ++ } ++ ++ if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) { ++ dev_err(&pdev->dev, "failed to request low IRQ\n"); ++ ret = -ENOENT; ++ goto err4; ++ } ++ ++ if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) { ++ dev_err(&pdev->dev, "failed to request high IRQ\n"); ++ ret = -ENOENT; ++ goto err5; ++ } ++ ++ gpio_chip->direction_input = em_gio_direction_input; ++ gpio_chip->get = em_gio_get; ++ gpio_chip->direction_output = em_gio_direction_output; ++ gpio_chip->set = em_gio_set; ++ ++ gpio_chip->to_irq = em_gio_to_irq; ++ ++ gpio_chip->label = name; ++ gpio_chip->owner = THIS_MODULE; ++ ++ gpio_chip->base = pdata->gpio_base; ++ gpio_chip->ngpio = pdata->number_of_pins; ++ ++ ret = gpiochip_add(gpio_chip); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add GPIO cntroller\n"); ++ goto err6; ++ } ++ return 0; ++ ++err6: ++ free_irq(irq[1]->start, pdev); ++err5: ++ free_irq(irq[0]->start, pdev); ++err4: ++ irq_free_descs(p->irq_base, pdata->number_of_pins); ++err3: ++ iounmap(p->base1); ++err2: ++ iounmap(p->base0); ++err1: ++ kfree(p); ++err0: ++ return ret; ++} ++ ++static int __devexit em_gio_remove(struct platform_device *pdev) ++{ ++ struct gpio_em_config *pdata = pdev->dev.platform_data; ++ struct em_gio_priv *p = platform_get_drvdata(pdev); ++ struct resource *irq[2]; ++ int ret; ++ ++ ret = gpiochip_remove(&p->gpio_chip); ++ if (ret) ++ return ret; ++ ++ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); ++ ++ free_irq(irq[1]->start, pdev); ++ free_irq(irq[0]->start, pdev); ++ irq_free_descs(p->irq_base, pdata->number_of_pins); ++ iounmap(p->base1); ++ iounmap(p->base0); ++ kfree(p); ++ return 0; ++} ++ ++static struct platform_driver em_gio_device_driver = { ++ .probe = em_gio_probe, ++ .remove = __devexit_p(em_gio_remove), ++ .driver = { ++ .name = "em_gio", ++ } ++}; ++ ++module_platform_driver(em_gio_device_driver); ++ ++MODULE_AUTHOR("Magnus Damm"); ++MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h +new file mode 100644 +index 0000000..573edfb +--- /dev/null ++++ b/include/linux/platform_data/gpio-em.h +@@ -0,0 +1,10 @@ ++#ifndef __GPIO_EM_H__ ++#define __GPIO_EM_H__ ++ ++struct gpio_em_config { ++ unsigned int gpio_base; ++ unsigned int irq_base; ++ unsigned int number_of_pins; ++}; ++ ++#endif /* __GPIO_EM_H__ */ +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0059-mach-shmobile-Emma-Mobile-EV2-SoC-base-support-V3.patch b/patches.kzm9g/0059-mach-shmobile-Emma-Mobile-EV2-SoC-base-support-V3.patch new file mode 100644 index 00000000000000..0706510e984c1a --- /dev/null +++ b/patches.kzm9g/0059-mach-shmobile-Emma-Mobile-EV2-SoC-base-support-V3.patch @@ -0,0 +1,493 @@ +From a60f89d7c6f7b301845e6943c6e2ec4c6d6197be Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 16 May 2012 15:44:58 +0900 +Subject: mach-shmobile: Emma Mobile EV2 SoC base support V3 + +This is V3 of the Emma Mobile EV2 SoC support. +Included here is support for serial and timer +devices which is just about enough to boot a kernel. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit 7f627f0380cb5ba3e05bcaac31ecf40c1f508ec1) + +Conflicts: + arch/arm/mach-shmobile/Kconfig + arch/arm/mach-shmobile/Makefile + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/Kconfig | 5 + + arch/arm/mach-shmobile/Makefile | 1 + + arch/arm/mach-shmobile/clock-emev2.c | 226 +++++++++++++++++++++++++++ + arch/arm/mach-shmobile/include/mach/emev2.h | 9 ++ + arch/arm/mach-shmobile/setup-emev2.c | 180 +++++++++++++++++++++ + 5 files changed, 421 insertions(+) + create mode 100644 arch/arm/mach-shmobile/clock-emev2.c + create mode 100644 arch/arm/mach-shmobile/include/mach/emev2.h + create mode 100644 arch/arm/mach-shmobile/setup-emev2.c + +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index 1e7656a..cabb9af 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -33,6 +33,11 @@ config ARCH_R8A7740 + select SH_CLK_CPG + select ARCH_WANT_OPTIONAL_GPIOLIB + ++config ARCH_EMEV2 ++ bool "Emma Mobile EV2" ++ select CPU_V7 ++ select ARM_GIC ++ + comment "SH-Mobile Board Type" + + config MACH_G3EVM +diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile +index 36bd37d..624f721 100644 +--- a/arch/arm/mach-shmobile/Makefile ++++ b/arch/arm/mach-shmobile/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o + obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o + obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o + obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o ++obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o + + # SMP objects + smp-y := platsmp.o headsmp.o +diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c +new file mode 100644 +index 0000000..73a1216 +--- /dev/null ++++ b/arch/arm/mach-shmobile/clock-emev2.c +@@ -0,0 +1,226 @@ ++/* ++ * Emma Mobile EV2 clock framework support ++ * ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/io.h> ++#include <linux/sh_clk.h> ++#include <linux/clkdev.h> ++#include <mach/common.h> ++ ++#define EMEV2_SMU_BASE 0xe0110000 ++ ++/* EMEV2 SMU registers */ ++#define USIAU0_RSTCTRL 0x094 ++#define USIBU1_RSTCTRL 0x0ac ++#define USIBU2_RSTCTRL 0x0b0 ++#define USIBU3_RSTCTRL 0x0b4 ++#define STI_RSTCTRL 0x124 ++#define USIAU0GCLKCTRL 0x4a0 ++#define USIBU1GCLKCTRL 0x4b8 ++#define USIBU2GCLKCTRL 0x4bc ++#define USIBU3GCLKCTRL 0x04c0 ++#define STIGCLKCTRL 0x528 ++#define USIAU0SCLKDIV 0x61c ++#define USIB2SCLKDIV 0x65c ++#define USIB3SCLKDIV 0x660 ++#define STI_CLKSEL 0x688 ++ ++/* not pretty, but hey */ ++static void __iomem *smu_base; ++ ++static void emev2_smu_write(unsigned long value, int offs) ++{ ++ BUG_ON(!smu_base || (offs >= PAGE_SIZE)); ++ iowrite32(value, smu_base + offs); ++} ++ ++static struct clk_mapping smu_mapping = { ++ .phys = EMEV2_SMU_BASE, ++ .len = PAGE_SIZE, ++}; ++ ++/* Fixed 32 KHz root clock from C32K pin */ ++static struct clk c32k_clk = { ++ .rate = 32768, ++ .mapping = &smu_mapping, ++}; ++ ++/* PLL3 multiplies C32K with 7000 */ ++static unsigned long pll3_recalc(struct clk *clk) ++{ ++ return clk->parent->rate * 7000; ++} ++ ++static struct sh_clk_ops pll3_clk_ops = { ++ .recalc = pll3_recalc, ++}; ++ ++static struct clk pll3_clk = { ++ .ops = &pll3_clk_ops, ++ .parent = &c32k_clk, ++}; ++ ++static struct clk *main_clks[] = { ++ &c32k_clk, ++ &pll3_clk, ++}; ++ ++enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3, ++ SCLKDIV_NR }; ++ ++#define SCLKDIV(_reg, _shift) \ ++{ \ ++ .parent = &pll3_clk, \ ++ .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ ++ .enable_bit = _shift, \ ++} ++ ++static struct clk sclkdiv_clks[SCLKDIV_NR] = { ++ [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0), ++ [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16), ++ [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0), ++ [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0), ++}; ++ ++enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK, ++ GCLK_STI_SCLK, ++ GCLK_NR }; ++ ++#define GCLK_SCLK(_parent, _reg) \ ++{ \ ++ .parent = _parent, \ ++ .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ ++ .enable_bit = 1, /* SCLK_GCC */ \ ++} ++ ++static struct clk gclk_clks[GCLK_NR] = { ++ [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0], ++ USIAU0GCLKCTRL), ++ [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1], ++ USIBU1GCLKCTRL), ++ [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2], ++ USIBU2GCLKCTRL), ++ [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3], ++ USIBU3GCLKCTRL), ++ [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL), ++}; ++ ++static int emev2_gclk_enable(struct clk *clk) ++{ ++ iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit), ++ clk->mapped_reg); ++ return 0; ++} ++ ++static void emev2_gclk_disable(struct clk *clk) ++{ ++ iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit), ++ clk->mapped_reg); ++} ++ ++static struct sh_clk_ops emev2_gclk_clk_ops = { ++ .enable = emev2_gclk_enable, ++ .disable = emev2_gclk_disable, ++ .recalc = followparent_recalc, ++}; ++ ++static int __init emev2_gclk_register(struct clk *clks, int nr) ++{ ++ struct clk *clkp; ++ int ret = 0; ++ int k; ++ ++ for (k = 0; !ret && (k < nr); k++) { ++ clkp = clks + k; ++ clkp->ops = &emev2_gclk_clk_ops; ++ ret |= clk_register(clkp); ++ } ++ ++ return ret; ++} ++ ++static unsigned long emev2_sclkdiv_recalc(struct clk *clk) ++{ ++ unsigned int sclk_div; ++ ++ sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff; ++ ++ return clk->parent->rate / (sclk_div + 1); ++} ++ ++static struct sh_clk_ops emev2_sclkdiv_clk_ops = { ++ .recalc = emev2_sclkdiv_recalc, ++}; ++ ++static int __init emev2_sclkdiv_register(struct clk *clks, int nr) ++{ ++ struct clk *clkp; ++ int ret = 0; ++ int k; ++ ++ for (k = 0; !ret && (k < nr); k++) { ++ clkp = clks + k; ++ clkp->ops = &emev2_sclkdiv_clk_ops; ++ ret |= clk_register(clkp); ++ } ++ ++ return ret; ++} ++ ++static struct clk_lookup lookups[] = { ++ CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]), ++ CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]), ++ CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]), ++ CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]), ++ CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]), ++}; ++ ++void __init emev2_clock_init(void) ++{ ++ int k, ret = 0; ++ ++ smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); ++ BUG_ON(!smu_base); ++ ++ /* setup STI timer to run on 37.768 kHz and deassert reset */ ++ emev2_smu_write(0, STI_CLKSEL); ++ emev2_smu_write(1, STI_RSTCTRL); ++ ++ /* deassert reset for UART0->UART3 */ ++ emev2_smu_write(2, USIAU0_RSTCTRL); ++ emev2_smu_write(2, USIBU1_RSTCTRL); ++ emev2_smu_write(2, USIBU2_RSTCTRL); ++ emev2_smu_write(2, USIBU3_RSTCTRL); ++ ++ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) ++ ret = clk_register(main_clks[k]); ++ ++ if (!ret) ++ ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR); ++ ++ if (!ret) ++ ret = emev2_gclk_register(gclk_clks, GCLK_NR); ++ ++ clkdev_add_table(lookups, ARRAY_SIZE(lookups)); ++ ++ if (!ret) ++ shmobile_clk_init(); ++ else ++ panic("failed to setup emev2 clocks\n"); ++} +diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h +new file mode 100644 +index 0000000..92646c1 +--- /dev/null ++++ b/arch/arm/mach-shmobile/include/mach/emev2.h +@@ -0,0 +1,9 @@ ++#ifndef __ASM_EMEV2_H__ ++#define __ASM_EMEV2_H__ ++ ++extern void emev2_init_irq(void); ++extern void emev2_add_early_devices(void); ++extern void emev2_add_standard_devices(void); ++extern void emev2_clock_init(void); ++ ++#endif /* __ASM_EMEV2_H__ */ +diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c +new file mode 100644 +index 0000000..9fff623 +--- /dev/null ++++ b/arch/arm/mach-shmobile/setup-emev2.c +@@ -0,0 +1,180 @@ ++/* ++ * Emma Mobile EV2 processor support ++ * ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/platform_device.h> ++#include <linux/delay.h> ++#include <linux/input.h> ++#include <linux/io.h> ++#include <mach/hardware.h> ++#include <mach/common.h> ++#include <mach/emev2.h> ++#include <mach/irqs.h> ++#include <asm/mach-types.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/time.h> ++#include <asm/hardware/gic.h> ++ ++/* UART */ ++static struct resource uart0_resources[] = { ++ [0] = { ++ .start = 0xe1020000, ++ .end = 0xe1020037, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 40, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device uart0_device = { ++ .name = "serial8250-em", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(uart0_resources), ++ .resource = uart0_resources, ++}; ++ ++static struct resource uart1_resources[] = { ++ [0] = { ++ .start = 0xe1030000, ++ .end = 0xe1030037, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 41, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device uart1_device = { ++ .name = "serial8250-em", ++ .id = 1, ++ .num_resources = ARRAY_SIZE(uart1_resources), ++ .resource = uart1_resources, ++}; ++ ++static struct resource uart2_resources[] = { ++ [0] = { ++ .start = 0xe1040000, ++ .end = 0xe1040037, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 42, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device uart2_device = { ++ .name = "serial8250-em", ++ .id = 2, ++ .num_resources = ARRAY_SIZE(uart2_resources), ++ .resource = uart2_resources, ++}; ++ ++static struct resource uart3_resources[] = { ++ [0] = { ++ .start = 0xe1050000, ++ .end = 0xe1050037, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 43, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device uart3_device = { ++ .name = "serial8250-em", ++ .id = 3, ++ .num_resources = ARRAY_SIZE(uart3_resources), ++ .resource = uart3_resources, ++}; ++ ++/* STI */ ++static struct resource sti_resources[] = { ++ [0] = { ++ .name = "STI", ++ .start = 0xe0180000, ++ .end = 0xe0180053, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 157, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device sti_device = { ++ .name = "em_sti", ++ .id = 0, ++ .resource = sti_resources, ++ .num_resources = ARRAY_SIZE(sti_resources), ++}; ++ ++static struct platform_device *emev2_early_devices[] __initdata = { ++ &uart0_device, ++ &uart1_device, ++ &uart2_device, ++ &uart3_device, ++}; ++ ++static struct platform_device *emev2_late_devices[] __initdata = { ++ &sti_device, ++}; ++ ++void __init emev2_add_standard_devices(void) ++{ ++ emev2_clock_init(); ++ ++ platform_add_devices(emev2_early_devices, ++ ARRAY_SIZE(emev2_early_devices)); ++ ++ platform_add_devices(emev2_late_devices, ++ ARRAY_SIZE(emev2_late_devices)); ++} ++ ++void __init emev2_add_early_devices(void) ++{ ++ shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ ++ ++ early_platform_add_devices(emev2_early_devices, ++ ARRAY_SIZE(emev2_early_devices)); ++ ++ /* setup early console here as well */ ++ shmobile_setup_console(); ++} ++ ++void __init emev2_init_irq(void) ++{ ++ void __iomem *gic_dist_base; ++ void __iomem *gic_cpu_base; ++ ++ /* Static mappings, never released */ ++ gic_dist_base = ioremap(0xe0028000, PAGE_SIZE); ++ gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE); ++ BUG_ON(!gic_dist_base || !gic_cpu_base); ++ ++ /* Use GIC to handle interrupts */ ++ gic_init(0, 29, gic_dist_base, gic_cpu_base); ++} +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0060-mach-shmobile-KZM9D-board-support-V3.patch b/patches.kzm9g/0060-mach-shmobile-KZM9D-board-support-V3.patch new file mode 100644 index 00000000000000..ca4b244a9b6109 --- /dev/null +++ b/patches.kzm9g/0060-mach-shmobile-KZM9D-board-support-V3.patch @@ -0,0 +1,110 @@ +From e11d7a5d8be762494c2bf51a6585f61bdf8b290c Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 16 May 2012 15:45:16 +0900 +Subject: mach-shmobile: KZM9D board support V3 + +V3 of basic KZM9D board support. At this point a quite +thin layer that makes use of the Emma Mobile EV2 SoC code. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit c050fb10c425cf189da5ca9b84e948ec2fc99049) + +Conflicts: + arch/arm/mach-shmobile/Makefile + arch/arm/mach-shmobile/clock-emev2.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/Kconfig | 4 ++++ + arch/arm/mach-shmobile/Makefile | 1 + + arch/arm/mach-shmobile/board-kzm9d.c | 36 ++++++++++++++++++++++++++++++++++ + arch/arm/mach-shmobile/clock-emev2.c | 2 ++ + 4 files changed, 43 insertions(+) + create mode 100644 arch/arm/mach-shmobile/board-kzm9d.c + +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index cabb9af..d4dc4ee 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -92,6 +92,10 @@ config MACH_KZM9G + select ARCH_REQUIRE_GPIOLIB + select SND_SOC_AK4642 if SND_SIMPLE_CARD + ++config MACH_KZM9D ++ bool "KZM9D board" ++ depends on ARCH_EMEV2 ++ + comment "SH-Mobile System Configuration" + + config CPU_HAS_INTEVT +diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile +index 624f721..bdd4383 100644 +--- a/arch/arm/mach-shmobile/Makefile ++++ b/arch/arm/mach-shmobile/Makefile +@@ -47,6 +47,7 @@ obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o + obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o + obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o + obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o ++obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o + + # Framework support + obj-$(CONFIG_SMP) += $(smp-y) +diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c +new file mode 100644 +index 0000000..e743f90 +--- /dev/null ++++ b/arch/arm/mach-shmobile/board-kzm9d.c +@@ -0,0 +1,36 @@ ++/* ++ * kzm9d board support ++ * ++ * Copyright (C) 2012 Renesas Solutions Corp. ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/interrupt.h> ++#include <mach/common.h> ++#include <mach/emev2.h> ++#include <asm/mach-types.h> ++#include <asm/mach/arch.h> ++#include <asm/hardware/gic.h> ++ ++MACHINE_START(KZM9D, "kzm9d") ++ .init_early = emev2_add_early_devices, ++ .nr_irqs = NR_IRQS_LEGACY, ++ .init_irq = emev2_init_irq, ++ .handle_irq = gic_handle_irq, ++ .init_machine = emev2_add_standard_devices, ++ .timer = &shmobile_timer, ++MACHINE_END +diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c +index 73a1216..64d4a56 100644 +--- a/arch/arm/mach-shmobile/clock-emev2.c ++++ b/arch/arm/mach-shmobile/clock-emev2.c +@@ -84,6 +84,8 @@ static struct clk *main_clks[] = { + enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3, + SCLKDIV_NR }; + ++#define IOMEM(x) ((void __force __iomem *)(x)) ++ + #define SCLKDIV(_reg, _shift) \ + { \ + .parent = &pll3_clk, \ +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0061-mach-shmobile-Emma-Mobile-EV2-SMP-support-V3.patch b/patches.kzm9g/0061-mach-shmobile-Emma-Mobile-EV2-SMP-support-V3.patch new file mode 100644 index 00000000000000..12ddf536a6297b --- /dev/null +++ b/patches.kzm9g/0061-mach-shmobile-Emma-Mobile-EV2-SMP-support-V3.patch @@ -0,0 +1,329 @@ +From 0af702823eae60eceedd80cbd4bd0670285a2cca Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 16 May 2012 15:45:25 +0900 +Subject: mach-shmobile: Emma Mobile EV2 SMP support V3 + +This is V3 of Emma Mobile EV2 SMP support. + +At this point only the most basic form of SMP operation +is supported. TWD and CPU Hotplug support is excluded. + +Tied to both the Emma Mobile EV2 and the KZM9D board +due to the need to switch on board in platsmp.c and +the newly introduced need for static mappings. + +The static mappings are needed to allow hardware +acces early during boot when SMP is initialized. +This early requirement forces us to also map in +the SMU registers. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit bd5a875d90c878be4d23f54ea565253734ae2377) + +Conflicts: + arch/arm/mach-shmobile/Makefile + arch/arm/mach-shmobile/platsmp.c + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/Makefile | 1 + + arch/arm/mach-shmobile/board-kzm9d.c | 1 + + arch/arm/mach-shmobile/clock-emev2.c | 18 +++++ + arch/arm/mach-shmobile/include/mach/emev2.h | 7 ++ + arch/arm/mach-shmobile/platsmp.c | 17 +++++ + arch/arm/mach-shmobile/setup-emev2.c | 24 +++++++ + arch/arm/mach-shmobile/smp-emev2.c | 97 +++++++++++++++++++++++++++ + 7 files changed, 165 insertions(+) + create mode 100644 arch/arm/mach-shmobile/smp-emev2.c + +diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile +index bdd4383..a2c56d5 100644 +--- a/arch/arm/mach-shmobile/Makefile ++++ b/arch/arm/mach-shmobile/Makefile +@@ -18,6 +18,7 @@ smp-y := platsmp.o headsmp.o + smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o + smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o + smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o ++smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o + + # Pinmux setup + pfc-y := +diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c +index e743f90..42fc479 100644 +--- a/arch/arm/mach-shmobile/board-kzm9d.c ++++ b/arch/arm/mach-shmobile/board-kzm9d.c +@@ -27,6 +27,7 @@ + #include <asm/hardware/gic.h> + + MACHINE_START(KZM9D, "kzm9d") ++ .map_io = emev2_map_io, + .init_early = emev2_add_early_devices, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = emev2_init_irq, +diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c +index 64d4a56..9414383 100644 +--- a/arch/arm/mach-shmobile/clock-emev2.c ++++ b/arch/arm/mach-shmobile/clock-emev2.c +@@ -40,6 +40,7 @@ + #define USIB2SCLKDIV 0x65c + #define USIB3SCLKDIV 0x660 + #define STI_CLKSEL 0x688 ++#define SMU_GENERAL_REG0 0x7c0 + + /* not pretty, but hey */ + static void __iomem *smu_base; +@@ -50,6 +51,11 @@ static void emev2_smu_write(unsigned long value, int offs) + iowrite32(value, smu_base + offs); + } + ++void emev2_set_boot_vector(unsigned long value) ++{ ++ emev2_smu_write(value, SMU_GENERAL_REG0); ++} ++ + static struct clk_mapping smu_mapping = { + .phys = EMEV2_SMU_BASE, + .len = PAGE_SIZE, +@@ -196,6 +202,18 @@ static struct clk_lookup lookups[] = { + void __init emev2_clock_init(void) + { + int k, ret = 0; ++ static int is_setup; ++ ++ /* yuck, this is ugly as hell, but the non-smp case of clocks ++ * code is now designed to rely on ioremap() instead of static ++ * entity maps. in the case of smp we need access to the SMU ++ * register earlier than ioremap() is actually working without ++ * any static maps. to enable SMP in ugly but with dynamic ++ * mappings we have to call emev2_clock_init() from different ++ * places depending on UP and SMP... ++ */ ++ if (is_setup++) ++ return; + + smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); + BUG_ON(!smu_base); +diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h +index 92646c1..3fc7184 100644 +--- a/arch/arm/mach-shmobile/include/mach/emev2.h ++++ b/arch/arm/mach-shmobile/include/mach/emev2.h +@@ -1,9 +1,16 @@ + #ifndef __ASM_EMEV2_H__ + #define __ASM_EMEV2_H__ + ++extern void emev2_map_io(void); + extern void emev2_init_irq(void); + extern void emev2_add_early_devices(void); + extern void emev2_add_standard_devices(void); + extern void emev2_clock_init(void); ++extern void emev2_set_boot_vector(unsigned long value); ++extern unsigned int emev2_get_core_count(void); ++extern int emev2_platform_cpu_kill(unsigned int cpu); ++extern void emev2_secondary_init(unsigned int cpu); ++extern int emev2_boot_secondary(unsigned int cpu); ++extern void emev2_smp_prepare_cpus(void); + + #endif /* __ASM_EMEV2_H__ */ +diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c +index 1103ce5..9e98f9e 100644 +--- a/arch/arm/mach-shmobile/platsmp.c ++++ b/arch/arm/mach-shmobile/platsmp.c +@@ -20,14 +20,19 @@ + #include <asm/localtimer.h> + #include <asm/mach-types.h> + #include <mach/common.h> ++#include <mach/emev2.h> + + #define is_sh73a0() (machine_is_ag5evm() || machine_is_kzm9g()) ++#define is_emev2() machine_is_kzm9d() + + static unsigned int __init shmobile_smp_get_core_count(void) + { + if (is_sh73a0()) + return sh73a0_get_core_count(); + ++ if (is_emev2()) ++ return emev2_get_core_count(); ++ + return 1; + } + +@@ -35,10 +40,16 @@ static void __init shmobile_smp_prepare_cpus(void) + { + if (is_sh73a0()) + sh73a0_smp_prepare_cpus(); ++ ++ if (is_emev2()) ++ emev2_smp_prepare_cpus(); + } + + int shmobile_platform_cpu_kill(unsigned int cpu) + { ++ if (is_emev2()) ++ return emev2_platform_cpu_kill(cpu); ++ + return 1; + } + +@@ -48,6 +59,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu) + + if (is_sh73a0()) + sh73a0_secondary_init(cpu); ++ ++ if (is_emev2()) ++ emev2_secondary_init(cpu); + } + + int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +@@ -55,6 +69,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) + if (is_sh73a0()) + return sh73a0_boot_secondary(cpu); + ++ if (is_emev2()) ++ return emev2_boot_secondary(cpu); ++ + return -ENOSYS; + } + +diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c +index 9fff623..2a03a78 100644 +--- a/arch/arm/mach-shmobile/setup-emev2.c ++++ b/arch/arm/mach-shmobile/setup-emev2.c +@@ -34,6 +34,30 @@ + #include <asm/mach/time.h> + #include <asm/hardware/gic.h> + ++static struct map_desc emev2_io_desc[] __initdata = { ++#ifdef CONFIG_SMP ++ /* 128K entity map for 0xe0100000 (SMU) */ ++ { ++ .virtual = 0xe0100000, ++ .pfn = __phys_to_pfn(0xe0100000), ++ .length = SZ_128K, ++ .type = MT_DEVICE ++ }, ++ /* 2M mapping for SCU + L2 controller */ ++ { ++ .virtual = 0xf0000000, ++ .pfn = __phys_to_pfn(0x1e000000), ++ .length = SZ_2M, ++ .type = MT_DEVICE ++ }, ++#endif ++}; ++ ++void __init emev2_map_io(void) ++{ ++ iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc)); ++} ++ + /* UART */ + static struct resource uart0_resources[] = { + [0] = { +diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c +new file mode 100644 +index 0000000..6a35c4a +--- /dev/null ++++ b/arch/arm/mach-shmobile/smp-emev2.c +@@ -0,0 +1,97 @@ ++/* ++ * SMP support for Emma Mobile EV2 ++ * ++ * Copyright (C) 2012 Renesas Solutions Corp. ++ * Copyright (C) 2012 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/spinlock.h> ++#include <linux/io.h> ++#include <linux/delay.h> ++#include <mach/common.h> ++#include <mach/emev2.h> ++#include <asm/smp_plat.h> ++#include <asm/smp_scu.h> ++#include <asm/hardware/gic.h> ++#include <asm/cacheflush.h> ++ ++#define EMEV2_SCU_BASE 0x1e000000 ++ ++static DEFINE_SPINLOCK(scu_lock); ++static void __iomem *scu_base; ++ ++static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) ++{ ++ unsigned long tmp; ++ ++ /* we assume this code is running on a different cpu ++ * than the one that is changing coherency setting */ ++ spin_lock(&scu_lock); ++ tmp = readl(scu_base + 8); ++ tmp &= ~clr; ++ tmp |= set; ++ writel(tmp, scu_base + 8); ++ spin_unlock(&scu_lock); ++ ++} ++ ++unsigned int __init emev2_get_core_count(void) ++{ ++ if (!scu_base) { ++ scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); ++ emev2_clock_init(); /* need ioremapped SMU */ ++ } ++ ++ WARN_ON_ONCE(!scu_base); ++ ++ return scu_base ? scu_get_core_count(scu_base) : 1; ++} ++ ++int emev2_platform_cpu_kill(unsigned int cpu) ++{ ++ return 0; /* not supported yet */ ++} ++ ++void __cpuinit emev2_secondary_init(unsigned int cpu) ++{ ++ gic_secondary_init(0); ++} ++ ++int __cpuinit emev2_boot_secondary(unsigned int cpu) ++{ ++ cpu = cpu_logical_map(cpu); ++ ++ /* enable cache coherency */ ++ modify_scu_cpu_psr(0, 3 << (cpu * 8)); ++ ++ /* Tell ROM loader about our vector (in headsmp.S) */ ++ emev2_set_boot_vector(__pa(shmobile_secondary_vector)); ++ ++ gic_raise_softirq(cpumask_of(cpu), 1); ++ return 0; ++} ++ ++void __init emev2_smp_prepare_cpus(void) ++{ ++ int cpu = cpu_logical_map(0); ++ ++ scu_enable(scu_base); ++ ++ /* enable cache coherency on CPU0 */ ++ modify_scu_cpu_psr(0, 3 << (cpu * 8)); ++} +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0062-mach-shmobile-Emma-Mobile-EV2-GPIO-support-V3.patch b/patches.kzm9g/0062-mach-shmobile-Emma-Mobile-EV2-GPIO-support-V3.patch new file mode 100644 index 00000000000000..7604f5b5fbef4e --- /dev/null +++ b/patches.kzm9g/0062-mach-shmobile-Emma-Mobile-EV2-GPIO-support-V3.patch @@ -0,0 +1,280 @@ +From dbf1eecc80eac3500e8456e46d12601641756cd1 Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 16 May 2012 15:45:34 +0900 +Subject: mach-shmobile: Emma Mobile EV2 GPIO support V3 + +Tie in the Emma Mobile GPIO driver "em-gio" to +support the GPIOs on Emma Mobile EV2. + +A static IRQ range is used to allow boards to +hook up their platform devices to the GPIOs. + +DT support is still on the TODO for the GPIO driver, +so only platform device support is included here. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit 088efd9273b5076a0aead479aa31f1066d182b3e) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/Kconfig | 1 + + arch/arm/mach-shmobile/include/mach/emev2.h | 3 + + arch/arm/mach-shmobile/setup-emev2.c | 203 +++++++++++++++++++++++++++ + 3 files changed, 207 insertions(+) + +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index d4dc4ee..4ce90f3 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -37,6 +37,7 @@ config ARCH_EMEV2 + bool "Emma Mobile EV2" + select CPU_V7 + select ARM_GIC ++ select ARCH_WANT_OPTIONAL_GPIOLIB + + comment "SH-Mobile Board Type" + +diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h +index 3fc7184..e6b0c1b 100644 +--- a/arch/arm/mach-shmobile/include/mach/emev2.h ++++ b/arch/arm/mach-shmobile/include/mach/emev2.h +@@ -13,4 +13,7 @@ extern void emev2_secondary_init(unsigned int cpu); + extern int emev2_boot_secondary(unsigned int cpu); + extern void emev2_smp_prepare_cpus(void); + ++#define EMEV2_GPIO_BASE 200 ++#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n)) ++ + #endif /* __ASM_EMEV2_H__ */ +diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c +index 2a03a78..d40fede 100644 +--- a/arch/arm/mach-shmobile/setup-emev2.c ++++ b/arch/arm/mach-shmobile/setup-emev2.c +@@ -21,6 +21,7 @@ + #include <linux/interrupt.h> + #include <linux/irq.h> + #include <linux/platform_device.h> ++#include <linux/platform_data/gpio-em.h> + #include <linux/delay.h> + #include <linux/input.h> + #include <linux/io.h> +@@ -156,6 +157,203 @@ static struct platform_device sti_device = { + .num_resources = ARRAY_SIZE(sti_resources), + }; + ++ ++/* GIO */ ++static struct gpio_em_config gio0_config = { ++ .gpio_base = 0, ++ .irq_base = EMEV2_GPIO_IRQ(0), ++ .number_of_pins = 32, ++}; ++ ++static struct resource gio0_resources[] = { ++ [0] = { ++ .name = "GIO_000", ++ .start = 0xe0050000, ++ .end = 0xe005002b, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "GIO_000", ++ .start = 0xe0050040, ++ .end = 0xe005005f, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = 99, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = 100, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device gio0_device = { ++ .name = "em_gio", ++ .id = 0, ++ .resource = gio0_resources, ++ .num_resources = ARRAY_SIZE(gio0_resources), ++ .dev = { ++ .platform_data = &gio0_config, ++ }, ++}; ++ ++static struct gpio_em_config gio1_config = { ++ .gpio_base = 32, ++ .irq_base = EMEV2_GPIO_IRQ(32), ++ .number_of_pins = 32, ++}; ++ ++static struct resource gio1_resources[] = { ++ [0] = { ++ .name = "GIO_032", ++ .start = 0xe0050080, ++ .end = 0xe00500ab, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "GIO_032", ++ .start = 0xe00500c0, ++ .end = 0xe00500df, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = 101, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = 102, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device gio1_device = { ++ .name = "em_gio", ++ .id = 1, ++ .resource = gio1_resources, ++ .num_resources = ARRAY_SIZE(gio1_resources), ++ .dev = { ++ .platform_data = &gio1_config, ++ }, ++}; ++ ++static struct gpio_em_config gio2_config = { ++ .gpio_base = 64, ++ .irq_base = EMEV2_GPIO_IRQ(64), ++ .number_of_pins = 32, ++}; ++ ++static struct resource gio2_resources[] = { ++ [0] = { ++ .name = "GIO_064", ++ .start = 0xe0050100, ++ .end = 0xe005012b, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "GIO_064", ++ .start = 0xe0050140, ++ .end = 0xe005015f, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = 103, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = 104, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device gio2_device = { ++ .name = "em_gio", ++ .id = 2, ++ .resource = gio2_resources, ++ .num_resources = ARRAY_SIZE(gio2_resources), ++ .dev = { ++ .platform_data = &gio2_config, ++ }, ++}; ++ ++static struct gpio_em_config gio3_config = { ++ .gpio_base = 96, ++ .irq_base = EMEV2_GPIO_IRQ(96), ++ .number_of_pins = 32, ++}; ++ ++static struct resource gio3_resources[] = { ++ [0] = { ++ .name = "GIO_096", ++ .start = 0xe0050100, ++ .end = 0xe005012b, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "GIO_096", ++ .start = 0xe0050140, ++ .end = 0xe005015f, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = 105, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = 106, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device gio3_device = { ++ .name = "em_gio", ++ .id = 3, ++ .resource = gio3_resources, ++ .num_resources = ARRAY_SIZE(gio3_resources), ++ .dev = { ++ .platform_data = &gio3_config, ++ }, ++}; ++ ++static struct gpio_em_config gio4_config = { ++ .gpio_base = 128, ++ .irq_base = EMEV2_GPIO_IRQ(128), ++ .number_of_pins = 31, ++}; ++ ++static struct resource gio4_resources[] = { ++ [0] = { ++ .name = "GIO_128", ++ .start = 0xe0050200, ++ .end = 0xe005022b, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "GIO_128", ++ .start = 0xe0050240, ++ .end = 0xe005025f, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = 107, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = 108, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device gio4_device = { ++ .name = "em_gio", ++ .id = 4, ++ .resource = gio4_resources, ++ .num_resources = ARRAY_SIZE(gio4_resources), ++ .dev = { ++ .platform_data = &gio4_config, ++ }, ++}; ++ + static struct platform_device *emev2_early_devices[] __initdata = { + &uart0_device, + &uart1_device, +@@ -165,6 +363,11 @@ static struct platform_device *emev2_early_devices[] __initdata = { + + static struct platform_device *emev2_late_devices[] __initdata = { + &sti_device, ++ &gio0_device, ++ &gio1_device, ++ &gio2_device, ++ &gio3_device, ++ &gio4_device, + }; + + void __init emev2_add_standard_devices(void) +-- +1.7.10.1.362.g242cab3 + diff --git a/patches.kzm9g/0063-mach-shmobile-KZM9D-board-Ethernet-support-V3.patch b/patches.kzm9g/0063-mach-shmobile-KZM9D-board-Ethernet-support-V3.patch new file mode 100644 index 00000000000000..78f4bbc6106e82 --- /dev/null +++ b/patches.kzm9g/0063-mach-shmobile-KZM9D-board-Ethernet-support-V3.patch @@ -0,0 +1,82 @@ +From adaf8f8c3a969904f01b38f842fb7416858ea4cc Mon Sep 17 00:00:00 2001 +From: Magnus Damm <damm@opensource.se> +Date: Wed, 16 May 2012 15:45:42 +0900 +Subject: mach-shmobile: KZM9D board Ethernet support V3 + +Tie in the on-board Ethernet controller on KZM9D +and make use of the GPIO controller for external +IRQ pin support. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +(cherry picked from commit 0c73f7bc124e1657a583d9dfb0d168a69005e2d3) + +Signed-off-by: Simon Horman <horms@verge.net.au> +--- + arch/arm/mach-shmobile/board-kzm9d.c | 44 ++++++++++++++++++++++++++++++++++- + 1 file changed, 43 insertions(+), 1 deletion(-) + +--- a/arch/arm/mach-shmobile/board-kzm9d.c ++++ b/arch/arm/mach-shmobile/board-kzm9d.c +@@ -20,18 +20,60 @@ + + #include <linux/kernel.h> + #include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/smsc911x.h> + #include <mach/common.h> + #include <mach/emev2.h> + #include <asm/mach-types.h> + #include <asm/mach/arch.h> + #include <asm/hardware/gic.h> + ++/* Ether */ ++static struct resource smsc911x_resources[] = { ++ [0] = { ++ .start = 0x20000000, ++ .end = 0x2000ffff, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = EMEV2_GPIO_IRQ(1), ++ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH, ++ }, ++}; ++ ++static struct smsc911x_platform_config smsc911x_platdata = { ++ .flags = SMSC911X_USE_32BIT, ++ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, ++ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, ++}; ++ ++static struct platform_device smsc91x_device = { ++ .name = "smsc911x", ++ .id = 0, ++ .dev = { ++ .platform_data = &smsc911x_platdata, ++ }, ++ .num_resources = ARRAY_SIZE(smsc911x_resources), ++ .resource = smsc911x_resources, ++}; ++ ++static struct platform_device *kzm9d_devices[] __initdata = { ++ &smsc91x_device, ++}; ++ ++void __init kzm9d_add_standard_devices(void) ++{ ++ emev2_add_standard_devices(); ++ ++ platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices)); ++} ++ + MACHINE_START(KZM9D, "kzm9d") + .map_io = emev2_map_io, + .init_early = emev2_add_early_devices, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = emev2_init_irq, + .handle_irq = gic_handle_irq, +- .init_machine = emev2_add_standard_devices, ++ .init_machine = kzm9d_add_standard_devices, + .timer = &shmobile_timer, + MACHINE_END @@ -791,3 +791,69 @@ patches.kzm9g/0202-ARM-mach-shmobile-kzm9g-add-PCF8757-gpio-key.patch patches.kzm9g/0203-ARM-mach-shmobile-kzm9g-defconfig-update.patch patches.kzm9g/0204-ARM-mach-shmobile-clock-sh73a0-add-FSI-clock.patch patches.kzm9g/0205-ARM-mach-shmobile-kzm9g-add-FSI-AK4648-support.patch + +patches.kzm9g/0001-tty-serial-allow-ports-to-override-the-irq-handler.patch +patches.kzm9g/0002-serial-introduce-generic-port-in-out-helpers.patch +patches.kzm9g/0003-serial-8250-increase-PASS_LIMIT.patch +patches.kzm9g/0004-serial-Fix-wakeup-init-logic-to-speed-up-startup.patch +patches.kzm9g/0005-tty-serial8250-allow-platforms-to-override-irq-handl.patch +patches.kzm9g/0006-tty-serial8250-remove-UPIO_DWAPB-32.patch +patches.kzm9g/0007-tty-8250-export-serial8250_handle_irq.patch +patches.kzm9g/0008-serial-8250-Move-UPIO_TSI-to-powerpc.patch +patches.kzm9g/0009-serial-Support-the-EFR-register-of-XR1715x-uarts.patch +patches.kzm9g/0010-8250-ratelimit-LSR-safety-check-engaged-warning.patch +patches.kzm9g/0011-serial-8250-replace-hardcoded-0xbf-with-define.patch +patches.kzm9g/0012-serial-move-struct-uart_8250_port-from-8250.c-to-825.patch +patches.kzm9g/0013-serial-clean-up-parameter-passing-for-8250-Rx-IRQ-ha.patch +patches.kzm9g/0014-serial-export-the-key-functions-for-an-8250-IRQ-hand.patch +patches.kzm9g/0015-serial-make-8250-timeout-use-the-specified-IRQ-handl.patch +patches.kzm9g/0016-serial-manually-inline-serial8250_handle_port.patch +patches.kzm9g/0017-serial-group-all-the-8250-related-code-together.patch +patches.kzm9g/0018-serial-Kill-off-NO_IRQ.patch +patches.kzm9g/0019-tty-fix-a-build-failure-on-sparc.patch +patches.kzm9g/0020-tty-sparc-rename-drivers-tty-serial-suncore.h-includ.patch +patches.kzm9g/0021-serial-delete-last-unused-traces-of-pausing-I-O-in-8.patch +patches.kzm9g/0022-serial-make-8250-s-serial_in-shareable-to-other-driv.patch +patches.kzm9g/0023-serial-delete-useless-void-casts-in-8250.c.patch +patches.kzm9g/0024-serial-reduce-number-of-indirections-in-8250-code.patch +patches.kzm9g/0025-serial-use-serial_port_in-out-vs-serial_in-out-in-82.patch +patches.kzm9g/0026-serial-remove-back-and-forth-conversions-in-serial_o.patch +patches.kzm9g/0027-serial-8250_pci-add-a-force-background-timer-flag-an.patch +patches.kzm9g/0028-8250.c-less-than-2400-baud-fix.patch +patches.kzm9g/0029-serial8250-Add-dl_read-dl_write-callbacks.patch +patches.kzm9g/0030-serial8250-Use-dl_read-dl_write-on-Alchemy.patch +patches.kzm9g/0031-serial8250-Use-dl_read-dl_write-on-RM9K.patch +patches.kzm9g/0032-serial8250-Clean-up-default-map-and-dl-code.patch +patches.kzm9g/0033-serial8250-Introduce-serial8250_register_8250_port.patch +patches.kzm9g/0034-serial8250-em-Emma-Mobile-UART-driver-V2.patch +patches.kzm9g/0035-serial8250-em-clk_get-IS_ERR-error-handling-fix.patch +patches.kzm9g/0036-cpuidle-create-bootparam-cpuidle.off-1.patch +patches.kzm9g/0037-cpuidle-replace-xen-access-to-x86-pm_idle-and-defaul.patch +patches.kzm9g/0038-cpuidle-stop-depending-on-pm_idle.patch +patches.kzm9g/0039-cpuidle-Consistent-spelling-of-cpuidle_idle_call.patch +patches.kzm9g/0040-sh-Fix-up-fallout-from-cpuidle-changes.patch +patches.kzm9g/0041-cpuidle-Add-module.h-to-drivers-cpuidle-files-as-req.patch +patches.kzm9g/0042-cpuidle-Move-dev-last_residency-update-to-driver-ent.patch +patches.kzm9g/0043-cpuidle-Remove-CPUIDLE_FLAG_IGNORE-and-dev-prepare.patch +patches.kzm9g/0044-cpuidle-Split-cpuidle_state-structure-and-move-per-c.patch +patches.kzm9g/0045-cpuidle-Single-Global-registration-of-idle-states.patch +patches.kzm9g/0046-cpuidle-Add-common-time-keeping-and-irq-enabling.patch +patches.kzm9g/0047-mm-add-vm_area_add_early.patch +patches.kzm9g/0048-clockevents-Make-clockevents_config-a-global-symbol.patch +patches.kzm9g/0049-clocksource-em_sti-Emma-Mobile-STI-driver-V2.patch +patches.kzm9g/0050-ARM-move-initialization-of-the-high_memory-variable-.patch +patches.kzm9g/0051-ARM-move-iotable-mappings-within-the-vmalloc-region.patch +patches.kzm9g/0052-ARM-simplify-__iounmap-when-dealing-with-section-bas.patch +patches.kzm9g/0053-ARM-add-generic-ioremap-optimization-by-reusing-stat.patch +patches.kzm9g/0054-ARM-mach-shmobile-Introduce-shmobile_setup_delay.patch +patches.kzm9g/0055-ARM-mach-shmobile-Allow-SoC-specific-CPU-kill-code.patch +patches.kzm9g/0056-ARM-mach-shmobile-Use-preset_lpj-with-calibrate_dela.patch +patches.kzm9g/0057-ARM-Undelete-KZM9D-mach-type.patch +patches.kzm9g/0058-gpio-Emma-Mobile-GPIO-driver.patch +patches.kzm9g/0059-mach-shmobile-Emma-Mobile-EV2-SoC-base-support-V3.patch +patches.kzm9g/0060-mach-shmobile-KZM9D-board-support-V3.patch +patches.kzm9g/0061-mach-shmobile-Emma-Mobile-EV2-SMP-support-V3.patch +patches.kzm9g/0062-mach-shmobile-Emma-Mobile-EV2-GPIO-support-V3.patch +patches.kzm9g/0063-mach-shmobile-KZM9D-board-Ethernet-support-V3.patch + + |