diff options
Diffstat (limited to 'arch/xtensa/platforms/iss/network.c')
| -rw-r--r-- | arch/xtensa/platforms/iss/network.c | 355 | 
1 files changed, 107 insertions, 248 deletions
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index f717e20d961..d05f8feeb8d 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -38,7 +38,7 @@  #define DRIVER_NAME "iss-netdev"  #define ETH_MAX_PACKET 1500  #define ETH_HEADER_OTHER 14 -#define ISS_NET_TIMER_VALUE (2 * HZ) +#define ISS_NET_TIMER_VALUE (HZ / 10)  static DEFINE_SPINLOCK(opened_lock); @@ -56,8 +56,6 @@ static LIST_HEAD(devices);  struct tuntap_info {  	char dev_name[IFNAMSIZ]; -	int fixed_config; -	unsigned char gw[ETH_ALEN];  	int fd;  }; @@ -67,7 +65,6 @@ struct tuntap_info {  /* This structure contains out private information for the driver. */  struct iss_net_private { -  	struct list_head device_list;  	struct list_head opened_list; @@ -83,9 +80,6 @@ struct iss_net_private {  	int index;  	int mtu; -	unsigned char mac[ETH_ALEN]; -	int have_mac; -  	struct {  		union {  			struct tuntap_info tuntap; @@ -101,55 +95,6 @@ struct iss_net_private {  }; -/* ======================= 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) __attribute__((__noinline__)); -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 ================================ */ @@ -167,68 +112,48 @@ static char *split_if_spec(char *str, ...)  			*arg = str;  		if (end == NULL)  			return NULL; -		*end ++ = '\0'; +		*end++ = '\0';  		str = end;  	}  	va_end(ap);  	return str;  } +/* Set Ethernet address of the specified device. */ -#if 0 -/* Adjust SKB. */ - -struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) +static void setup_etheraddr(struct net_device *dev, char *str)  { -	if ((skb != NULL) && (skb_tailroom(skb) < extra)) { -		struct sk_buff *skb2; +	unsigned char *addr = dev->dev_addr; -		skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); -		dev_kfree_skb(skb); -		skb = skb2; -	} -	if (skb != NULL) -		skb_put(skb, extra); +	if (str == NULL) +		goto random; -	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; +	if (!mac_pton(str, addr)) { +		pr_err("%s: failed to parse '%s' as an ethernet address\n", +		       dev->name, str); +		goto random;  	} - -	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; +	if (is_multicast_ether_addr(addr)) { +		pr_err("%s: attempt to assign a multicast ethernet address\n", +		       dev->name); +		goto random;  	} -} - -/* Set Ethernet address of the specified device. */ +	if (!is_valid_ether_addr(addr)) { +		pr_err("%s: attempt to assign an invalid ethernet address\n", +		       dev->name); +		goto random; +	} +	if (!is_local_ether_addr(addr)) +		pr_warn("%s: assigning a globally valid ethernet address\n", +			dev->name); +	return; -static void inline set_ether_mac(void *d, unsigned char *addr) -{ -	struct net_device *dev = d; -	memcpy(dev->dev_addr, addr, ETH_ALEN); +random: +	pr_info("%s: choosing a random ethernet address\n", +		dev->name); +	eth_hw_addr_random(dev);  } -  /* ======================= TUNTAP TRANSPORT INTERFACE ====================== */  static int tuntap_open(struct iss_net_private *lp) @@ -238,24 +163,21 @@ static int tuntap_open(struct iss_net_private *lp)  	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); +	fd = simc_open("/dev/net/tun", 02, 0); /* O_RDWR */ +	if (fd < 0) { +		pr_err("%s: failed to open /dev/net/tun, returned %d (errno = %d)\n", +		       lp->dev->name, fd, errno);  		return fd;  	} -	memset(&ifr, 0, sizeof ifr); +	memset(&ifr, 0, sizeof(ifr));  	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; -	strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name); +	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); +	err = simc_ioctl(fd, TUNSETIFF, &ifr); +	if (err < 0) { +		pr_err("%s: failed to set interface %s, returned %d (errno = %d)\n", +		       lp->dev->name, dev_name, err, errno);  		simc_close(fd);  		return err;  	} @@ -266,27 +188,17 @@ static int tuntap_open(struct iss_net_private *lp)  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) +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) +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);  } @@ -302,45 +214,45 @@ static int tuntap_poll(struct iss_net_private *lp)  }  /* - * Currently only a device name is supported. - * ethX=tuntap[,[mac address][,[device name]]] + * 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); +	struct net_device *dev = lp->dev;  	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)) +	if (strncmp(init, TRANSPORT_TUNTAP_NAME, +		    sizeof(TRANSPORT_TUNTAP_NAME) - 1))  		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); +	init += sizeof(TRANSPORT_TUNTAP_NAME) - 1; +	if (*init == ',') { +		rem = split_if_spec(init + 1, &mac_str, &dev_name); +		if (rem != NULL) { +			pr_err("%s: extra garbage on specification : '%s'\n", +			       dev->name, rem);  			return 0;  		}  	} else if (*init != '\0') { -		printk("Invalid argument: %s. Skipping device!\n", init); +		pr_err("%s: invalid argument: %s. Skipping device!\n", +		       dev->name, 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 (!dev_name) { +		pr_err("%s: missing tuntap device name\n", dev->name); +		return 0; +	} +	strlcpy(lp->tp.info.tuntap.dev_name, dev_name, +		sizeof(lp->tp.info.tuntap.dev_name)); -#if 0 -	if (setup_etheraddr(mac_str, lp->mac)) -		lp->have_mac = 1; -#endif -	lp->mtu = TRANSPORT_TUNTAP_MTU; +	setup_etheraddr(dev, mac_str); -	//lp->info.tuntap.gate_addr = gate_addr; +	lp->mtu = TRANSPORT_TUNTAP_MTU;  	lp->tp.info.tuntap.fd = -1; @@ -351,13 +263,6 @@ static int tuntap_probe(struct iss_net_private *lp, int index, char *init)  	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;  } @@ -376,7 +281,8 @@ static int iss_net_rx(struct net_device *dev)  	/* Try to allocate memory, if it fails, try again next round. */ -	if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) { +	skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER); +	if (skb == NULL) {  		lp->stats.rx_dropped++;  		return 0;  	} @@ -396,7 +302,6 @@ static int iss_net_rx(struct net_device *dev)  		lp->stats.rx_bytes += skb->len;  		lp->stats.rx_packets++; -	//	netif_rx(skb);  		netif_rx_ni(skb);  		return pkt_len;  	} @@ -427,11 +332,11 @@ static int iss_net_poll(void)  		spin_unlock(&lp->lock);  		if (err < 0) { -			printk(KERN_ERR "Device '%s' read returned %d, " -			       "shutting it down\n", lp->dev->name, err); +			pr_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); +			/* FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); */  		}  	} @@ -442,14 +347,11 @@ static int iss_net_poll(void)  static void iss_net_timer(unsigned long priv)  { -	struct iss_net_private* lp = (struct iss_net_private*) 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);  } @@ -457,19 +359,14 @@ static void iss_net_timer(unsigned long priv)  static int iss_net_open(struct net_device *dev)  {  	struct iss_net_private *lp = netdev_priv(dev); -	char addr[sizeof "255.255.255.255\0"];  	int err;  	spin_lock(&lp->lock); -	if ((err = lp->tp.open(lp)) < 0) +	err = lp->tp.open(lp); +	if (err < 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 @@ -497,7 +394,6 @@ out:  static int iss_net_close(struct net_device *dev)  {  	struct iss_net_private *lp = netdev_priv(dev); -printk("iss_net_close!\n");  	netif_stop_queue(dev);  	spin_lock(&lp->lock); @@ -539,7 +435,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)  	} else {  		netif_start_queue(dev); -		printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len); +		pr_err("%s: %s failed(%d)\n", dev->name, __func__, len);  	}  	spin_unlock_irqrestore(&lp->lock, flags); @@ -557,56 +453,27 @@ static struct net_device_stats *iss_net_get_stats(struct net_device *dev)  static void iss_net_set_multicast_list(struct net_device *dev)  { -#if 0 -	if (dev->flags & IFF_PROMISC) -		return; -	else if (!netdev_mc_empty(dev)) -		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 = netdev_priv(dev);  	struct sockaddr *hwaddr = addr; +	if (!is_valid_ether_addr(hwaddr->sa_data)) +		return -EADDRNOTAVAIL;  	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 = netdev_priv(dev); -	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;  } @@ -631,9 +498,8 @@ static const struct net_device_ops iss_netdev_ops = {  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_change_mtu		= iss_net_change_mtu,  	.ndo_set_mac_address	= iss_net_set_mac, -	//.ndo_do_ioctl		= iss_net_ioctl,  	.ndo_tx_timeout		= iss_net_tx_timeout, -	.ndo_set_multicast_list = iss_net_set_multicast_list, +	.ndo_set_rx_mode	= iss_net_set_multicast_list,  };  static int iss_net_configure(int index, char *init) @@ -642,24 +508,29 @@ static int iss_net_configure(int index, char *init)  	struct iss_net_private *lp;  	int err; -	if ((dev = alloc_etherdev(sizeof *lp)) == NULL) { -		printk(KERN_ERR "eth_configure: failed to allocate device\n"); +	dev = alloc_etherdev(sizeof(*lp)); +	if (dev == NULL) { +		pr_err("eth_configure: failed to allocate device\n");  		return 1;  	}  	/* Initialize private element. */  	lp = netdev_priv(dev); -	*lp = ((struct iss_net_private) { +	*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(lp.lock),  		.dev			= dev,  		.index			= index, -		//.fd                   = -1, -		.mac			= { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }, -		.have_mac		= 0, -		}); +		}; + +	/* +	 * 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);  	/*  	 * Try all transport protocols. @@ -667,14 +538,12 @@ static int iss_net_configure(int index, char *init)  	 */  	if (!tuntap_probe(lp, index, init)) { -		printk("Invalid arguments. Skipping device!\n"); +		pr_err("%s: invalid arguments. Skipping device!\n", +		       dev->name);  		goto errout;  	} -	printk(KERN_INFO "Netdevice %d ", index); -	if (lp->have_mac) -		printk("(%pM) ", lp->mac); -	printk(": "); +	pr_info("Netdevice %d (%pM)\n", index, dev->dev_addr);  	/* sysfs register */ @@ -690,14 +559,7 @@ static int iss_net_configure(int index, char *init)  	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); +	SET_NETDEV_DEV(dev, &lp->pdev.dev);  	dev->netdev_ops = &iss_netdev_ops;  	dev->mtu = lp->mtu; @@ -709,7 +571,7 @@ static int iss_net_configure(int index, char *init)  	rtnl_unlock();  	if (err) { -		printk("Error registering net device!\n"); +		pr_err("%s: error registering net device!\n", dev->name);  		/* XXX: should we call ->remove() here? */  		free_netdev(dev);  		return 1; @@ -718,16 +580,11 @@ static int iss_net_configure(int index, char *init)  	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.. +	/* FIXME: unregister; free, etc.. */  	return -EIO; -  }  /* ------------------------------------------------------------------------- */ @@ -749,27 +606,28 @@ struct iss_net_init {  #define ERR KERN_ERR "iss_net_setup: " -static int iss_net_setup(char *str) +static int __init iss_net_setup(char *str)  {  	struct iss_net_private *device = NULL;  	struct iss_net_init *new;  	struct list_head *ele;  	char *end; -	int n; +	int rc; +	unsigned 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); +	end = strchr(str, '='); +	if (!end) { +		printk(ERR "Expected '=' after device number\n");  		return 1;  	} -	if (*(str = end) != '=') { -		printk(ERR "Expected '=' after device number\n"); +	*end = 0; +	rc = kstrtouint(str, 0, &n); +	*end = '='; +	if (rc < 0) { +		printk(ERR "Failed to parse '%s'\n", str);  		return 1;  	} +	str = end;  	spin_lock(&devices_lock); @@ -782,12 +640,13 @@ static int iss_net_setup(char *str)  	spin_unlock(&devices_lock);  	if (device && device->index == n) { -		printk(ERR "Device %d already configured\n", n); +		printk(ERR "Device %u already configured\n", n);  		return 1;  	} -	if ((new = alloc_bootmem(sizeof new)) == NULL) { -		printk("Alloc_bootmem failed\n"); +	new = alloc_bootmem(sizeof(*new)); +	if (new == NULL) { +		printk(ERR "Alloc_bootmem failed\n");  		return 1;  	} @@ -801,7 +660,7 @@ static int iss_net_setup(char *str)  #undef ERR -__setup("eth=", iss_net_setup); +__setup("eth", iss_net_setup);  /*   * Initialize all ISS Ethernet devices previously registered in iss_net_setup.  | 
