From b26d0ab0e6fa3a886d2799bf89eb05dd52f8b7c2 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 13 Sep 2007 13:44:07 -0700 Subject: [XTENSA] Concentrate platforms into one platforms directory. Create arch/xtensa/platforms/ directory to concentrate all platforms under that subdirectory and moves the ISS platform to that directory. Signed-off-by: Chris Zankel --- arch/xtensa/Makefile | 2 +- arch/xtensa/platform-iss/Makefile | 8 - arch/xtensa/platform-iss/console.c | 296 ------------- arch/xtensa/platform-iss/io.c | 32 -- arch/xtensa/platform-iss/network.c | 822 ------------------------------------ arch/xtensa/platform-iss/setup.c | 110 ----- arch/xtensa/platforms/iss/Makefile | 8 + arch/xtensa/platforms/iss/console.c | 296 +++++++++++++ arch/xtensa/platforms/iss/io.c | 32 ++ arch/xtensa/platforms/iss/network.c | 822 ++++++++++++++++++++++++++++++++++++ arch/xtensa/platforms/iss/setup.c | 110 +++++ 11 files changed, 1269 insertions(+), 1269 deletions(-) delete mode 100644 arch/xtensa/platform-iss/Makefile delete mode 100644 arch/xtensa/platform-iss/console.c delete mode 100644 arch/xtensa/platform-iss/io.c delete mode 100644 arch/xtensa/platform-iss/network.c delete mode 100644 arch/xtensa/platform-iss/setup.c create mode 100644 arch/xtensa/platforms/iss/Makefile create mode 100644 arch/xtensa/platforms/iss/console.c create mode 100644 arch/xtensa/platforms/iss/io.c create mode 100644 arch/xtensa/platforms/iss/network.c create mode 100644 arch/xtensa/platforms/iss/setup.c (limited to 'arch') diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 56685a883347..4bd1e14c6b90 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -59,7 +59,7 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) head-y := arch/xtensa/kernel/head.o core-y += arch/xtensa/kernel/ arch/xtensa/mm/ ifneq ($(PLATFORM),) -core-y += arch/xtensa/platform-$(PLATFORM)/ +core-y += arch/xtensa/platforms/$(PLATFORM)/ endif libs-y += arch/xtensa/lib/ $(LIBGCC) diff --git a/arch/xtensa/platform-iss/Makefile b/arch/xtensa/platform-iss/Makefile deleted file mode 100644 index af96e314d71f..000000000000 --- a/arch/xtensa/platform-iss/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $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. -# - -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 deleted file mode 100644 index 854677d0c3f6..000000000000 --- a/arch/xtensa/platform-iss/console.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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 - -#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_insert_flip_char(tty, c, 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); -} - - -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 deleted file mode 100644 index 5b161a5cb65f..000000000000 --- a/arch/xtensa/platform-iss/io.c +++ /dev/null @@ -1,32 +0,0 @@ -/* 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 deleted file mode 100644 index d89fb18d7971..000000000000 --- a/arch/xtensa/platform-iss/network.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * - * 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 - -#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; - __be32 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); - - 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_reset_mac_header(skb); - 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); - - lp->stats.rx_bytes += skb->len; - lp->stats.rx_packets++; - // netif_rx(skb); - netif_rx_ni(skb); - 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 get here. 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; -} - -void iss_net_user_timer_expire(unsigned long _conn) -{ -} - - -static struct platform_driver iss_net_driver = { - .driver = { - .name = DRIVER_NAME, - }, -}; - -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) { - platform_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->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 deleted file mode 100644 index f60c8cf6dfbe..000000000000 --- a/arch/xtensa/platform-iss/setup.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * 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 - - -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) -{ - atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); -} diff --git a/arch/xtensa/platforms/iss/Makefile b/arch/xtensa/platforms/iss/Makefile new file mode 100644 index 000000000000..af96e314d71f --- /dev/null +++ b/arch/xtensa/platforms/iss/Makefile @@ -0,0 +1,8 @@ +# $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. +# + +obj-y = io.o console.o setup.o network.o + diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c new file mode 100644 index 000000000000..854677d0c3f6 --- /dev/null +++ b/arch/xtensa/platforms/iss/console.c @@ -0,0 +1,296 @@ +/* + * 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 + +#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_insert_flip_char(tty, c, 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); +} + + +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/platforms/iss/io.c b/arch/xtensa/platforms/iss/io.c new file mode 100644 index 000000000000..5b161a5cb65f --- /dev/null +++ b/arch/xtensa/platforms/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/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c new file mode 100644 index 000000000000..d89fb18d7971 --- /dev/null +++ b/arch/xtensa/platforms/iss/network.c @@ -0,0 +1,822 @@ +/* + * + * 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 + +#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; + __be32 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); + + 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_reset_mac_header(skb); + 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); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + // netif_rx(skb); + netif_rx_ni(skb); + 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 get here. 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; +} + +void iss_net_user_timer_expire(unsigned long _conn) +{ +} + + +static struct platform_driver iss_net_driver = { + .driver = { + .name = DRIVER_NAME, + }, +}; + +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) { + platform_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->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/platforms/iss/setup.c b/arch/xtensa/platforms/iss/setup.c new file mode 100644 index 000000000000..f60c8cf6dfbe --- /dev/null +++ b/arch/xtensa/platforms/iss/setup.c @@ -0,0 +1,110 @@ +/* + * + * 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 + + +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) +{ + atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); +} -- cgit v1.2.3-59-g8ed1b