From 7282bee78798294bb1f0211a842cdb9f4872db3d Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 23 Jun 2005 22:01:33 -0700 Subject: [PATCH] xtensa: Architecture support for Tensilica Xtensa Part 8 The attached patches provides part 8 of an architecture implementation for the Tensilica Xtensa CPU series. Signed-off-by: Chris Zankel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/xtensa/configs/iss_defconfig | 531 +++++++++++++++++++++++ arch/xtensa/platform-iss/Makefile | 13 + arch/xtensa/platform-iss/console.c | 303 +++++++++++++ arch/xtensa/platform-iss/io.c | 32 ++ arch/xtensa/platform-iss/network.c | 855 +++++++++++++++++++++++++++++++++++++ arch/xtensa/platform-iss/setup.c | 112 +++++ 6 files changed, 1846 insertions(+) create mode 100644 arch/xtensa/configs/iss_defconfig create mode 100644 arch/xtensa/platform-iss/Makefile create mode 100644 arch/xtensa/platform-iss/console.c create mode 100644 arch/xtensa/platform-iss/io.c create mode 100644 arch/xtensa/platform-iss/network.c create mode 100644 arch/xtensa/platform-iss/setup.c (limited to 'arch') diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig new file mode 100644 index 000000000000..802621dd4867 --- /dev/null +++ b/arch/xtensa/configs/iss_defconfig @@ -0,0 +1,531 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc2 +# Fri Feb 25 19:21:24 2005 +# +CONFIG_FRAME_POINTER=y +CONFIG_XTENSA=y +# CONFIG_UID16 is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_GENERIC_HARDIRQS=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_KOBJECT_UEVENT is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor type and features +# +CONFIG_XTENSA_ARCH_LINUX_BE=y +# CONFIG_XTENSA_ARCH_LINUX_LE is not set +# CONFIG_XTENSA_ARCH_LINUX_TEST is not set +# CONFIG_XTENSA_ARCH_S5 is not set +# CONFIG_XTENSA_CUSTOM is not set +CONFIG_MMU=y +# CONFIG_XTENSA_UNALIGNED_USER is not set +# CONFIG_PREEMPT is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_HIGHMEM is not set + +# +# Platform options +# +CONFIG_XTENSA_PLATFORM_ISS=y +# CONFIG_XTENSA_PLATFORM_XT2000 is not set +# CONFIG_XTENSA_PLATFORM_ARUBA is not set +# CONFIG_XTENSA_CALIBRATE_CCOUNT is not set +CONFIG_XTENSA_CPU_CLOCK=10 +# CONFIG_GENERIC_CALIBRATE_DELAY is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target" +CONFIG_SERIAL_CONSOLE=y +CONFIG_XTENSA_ISS_NETWORK=y + +# +# Bus options +# + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# PCI Hotplug Support +# + +# +# Exectuable file formats +# +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +# CONFIG_SCTP_HMAC_MD5 is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_SCH_CLK_JIFFIES is not set +# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set +# CONFIG_NET_SCH_CLK_CPU is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=y +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +CONFIG_NFS_DIRECTIO=y +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/xtensa/platform-iss/Makefile b/arch/xtensa/platform-iss/Makefile new file mode 100644 index 000000000000..5b394e9620e5 --- /dev/null +++ b/arch/xtensa/platform-iss/Makefile @@ -0,0 +1,13 @@ +# $Id: Makefile,v 1.1.1.1 2002/08/28 16:10:14 aroll Exp $ +# +# Makefile for the Xtensa Instruction Set Simulator (ISS) +# "prom monitor" library routines under Linux. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are in the main makefile... + +obj-y = io.o console.o setup.o network.o + diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c new file mode 100644 index 000000000000..9e2b53f6a907 --- /dev/null +++ b/arch/xtensa/platform-iss/console.c @@ -0,0 +1,303 @@ +/* + * arch/xtensa/platform-iss/console.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2005 Tensilica Inc. + * Authors Christian Zankel, Joe Taylor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +#define SERIAL_MAX_NUM_LINES 1 +#define SERIAL_TIMER_VALUE (20 * HZ) + +static struct tty_driver *serial_driver; +static struct timer_list serial_timer; + +static DEFINE_SPINLOCK(timer_lock); + +int errno; + +static int __simc (int a, int b, int c, int d, int e, int f) +{ + int ret; + __asm__ __volatile__ ("simcall\n" + "mov %0, a2\n" + "mov %1, a3\n" : "=a" (ret), "=a" (errno) + : : "a2", "a3"); + return ret; +} + +static char *serial_version = "0.1"; +static char *serial_name = "ISS serial driver"; + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ + +static void rs_poll(unsigned long); + +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + int line = tty->index; + + if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES)) + return -ENODEV; + + spin_lock(&timer_lock); + + if (tty->count == 1) { + init_timer(&serial_timer); + serial_timer.data = (unsigned long) tty; + serial_timer.function = rs_poll; + mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); + } + spin_unlock(&timer_lock); + + return 0; +} + + +/* + * ------------------------------------------------------------ + * iss_serial_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + spin_lock(&timer_lock); + if (tty->count == 1) + del_timer_sync(&serial_timer); + spin_unlock(&timer_lock); +} + + +static int rs_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + /* see drivers/char/serialX.c to reference original version */ + + __simc (SYS_write, 1, (unsigned long)buf, count, 0, 0); + return count; +} + +static void rs_poll(unsigned long priv) +{ + struct tty_struct* tty = (struct tty_struct*) priv; + + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + int i = 0; + unsigned char c; + + spin_lock(&timer_lock); + + while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){ + __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0); + tty->flip.count++; + *tty->flip.char_buf_ptr++ = c; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + i++; + } + + if (i) + tty_flip_buffer_push(tty); + + + mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); + spin_unlock(&timer_lock); +} + + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + char buf[2]; + + if (!tty) + return; + + buf[0] = ch; + buf[1] = '\0'; /* Is this NULL necessary? */ + __simc (SYS_write, 1, (unsigned long) buf, 1, 0, 0); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ +} + +static int rs_write_room(struct tty_struct *tty) +{ + /* Let's say iss can always accept 2K characters.. */ + return 2 * 1024; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + /* the iss doesn't buffer characters */ + return 0; +} + +static void rs_hangup(struct tty_struct *tty) +{ + /* Stub, once again.. */ +} + +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + /* Stub, once again.. */ +} + +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + *eof = 1; + + if (off >= len + begin) + return 0; + + *start = page + (off - begin); + return ((count < begin + len - off) ? count : begin + len - off); +} + + +int register_serial(struct serial_struct*); +void unregister_serial(int); + +static struct tty_operations serial_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .put_char = rs_put_char, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .hangup = rs_hangup, + .wait_until_sent = rs_wait_until_sent, + .read_proc = rs_read_proc +}; + +int __init rs_init(void) +{ + serial_driver = alloc_tty_driver(1); + + printk ("%s %s\n", serial_name, serial_version); + + /* Initialize the tty_driver structure */ + + serial_driver->owner = THIS_MODULE; + serial_driver->driver_name = "iss_serial"; + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + + tty_set_operations(serial_driver, &serial_ops); + + if (tty_register_driver(serial_driver)) + panic("Couldn't register serial driver\n"); + return 0; +} + + +static __exit void rs_exit(void) +{ + int error; + + if ((error = tty_unregister_driver(serial_driver))) + printk("ISS_SERIAL: failed to unregister serial driver (%d)\n", + error); + put_tty_driver(serial_driver); +} + + +/* We use `late_initcall' instead of just `__initcall' as a workaround for + * the fact that (1) simcons_tty_init can't be called before tty_init, + * (2) tty_init is called via `module_init', (3) if statically linked, + * module_init == device_init, and (4) there's no ordering of init lists. + * We can do this easily because simcons is always statically linked, but + * other tty drivers that depend on tty_init and which must use + * `module_init' to declare their init routines are likely to be broken. + */ + +late_initcall(rs_init); + + +#ifdef CONFIG_SERIAL_CONSOLE + +static void iss_console_write(struct console *co, const char *s, unsigned count) +{ + int len = strlen(s); + + if (s != 0 && *s != 0) + __simc (SYS_write, 1, (unsigned long)s, + count < len ? count : len,0,0); +} + +static struct tty_driver* iss_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + + +static struct console sercons = { + .name = "ttyS", + .write = iss_console_write, + .device = iss_console_device, + .flags = CON_PRINTBUFFER, + .index = -1 +}; + +static int __init iss_console_init(void) +{ + register_console(&sercons); + return 0; +} + +console_initcall(iss_console_init); + +#endif /* CONFIG_SERIAL_CONSOLE */ + diff --git a/arch/xtensa/platform-iss/io.c b/arch/xtensa/platform-iss/io.c new file mode 100644 index 000000000000..5b161a5cb65f --- /dev/null +++ b/arch/xtensa/platform-iss/io.c @@ -0,0 +1,32 @@ +/* This file isn't really needed right now. */ + +#if 0 + +#include +#include + +extern int __simc (); + + +char iss_serial_getc() +{ + char c; + __simc( SYS_read, 0, &c, 1 ); + return c; +} + +void iss_serial_putc( char c ) +{ + __simc( SYS_write, 1, &c, 1 ); +} + +void iss_serial_puts( char *s ) +{ + if( s != 0 && *s != 0 ) + __simc( SYS_write, 1, s, strlen(s) ); +} + +/*#error Need I/O ports to specific hardware!*/ + +#endif + diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c new file mode 100644 index 000000000000..498d7dced1f4 --- /dev/null +++ b/arch/xtensa/platform-iss/network.c @@ -0,0 +1,855 @@ +/* + * + * arch/xtensa/platform-iss/network.c + * + * Platform specific initialization. + * + * Authors: Chris Zankel + * Based on work form the UML team. + * + * Copyright 2005 Tensilica Inc. + * + * 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, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "iss-netdev" +#define ETH_MAX_PACKET 1500 +#define ETH_HEADER_OTHER 14 +#define ISS_NET_TIMER_VALUE (2 * HZ) + + +static DEFINE_SPINLOCK(opened_lock); +static LIST_HEAD(opened); + +static DEFINE_SPINLOCK(devices_lock); +static LIST_HEAD(devices); + +/* ------------------------------------------------------------------------- */ + +/* We currently only support the TUNTAP transport protocol. */ + +#define TRANSPORT_TUNTAP_NAME "tuntap" +#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET + +struct tuntap_info { + char dev_name[IFNAMSIZ]; + int fixed_config; + unsigned char gw[ETH_ALEN]; + int fd; +}; + +/* ------------------------------------------------------------------------- */ + + +/* This structure contains out private information for the driver. */ + +struct iss_net_private { + + struct list_head device_list; + struct list_head opened_list; + + spinlock_t lock; + struct net_device *dev; + struct platform_device pdev; + struct timer_list tl; + struct net_device_stats stats; + + struct timer_list timer; + unsigned int timer_val; + + int index; + int mtu; + + unsigned char mac[ETH_ALEN]; + int have_mac; + + struct { + union { + struct tuntap_info tuntap; + } info; + + int (*open)(struct iss_net_private *lp); + void (*close)(struct iss_net_private *lp); + int (*read)(struct iss_net_private *lp, struct sk_buff **skb); + int (*write)(struct iss_net_private *lp, struct sk_buff **skb); + unsigned short (*protocol)(struct sk_buff *skb); + int (*poll)(struct iss_net_private *lp); + } tp; + +}; + +/* ======================= ISS SIMCALL INTERFACE =========================== */ + +/* Note: __simc must _not_ be declared inline! */ + +static int errno; + +static int __simc (int a, int b, int c, int d, int e, int f) +{ + int ret; + __asm__ __volatile__ ("simcall\n" + "mov %0, a2\n" + "mov %1, a3\n" : "=a" (ret), "=a" (errno) + : : "a2", "a3"); + return ret; +} + +static int inline simc_open(char *file, int flags, int mode) +{ + return __simc(SYS_open, (int) file, flags, mode, 0, 0); +} + +static int inline simc_close(int fd) +{ + return __simc(SYS_close, fd, 0, 0, 0, 0); +} + +static int inline simc_ioctl(int fd, int request, void *arg) +{ + return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0); +} + +static int inline simc_read(int fd, void *buf, size_t count) +{ + return __simc(SYS_read, fd, (int) buf, count, 0, 0); +} + +static int inline simc_write(int fd, void *buf, size_t count) +{ + return __simc(SYS_write, fd, (int) buf, count, 0, 0); +} + +static int inline simc_poll(int fd) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + + return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0); +} + +/* ================================ HELPERS ================================ */ + + +static char *split_if_spec(char *str, ...) +{ + char **arg, *end; + va_list ap; + + va_start(ap, str); + while ((arg = va_arg(ap, char**)) != NULL) { + if (*str == '\0') + return NULL; + end = strchr(str, ','); + if (end != str) + *arg = str; + if (end == NULL) + return NULL; + *end ++ = '\0'; + str = end; + } + va_end(ap); + return str; +} + + +#if 0 +/* Adjust SKB. */ + +struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) +{ + if ((skb != NULL) && (skb_tailroom(skb) < extra)) { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); + dev_kfree_skb(skb); + skb = skb2; + } + if (skb != NULL) + skb_put(skb, extra); + + return skb; +} +#endif + +/* Return the IP address as a string for a given device. */ + +static void dev_ip_addr(void *d, char *buf, char *bin_buf) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + u32 addr; + + if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) { + printk(KERN_WARNING "Device not assigned an IP address!\n"); + return; + } + + addr = in->ifa_address; + sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, + (addr >> 16) & 0xff, addr >> 24); + + if (bin_buf) { + bin_buf[0] = addr & 0xff; + bin_buf[1] = (addr >> 8) & 0xff; + bin_buf[2] = (addr >> 16) & 0xff; + bin_buf[3] = addr >> 24; + } +} + +/* Set Ethernet address of the specified device. */ + +static void inline set_ether_mac(void *d, unsigned char *addr) +{ + struct net_device *dev = d; + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + + +/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */ + +static int tuntap_open(struct iss_net_private *lp) +{ + struct ifreq ifr; + char *dev_name = lp->tp.info.tuntap.dev_name; + int err = -EINVAL; + int fd; + + /* We currently only support a fixed configuration. */ + + if (!lp->tp.info.tuntap.fixed_config) + return -EINVAL; + + if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */ + printk("Failed to open /dev/net/tun, returned %d " + "(errno = %d)\n", fd, errno); + return fd; + } + + memset(&ifr, 0, sizeof ifr); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1); + + if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) { + printk("Failed to set interface, returned %d " + "(errno = %d)\n", err, errno); + simc_close(fd); + return err; + } + + lp->tp.info.tuntap.fd = fd; + return err; +} + +static void tuntap_close(struct iss_net_private *lp) +{ +#if 0 + if (lp->tp.info.tuntap.fixed_config) + iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name); +#endif + simc_close(lp->tp.info.tuntap.fd); + lp->tp.info.tuntap.fd = -1; +} + +static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb) +{ +#if 0 + *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); + if (*skb == NULL) + return -ENOMEM; +#endif + + return simc_read(lp->tp.info.tuntap.fd, + (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER); +} + +static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb) +{ + return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len); +} + +unsigned short tuntap_protocol(struct sk_buff *skb) +{ + return eth_type_trans(skb, skb->dev); +} + +static int tuntap_poll(struct iss_net_private *lp) +{ + return simc_poll(lp->tp.info.tuntap.fd); +} + +/* + * Currently only a device name is supported. + * ethX=tuntap[,[mac address][,[device name]]] + */ + +static int tuntap_probe(struct iss_net_private *lp, int index, char *init) +{ + const int len = strlen(TRANSPORT_TUNTAP_NAME); + char *dev_name = NULL, *mac_str = NULL, *rem = NULL; + + /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */ + + if (strncmp(init, TRANSPORT_TUNTAP_NAME, len)) + return 0; + + if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') { + if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) { + printk("Extra garbage on specification : '%s'\n", rem); + return 0; + } + } else if (*init != '\0') { + printk("Invalid argument: %s. Skipping device!\n", init); + return 0; + } + + if (dev_name) { + strncpy(lp->tp.info.tuntap.dev_name, dev_name, + sizeof lp->tp.info.tuntap.dev_name); + lp->tp.info.tuntap.fixed_config = 1; + } else + strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME); + + +#if 0 + if (setup_etheraddr(mac_str, lp->mac)) + lp->have_mac = 1; +#endif + lp->mtu = TRANSPORT_TUNTAP_MTU; + + //lp->info.tuntap.gate_addr = gate_addr; + + lp->tp.info.tuntap.fd = -1; + + lp->tp.open = tuntap_open; + lp->tp.close = tuntap_close; + lp->tp.read = tuntap_read; + lp->tp.write = tuntap_write; + lp->tp.protocol = tuntap_protocol; + lp->tp.poll = tuntap_poll; + + printk("TUN/TAP backend - "); +#if 0 + if (lp->host.gate_addr != NULL) + printk("IP = %s", lp->host.gate_addr); +#endif + printk("\n"); + + return 1; +} + +/* ================================ ISS NET ================================ */ + +static int iss_net_rx(struct net_device *dev) +{ + struct iss_net_private *lp = dev->priv; + int pkt_len; + struct sk_buff *skb; + + /* Check if there is any new data. */ + + if (lp->tp.poll(lp) == 0) + return 0; + + /* Try to allocate memory, if it fails, try again next round. */ + + if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) { + lp->stats.rx_dropped++; + return 0; + } + + skb_reserve(skb, 2); + + /* Setup skb */ + + skb->dev = dev; + skb->mac.raw = skb->data; + pkt_len = lp->tp.read(lp, &skb); + skb_put(skb, pkt_len); + + if (pkt_len > 0) { + skb_trim(skb, pkt_len); + skb->protocol = lp->tp.protocol(skb); + // netif_rx(skb); + netif_rx_ni(skb); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + return pkt_len; + } + kfree_skb(skb); + return pkt_len; +} + +static int iss_net_poll(void) +{ + struct list_head *ele; + int err, ret = 0; + + spin_lock(&opened_lock); + + list_for_each(ele, &opened) { + struct iss_net_private *lp; + + lp = list_entry(ele, struct iss_net_private, opened_list); + + if (!netif_running(lp->dev)) + break; + + spin_lock(&lp->lock); + + while ((err = iss_net_rx(lp->dev)) > 0) + ret++; + + spin_unlock(&lp->lock); + + if (err < 0) { + printk(KERN_ERR "Device '%s' read returned %d, " + "shutting it down\n", lp->dev->name, err); + dev_close(lp->dev); + } else { + // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); + } + } + + spin_unlock(&opened_lock); + return ret; +} + + +static void iss_net_timer(unsigned long priv) +{ + struct iss_net_private* lp = (struct iss_net_private*) priv; + + spin_lock(&lp->lock); + + iss_net_poll(); + + mod_timer(&lp->timer, jiffies + lp->timer_val); + + spin_unlock(&lp->lock); +} + + +static int iss_net_open(struct net_device *dev) +{ + struct iss_net_private *lp = dev->priv; + char addr[sizeof "255.255.255.255\0"]; + int err; + + spin_lock(&lp->lock); + + if ((err = lp->tp.open(lp)) < 0) + goto out; + + if (!lp->have_mac) { + dev_ip_addr(dev, addr, &lp->mac[2]); + set_ether_mac(dev, lp->mac); + } + + netif_start_queue(dev); + + /* clear buffer - it can happen that the host side of the interface + * is full when we gethere. In this case, new data is never queued, + * SIGIOs never arrive, and the net never works. + */ + while ((err = iss_net_rx(dev)) > 0) + ; + + spin_lock(&opened_lock); + list_add(&lp->opened_list, &opened); + spin_unlock(&opened_lock); + + init_timer(&lp->timer); + lp->timer_val = ISS_NET_TIMER_VALUE; + lp->timer.data = (unsigned long) lp; + lp->timer.function = iss_net_timer; + mod_timer(&lp->timer, jiffies + lp->timer_val); + +out: + spin_unlock(&lp->lock); + return err; +} + +static int iss_net_close(struct net_device *dev) +{ + struct iss_net_private *lp = dev->priv; +printk("iss_net_close!\n"); + netif_stop_queue(dev); + spin_lock(&lp->lock); + + spin_lock(&opened_lock); + list_del(&opened); + spin_unlock(&opened_lock); + + del_timer_sync(&lp->timer); + + lp->tp.close(lp); + + spin_unlock(&lp->lock); + return 0; +} + +static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct iss_net_private *lp = dev->priv; + unsigned long flags; + int len; + + netif_stop_queue(dev); + spin_lock_irqsave(&lp->lock, flags); + + len = lp->tp.write(lp, &skb); + + if (len == skb->len) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* this is normally done in the interrupt when tx finishes */ + netif_wake_queue(dev); + + } else if (len == 0) { + netif_start_queue(dev); + lp->stats.tx_dropped++; + + } else { + netif_start_queue(dev); + printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len); + } + + spin_unlock_irqrestore(&lp->lock, flags); + + dev_kfree_skb(skb); + return 0; +} + + +static struct net_device_stats *iss_net_get_stats(struct net_device *dev) +{ + struct iss_net_private *lp = dev->priv; + return &lp->stats; +} + +static void iss_net_set_multicast_list(struct net_device *dev) +{ +#if 0 + if (dev->flags & IFF_PROMISC) + return; + else if (dev->mc_count) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; +#endif +} + +static void iss_net_tx_timeout(struct net_device *dev) +{ +#if 0 + dev->trans_start = jiffies; + netif_wake_queue(dev); +#endif +} + +static int iss_net_set_mac(struct net_device *dev, void *addr) +{ +#if 0 + struct iss_net_private *lp = dev->priv; + struct sockaddr *hwaddr = addr; + + spin_lock(&lp->lock); + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + spin_unlock(&lp->lock); +#endif + + return 0; +} + +static int iss_net_change_mtu(struct net_device *dev, int new_mtu) +{ +#if 0 + struct iss_net_private *lp = dev->priv; + int err = 0; + + spin_lock(&lp->lock); + + // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user); + + if (new_mtu < 0) + err = new_mtu; + else + dev->mtu = new_mtu; + + spin_unlock(&lp->lock); + return err; +#endif + return -EINVAL; +} + +static int iss_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ +#if 0 + static const struct ethtool_drvinfo info = { + .cmd = ETHTOOL_GDRVINFO, + .driver = DRIVER_NAME, + .version = "42", + }; + void *useraddr; + u32 ethcmd; + + switch (cmd) { + case SIOCETHTOOL: + useraddr = ifr->ifr_data; + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + default: + return -EOPNOTSUPP; + } + default: + return -EINVAL; + } +#endif + return -EINVAL; +} + +void iss_net_user_timer_expire(unsigned long _conn) +{ +} + + +static struct device_driver iss_net_driver = { + .name = DRIVER_NAME, + .bus = &platform_bus_type, +}; + +static int driver_registered; + +static int iss_net_configure(int index, char *init) +{ + struct net_device *dev; + struct iss_net_private *lp; + int err; + + if ((dev = alloc_etherdev(sizeof *lp)) == NULL) { + printk(KERN_ERR "eth_configure: failed to allocate device\n"); + return 1; + } + + /* Initialize private element. */ + + lp = dev->priv; + *lp = ((struct iss_net_private) { + .device_list = LIST_HEAD_INIT(lp->device_list), + .opened_list = LIST_HEAD_INIT(lp->opened_list), + .lock = SPIN_LOCK_UNLOCKED, + .dev = dev, + .index = index, + //.fd = -1, + .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }, + .have_mac = 0, + }); + + /* + * Try all transport protocols. + * Note: more protocols can be added by adding '&& !X_init(lp, eth)'. + */ + + if (!tuntap_probe(lp, index, init)) { + printk("Invalid arguments. Skipping device!\n"); + goto errout; + } + + printk(KERN_INFO "Netdevice %d ", index); + if (lp->have_mac) + printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", + lp->mac[0], lp->mac[1], + lp->mac[2], lp->mac[3], + lp->mac[4], lp->mac[5]); + printk(": "); + + /* sysfs register */ + + if (!driver_registered) { + driver_register(&iss_net_driver); + driver_registered = 1; + } + + spin_lock(&devices_lock); + list_add(&lp->device_list, &devices); + spin_unlock(&devices_lock); + + lp->pdev.id = index; + lp->pdev.name = DRIVER_NAME; + platform_device_register(&lp->pdev); + SET_NETDEV_DEV(dev,&lp->pdev.dev); + + /* + * If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof dev->name, "eth%d", index); + + dev->mtu = lp->mtu; + dev->open = iss_net_open; + dev->hard_start_xmit = iss_net_start_xmit; + dev->stop = iss_net_close; + dev->get_stats = iss_net_get_stats; + dev->set_multicast_list = iss_net_set_multicast_list; + dev->tx_timeout = iss_net_tx_timeout; + dev->set_mac_address = iss_net_set_mac; + dev->change_mtu = iss_net_change_mtu; + dev->do_ioctl = iss_net_ioctl; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = -1; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + + if (err) { + printk("Error registering net device!\n"); + /* XXX: should we call ->remove() here? */ + free_netdev(dev); + return 1; + } + + init_timer(&lp->tl); + lp->tl.function = iss_net_user_timer_expire; + +#if 0 + if (lp->have_mac) + set_ether_mac(dev, lp->mac); +#endif + return 0; + +errout: + // FIXME: unregister; free, etc.. + return -EIO; + +} + +/* ------------------------------------------------------------------------- */ + +/* Filled in during early boot */ + +struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); + +struct iss_net_init { + struct list_head list; + char *init; /* init string */ + int index; +}; + +/* + * Parse the command line and look for 'ethX=...' fields, and register all + * those fields. They will be later initialized in iss_net_init. + */ + +#define ERR KERN_ERR "iss_net_setup: " + +static int iss_net_setup(char *str) +{ + struct iss_net_private *device = NULL; + struct iss_net_init *new; + struct list_head *ele; + char *end; + int n; + + n = simple_strtoul(str, &end, 0); + if (end == str) { + printk(ERR "Failed to parse '%s'\n", str); + return 1; + } + if (n < 0) { + printk(ERR "Device %d is negative\n", n); + return 1; + } + if (*(str = end) != '=') { + printk(ERR "Expected '=' after device number\n"); + return 1; + } + + spin_lock(&devices_lock); + + list_for_each(ele, &devices) { + device = list_entry(ele, struct iss_net_private, device_list); + if (device->index == n) + break; + } + + spin_unlock(&devices_lock); + + if (device && device->index == n) { + printk(ERR "Device %d already configured\n", n); + return 1; + } + + if ((new = alloc_bootmem(sizeof new)) == NULL) { + printk("Alloc_bootmem failed\n"); + return 1; + } + + INIT_LIST_HEAD(&new->list); + new->index = n; + new->init = str + 1; + + list_add_tail(&new->list, ð_cmd_line); + return 1; +} + +#undef ERR + +__setup("eth", iss_net_setup); + +/* + * Initialize all ISS Ethernet devices previously registered in iss_net_setup. + */ + +static int iss_net_init(void) +{ + struct list_head *ele, *next; + + /* Walk through all Ethernet devices specified in the command line. */ + + list_for_each_safe(ele, next, ð_cmd_line) { + struct iss_net_init *eth; + eth = list_entry(ele, struct iss_net_init, list); + iss_net_configure(eth->index, eth->init); + } + + return 1; +} + +module_init(iss_net_init); + diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c new file mode 100644 index 000000000000..2e6dcbf0cc04 --- /dev/null +++ b/arch/xtensa/platform-iss/setup.c @@ -0,0 +1,112 @@ +/* + * + * arch/xtensa/platform-iss/setup.c + * + * Platform specific initialization. + * + * Authors: Chris Zankel + * Joe Taylor + * + * Copyright 2001 - 2005 Tensilica Inc. + * + * 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, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +void __init platform_init(bp_tag_t* bootparam) +{ + +} + +void platform_halt(void) +{ + printk (" ** Called platform_halt(), looping forever! **\n"); + while (1); +} + +void platform_power_off(void) +{ + printk (" ** Called platform_power_off(), looping forever! **\n"); + while (1); +} +void platform_restart(void) +{ + /* Flush and reset the mmu, simulate a processor reset, and + * jump to the reset vector. */ + + __asm__ __volatile__("movi a2, 15\n\t" + "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t" + "movi a2, 0\n\t" + "wsr a2, " __stringify(ICOUNT) "\n\t" + "wsr a2, " __stringify(IBREAKENABLE) "\n\t" + "wsr a2, " __stringify(LCOUNT) "\n\t" + "movi a2, 0x1f\n\t" + "wsr a2, " __stringify(PS) "\n\t" + "isync\n\t" + "jx %0\n\t" + : + : "a" (XCHAL_RESET_VECTOR_VADDR) + : "a2"); + + /* control never gets here */ +} + +extern void iss_net_poll(void); + +const char twirl[]="|/-\\|/-\\"; + +void platform_heartbeat(void) +{ +#if 0 + static int i = 0, j = 0; + + if (--i < 0) { + i = 99; + printk("\r%c\r", twirl[j++]); + if (j == 8) + j = 0; + } +#endif +} + + + +static int +iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + __asm__ __volatile__("movi a2, -1; simcall\n"); + return NOTIFY_DONE; +} + +static struct notifier_block iss_panic_block = { + iss_panic_event, + NULL, + 0 +}; + +void __init platform_setup(char **p_cmdline) +{ + notifier_chain_register(&panic_notifier_list, &iss_panic_block); +} -- cgit v1.2.3