Hi there,
This patch is against the BK tree of an hour or two ago. It should
apply with minimal effort to almost any tree though.
There doesn't seem to be a maintainer for console-only things so
hoepfully this will do. This patch adds support for the SGI Altix
(SN2) console driver.
No generic/non-sn2 code paths should be affected by this.
Documentation/Configure.help | 15
MAINTAINERS | 5
drivers/char/Config.in | 3
drivers/char/Makefile | 1
drivers/char/sn_serial.c | 912 +++++++++++++++++++++++++++++++++
drivers/char/tty_io.c | 8
6 files changed, 929 insertions(+), 15 deletions(-)
Pending any nasties please apply!
Thanks,
--cw
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1123 -> 1.1124
# drivers/char/Config.in 1.47 -> 1.48
# drivers/char/tty_io.c 1.25 -> 1.26
# MAINTAINERS 1.102 -> 1.103
# Documentation/Configure.help 1.170 -> 1.171
# drivers/char/Makefile 1.34 -> 1.35
# (new) -> 1.1 drivers/char/sn_serial.c
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/07/15 cw@taniwha.engr.sgi.com 1.1124
# Add SGI Altix (SN2) console driver
# --------------------------------------------
#
diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help
--- a/Documentation/Configure.help Tue Jul 15 16:15:34 2003
+++ b/Documentation/Configure.help Tue Jul 15 16:15:34 2003
@@ -26203,12 +26203,6 @@
IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable
NUMA) platform for IA64. Unless you are compiling a kernel for an SGI SN IA64 box, say N.
-Enable protocol mode for the L1 console
-SERIAL_SGI_L1_PROTOCOL
- Uses protocol mode instead of raw mode for the level 1 console on the
- SGI SN (Scalable NUMA) platform for IA64. If you are compiling for
- an SGI SN box then Y is the recommended value, otherwise say N.
-
Directly Connected Compact Flash support
CONFIG_CF_ENABLER
Compact Flash is a small, removable mass storage device introduced
@@ -26857,11 +26851,10 @@
Say Y here to support tuning the ITE8172's IDE interface. This makes
it possible to set DMA channel or PIO opration and the transfer rate.
-Enable protocol mode for the L1 console
-CONFIG_SERIAL_SGI_L1_PROTOCOL
- Uses protocol mode instead of raw mode for the level 1 console on the
- SGI SN (Scalable NUMA) platform for IA64. If you are compiling for
- an SGI SN box then Y is the recommended value, otherwise say N.
+SGI Altix (SN2) Console Support
+CONFIG_SGI_SN_SERIAL_CONSOLE
+ Enables Console support for SGI Altix (SN2) machines. If you have
+ an Altix you almost certainly want this --- otherwise choose N.
New bus configuration (EXPERIMENTAL)
CONFIG_TULIP_MWI
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS Tue Jul 15 16:15:34 2003
+++ b/MAINTAINERS Tue Jul 15 16:15:34 2003
@@ -1547,6 +1547,11 @@
M: mingo@redhat.com
S: Maintained
+SGI Altix (SN2) Console Driver
+P: Chad Talbott
+M: chadt@sgi.com
+S: Maintained
+
SIS 5513 IDE CONTROLLER DRIVER
P: Lionel Bouton
M: Lionel.Bouton@inet6.fr
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in Tue Jul 15 16:15:34 2003
+++ b/drivers/char/Config.in Tue Jul 15 16:15:34 2003
@@ -104,6 +104,9 @@
fi
fi
fi
+ if [ "$CONFIG_IA64" = "y" ]; then
+ bool ' SGI Altix (SN2) Console support' CONFIG_SGI_SN_SERIAL_CONSOLE
+ fi
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile Tue Jul 15 16:15:34 2003
+++ b/drivers/char/Makefile Tue Jul 15 16:15:34 2003
@@ -211,6 +211,7 @@
obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o
+obj-$(CONFIG_SGI_SN_SERIAL) += sn_serial.o
subdir-$(CONFIG_RIO) += rio
subdir-$(CONFIG_INPUT) += joystick
diff -Nru a/drivers/char/sn_serial.c b/drivers/char/sn_serial.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/char/sn_serial.c Tue Jul 15 16:15:34 2003
@@ -0,0 +1,912 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+#include <linux/circ_buf.h>
+#include <asm/irq.h>
+
+#include <asm/system.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/uart16550.h>
+
+#define GMSH_DEBUG(_a, _b)
+#define GMSH_DEBUG_BUF(_a, _b)
+
+#ifndef NR_NODES
+/* This should be removed once all the header file changes have propigated */
+#define NR_NODES 1024
+#endif
+
+#if defined(CONFIG_SGI_SN_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_SGI_SN_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+static char *serial_name = "SGI SN SAL Console Serial driver";
+static char *serial_version = "1.0";
+static char *serial_revdate = "2003-07-15";
+
+static struct tty_struct *sal_cons_tty;
+static struct console sal_console;
+static struct tq_struct tq;
+static struct circ_buf xmit;
+static struct timer_list sal_cons_timer_list;
+static int sal_cons_event; /* event type for task queue */
+static int sal_cons_refcount;
+static char *sal_tmp_buffer;
+static int sal_cons_irq;
+static spinlock_t sal_cons_lock;
+static int tx_count;
+static int rx_count;
+
+static struct tty_struct *sal_cons_table;
+static struct termios *sal_cons_termios;
+static struct termios *sal_cons_termios_locked;
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+/* driver subtype - what does this mean? */
+#define SAL_CONS_SUBTYPE 1
+
+/* minor device number */
+#define SAL_CONS_MINOR 64
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SAL_CONS_MAX_CHARS 120
+
+/* event types for our task queue -- so far just one */
+#define SAL_CONS_EVENT_WRITE_WAKEUP 0
+
+#define CONSOLE_RESTART 1
+
+#if CONSOLE_RESTART
+# define TIMER_WAIT_TIME 20*HZ
+#else
+# define TIMER_WAIT_TIME 2*HZ/100
+#endif
+/*
+ * sim_write() - general purpose console func when running the simulator
+ */
+
+static inline int
+sim_write(const char *str, int count)
+{
+ extern u64 master_node_bedrock_address;
+ void early_sn_setup(void);
+ int counter = count;
+
+ if (!master_node_bedrock_address)
+ early_sn_setup();
+
+ if (master_node_bedrock_address != 0l) {
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+ /* This is an easy way to pre-pend the output to know whether the output
+ * was done via sal or directly */
+ writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+ writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+ writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+ writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+#endif /* FLAG_DIRECT_CONSOLE_WRITES */
+ while (counter > 0) {
+ writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+ counter--;
+ str++;
+ }
+ }
+ return count;
+}
+
+/*********************************************************************
+ *
+ * Interrupt handling routines. Individual subroutines are declared
+ * as inline and folded into sal_cons_interrupt.
+ */
+
+static inline void
+sal_cons_sched_event(int event)
+{
+ sal_cons_event |= (1 << event);
+ queue_task(&tq, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+
+static inline void
+receive_chars(struct tty_struct *tty, int *status, struct pt_regs *regs)
+{
+ unsigned char ch;
+
+ do {
+ if (IS_RUNNING_ON_SIMULATOR()) {
+ extern u64 master_node_bedrock_address;
+ ch = readb((unsigned long)master_node_bedrock_address + (REG_DAT << 3));
+ } else {
+ if (sal_cons_irq) {
+ ch = (unsigned char) ia64_sn_console_readc();
+ } else {
+ if (ia64_sn_console_getc((int *)&ch))
+ break;
+ }
+ }
+
+#if defined(CONFIG_SGI_SN_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ if (sysrq_requested) {
+ unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+ sysrq_requested = 0;
+ if (ch && time_before(jiffies, sysrq_timeout)) {
+ handle_sysrq(ch, regs, NULL, NULL);
+ goto ignore_char;
+ }
+ }
+ if (ch == *sysrq_serial_ptr) {
+ if (!(*++sysrq_serial_ptr)) {
+ sysrq_requested = jiffies;
+ sysrq_serial_ptr = sysrq_serial_str;
+ }
+ } else
+ sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_SGI_SN_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+ *tty->flip.char_buf_ptr = ch;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ rx_count++;
+
+#if defined(CONFIG_SGI_SN_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ ignore_char:
+#endif
+ if (sal_cons_irq)
+ *status = ia64_sn_console_intr_status();
+ else {
+ int sal_call_status, input;
+
+ if (IS_RUNNING_ON_SIMULATOR()) {
+ extern u64 master_node_bedrock_address;
+ sal_call_status = readb((unsigned long)master_node_bedrock_address + (REG_LSR << 3));
+ if (sal_call_status & LSR_RCA)
+ *status = SAL_CONSOLE_INTR_RECV;
+ } else {
+ sal_call_status = ia64_sn_console_check(&input);
+ if (!sal_call_status && input) {
+ /* input pending */
+ *status = SAL_CONSOLE_INTR_RECV;
+ }
+ }
+ }
+ } while (*status & SAL_CONSOLE_INTR_RECV);
+
+ tty_flip_buffer_push(tty);
+}
+
+
+static inline void
+transmit_chars(struct tty_struct *tty)
+{
+ int xmit_count, tail, head, loops, ii;
+ int result;
+ unsigned long flags;
+ char *start;
+
+ if (xmit.head == xmit.tail || tty->stopped || tty->hw_stopped) {
+ /* Nothing to do. */
+ return;
+ }
+
+ /* Make sure no one gets here until we have drained the buffer */
+
+ spin_lock_irqsave(&sal_cons_lock, flags);
+
+ head = xmit.head;
+ tail = xmit.tail;
+ start = (char *)&xmit.buf[tail];
+
+ /* twice around gets the tail to the end of the buffer and then to the head, if needed */
+ loops = (head < tail) ? 2 : 1;
+
+ for (ii = 0; ii < loops; ii++) {
+ xmit_count = (head < tail) ? (SERIAL_XMIT_SIZE - tail) : (head - tail);
+
+ if (xmit_count > 0) {
+ if (IS_RUNNING_ON_SIMULATOR())
+ result = sim_write(start, xmit_count);
+ else {
+ if (sal_cons_irq)
+ result = ia64_sn_console_xmit_chars(start, xmit_count);
+ else
+ result = ia64_sn_console_putb(start, xmit_count);
+ }
+ if (result > 0) {
+ xmit_count -= result;
+ tx_count += result;
+ tail += result;
+ tail &= SERIAL_XMIT_SIZE - 1;
+ xmit.tail = tail;
+ start = (char *)&xmit.buf[tail];
+ }
+ }
+ }
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+
+ if (CIRC_CNT(xmit.head, xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS) {
+ /* There's few enough characters left in the xmit buffer
+ * that we could stand for the upper layer to send us some
+ * more. Ask for it.
+ */
+ sal_cons_sched_event(SAL_CONS_EVENT_WRITE_WAKEUP);
+ }
+}
+
+
+static void
+sal_cons_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int status;
+
+ if (irq) {
+ status = ia64_sn_console_intr_status();
+
+ if (status & SAL_CONSOLE_INTR_RECV) {
+ receive_chars(sal_cons_tty, &status, regs);
+ }
+
+ if (status & SAL_CONSOLE_INTR_XMIT) {
+ transmit_chars(sal_cons_tty);
+ }
+ } else {
+ /* Polling */
+ int input;
+
+ if (IS_RUNNING_ON_SIMULATOR()) {
+ extern u64 master_node_bedrock_address;
+ input = readb((unsigned long)master_node_bedrock_address + (REG_LSR << 3));
+ if (input & LSR_RCA)
+ receive_chars(sal_cons_tty, &status, regs);
+
+ } else {
+ status = ia64_sn_console_check(&input);
+ if (!status && input)
+ receive_chars(sal_cons_tty, &status, regs);
+ }
+ transmit_chars(sal_cons_tty);
+ }
+}
+
+
+static void
+sal_cons_connect_interrupt(void)
+{
+ cpuid_t intr_cpuid;
+ unsigned int intr_cpuloc;
+ nasid_t console_nasid;
+ unsigned int console_irq;
+ int result;
+
+#if defined(CONSOLE_POLLING_ONLY)
+ sal_cons_irq = 0;
+#else
+ /* if it is an old prom, run in poll mode */
+ if (((sn_sal_rev_major() <= 1) && (sn_sal_rev_minor() <= 3))
+ || (IS_RUNNING_ON_SIMULATOR())) {
+ /* before version 1.06 doesn't work */
+ printk("========== OLD prom version %x.%x - run in polled mode\n",
+ sn_sal_rev_major(), sn_sal_rev_minor());
+ sal_cons_irq = 0; /* Make sure */
+ return ;
+ }
+
+ console_nasid = ia64_sn_get_console_nasid();
+ intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))
+ -> node_first_cpu;
+ intr_cpuloc = cpu_physical_id(intr_cpuid);
+ console_irq = CPU_VECTOR_TO_IRQ(intr_cpuloc, SGI_UART_VECTOR);
+
+ result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR,
+ 0 /*not used*/, 0 /*not used*/);
+ if (result != SGI_UART_VECTOR) {
+ if (result < 0) GMSH_DEBUG("intr_connect_level failed", result);
+ else GMSH_DEBUG("intr_connect_level returns wrong bit", result);
+ return;
+ }
+
+ result = request_irq(console_irq, sal_cons_interrupt,
+ SA_INTERRUPT, "SAL console driver",
+ &sal_cons_tty);
+ if (result < 0) {
+ GMSH_DEBUG("request_irq failed", result);
+ return;
+ }
+
+ /* sal_cons_irq is a global variable. When it's set to a non-zero
+ * value, the console driver stops polling for input (since interrupts
+ * should now be enabled).
+ */
+ sal_cons_irq = console_irq;
+
+ /* ask SAL to turn on interrupts in the UART itself */
+ ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+ /* xmit interrupts are enabled by SAL as necessary */
+#endif /* CONSOLE_POLLING_ONLY */
+}
+
+
+/*
+ *
+ * End of the interrupt routines.
+ *********************************************************************/
+
+
+/*********************************************************************
+ * From drivers/char/serial.c:
+ *
+ * "This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * [sal_cons_interrupt()] has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using [sal_cons_sched_event()], and they get done here."
+ */
+static void
+do_sal_cons_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void
+do_softint(void *data)
+{
+ struct tty_struct *tty;
+
+ if (!(tty = sal_cons_tty))
+ return;
+
+ if (test_and_clear_bit(SAL_CONS_EVENT_WRITE_WAKEUP, &sal_cons_event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
+ }
+}
+
+
+/*
+ * This function handles polled mode.
+ */
+static void
+sal_cons_timer(unsigned long dummy)
+{
+ if (sal_cons_irq == 0) {
+ sal_cons_interrupt(0, NULL, NULL);
+ mod_timer(&sal_cons_timer_list, jiffies + TIMER_WAIT_TIME);
+ return;
+ }
+
+#if CONSOLE_RESTART
+ sal_cons_interrupt(1, NULL, NULL);
+ mod_timer(&sal_cons_timer_list, jiffies + TIMER_WAIT_TIME);
+#endif
+}
+
+
+/*
+ *
+ * End of "sofware interrupt" routines.
+ *********************************************************************/
+
+
+
+/*********************************************************************
+ *
+ * User-level console routines
+ *
+ */
+
+static int
+sal_cons_open(struct tty_struct *tty, struct file *filp)
+{
+ if (!sal_cons_tty)
+ sal_cons_tty = tty;
+
+ if (sal_cons_irq == 0 || CONSOLE_RESTART)
+ mod_timer(&sal_cons_timer_list, jiffies + TIMER_WAIT_TIME);
+
+ return 0;
+}
+
+
+/* We're keeping all our resources. We're keeping interrupts turned
+ * on. Maybe just let the tty layer finish its stuff...? GMSH
+ */
+static void
+sal_cons_close(struct tty_struct *tty, struct file * filp)
+{
+ tty->closing = 1;
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+
+ return;
+}
+
+
+static int
+sal_cons_write(struct tty_struct *tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, ret = 0;
+ unsigned long flags;
+
+#if 0 /* GMSH */
+ /* This code just reads and prints the value of the UART
+ * interrupt control register to ensure that SAL actually
+ * set the bits as requested.
+ */
+ if (strncmp(buf, "@CheckUART", strlen("@CheckUART")) == 0) {
+ unsigned long long icr;
+ icr = LOCAL_HUB_L(SH_JUNK_BUS_UART1);
+ GMSH_DEBUG("ICR reg value", icr);
+ }
+#endif
+
+ if (!tty || !xmit.buf || !sal_tmp_buffer) {
+ GMSH_DEBUG("sal_cons_write ran into trouble", 0);
+ if (!tty) GMSH_DEBUG("tty", tty);
+ if (!xmit.buf) GMSH_DEBUG("xmit.buf", xmit.buf);
+ if (!sal_tmp_buffer) GMSH_DEBUG("sal_tmp_buffer", sal_tmp_buffer);
+ GMSH_DEBUG_BUF(buf, count);
+ return 0;
+ }
+
+ if (from_user) {
+ while (1) {
+ int c1;
+ c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+ SERIAL_XMIT_SIZE);
+
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(sal_tmp_buffer, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ /* Turn off interrupts and see if the xmit buffer has
+ * moved since the last time we looked.
+ */
+ spin_lock_irqsave(&sal_cons_lock, flags);
+ c1 = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+ SERIAL_XMIT_SIZE);
+
+ if (c1 < c)
+ c = c1;
+
+ memcpy(xmit.buf + xmit.head, sal_tmp_buffer, c);
+ xmit.head = ((xmit.head + c) & (SERIAL_XMIT_SIZE - 1));
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ } else {
+ /* The buffer passed in isn't coming from userland,
+ * so cut out the middleman (sal_tmp_buffer).
+ */
+ spin_lock_irqsave(&sal_cons_lock, flags);
+ while (1) {
+ c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+ SERIAL_XMIT_SIZE);
+
+ if (count < c)
+ c = count;
+ if (c <= 0) {
+ break;
+ }
+ memcpy(xmit.buf + xmit.head, buf, c);
+ xmit.head = ((xmit.head + c) & (SERIAL_XMIT_SIZE - 1));
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+ }
+
+ if ((xmit.head != xmit.tail) && !tty->stopped && !tty->hw_stopped)
+ transmit_chars(tty);
+
+ return ret;
+}
+
+
+static void
+sal_cons_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ unsigned long flags;
+
+ if (!tty || !xmit.buf)
+ return;
+
+ spin_lock_irqsave(&sal_cons_lock, flags);
+ if (CIRC_SPACE(xmit.head, xmit.tail, SERIAL_XMIT_SIZE) == 0) {
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+ return;
+ }
+
+ xmit.buf[xmit.head] = ch;
+ xmit.head = (xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+}
+
+
+static void
+sal_cons_flush_chars(struct tty_struct *tty)
+{
+ if (CIRC_CNT(xmit.head, xmit.tail, SERIAL_XMIT_SIZE))
+ transmit_chars(tty);
+}
+
+
+static int
+sal_cons_write_room(struct tty_struct *tty)
+{
+ return CIRC_SPACE(xmit.head, xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+
+static int
+sal_cons_chars_in_buffer(struct tty_struct *tty)
+{
+ return CIRC_CNT(xmit.head, xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+
+static int
+sal_cons_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ /* nothing supported*/
+ return -ENOIOCTLCMD;
+}
+
+
+static void
+sal_cons_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ /* don't care about termios */
+ return;
+}
+
+
+static void
+sal_cons_flush_buffer(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ /* drop everything */
+ spin_lock_irqsave(&sal_cons_lock, flags);
+ xmit.head = xmit.tail = 0;
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+
+ /* wake up tty level */
+ wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+
+static void
+sal_cons_hangup(struct tty_struct *tty)
+{
+ sal_cons_flush_buffer(tty);
+}
+
+
+static void
+sal_cons_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ /* this is SAL's problem */
+ return;
+}
+
+
+/*
+ * sal_cons_read_proc
+ *
+ * Console /proc interface
+ */
+
+static int
+sal_cons_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+ off_t begin = 0;
+ extern nasid_t get_console_nasid(void);
+
+ len += sprintf(page, "sal_cons: %s 1.0 driver:%s revision:%s console nasid %d : irq %d tx/rx %d/%d\n",
+ serial_name, serial_version, serial_revdate, get_console_nasid(), sal_cons_irq,
+ tx_count, rx_count);
+ *eof = 1;
+
+ if (off >= len+begin)
+ return 0;
+ *start = page + (off-begin);
+
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+
+static struct tty_driver sal_cons_driver = {
+ .magic = TTY_DRIVER_MAGIC,
+ .driver_name = "SALconsole",
+#if defined(CONFIG_DEVFS_FS)
+ .name = "tts/%d",
+#else
+ .name = "ttyS",
+#endif
+ .major = TTY_MAJOR,
+ .minor_start = SAL_CONS_MINOR,
+ .num = 1,
+ .type = TTY_DRIVER_TYPE_SERIAL,
+ .subtype = SAL_CONS_SUBTYPE,
+ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+ .refcount = &sal_cons_refcount,
+ /* proc_entry omitted */
+ /* other omitted */
+ .table = &sal_cons_table,
+ .termios = &sal_cons_termios,
+ .termios_locked = &sal_cons_termios_locked,
+
+ .open = sal_cons_open,
+ .close = sal_cons_close,
+ .write = sal_cons_write,
+ .put_char = sal_cons_put_char,
+ .flush_chars = sal_cons_flush_chars,
+ .write_room = sal_cons_write_room,
+ .chars_in_buffer = sal_cons_chars_in_buffer,
+ .ioctl = sal_cons_ioctl,
+ .set_termios = sal_cons_set_termios,
+ .hangup = sal_cons_hangup,
+ .wait_until_sent = sal_cons_wait_until_sent,
+ .read_proc = sal_cons_read_proc,
+};
+
+/* sal_cons_init wishlist:
+ * - allocate sal_tmp_buffer
+ * - fix up the tty_driver struct
+ * - turn on receive interrupts
+ * - do any termios twiddling once and for all
+ */
+
+/*
+ * Boot-time initialization code
+ */
+static int __init
+sal_cons_init(void)
+{
+ if (!ia64_platform_is("sn2"))
+ return -ENODEV;
+
+ init_bh(SERIAL_BH, do_sal_cons_bh);
+
+ sal_cons_driver.init_termios = tty_std_termios;
+ sal_cons_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+ if (tty_register_driver(&sal_cons_driver))
+ panic("Couldn't register SALconsole driver\n");
+
+ tty_register_devfs(&sal_cons_driver, 0, sal_cons_driver.minor_start);
+
+ /* initialize xmit */
+ xmit.buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!xmit.buf)
+ panic("Couldn't allocate xmit buffer for SALconsole driver\n");
+ xmit.head = 0;
+ xmit.tail = 0;
+
+ sal_cons_lock = SPIN_LOCK_UNLOCKED;
+
+ /* allocate a temporary buffer for copying data from user land */
+ sal_tmp_buffer = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!sal_tmp_buffer)
+ panic("Couldn't allocate temp buffer for SALconsole driver\n");
+
+ /* turn on interrupts */
+ sal_cons_connect_interrupt();
+
+ /* Without interrupts, we have to rely on a timer to poll the
+ * SAL console driver.
+ */
+ if (sal_cons_irq == 0 || CONSOLE_RESTART) {
+ init_timer(&sal_cons_timer_list);
+ sal_cons_timer_list.function = sal_cons_timer;
+ mod_timer(&sal_cons_timer_list, jiffies + TIMER_WAIT_TIME);
+ }
+
+ /* task queue initialization */
+ tq.routine = do_softint;
+ tq.data = NULL;
+
+ return 0;
+}
+
+
+static void __exit
+sal_cons_fini(void)
+{
+ unsigned long flags;
+ int e;
+
+ del_timer_sync(&sal_cons_timer_list);
+ spin_lock_irqsave(&sal_cons_lock, flags);
+ remove_bh(SERIAL_BH);
+
+ if ((e = tty_unregister_driver(&sal_cons_driver)))
+ printk("SALconsole: failed to unregister driver (%d)\n", e);
+
+ spin_unlock_irqrestore(&sal_cons_lock, flags);
+
+ if (sal_tmp_buffer) {
+ unsigned long pg = (unsigned long) sal_tmp_buffer;
+ sal_tmp_buffer = NULL;
+ free_page(pg);
+ }
+}
+
+module_init(sal_cons_init);
+module_exit(sal_cons_fini);
+
+/*
+ *
+ * End of user-level console routines.
+ *********************************************************************/
+
+
+
+/*********************************************************************
+ *
+ * Kernel console definitions
+ *
+ */
+
+/*
+ * Print a string to the SAL console. The console_lock must be held
+ * when we get here.
+ */
+static void
+sal_cons_console_write(struct console *co, const char *s, unsigned count)
+{
+ if (IS_RUNNING_ON_SIMULATOR())
+ sim_write(s, count);
+ else
+ ia64_sn_console_putb(s, count);
+}
+
+#if defined(CONFIG_IA64_EARLY_PRINTK_SGI_SN)
+void
+sal_cons_console_out(const char *s, unsigned count)
+{
+ /* Need to setup SAL calls so the PROM calls will work */
+ static int inited;
+ void early_sn_setup(void);
+ if (!inited) {
+ if (!ia64_platform_is("sn2"))
+ return;
+ inited=1;
+ early_sn_setup();
+ }
+
+ if (IS_RUNNING_ON_SIMULATOR())
+ sim_write(s, count);
+ else
+ ia64_sn_console_putb(s, count);
+}
+#endif /* CONFIG_IA64_EARLY_PRINTK_SGI_SN */
+
+static kdev_t
+sal_cons_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+
+static int __init
+sal_cons_console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+
+static struct console sal_console = {
+ name: "ttyS",
+ write: sal_cons_console_write,
+ device: sal_cons_console_device,
+ setup: sal_cons_console_setup,
+ flags: 0,
+ index: -1
+};
+
+/*
+ *
+ * End of kernel console definitions.
+ *********************************************************************/
+
+
+
+#ifdef CONFIG_SGI_SN_SERIAL_CONSOLE
+/*
+ * Register console.
+ */
+void __init
+sgi_sn_serial_console_init(void)
+{
+ if (ia64_platform_is("sn2"))
+ register_console(&sal_console);
+}
+
+#endif /* CONFIG_SGI_SN_SERIAL_CONSOLE */
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c Tue Jul 15 16:15:34 2003
+++ b/drivers/char/tty_io.c Tue Jul 15 16:15:34 2003
@@ -152,7 +152,7 @@
extern void tub3270_init(void);
extern void rs285_console_init(void);
extern void sa1100_rs_console_init(void);
-extern void sgi_serial_console_init(void);
+extern void sgi_sn_serial_console_init(void);
extern void sci_console_init(void);
extern void tx3912_console_init(void);
extern void tx3912_rs_init(void);
@@ -2238,6 +2238,9 @@
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
au1000_serial_console_init();
#endif
+#ifdef CONFIG_SGI_SN_SERIAL_CONSOLE
+ sgi_sn_serial_console_init();
+#endif
#ifdef CONFIG_SERIAL_CONSOLE
#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
console_8xx_init();
@@ -2253,9 +2256,6 @@
#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif /* CONFIG_8xx */
-#ifdef CONFIG_SGI_SERIAL
- sgi_serial_console_init();
-#endif
#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
vme_scc_console_init();
#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Tue Jul 15 2003 - 22:01:00 EST