patch-2.4.21 linux-2.4.21/drivers/ieee1394/eth1394.c

Next file: linux-2.4.21/drivers/ieee1394/eth1394.h
Previous file: linux-2.4.21/drivers/ieee1394/dv1394.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/ieee1394/eth1394.c linux-2.4.21/drivers/ieee1394/eth1394.c
@@ -55,9 +55,9 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 #include <asm/delay.h>
 #include <asm/semaphore.h>
-#include <asm/bitops.h>
 #include <net/arp.h>
 
 #include "ieee1394_types.h"
@@ -65,6 +65,7 @@
 #include "ieee1394_transactions.h"
 #include "ieee1394.h"
 #include "highlevel.h"
+#include "iso.h"
 #include "eth1394.h"
 
 #define ETH1394_PRINT_G(level, fmt, args...) \
@@ -77,17 +78,14 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 906 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
 
 static kmem_cache_t *packet_task_cache;
-static struct hpsb_highlevel *hl_handle = NULL;
 
-/* Card handling */
-static LIST_HEAD (host_info_list);
-static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+static struct hpsb_highlevel eth1394_highlevel;
 
 /* Use common.lf to determine header len */
 static int hdr_type_len[] = {
@@ -101,39 +99,8 @@
 MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
 MODULE_LICENSE("GPL");
 
-/* Find our host_info struct for a given host pointer. Must be called
- * under spinlock.  */
-static inline struct host_info *find_host_info (struct hpsb_host *host)
-{
-	struct list_head *lh;
-	struct host_info *hi;
-
-	lh = host_info_list.next;
-	while (lh != &host_info_list) {
-		hi = list_entry (lh, struct host_info, list);
-
-		if (hi->host == host)
-			return hi;
-
-		lh = lh->next;
-	}
-	return NULL;
-}
-
-/* Find the network device for our host */
-static inline struct net_device *ether1394_find_dev (struct hpsb_host *host)
-{
-	struct host_info *hi;
-
-	spin_lock_irq (&host_info_lock);
-	hi = find_host_info (host);
-	spin_unlock_irq (&host_info_lock);
-
-	if (hi == NULL)
-		return NULL;
+static void ether1394_iso(struct hpsb_iso *iso);
 
-	return hi->dev;
-}
 
 /* This is called after an "ifup" */
 static int ether1394_open (struct net_device *dev)
@@ -178,15 +145,26 @@
  * XXX: This is where we need to create a list of skb's for fragmented
  * packets.  */
 static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev,
-			    int proto)
+                                          int proto, struct packet_task *ptask)
 {
 	union eth1394_hdr *hdr =
 		(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
 
+	hdr->words.word1 = 0;
 	hdr->common.lf = ETH1394_HDR_LF_UF;
 	hdr->words.word1 = htons(hdr->words.word1);
 	hdr->uf.ether_type = proto;
 
+	/* Set the transmission type for the packet.  Right now only ARP
+	 * packets are sent via GASP.  IP broadcast and IP multicast are not
+	 * yet supported properly, they too should use GASP. */
+	switch(proto) {
+	case __constant_htons(ETH_P_ARP):
+		ptask->tx_type = ETH1394_GASP;
+		break;
+	default:
+		ptask->tx_type = ETH1394_WRREQ;
+	}
 	return;
 }
 
@@ -199,14 +177,14 @@
 {
 	struct eth1394_priv *priv =
 		(struct eth1394_priv *)(dev->priv);
-	u16 phy_id = priv->host->node_id & NODE_MASK;
+	u16 phy_id = NODEID_TO_NODE(priv->host->node_id);
 
 	unsigned char *arp_ptr = (unsigned char *)skb->data;
 	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
 	unsigned char arp_data[2*(dev->addr_len+4)];
 
 	/* Copy the main data that we need */
-	arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
+	memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
 
 	/* Extend the buffer enough for our new header */
 	skb_put (skb, sizeof (struct eth1394_arp) -
@@ -214,7 +192,7 @@
 
 #define PROCESS_MEMBER(ptr,val,len) \
   memcpy (val, ptr, len); ptr += len
-	arp_ptr += arp1394->hw_addr_len;
+	arp_ptr = arp_data + arp1394->hw_addr_len;
 	PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len);
 	arp_ptr += arp1394->hw_addr_len;
 	PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len);
@@ -279,7 +257,8 @@
 {
 	unsigned long flags;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	int phy_id = priv->host->node_id & NODE_MASK;
+	int phy_id = NODEID_TO_NODE(priv->host->node_id);
+	struct hpsb_host *host = priv->host;
 
 	spin_lock_irqsave (&priv->lock, flags);
 
@@ -289,20 +268,23 @@
 	memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
 	memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
 
+	priv->bc_state = ETHER1394_BC_CHECK;
+
 	/* Register our limits now */
-	ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf,
-				   priv->host->speed_map[(phy_id << 6) + phy_id],
-				   (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) |
-				   be32_to_cpu(priv->host->csr.rom[4])),
+	ether1394_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf,
+				   host->speed_map[(phy_id << 6) + phy_id],
+				   (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) |
+				   be32_to_cpu(host->csr.rom[4])),
 				   ETHER1394_REGION_ADDR >> 32,
 				   ETHER1394_REGION_ADDR & 0xffffffff, priv);
 
 	/* We'll use our max_rec as the default mtu */
 	if (set_mtu)
-		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr);
+		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */
+			(sizeof (union eth1394_hdr) + 8);	/* (hdr + GASP) */
 
 	/* Set our hardware address while we're at it */
-	*(nodeid_t *)dev->dev_addr = htons (priv->host->node_id);
+	*(nodeid_t *)dev->dev_addr = htons (host->node_id);
 
 	spin_unlock_irqrestore (&priv->lock, flags);
 }
@@ -358,35 +340,41 @@
 	priv = (struct eth1394_priv *)dev->priv;
 
 	priv->host = host;
+	spin_lock_init(&priv->lock);
 
-	hi = (struct host_info *)kmalloc (sizeof (struct host_info),
-					  GFP_KERNEL);
+	hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
 
 	if (hi == NULL)
 		goto out;
 
 	if (register_netdev (dev)) {
 		ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
-		kfree (dev);
-		return;
+		goto out;
 	}
 
 	ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n",
 		       host->driver->name);
 
-	INIT_LIST_HEAD (&hi->list);
 	hi->host = host;
 	hi->dev = dev;
 
-	spin_lock_irq (&host_info_lock);
-	list_add_tail (&hi->list, &host_info_list);
-	spin_unlock_irq (&host_info_lock);
-
+	/* Ignore validity in hopes that it will be set in the future.  It'll
+	 * check it on transmit. */
+	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
+
+	priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel,
+				       1, ether1394_iso);
+	if (priv->iso == NULL) {
+		priv->bc_state = ETHER1394_BC_CLOSED;
+	}
 	return;
 
 out:
 	if (dev != NULL)
 		kfree (dev);
+	if (hi)
+		hpsb_destroy_hostinfo(&eth1394_highlevel, host);
+
 	ETH1394_PRINT_G (KERN_ERR, "Out of memory\n");
 
 	return;
@@ -395,17 +383,17 @@
 /* Remove a card from our list */
 static void ether1394_remove_host (struct hpsb_host *host)
 {
-	struct host_info *hi;
+	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 
-	spin_lock_irq (&host_info_lock);
-	hi = find_host_info (host);
 	if (hi != NULL) {
+		struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv;
+
+		priv->bc_state = ETHER1394_BC_CLOSED;
 		unregister_netdev (hi->dev);
+		hpsb_iso_shutdown(priv->iso);
+
 		kfree (hi->dev);
-		list_del (&hi->list);
-		kfree (hi);
 	}
-	spin_unlock_irq (&host_info_lock);
 
 	return;
 }
@@ -413,12 +401,15 @@
 /* A reset has just arisen */
 static void ether1394_host_reset (struct hpsb_host *host)
 {
-	struct net_device *dev = ether1394_find_dev(host);
+	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
+	struct net_device *dev;
 
 	/* This can happen for hosts that we don't use */
-	if (dev == NULL)
+	if (hi == NULL)
 		return;
 
+	dev = hi->dev;
+
 	/* Reset our private host data, but not our mtu */
 	netif_stop_queue (dev);
 	ether1394_reset_priv (dev, 0);
@@ -479,7 +470,7 @@
 	 * about the sending machine.  */
 	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
 		unsigned long flags;
-		u16 phy_id = srcid & NODE_MASK;
+		u16 phy_id = NODEID_TO_NODE(srcid);
 		struct eth1394_priv *priv =
 			(struct eth1394_priv *)dev->priv;
 		struct eth1394_arp arp1394;
@@ -497,7 +488,7 @@
 		spin_unlock_irqrestore (&priv->lock, flags);
 
 #define PROCESS_MEMBER(ptr,val,len) \
-  ptr = memcpy (ptr, val, len) + len
+  memcpy (ptr, val, len); ptr += len
                 PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len);
                 PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4);
                 PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len);
@@ -522,20 +513,23 @@
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
 static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len)
+			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
 	unsigned long flags;
-	struct net_device *dev = ether1394_find_dev (host);
+	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
+	struct net_device *dev;
 	struct eth1394_priv *priv;
 
-	if (dev == NULL) {
+	if (hi == NULL) {
 		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
 				 host);
 		return RCODE_ADDRESS_ERROR;
 	}
 
+	dev = hi->dev;
+
 	priv = (struct eth1394_priv *)dev->priv;
 
 	/* A packet has been received by the ieee1394 bus. Build an skbuff
@@ -590,6 +584,107 @@
 	return RCODE_COMPLETE;
 }
 
+static void ether1394_iso(struct hpsb_iso *iso)
+{
+	struct sk_buff *skb;
+	quadlet_t *data;
+	char *buf;
+	unsigned long flags;
+	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
+	struct net_device *dev;
+	struct eth1394_priv *priv;
+	unsigned int len;
+	u32 specifier_id;
+	u16 source_id;
+	int i;
+	int nready;
+
+	if (hi == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
+				 iso->host->driver->name);
+		return;
+	}
+
+	dev = hi->dev;
+
+	nready = hpsb_iso_n_ready(iso);
+	for(i = 0; i < nready; i++) {
+		struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i];
+		data = (quadlet_t*) (iso->data_buf.kvirt + info->offset);
+
+		/* skip over GASP header */
+		buf = (char *)data + 8;
+		len = info->len - 8;
+
+		specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) |
+				((be32_to_cpu(data[1]) & 0xff000000) >> 24));
+		source_id = be32_to_cpu(data[0]) >> 16;
+
+		priv = (struct eth1394_priv *)dev->priv;
+
+		if (info->channel != priv->broadcast_channel ||
+		    specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+			/* This packet is not for us */
+			continue;
+		}
+
+		/* A packet has been received by the ieee1394 bus. Build an skbuff
+		 * around it so we can pass it to the high level network layer. */
+		skb = dev_alloc_skb (len + dev->hard_header_len + 15);
+		if (!skb) {
+			HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+			priv->stats.rx_dropped++;
+			break;
+		}
+
+		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+		memcpy (skb_put (skb, len), buf, len);
+
+		/* Write metadata, and then pass to the receive level */
+		skb->dev = dev;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;	/* don't check it */
+
+		/* Parse the encapsulation header. This actually does the job of
+		 * converting to an ethernet frame header, aswell as arp
+		 * conversion if needed. ARP conversion is easier in this
+		 * direction, since we are using ethernet as our backend.  */
+		skb->protocol = ether1394_parse_encap (skb, dev, source_id,
+						       LOCAL_BUS | ALL_NODES);
+
+		spin_lock_irqsave (&priv->lock, flags);
+		if (!skb->protocol) {
+			priv->stats.rx_errors++;
+			priv->stats.rx_dropped++;
+			dev_kfree_skb_any(skb);
+			goto bad_proto;
+		}
+
+		netif_stop_queue(dev);
+		if (netif_rx (skb) == NET_RX_DROP) {
+			priv->stats.rx_errors++;
+			priv->stats.rx_dropped++;
+			goto bad_proto;
+		}
+
+		/* Statistics */
+		priv->stats.rx_packets++;
+		priv->stats.rx_bytes += skb->len;
+
+	bad_proto:
+		spin_unlock_irqrestore (&priv->lock, flags);
+	}
+
+	hpsb_iso_recv_release_packets(iso, i);
+
+	netif_start_queue(dev);
+	
+	dev->last_rx = jiffies;
+
+	return;
+}
+
+
 /* This function is our scheduled write */
 static void hpsb_write_sched (void *__ptask)
 {
@@ -597,13 +692,26 @@
 	struct sk_buff *skb = ptask->skb;
 	struct net_device *dev = ptask->skb->dev;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-        unsigned long flags;
+	unsigned long flags;
+	int status;
+ 
+	if (ptask->tx_type == ETH1394_GASP) {
+		status  = hpsb_send_gasp(priv->host, priv->broadcast_channel,
+					 get_hpsb_generation(priv->host),
+					 (quadlet_t *)skb->data, skb->len,
+					 ETHER1394_GASP_SPECIFIER_ID,
+					 ETHER1394_GASP_VERSION);
+	} else {
+		status = hpsb_write(priv->host, ptask->dest_node,
+				    get_hpsb_generation(priv->host),
+				    ptask->addr, (quadlet_t *)skb->data,
+				    skb->len);
+	}
+
 
 	/* Statistics */
 	spin_lock_irqsave (&priv->lock, flags);
-	if (!hpsb_write(priv->host, ptask->dest_node,
-			get_hpsb_generation(priv->host),
-			ptask->addr, (quadlet_t *)skb->data, skb->len)) {
+	if (!status) {
 		priv->stats.tx_bytes += skb->len;
 		priv->stats.tx_packets++;
 	} else {
@@ -635,6 +743,67 @@
 	struct packet_task *ptask = NULL;
 	int ret = 0;
 
+	spin_lock_irqsave (&priv->lock, flags);
+	if (priv->bc_state == ETHER1394_BC_CLOSED) {
+		ETH1394_PRINT(KERN_ERR, dev->name,
+			      "Cannot send packet, no broadcast channel available.");
+		ret = -EAGAIN;
+		goto fail;
+	}
+
+	/* First time sending?  Need a broadcast channel for ARP and for
+	 * listening on */
+	if (priv->bc_state == ETHER1394_BC_CHECK) {
+		quadlet_t bc;
+
+		/* Get the local copy of the broadcast channel and check its
+		 * validity (the IRM should validate it for us) */
+
+		bc = priv->host->csr.broadcast_channel;
+
+		if ((bc & 0xc0000000) != 0xc0000000) {
+			/* broadcast channel not validated yet */
+			ETH1394_PRINT(KERN_WARNING, dev->name,
+				      "Error BROADCAST_CHANNEL register valid "
+				      "bit not set, can't send IP traffic\n");
+			hpsb_iso_shutdown(priv->iso);
+			priv->bc_state = ETHER1394_BC_CLOSED;
+			ret = -EAGAIN;
+			spin_unlock_irqrestore (&priv->lock, flags);
+			goto fail;
+		}
+		if (priv->broadcast_channel != (bc & 0x3f)) {
+			/* This really shouldn't be possible, but just in case
+			 * the IEEE 1394 spec changes regarding broadcast
+			 * channels in the future. */
+			hpsb_iso_shutdown(priv->iso);
+
+			priv->broadcast_channel = bc & 0x3f;
+			ETH1394_PRINT(KERN_WARNING, dev->name,
+				      "Changing to broadcast channel %d...\n",
+				      priv->broadcast_channel);
+
+			priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096,
+						       8, priv->broadcast_channel,
+						       1, ether1394_iso);
+			if (priv->iso == NULL) {
+				ret = -EAGAIN;
+				goto fail;
+			}
+		}
+		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
+			ETH1394_PRINT(KERN_ERR, dev->name,
+				      "Could not start async reception\n");
+			hpsb_iso_shutdown(priv->iso);
+			priv->bc_state = ETHER1394_BC_CLOSED;
+			ret = -EAGAIN;
+			spin_unlock_irqrestore (&priv->lock, flags);
+			goto fail;
+		}
+		priv->bc_state = ETHER1394_BC_OPENED;
+	}
+	spin_unlock_irqrestore (&priv->lock, flags);
+
 	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
 		ret = -ENOMEM;
 		goto fail;
@@ -653,8 +822,14 @@
 	if (proto == __constant_htons (ETH_P_ARP))
 		ether1394_arp_to_1394arp (skb, dev);
 
+	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+	if (ptask == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	/* Now add our encapsulation header */
-	ether1394_encapsulate (skb, dev, proto);
+	ether1394_encapsulate (skb, dev, proto, ptask);
 
 	/* TODO: The above encapsulate function needs to recognize when a
 	 * packet needs to be split for a specified node. It should create
@@ -662,26 +837,22 @@
 	 * call to schedule our writes.  */
 
 	/* XXX: Right now we accept that we don't exactly follow RFC. When
-	 * we do, we will send ARP requests via GASP format, and so we wont
+	 * we do, we will send ARP requests via GASP format, and so we won't
 	 * need this hack.  */
 
 	spin_lock_irqsave (&priv->lock, flags);
-	addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 |
-		priv->fifo_lo[dest_node & NODE_MASK];
+	addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 |
+		priv->fifo_lo[NODEID_TO_NODE(dest_node)];
 	spin_unlock_irqrestore (&priv->lock, flags);
 
 	if (!addr)
 		addr = ETHER1394_REGION_ADDR;
 
-	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
-	if (ptask == NULL) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
 	ptask->skb = skb;
 	ptask->addr = addr;
 	ptask->dest_node = dest_node;
+	/* TODO: When 2.4 is out of the way, give each of our ethernet
+	 * dev's a workqueue to handle these.  */
 	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
 	schedule_task(&ptask->tq);
 
@@ -699,7 +870,7 @@
 		netif_wake_queue (dev);
 	spin_unlock_irqrestore (&priv->lock, flags);
 
-	return ret;
+	return 0;  /* returning non-zero causes serious problems */
 }
 
 /* Function for incoming 1394 packets */
@@ -708,7 +879,8 @@
 };
 
 /* Ieee1394 highlevel driver functions */
-static struct hpsb_highlevel_ops hl_ops = {
+static struct hpsb_highlevel eth1394_highlevel = {
+	.name =		ETHER1394_DRIVER_NAME,
 	.add_host =	ether1394_add_host,
 	.remove_host =	ether1394_remove_host,
 	.host_reset =	ether1394_host_reset,
@@ -720,14 +892,9 @@
 					      0, 0, NULL, NULL);
 
 	/* Register ourselves as a highlevel driver */
-	hl_handle = hpsb_register_highlevel (ETHER1394_DRIVER_NAME, &hl_ops);
-
-	if (hl_handle == NULL) {
-		ETH1394_PRINT_G (KERN_ERR, "No more memory for driver\n");
-		return -ENOMEM;
-	}
+	hpsb_register_highlevel(&eth1394_highlevel);
 
-	hpsb_register_addrspace (hl_handle, &addr_ops, ETHER1394_REGION_ADDR,
+	hpsb_register_addrspace(&eth1394_highlevel, &addr_ops, ETHER1394_REGION_ADDR,
 				 ETHER1394_REGION_ADDR_END);
 
 	return 0;
@@ -735,7 +902,7 @@
 
 static void __exit ether1394_exit_module (void)
 {
-	hpsb_unregister_highlevel (hl_handle);
+	hpsb_unregister_highlevel(&eth1394_highlevel);
 	kmem_cache_destroy(packet_task_cache);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)