]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
drop niagra hv console patch because it's too big for -stable
authorChris Wright <chrisw@sous-sol.org>
Thu, 7 Jun 2007 18:38:59 +0000 (11:38 -0700)
committerChris Wright <chrisw@sous-sol.org>
Thu, 7 Jun 2007 18:38:59 +0000 (11:38 -0700)
queue-2.6.20/series
queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch [deleted file]

index afe61756cea8d42c85d08fa5d4e99f7a642e0759..74f6e97d19219b6a558fafb0a76afe1a3b0b293e 100644 (file)
@@ -24,7 +24,6 @@ ipv4-correct-rp_filter-help-text.patch
 sparc-linux-always-started-with-9600-8n1.patch
 net-wrong-timeout-value-in-sk_wait_data-v2.patch
 sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch
-sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch
 sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch
 tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch
 net-fix-race-condition-about-network-device-name-allocation.patch
diff --git a/queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch b/queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch
deleted file mode 100644 (file)
index e93fb10..0000000
+++ /dev/null
@@ -1,879 +0,0 @@
-From stable-bounces@linux.kernel.org  Wed Jun  6 22:54:25 2007
-Date: Wed, 06 Jun 2007 22:54:33 -0700 (PDT)
-Message-Id: <20070606.225433.58454202.davem@davemloft.net>
-To: stable@kernel.org
-From: David Miller <davem@davemloft.net>
-Cc: bunk@stusta.de
-Subject: SPARC64: Add hypervisor API negotiation and fix console bugs.
-
-Hypervisor interfaces need to be negotiated in order to use
-some API calls reliably.  So add a small set of interfaces
-to request API versions and query current settings.
-
-This allows us to fix some bugs in the hypervisor console:
-
-1) If we can negotiate API group CORE of at least major 1
-   minor 1 we can use con_read and con_write which can improve
-   console performance quite a bit.
-
-2) When we do a console write request, we should hold the
-   spinlock around the whole request, not a byte at a time.
-   What would happen is that it's easy for output from
-   different cpus to get mixed with each other.
-
-3) Use consistent udelay() based polling, udelay(1) each
-   loop with a limit of 1000 polls to handle stuck hypervisor
-   console.
-
-Signed-off-by: David S. Miller <davem@davemloft.net>
-Signed-off-by: Chris Wright <chrisw@sous-sol.org>
-
----
- arch/sparc64/kernel/Makefile     |    2 
- arch/sparc64/kernel/entry.S      |   94 +++++++++++++
- arch/sparc64/kernel/hvapi.c      |  189 ++++++++++++++++++++++++++
- arch/sparc64/kernel/setup.c      |    3 
- drivers/serial/sunhv.c           |  276 ++++++++++++++++++++++++++++-----------
- include/asm-sparc64/hypervisor.h |   83 +++++++++++
- 6 files changed, 574 insertions(+), 73 deletions(-)
-
---- linux-2.6.20.12.orig/arch/sparc64/kernel/Makefile
-+++ linux-2.6.20.12/arch/sparc64/kernel/Makefile
-@@ -12,7 +12,7 @@ obj-y                := process.o setup.o cpu.o idprom
-                  irq.o ptrace.o time.o sys_sparc.o signal.o \
-                  unaligned.o central.o pci.o starfire.o semaphore.o \
-                  power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
--                 visemul.o prom.o of_device.o
-+                 visemul.o prom.o of_device.o hvapi.o
- obj-$(CONFIG_STACKTRACE) += stacktrace.o
- obj-$(CONFIG_PCI)      += ebus.o isa.o pci_common.o pci_iommu.o \
---- linux-2.6.20.12.orig/arch/sparc64/kernel/entry.S
-+++ linux-2.6.20.12/arch/sparc64/kernel/entry.S
-@@ -1843,3 +1843,97 @@ sun4v_cpu_state:
-       mov     %o1, %o0
- 1:    retl
-        nop
-+
-+      /* %o0: API group number
-+       * %o1: pointer to unsigned long major number storage
-+       * %o2: pointer to unsigned long minor number storage
-+       *
-+       * returns %o0: status
-+       */
-+      .globl  sun4v_get_version
-+sun4v_get_version:
-+      mov     HV_CORE_GET_VER, %o5
-+      mov     %o1, %o3
-+      mov     %o2, %o4
-+      ta      HV_CORE_TRAP
-+      stx     %o1, [%o3]
-+      retl
-+       stx    %o2, [%o4]
-+
-+      /* %o0: API group number
-+       * %o1: desired major number
-+       * %o2: desired minor number
-+       * %o3: pointer to unsigned long actual minor number storage
-+       *
-+       * returns %o0: status
-+       */
-+      .globl  sun4v_set_version
-+sun4v_set_version:
-+      mov     HV_CORE_SET_VER, %o5
-+      mov     %o3, %o4
-+      ta      HV_CORE_TRAP
-+      retl
-+       stx    %o1, [%o4]
-+
-+      /* %o0: pointer to unsigned long status
-+       *
-+       * returns %o0: signed character
-+       */
-+      .globl  sun4v_con_getchar
-+sun4v_con_getchar:
-+      mov     %o0, %o4
-+      mov     HV_FAST_CONS_GETCHAR, %o5
-+      clr     %o0
-+      clr     %o1
-+      ta      HV_FAST_TRAP
-+      stx     %o0, [%o4]
-+      retl
-+       sra    %o1, 0, %o0
-+
-+      /* %o0: signed long character
-+       *
-+       * returns %o0: status
-+       */
-+      .globl  sun4v_con_putchar
-+sun4v_con_putchar:
-+      mov     HV_FAST_CONS_PUTCHAR, %o5
-+      ta      HV_FAST_TRAP
-+      retl
-+       sra    %o0, 0, %o0
-+
-+      /* %o0: buffer real address
-+       * %o1: buffer size
-+       * %o2: pointer to unsigned long bytes_read
-+       *
-+       * returns %o0: status
-+       */
-+      .globl  sun4v_con_read
-+sun4v_con_read:
-+      mov     %o2, %o4
-+      mov     HV_FAST_CONS_READ, %o5
-+      ta      HV_FAST_TRAP
-+      brnz    %o0, 1f
-+       cmp    %o1, -1         /* break */
-+      be,a,pn %icc, 1f
-+       mov    %o1, %o0
-+      cmp     %o1, -2         /* hup */
-+      be,a,pn %icc, 1f
-+       mov    %o1, %o0
-+      stx     %o1, [%o4]
-+1:    retl
-+       nop
-+
-+      /* %o0: buffer real address
-+       * %o1: buffer size
-+       * %o2: pointer to unsigned long bytes_written
-+       *
-+       * returns %o0: status
-+       */
-+      .globl  sun4v_con_write
-+sun4v_con_write:
-+      mov     %o2, %o4
-+      mov     HV_FAST_CONS_WRITE, %o5
-+      ta      HV_FAST_TRAP
-+      stx     %o1, [%o4]
-+      retl
-+       nop
---- /dev/null
-+++ linux-2.6.20.12/arch/sparc64/kernel/hvapi.c
-@@ -0,0 +1,189 @@
-+/* hvapi.c: Hypervisor API management.
-+ *
-+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
-+ */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+
-+#include <asm/hypervisor.h>
-+#include <asm/oplib.h>
-+
-+/* If the hypervisor indicates that the API setting
-+ * calls are unsupported, by returning HV_EBADTRAP or
-+ * HV_ENOTSUPPORTED, we assume that API groups with the
-+ * PRE_API flag set are major 1 minor 0.
-+ */
-+struct api_info {
-+      unsigned long group;
-+      unsigned long major;
-+      unsigned long minor;
-+      unsigned int refcnt;
-+      unsigned int flags;
-+#define FLAG_PRE_API          0x00000001
-+};
-+
-+static struct api_info api_table[] = {
-+      { .group = HV_GRP_SUN4V,        .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_CORE,         .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_INTR,                                 },
-+      { .group = HV_GRP_SOFT_STATE,                           },
-+      { .group = HV_GRP_PCI,          .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_LDOM,                                 },
-+      { .group = HV_GRP_SVC_CHAN,     .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_NCS,          .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_NIAG_PERF,    .flags = FLAG_PRE_API   },
-+      { .group = HV_GRP_FIRE_PERF,                            },
-+      { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
-+};
-+
-+static DEFINE_SPINLOCK(hvapi_lock);
-+
-+static struct api_info *__get_info(unsigned long group)
-+{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(api_table); i++) {
-+              if (api_table[i].group == group)
-+                      return &api_table[i];
-+      }
-+      return NULL;
-+}
-+
-+static void __get_ref(struct api_info *p)
-+{
-+      p->refcnt++;
-+}
-+
-+static void __put_ref(struct api_info *p)
-+{
-+      if (--p->refcnt == 0) {
-+              unsigned long ignore;
-+
-+              sun4v_set_version(p->group, 0, 0, &ignore);
-+              p->major = p->minor = 0;
-+      }
-+}
-+
-+/* Register a hypervisor API specification.  It indicates the
-+ * API group and desired major+minor.
-+ *
-+ * If an existing API registration exists '0' (success) will
-+ * be returned if it is compatible with the one being registered.
-+ * Otherwise a negative error code will be returned.
-+ *
-+ * Otherwise an attempt will be made to negotiate the requested
-+ * API group/major/minor with the hypervisor, and errors returned
-+ * if that does not succeed.
-+ */
-+int sun4v_hvapi_register(unsigned long group, unsigned long major,
-+                       unsigned long *minor)
-+{
-+      struct api_info *p;
-+      unsigned long flags;
-+      int ret;
-+
-+      spin_lock_irqsave(&hvapi_lock, flags);
-+      p = __get_info(group);
-+      ret = -EINVAL;
-+      if (p) {
-+              if (p->refcnt) {
-+                      ret = -EINVAL;
-+                      if (p->major == major) {
-+                              *minor = p->minor;
-+                              ret = 0;
-+                      }
-+              } else {
-+                      unsigned long actual_minor;
-+                      unsigned long hv_ret;
-+
-+                      hv_ret = sun4v_set_version(group, major, *minor,
-+                                                 &actual_minor);
-+                      ret = -EINVAL;
-+                      if (hv_ret == HV_EOK) {
-+                              *minor = actual_minor;
-+                              p->major = major;
-+                              p->minor = actual_minor;
-+                              ret = 0;
-+                      } else if (hv_ret == HV_EBADTRAP ||
-+                                 HV_ENOTSUPPORTED) {
-+                              if (p->flags & FLAG_PRE_API) {
-+                                      if (major == 1) {
-+                                              p->major = 1;
-+                                              p->minor = 0;
-+                                              *minor = 0;
-+                                              ret = 0;
-+                                      }
-+                              }
-+                      }
-+              }
-+
-+              if (ret == 0)
-+                      __get_ref(p);
-+      }
-+      spin_unlock_irqrestore(&hvapi_lock, flags);
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(sun4v_hvapi_register);
-+
-+void sun4v_hvapi_unregister(unsigned long group)
-+{
-+      struct api_info *p;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&hvapi_lock, flags);
-+      p = __get_info(group);
-+      if (p)
-+              __put_ref(p);
-+      spin_unlock_irqrestore(&hvapi_lock, flags);
-+}
-+EXPORT_SYMBOL(sun4v_hvapi_unregister);
-+
-+int sun4v_hvapi_get(unsigned long group,
-+                  unsigned long *major,
-+                  unsigned long *minor)
-+{
-+      struct api_info *p;
-+      unsigned long flags;
-+      int ret;
-+
-+      spin_lock_irqsave(&hvapi_lock, flags);
-+      ret = -EINVAL;
-+      p = __get_info(group);
-+      if (p && p->refcnt) {
-+              *major = p->major;
-+              *minor = p->minor;
-+              ret = 0;
-+      }
-+      spin_unlock_irqrestore(&hvapi_lock, flags);
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(sun4v_hvapi_get);
-+
-+void __init sun4v_hvapi_init(void)
-+{
-+      unsigned long group, major, minor;
-+
-+      group = HV_GRP_SUN4V;
-+      major = 1;
-+      minor = 0;
-+      if (sun4v_hvapi_register(group, major, &minor))
-+              goto bad;
-+
-+      group = HV_GRP_CORE;
-+      major = 1;
-+      minor = 1;
-+      if (sun4v_hvapi_register(group, major, &minor))
-+              goto bad;
-+
-+      return;
-+
-+bad:
-+      prom_printf("HVAPI: Cannot register API group "
-+                  "%lx with major(%u) minor(%u)\n",
-+                  group, major, minor);
-+      prom_halt();
-+}
---- linux-2.6.20.12.orig/arch/sparc64/kernel/setup.c
-+++ linux-2.6.20.12/arch/sparc64/kernel/setup.c
-@@ -269,6 +269,7 @@ void __init per_cpu_patch(void)
- void __init sun4v_patch(void)
- {
-+      extern void sun4v_hvapi_init(void);
-       struct sun4v_1insn_patch_entry *p1;
-       struct sun4v_2insn_patch_entry *p2;
-@@ -300,6 +301,8 @@ void __init sun4v_patch(void)
-               p2++;
-       }
-+
-+      sun4v_hvapi_init();
- }
- #ifdef CONFIG_SMP
---- linux-2.6.20.12.orig/drivers/serial/sunhv.c
-+++ linux-2.6.20.12/drivers/serial/sunhv.c
-@@ -1,6 +1,6 @@
- /* sunhv.c: Serial driver for SUN4V hypervisor console.
-  *
-- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
-+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
-  */
- #include <linux/module.h>
-@@ -35,57 +35,51 @@
- #define CON_BREAK     ((long)-1)
- #define CON_HUP               ((long)-2)
--static inline long hypervisor_con_getchar(long *status)
--{
--      register unsigned long func asm("%o5");
--      register unsigned long arg0 asm("%o0");
--      register unsigned long arg1 asm("%o1");
--
--      func = HV_FAST_CONS_GETCHAR;
--      arg0 = 0;
--      arg1 = 0;
--      __asm__ __volatile__("ta        %6"
--                           : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
--                           : "0" (func), "1" (arg0), "2" (arg1),
--                             "i" (HV_FAST_TRAP));
-+#define IGNORE_BREAK  0x1
-+#define IGNORE_ALL    0x2
--      *status = arg0;
-+static char *con_write_page;
-+static char *con_read_page;
--      return (long) arg1;
--}
-+static int hung_up = 0;
--static inline long hypervisor_con_putchar(long ch)
-+static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
- {
--      register unsigned long func asm("%o5");
--      register unsigned long arg0 asm("%o0");
-+      while (!uart_circ_empty(xmit)) {
-+              long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
--      func = HV_FAST_CONS_PUTCHAR;
--      arg0 = ch;
--      __asm__ __volatile__("ta        %4"
--                           : "=&r" (func), "=&r" (arg0)
--                           : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
-+              if (status != HV_EOK)
-+                      break;
--      return (long) arg0;
-+              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-+              port->icount.tx++;
-+      }
- }
--#define IGNORE_BREAK  0x1
--#define IGNORE_ALL    0x2
-+static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
-+{
-+      while (!uart_circ_empty(xmit)) {
-+              unsigned long ra = __pa(xmit->buf + xmit->tail);
-+              unsigned long len, status, sent;
--static int hung_up = 0;
-+              len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
-+                                    UART_XMIT_SIZE);
-+              status = sun4v_con_write(ra, len, &sent);
-+              if (status != HV_EOK)
-+                      break;
-+              xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
-+              port->icount.tx += sent;
-+      }
-+}
--static struct tty_struct *receive_chars(struct uart_port *port)
-+static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
- {
--      struct tty_struct *tty = NULL;
-       int saw_console_brk = 0;
-       int limit = 10000;
--      if (port->info != NULL)         /* Unopened serial console */
--              tty = port->info->tty;
--
-       while (limit-- > 0) {
-               long status;
--              long c = hypervisor_con_getchar(&status);
--              unsigned char flag;
-+              long c = sun4v_con_getchar(&status);
-               if (status == HV_EWOULDBLOCK)
-                       break;
-@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(
-                       continue;
-               }
--              flag = TTY_NORMAL;
-               port->icount.rx++;
--              if (c == CON_BREAK) {
--                      port->icount.brk++;
--                      if (uart_handle_break(port))
--                              continue;
--                      flag = TTY_BREAK;
--              }
-               if (uart_handle_sysrq_char(port, c))
-                       continue;
--              if ((port->ignore_status_mask & IGNORE_ALL) ||
--                  ((port->ignore_status_mask & IGNORE_BREAK) &&
--                   (c == CON_BREAK)))
-+              tty_insert_flip_char(tty, c, TTY_NORMAL);
-+      }
-+
-+      return saw_console_brk;
-+}
-+
-+static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
-+{
-+      int saw_console_brk = 0;
-+      int limit = 10000;
-+
-+      while (limit-- > 0) {
-+              unsigned long ra = __pa(con_read_page);
-+              unsigned long bytes_read, i;
-+              long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
-+
-+              if (stat != HV_EOK) {
-+                      bytes_read = 0;
-+
-+                      if (stat == CON_BREAK) {
-+                              if (uart_handle_break(port))
-+                                      continue;
-+                              saw_console_brk = 1;
-+                              *con_read_page = 0;
-+                              bytes_read = 1;
-+                      } else if (stat == CON_HUP) {
-+                              hung_up = 1;
-+                              uart_handle_dcd_change(port, 0);
-+                              continue;
-+                      } else {
-+                              /* HV_EWOULDBLOCK, etc.  */
-+                              break;
-+                      }
-+              }
-+
-+              if (hung_up) {
-+                      hung_up = 0;
-+                      uart_handle_dcd_change(port, 1);
-+              }
-+
-+              for (i = 0; i < bytes_read; i++)
-+                      uart_handle_sysrq_char(port, con_read_page[i]);
-+
-+              if (tty == NULL)
-                       continue;
--              tty_insert_flip_char(tty, c, flag);
-+              port->icount.rx += bytes_read;
-+
-+              tty_insert_flip_string(tty, con_read_page, bytes_read);
-       }
--      if (saw_console_brk)
-+      return saw_console_brk;
-+}
-+
-+struct sunhv_ops {
-+      void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
-+      int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
-+};
-+
-+static struct sunhv_ops bychar_ops = {
-+      .transmit_chars = transmit_chars_putchar,
-+      .receive_chars = receive_chars_getchar,
-+};
-+
-+static struct sunhv_ops bywrite_ops = {
-+      .transmit_chars = transmit_chars_write,
-+      .receive_chars = receive_chars_read,
-+};
-+
-+static struct sunhv_ops *sunhv_ops = &bychar_ops;
-+
-+static struct tty_struct *receive_chars(struct uart_port *port)
-+{
-+      struct tty_struct *tty = NULL;
-+
-+      if (port->info != NULL)         /* Unopened serial console */
-+              tty = port->info->tty;
-+
-+      if (sunhv_ops->receive_chars(port, tty))
-               sun_do_break();
-       return tty;
-@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_p
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
--      while (!uart_circ_empty(xmit)) {
--              long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
--
--              if (status != HV_EOK)
--                      break;
--
--              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
--              port->icount.tx++;
--      }
-+      sunhv_ops->transmit_chars(port, xmit);
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_p
-       struct circ_buf *xmit = &port->info->xmit;
-       while (!uart_circ_empty(xmit)) {
--              long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
-+              long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
-               if (status != HV_EOK)
-                       break;
-@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart
-       spin_lock_irqsave(&port->lock, flags);
-       while (limit-- > 0) {
--              long status = hypervisor_con_putchar(ch);
-+              long status = sun4v_con_putchar(ch);
-               if (status == HV_EOK)
-                       break;
-+              udelay(1);
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_
- {
-       if (break_state) {
-               unsigned long flags;
--              int limit = 1000000;
-+              int limit = 10000;
-               spin_lock_irqsave(&port->lock, flags);
-               while (limit-- > 0) {
--                      long status = hypervisor_con_putchar(CON_BREAK);
-+                      long status = sun4v_con_putchar(CON_BREAK);
-                       if (status == HV_EOK)
-                               break;
--                      udelay(2);
-+                      udelay(1);
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = {
- static struct uart_port *sunhv_port;
--static inline void sunhv_console_putchar(struct uart_port *port, char c)
-+/* Copy 's' into the con_write_page, decoding "\n" into
-+ * "\r\n" along the way.  We have to return two lengths
-+ * because the caller needs to know how much to advance
-+ * 's' and also how many bytes to output via con_write_page.
-+ */
-+static int fill_con_write_page(const char *s, unsigned int n,
-+                             unsigned long *page_bytes)
- {
-+      const char *orig_s = s;
-+      char *p = con_write_page;
-+      int left = PAGE_SIZE;
-+
-+      while (n--) {
-+              if (*s == '\n') {
-+                      if (left < 2)
-+                              break;
-+                      *p++ = '\r';
-+                      left--;
-+              } else if (left < 1)
-+                      break;
-+              *p++ = *s++;
-+              left--;
-+      }
-+      *page_bytes = p - con_write_page;
-+      return s - orig_s;
-+}
-+
-+static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
-+{
-+      struct uart_port *port = sunhv_port;
-       unsigned long flags;
--      int limit = 1000000;
-       spin_lock_irqsave(&port->lock, flags);
-+      while (n > 0) {
-+              unsigned long ra = __pa(con_write_page);
-+              unsigned long page_bytes;
-+              unsigned int cpy = fill_con_write_page(s, n,
-+                                                     &page_bytes);
-+
-+              n -= cpy;
-+              s += cpy;
-+              while (page_bytes > 0) {
-+                      unsigned long written;
-+                      int limit = 1000000;
-+
-+                      while (limit--) {
-+                              unsigned long stat;
-+
-+                              stat = sun4v_con_write(ra, page_bytes,
-+                                                     &written);
-+                              if (stat == HV_EOK)
-+                                      break;
-+                              udelay(1);
-+                      }
-+                      if (limit <= 0)
-+                              break;
-+                      page_bytes -= written;
-+                      ra += written;
-+              }
-+      }
-+      spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static inline void sunhv_console_putchar(struct uart_port *port, char c)
-+{
-+      int limit = 1000000;
-       while (limit-- > 0) {
--              long status = hypervisor_con_putchar(c);
-+              long status = sun4v_con_putchar(c);
-               if (status == HV_EOK)
-                       break;
--              udelay(2);
-+              udelay(1);
-       }
--
--      spin_unlock_irqrestore(&port->lock, flags);
- }
--static void sunhv_console_write(struct console *con, const char *s, unsigned n)
-+static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
- {
-       struct uart_port *port = sunhv_port;
-+      unsigned long flags;
-       int i;
-+      spin_lock_irqsave(&port->lock, flags);
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sunhv_console_putchar(port, '\r');
-               sunhv_console_putchar(port, *s++);
-       }
-+      spin_unlock_irqrestore(&port->lock, flags);
- }
- static struct console sunhv_console = {
-       .name   =       "ttyHV",
--      .write  =       sunhv_console_write,
-+      .write  =       sunhv_console_write_bychar,
-       .device =       uart_console_device,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONS
- static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
- {
-       struct uart_port *port;
-+      unsigned long minor;
-       int err;
-       if (op->irqs[0] == 0xffffffff)
-@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_
-       if (unlikely(!port))
-               return -ENOMEM;
-+      minor = 1;
-+      if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
-+          minor >= 1) {
-+              err = -ENOMEM;
-+              con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-+              if (!con_write_page)
-+                      goto out_free_port;
-+
-+              con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-+              if (!con_read_page)
-+                      goto out_free_con_write_page;
-+
-+              sunhv_console.write = sunhv_console_write_paged;
-+              sunhv_ops = &bywrite_ops;
-+      }
-+
-       sunhv_port = port;
-       port->line = 0;
-@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_
-       err = uart_register_driver(&sunhv_reg);
-       if (err)
--              goto out_free_port;
-+              goto out_free_con_read_page;
-       sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
-       sunserial_current_minor += 1;
-@@ -463,6 +591,12 @@ out_unregister_driver:
-       sunserial_current_minor -= 1;
-       uart_unregister_driver(&sunhv_reg);
-+out_free_con_read_page:
-+      kfree(con_read_page);
-+
-+out_free_con_write_page:
-+      kfree(con_write_page);
-+
- out_free_port:
-       kfree(port);
-       sunhv_port = NULL;
---- linux-2.6.20.12.orig/include/asm-sparc64/hypervisor.h
-+++ linux-2.6.20.12/include/asm-sparc64/hypervisor.h
-@@ -940,6 +940,54 @@ struct hv_fault_status {
-  */
- #define HV_FAST_CONS_PUTCHAR          0x61
-+/* con_read()
-+ * TRAP:      HV_FAST_TRAP
-+ * FUNCTION:  HV_FAST_CONS_READ
-+ * ARG0:      buffer real address
-+ * ARG1:      buffer size in bytes
-+ * RET0:      status
-+ * RET1:      bytes read or BREAK or HUP
-+ * ERRORS:    EWOULDBLOCK     No character available.
-+ *
-+ * Reads characters into a buffer from the console device.  If no
-+ * character is available then an EWOULDBLOCK error is returned.
-+ * If a character is available, then the returned status is EOK
-+ * and the number of bytes read into the given buffer is provided
-+ * in RET1.
-+ *
-+ * A virtual BREAK is represented by the 64-bit RET1 value -1.
-+ *
-+ * A virtual HUP signal is represented by the 64-bit RET1 value -2.
-+ *
-+ * If BREAK or HUP are indicated, no bytes were read into buffer.
-+ */
-+#define HV_FAST_CONS_READ             0x62
-+
-+/* con_write()
-+ * TRAP:      HV_FAST_TRAP
-+ * FUNCTION:  HV_FAST_CONS_WRITE
-+ * ARG0:      buffer real address
-+ * ARG1:      buffer size in bytes
-+ * RET0:      status
-+ * RET1:      bytes written
-+ * ERRORS:    EWOULDBLOCK     Output buffer currently full, would block
-+ *
-+ * Send a characters in buffer to the console device.  Breaks must be
-+ * sent using con_putchar().
-+ */
-+#define HV_FAST_CONS_WRITE            0x63
-+
-+#ifndef __ASSEMBLY__
-+extern long sun4v_con_getchar(long *status);
-+extern long sun4v_con_putchar(long c);
-+extern long sun4v_con_read(unsigned long buffer,
-+                         unsigned long size,
-+                         unsigned long *bytes_read);
-+extern unsigned long sun4v_con_write(unsigned long buffer,
-+                                   unsigned long size,
-+                                   unsigned long *bytes_written);
-+#endif
-+
- /* Trap trace services.
-  *
-  * The hypervisor provides a trap tracing capability for privileged
-@@ -2121,8 +2169,41 @@ struct hv_mmu_statistics {
- #define HV_FAST_MMUSTAT_INFO          0x103
- /* Function numbers for HV_CORE_TRAP.  */
--#define HV_CORE_VER                   0x00
-+#define HV_CORE_SET_VER                       0x00
- #define HV_CORE_PUTCHAR                       0x01
- #define HV_CORE_EXIT                  0x02
-+#define HV_CORE_GET_VER                       0x03
-+
-+/* Hypervisor API groups for use with HV_CORE_SET_VER and
-+ * HV_CORE_GET_VER.
-+ */
-+#define HV_GRP_SUN4V                  0x0000
-+#define HV_GRP_CORE                   0x0001
-+#define HV_GRP_INTR                   0x0002
-+#define HV_GRP_SOFT_STATE             0x0003
-+#define HV_GRP_PCI                    0x0100
-+#define HV_GRP_LDOM                   0x0101
-+#define HV_GRP_SVC_CHAN                       0x0102
-+#define HV_GRP_NCS                    0x0103
-+#define HV_GRP_NIAG_PERF              0x0200
-+#define HV_GRP_FIRE_PERF              0x0201
-+#define HV_GRP_DIAG                   0x0300
-+
-+#ifndef __ASSEMBLY__
-+extern unsigned long sun4v_get_version(unsigned long group,
-+                                     unsigned long *major,
-+                                     unsigned long *minor);
-+extern unsigned long sun4v_set_version(unsigned long group,
-+                                     unsigned long major,
-+                                     unsigned long minor,
-+                                     unsigned long *actual_minor);
-+
-+extern int sun4v_hvapi_register(unsigned long group, unsigned long major,
-+                              unsigned long *minor);
-+extern void sun4v_hvapi_unregister(unsigned long group);
-+extern int sun4v_hvapi_get(unsigned long group,
-+                         unsigned long *major,
-+                         unsigned long *minor);
-+#endif
- #endif /* !(_SPARC64_HYPERVISOR_H) */