Index: drivers/net/l4ore.c =================================================================== RCS file: /home/cvs/l4linux-2.6/drivers/net/l4ore.c,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- drivers/net/l4ore.c 26 Jun 2006 14:06:55 -0000 1.11 +++ drivers/net/l4ore.c 12 Jul 2006 15:08:40 -0000 1.12 @@ -2,18 +2,11 @@ * Ore network driver stub. */ -#include -#include -#include -#include #include -#include -#include #include #include -#include #include #include @@ -23,8 +16,11 @@ MODULE_DESCRIPTION("Ore stub driver"); MODULE_LICENSE("GPL"); -static char l4x_ore_devname[8] = "eth0"; static int l4x_ore_irqnum = -1; +static int l4x_ore_numdevs = 1; +#define MAX_OREINST 6 +static char *l4x_ore_instances[MAX_OREINST] = { "ORe:eth0", 0, 0, 0, 0, 0 }; +static LIST_HEAD(l4x_ore_netdevices); #define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X" #define MAC_ARG(x) x->dev_addr[0], x->dev_addr[1], x->dev_addr[2], \ @@ -42,7 +38,10 @@ struct hw_interrupt_type *previous_interrupt_type; }; -static struct net_device *l4x_ore_dev; +struct l4x_ore_netdev { + struct list_head list; + struct net_device *dev; +}; static int l4x_ore_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -89,12 +88,20 @@ struct l4x_ore_priv *priv = netdev_priv(netdev); struct sk_buff *skb; + /* if packet size is zero, this interface did not cause the interrupt */ + if (!priv->pkt_size) + return IRQ_HANDLED; + skb = dev_alloc_skb(priv->pkt_size); if (likely(skb)) { skb->dev = netdev; memcpy(skb_put(skb, priv->pkt_size), priv->pkt_buffer, priv->pkt_size); + /* reset packet size to zero - we do this since we provide + * several interfaces sharing the same IRQ and we need to + * detect on which interface the current IRQ occured */ + priv->pkt_size = 0; skb->protocol = eth_type_trans(skb, netdev); netif_rx(skb); @@ -132,12 +139,10 @@ netdev->name, ret); l4_sleep(100); continue; - } else if (unlikely(ret > 0)) { + } else if (unlikely(ret > 0)) LOG_printf("%s: buffer too small (%d)\n", netdev->name, ret); - } priv->pkt_size = size; - l4x_do_IRQ(netdev->irq, ctx); } } @@ -196,10 +201,10 @@ } if ((err = request_irq(netdev->irq, l4x_ore_interrupt, - SA_SAMPLE_RANDOM, netdev->name, - netdev))) { - printk("%s: request_irq(%d, ...) failed.\n", - netdev->name, netdev->irq); + SA_SAMPLE_RANDOM | SA_SHIRQ, + netdev->name, netdev))) { + printk("%s: request_irq(%d, ...) failed: %d\n", + netdev->name, netdev->irq, err); goto err_out_kfree; } @@ -252,16 +257,37 @@ return 0; } -static int __init l4x_ore_init(void) +/* + * Split 'inst:foo' into separate strings 'inst' and 'foo' + */ +static int l4x_ore_parse_instance(int id, char *inst, int instsize, + char *dev, int devsize) +{ + char *string = l4x_ore_instances[id]; + char *s2; + + s2 = strsep(&string, ":"); + if (!s2 || !string) + return -1; + strcpy(inst, s2); + strcpy(dev, string); + inst[instsize - 1] = 0; + dev[devsize - 1] = 0; + + return 0; +} + +/* Initialize one virtual interface. */ +static int __init l4x_ore_init_device(char *oreinst, char *devname) { struct l4x_ore_priv *priv; - struct net_device *dev; + struct net_device *dev = NULL; + struct l4x_ore_netdev *nd = NULL; int err = -ENODEV; if (!(dev = alloc_etherdev(sizeof(struct l4x_ore_priv)))) return -ENOMEM; - l4x_ore_dev = dev; dev->open = l4x_ore_open; dev->stop = l4x_ore_close; dev->hard_start_xmit = l4x_ore_xmit_frame; @@ -273,12 +299,17 @@ priv->config = L4ORE_DEFAULT_CONFIG; priv->config.rw_debug = 0; priv->config.rw_broadcast = 1; - priv->config.ro_keep_device_mac = 1; + // lo devices have useless MAC 00:00:00:00:00:00 + if (strcmp(devname, "lo")) + priv->config.ro_keep_device_mac = 1; + else + priv->config.ro_keep_device_mac = 0; priv->config.rw_active = 0; + strncpy(priv->config.ro_orename, oreinst, sizeof(priv->config.ro_orename)); + priv->config.ro_orename[sizeof(priv->config.ro_orename)-1] = 0; /* Hmm, we need to open the connection here to get the MAC :/ */ - if ((priv->handle = l4ore_open(l4x_ore_devname, dev->dev_addr, - &priv->config)) < 0) { + if ((priv->handle = l4ore_open(devname, dev->dev_addr, &priv->config)) < 0) { printk("%s: l4ore_open failed: %d\n", dev->name, priv->handle); goto err_out_free_dev; @@ -295,6 +326,14 @@ goto err_out_free_dev; } + nd = kmalloc(sizeof(struct l4x_ore_netdev), GFP_KERNEL); + if (!nd) { + printk("Out of memory.\n"); + return -1; + } + nd->dev = dev; + list_add(&nd->list, &l4x_ore_netdevices); + printk(KERN_INFO "%s: L4Ore card found with " MAC_FMT ", IRQ %d\n", dev->name, MAC_ARG(dev), dev->irq); @@ -306,17 +345,52 @@ return err; } +static int __init l4x_ore_init(void) +{ + int i = 0; + int num_init = 0; + + LOG_printf("Creating %d ORe device(s).\n", l4x_ore_numdevs); + + for (i = 0; i < l4x_ore_numdevs; i++) { + char instbuf[16], devbuf[16]; + int ret = l4x_ore_parse_instance(i, instbuf, sizeof(instbuf), + devbuf, sizeof(devbuf)); + if (!ret) { + LOG_printf("Opening device %s at ORe instance %s\n", + devbuf, instbuf); + ret = l4x_ore_init_device(instbuf, devbuf); + if (!ret) + num_init++; + } + else + LOG_printf("Invalid device string: %s\n", + l4x_ore_instances[i]); + } + + return num_init > 0 ? 0 : -1; +} + static void __exit l4x_ore_exit(void) { - l4ore_close(((struct l4x_ore_priv *)l4x_ore_dev->priv)->handle); - unregister_netdev(l4x_ore_dev); - free_netdev(l4x_ore_dev); + struct list_head *p, *h, *n; + h = &l4x_ore_netdevices; + list_for_each_safe(p, n, h) { + struct l4x_ore_netdev *nd + = list_entry(p, struct l4x_ore_netdev, list); + struct net_device *dev = nd->dev; + l4ore_close(((struct l4x_ore_priv *)dev->priv)->handle); + unregister_netdev(dev); + free_netdev(dev); + list_del(p); + kfree(nd); + } } module_init(l4x_ore_init); module_exit(l4x_ore_exit); -module_param_string(oredev, l4x_ore_devname, sizeof(l4x_ore_devname), 0); -MODULE_PARM_DESC(oredev, "Device name to request at ORe server"); module_param_named(irqnum, l4x_ore_irqnum, int, 0); MODULE_PARM_DESC(irqnum, "Virtual IRQ number override"); +module_param_array_named(instances, l4x_ore_instances, charp, &l4x_ore_numdevs, 0); +MODULE_PARM_DESC(oreinstances, "ORe instances to connect to");