diff options
Diffstat (limited to 'drivers/firewire/net.c')
| -rw-r--r-- | drivers/firewire/net.c | 803 | 
1 files changed, 427 insertions, 376 deletions
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 18fdd9703b4..c3986452194 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1,5 +1,6 @@  /*   * IPv4 over IEEE 1394, per RFC 2734 + * IPv6 over IEEE 1394, per RFC 3146   *   * Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com>   * @@ -7,7 +8,10 @@   */  #include <linux/bug.h> +#include <linux/compiler.h> +#include <linux/delay.h>  #include <linux/device.h> +#include <linux/ethtool.h>  #include <linux/firewire.h>  #include <linux/firewire-constants.h>  #include <linux/highmem.h> @@ -25,9 +29,16 @@  #include <asm/unaligned.h>  #include <net/arp.h> +#include <net/firewire.h> -#define FWNET_MAX_FRAGMENTS	25	/* arbitrary limit */ -#define FWNET_ISO_PAGE_COUNT	(PAGE_SIZE < 16 * 1024 ? 4 : 2) +/* rx limits */ +#define FWNET_MAX_FRAGMENTS		30 /* arbitrary, > TX queue depth */ +#define FWNET_ISO_PAGE_COUNT		(PAGE_SIZE < 16*1024 ? 4 : 2) + +/* tx limits */ +#define FWNET_MAX_QUEUED_DATAGRAMS	20 /* < 64 = number of tlabels */ +#define FWNET_MIN_QUEUED_DATAGRAMS	10 /* should keep AT DMA busy enough */ +#define FWNET_TX_QUEUE_LEN		FWNET_MAX_QUEUED_DATAGRAMS /* ? */  #define IEEE1394_BROADCAST_CHANNEL	31  #define IEEE1394_ALL_NODES		(0xffc0 | 0x003f) @@ -36,6 +47,7 @@  #define IANA_SPECIFIER_ID		0x00005eU  #define RFC2734_SW_VERSION		0x000001U +#define RFC3146_SW_VERSION		0x000002U  #define IEEE1394_GASP_HDR_SIZE	8 @@ -48,32 +60,10 @@  #define RFC2374_HDR_LASTFRAG	2	/* last fragment	*/  #define RFC2374_HDR_INTFRAG	3	/* interior fragment	*/ -#define RFC2734_HW_ADDR_LEN	16 - -struct rfc2734_arp { -	__be16 hw_type;		/* 0x0018	*/ -	__be16 proto_type;	/* 0x0806       */ -	u8 hw_addr_len;		/* 16		*/ -	u8 ip_addr_len;		/* 4		*/ -	__be16 opcode;		/* ARP Opcode	*/ -	/* Above is exactly the same format as struct arphdr */ - -	__be64 s_uniq_id;	/* Sender's 64bit EUI			*/ -	u8 max_rec;		/* Sender's max packet size		*/ -	u8 sspd;		/* Sender's max speed			*/ -	__be16 fifo_hi;		/* hi 16bits of sender's FIFO addr	*/ -	__be32 fifo_lo;		/* lo 32bits of sender's FIFO addr	*/ -	__be32 sip;		/* Sender's IP Address			*/ -	__be32 tip;		/* IP Address of requested hw addr	*/ -} __attribute__((packed)); - -/* This header format is specific to this driver implementation. */ -#define FWNET_ALEN	8 -#define FWNET_HLEN	10 -struct fwnet_header { -	u8 h_dest[FWNET_ALEN];	/* destination address */ -	__be16 h_proto;		/* packet type ID field */ -} __attribute__((packed)); +static bool fwnet_hwaddr_is_multicast(u8 *ha) +{ +	return !!(*ha & 1); +}  /* IPv4 and IPv6 encapsulation header */  struct rfc2734_header { @@ -169,16 +159,10 @@ struct fwnet_device {  	struct fw_address_handler handler;  	u64 local_fifo; -	/* List of packets to be sent */ -	struct list_head packet_list; -	/* -	 * List of packets that were broadcasted.  When we get an ISO interrupt -	 * one of them has been sent -	 */ -	struct list_head broadcasted_list; -	/* List of packets that have been sent but not yet acked */ -	struct list_head sent_list; +	/* Number of tx datagrams that have been queued but not yet acked */ +	int queued_datagrams; +	int peer_count;  	struct list_head peer_list;  	struct fw_card *card;  	struct net_device *netdev; @@ -188,14 +172,13 @@ struct fwnet_peer {  	struct list_head peer_link;  	struct fwnet_device *dev;  	u64 guid; -	u64 fifo;  	/* guarded by dev->lock */  	struct list_head pd_list; /* received partial datagrams */  	unsigned pdg_size;        /* pd_list size */  	u16 datagram_label;       /* outgoing datagram label */ -	unsigned max_payload;     /* includes RFC2374_FRAG_HDR_SIZE overhead */ +	u16 max_payload;          /* includes RFC2374_FRAG_HDR_SIZE overhead */  	int node_id;  	int generation;  	unsigned speed; @@ -203,25 +186,30 @@ struct fwnet_peer {  /* This is our task struct. It's used for the packet complete callback.  */  struct fwnet_packet_task { -	/* -	 * ptask can actually be on dev->packet_list, dev->broadcasted_list, -	 * or dev->sent_list depending on its current state. -	 */ -	struct list_head pt_link;  	struct fw_transaction transaction;  	struct rfc2734_header hdr;  	struct sk_buff *skb;  	struct fwnet_device *dev;  	int outstanding_pkts; -	unsigned max_payload;  	u64 fifo_addr;  	u16 dest_node; +	u16 max_payload;  	u8 generation;  	u8 speed; +	u8 enqueued;  };  /* + * Get fifo address embedded in hwaddr + */ +static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha) +{ +	return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32 +	       | get_unaligned_be32(&ha->uc.fifo_lo); +} + +/*   * saddr == NULL means use device source address.   * daddr == NULL means leave destination address (eg unresolved arp).   */ @@ -256,22 +244,22 @@ static int fwnet_header_rebuild(struct sk_buff *skb)  	if (get_unaligned_be16(&h->h_proto) == ETH_P_IP)  		return arp_find((unsigned char *)&h->h_dest, skb); -	fw_notify("%s: unable to resolve type %04x addresses\n", -		  skb->dev->name, be16_to_cpu(h->h_proto)); +	dev_notice(&skb->dev->dev, "unable to resolve type %04x addresses\n", +		   be16_to_cpu(h->h_proto));  	return 0;  }  static int fwnet_header_cache(const struct neighbour *neigh, -			      struct hh_cache *hh) +			      struct hh_cache *hh, __be16 type)  {  	struct net_device *net;  	struct fwnet_header *h; -	if (hh->hh_type == cpu_to_be16(ETH_P_802_3)) +	if (type == cpu_to_be16(ETH_P_802_3))  		return -1;  	net = neigh->dev; -	h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h)); -	h->h_proto = hh->hh_type; +	h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h))); +	h->h_proto = type;  	memcpy(h->h_dest, neigh->ha, net->addr_len);  	hh->hh_len = FWNET_HLEN; @@ -282,7 +270,7 @@ static int fwnet_header_cache(const struct neighbour *neigh,  static void fwnet_header_cache_update(struct hh_cache *hh,  		const struct net_device *net, const unsigned char *haddr)  { -	memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len); +	memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);  }  static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr) @@ -368,10 +356,8 @@ static struct fwnet_fragment_info *fwnet_frag_new(  	}  	new = kmalloc(sizeof(*new), GFP_ATOMIC); -	if (!new) { -		fw_error("out of memory\n"); +	if (!new)  		return NULL; -	}  	new->offset = offset;  	new->len = len; @@ -398,11 +384,11 @@ static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net,  	new->datagram_label = datagram_label;  	new->datagram_size = dg_size; -	new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15); +	new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net));  	if (new->skb == NULL)  		goto fail_w_fi; -	skb_reserve(new->skb, (net->hard_header_len + 15) & ~15); +	skb_reserve(new->skb, LL_RESERVED_SPACE(net));  	new->pbuf = skb_put(new->skb, dg_size);  	memcpy(new->pbuf + frag_off, frag_buf, frag_len);  	list_add_tail(&new->pd_link, &peer->pd_list); @@ -414,8 +400,6 @@ fail_w_fi:  fail_w_new:  	kfree(new);  fail: -	fw_error("out of memory\n"); -  	return NULL;  } @@ -454,7 +438,7 @@ static bool fwnet_pd_update(struct fwnet_peer *peer,  	memcpy(pd->pbuf + frag_off, frag_buf, frag_len);  	/* -	 * Move list entry to beginnig of list so that oldest partial +	 * Move list entry to beginning of list so that oldest partial  	 * datagrams percolate to the end of the list  	 */  	list_move_tail(&pd->pd_link, &peer->pd_list); @@ -502,11 +486,7 @@ static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,  static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed)  {  	max_rec = min(max_rec, speed + 8); -	max_rec = min(max_rec, 0xbU); /* <= 4096 */ -	if (max_rec < 8) { -		fw_notify("max_rec %x out of range\n", max_rec); -		max_rec = 8; -	} +	max_rec = clamp(max_rec, 8U, 11U); /* 512...4096 */  	return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE;  } @@ -517,100 +497,32 @@ static int fwnet_finish_incoming_packet(struct net_device *net,  					bool is_broadcast, u16 ether_type)  {  	struct fwnet_device *dev; -	static const __be64 broadcast_hw = cpu_to_be64(~0ULL);  	int status;  	__be64 guid; +	switch (ether_type) { +	case ETH_P_ARP: +	case ETH_P_IP: +#if IS_ENABLED(CONFIG_IPV6) +	case ETH_P_IPV6: +#endif +		break; +	default: +		goto err; +	} +  	dev = netdev_priv(net);  	/* Write metadata, and then pass to the receive level */  	skb->dev = net; -	skb->ip_summed = CHECKSUM_UNNECESSARY;  /* don't check it */ +	skb->ip_summed = CHECKSUM_NONE;  	/*  	 * Parse the encapsulation header. This actually does the job of -	 * converting to an ethernet frame header, as well as arp -	 * conversion if needed. ARP conversion is easier in this -	 * direction, since we are using ethernet as our backend. +	 * converting to an ethernet-like pseudo frame header.  	 */ -	/* -	 * If this is an ARP packet, convert it. First, we want to make -	 * use of some of the fields, since they tell us a little bit -	 * about the sending machine. -	 */ -	if (ether_type == ETH_P_ARP) { -		struct rfc2734_arp *arp1394; -		struct arphdr *arp; -		unsigned char *arp_ptr; -		u64 fifo_addr; -		u64 peer_guid; -		unsigned sspd; -		u16 max_payload; -		struct fwnet_peer *peer; -		unsigned long flags; - -		arp1394   = (struct rfc2734_arp *)skb->data; -		arp       = (struct arphdr *)skb->data; -		arp_ptr   = (unsigned char *)(arp + 1); -		peer_guid = get_unaligned_be64(&arp1394->s_uniq_id); -		fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32 -				| get_unaligned_be32(&arp1394->fifo_lo); - -		sspd = arp1394->sspd; -		/* Sanity check.  OS X 10.3 PPC reportedly sends 131. */ -		if (sspd > SCODE_3200) { -			fw_notify("sspd %x out of range\n", sspd); -			sspd = SCODE_3200; -		} -		max_payload = fwnet_max_payload(arp1394->max_rec, sspd); - -		spin_lock_irqsave(&dev->lock, flags); -		peer = fwnet_peer_find_by_guid(dev, peer_guid); -		if (peer) { -			peer->fifo = fifo_addr; - -			if (peer->speed > sspd) -				peer->speed = sspd; -			if (peer->max_payload > max_payload) -				peer->max_payload = max_payload; -		} -		spin_unlock_irqrestore(&dev->lock, flags); - -		if (!peer) { -			fw_notify("No peer for ARP packet from %016llx\n", -				  (unsigned long long)peer_guid); -			goto no_peer; -		} - -		/* -		 * Now that we're done with the 1394 specific stuff, we'll -		 * need to alter some of the data.  Believe it or not, all -		 * that needs to be done is sender_IP_address needs to be -		 * moved, the destination hardware address get stuffed -		 * in and the hardware address length set to 8. -		 * -		 * IMPORTANT: The code below overwrites 1394 specific data -		 * needed above so keep the munging of the data for the -		 * higher level IP stack last. -		 */ - -		arp->ar_hln = 8; -		/* skip over sender unique id */ -		arp_ptr += arp->ar_hln; -		/* move sender IP addr */ -		put_unaligned(arp1394->sip, (u32 *)arp_ptr); -		/* skip over sender IP addr */ -		arp_ptr += arp->ar_pln; - -		if (arp->ar_op == htons(ARPOP_REQUEST)) -			memset(arp_ptr, 0, sizeof(u64)); -		else -			memcpy(arp_ptr, net->dev_addr, sizeof(u64)); -	} - -	/* Now add the ethernet header. */  	guid = cpu_to_be64(dev->card->guid);  	if (dev_hard_header(skb, net, ether_type, -			   is_broadcast ? &broadcast_hw : &guid, +			   is_broadcast ? net->broadcast : net->dev_addr,  			   NULL, skb->len) >= 0) {  		struct fwnet_header *eth;  		u16 *rawp; @@ -619,7 +531,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,  		skb_reset_mac_header(skb);  		skb_pull(skb, sizeof(*eth));  		eth = (struct fwnet_header *)skb_mac_header(skb); -		if (*eth->h_dest & 1) { +		if (fwnet_hwaddr_is_multicast(eth->h_dest)) {  			if (memcmp(eth->h_dest, net->broadcast,  				   net->addr_len) == 0)  				skb->pkt_type = PACKET_BROADCAST; @@ -631,7 +543,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,  			if (memcmp(eth->h_dest, net->dev_addr, net->addr_len))  				skb->pkt_type = PACKET_OTHERHOST;  		} -		if (ntohs(eth->h_proto) >= 1536) { +		if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) {  			protocol = eth->h_proto;  		} else {  			rawp = (u16 *)skb->data; @@ -650,18 +562,14 @@ static int fwnet_finish_incoming_packet(struct net_device *net,  		net->stats.rx_packets++;  		net->stats.rx_bytes += skb->len;  	} -	if (netif_queue_stopped(net)) -		netif_wake_queue(net);  	return 0; - no_peer: + err:  	net->stats.rx_errors++;  	net->stats.rx_dropped++;  	dev_kfree_skb_any(skb); -	if (netif_queue_stopped(net)) -		netif_wake_queue(net);  	return -ENOENT;  } @@ -695,14 +603,13 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,  		buf++;  		len -= RFC2374_UNFRAG_HDR_SIZE; -		skb = dev_alloc_skb(len + net->hard_header_len + 15); +		skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net));  		if (unlikely(!skb)) { -			fw_error("out of memory\n");  			net->stats.rx_dropped++;  			return -ENOMEM;  		} -		skb_reserve(skb, (net->hard_header_len + 15) & ~15); +		skb_reserve(skb, LL_RESERVED_SPACE(net));  		memcpy(skb_put(skb, len), buf, len);  		return fwnet_finish_incoming_packet(net, skb, source_node_id, @@ -793,15 +700,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,  	 * Datagram is not complete, we're done for the  	 * moment.  	 */ -	spin_unlock_irqrestore(&dev->lock, flags); - -	return 0; +	retval = 0;   fail:  	spin_unlock_irqrestore(&dev->lock, flags); -	if (netif_queue_stopped(net)) -		netif_wake_queue(net); -  	return retval;  } @@ -825,7 +727,7 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,  		rcode = RCODE_TYPE_ERROR;  	else if (fwnet_incoming_packet(dev, payload, length,  				       source, generation, false) != 0) { -		fw_error("Incoming packet failure\n"); +		dev_err(&dev->netdev->dev, "incoming packet failure\n");  		rcode = RCODE_CONFLICT_ERROR;  	} else  		rcode = RCODE_COMPLETE; @@ -838,7 +740,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,  {  	struct fwnet_device *dev;  	struct fw_iso_packet packet; -	struct fw_card *card;  	__be16 *hdr_ptr;  	__be32 *buf_ptr;  	int retval; @@ -850,7 +751,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,  	unsigned long flags;  	dev = data; -	card = dev->card;  	hdr_ptr = header;  	length = be16_to_cpup(hdr_ptr); @@ -868,11 +768,16 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,  	ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;  	source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; -	if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) { +	if (specifier_id == IANA_SPECIFIER_ID && +	    (ver == RFC2734_SW_VERSION +#if IS_ENABLED(CONFIG_IPV6) +	     || ver == RFC3146_SW_VERSION +#endif +	    )) {  		buf_ptr += 2;  		length -= IEEE1394_GASP_HDR_SIZE; -		fwnet_incoming_packet(dev, buf_ptr, length, -				      source_node_id, -1, true); +		fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, +				      context->card->generation, true);  	}  	packet.payload_length = dev->rcv_buffer_size; @@ -889,8 +794,10 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,  	spin_unlock_irqrestore(&dev->lock, flags); -	if (retval < 0) -		fw_error("requeue failed\n"); +	if (retval >= 0) +		fw_iso_context_queue_flush(dev->broadcast_rcv_context); +	else +		dev_err(&dev->netdev->dev, "requeue failed\n");  }  static struct kmem_cache *fwnet_packet_task_cache; @@ -901,11 +808,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask)  	kmem_cache_free(fwnet_packet_task_cache, ptask);  } +/* Caller must hold dev->lock. */ +static void dec_queued_datagrams(struct fwnet_device *dev) +{ +	if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS) +		netif_wake_queue(dev->netdev); +} +  static int fwnet_send_packet(struct fwnet_packet_task *ptask);  static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  {  	struct fwnet_device *dev = ptask->dev; +	struct sk_buff *skb = ptask->skb;  	unsigned long flags;  	bool free; @@ -914,10 +829,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  	ptask->outstanding_pkts--;  	/* Check whether we or the networking TX soft-IRQ is last user. */ -	free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link)); +	free = (ptask->outstanding_pkts == 0 && ptask->enqueued); +	if (free) +		dec_queued_datagrams(dev); -	if (ptask->outstanding_pkts == 0) -		list_del(&ptask->pt_link); +	if (ptask->outstanding_pkts == 0) { +		dev->netdev->stats.tx_packets++; +		dev->netdev->stats.tx_bytes += skb->len; +	}  	spin_unlock_irqrestore(&dev->lock, flags); @@ -926,7 +845,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  		u16 fg_off;  		u16 datagram_label;  		u16 lf; -		struct sk_buff *skb;  		/* Update the ptask to point to the next fragment and send it */  		lf = fwnet_get_hdr_lf(&ptask->hdr); @@ -934,9 +852,10 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  		case RFC2374_HDR_LASTFRAG:  		case RFC2374_HDR_UNFRAG:  		default: -			fw_error("Outstanding packet %x lf %x, header %x,%x\n", -				 ptask->outstanding_pkts, lf, ptask->hdr.w0, -				 ptask->hdr.w1); +			dev_err(&dev->netdev->dev, +				"outstanding packet %x lf %x, header %x,%x\n", +				ptask->outstanding_pkts, lf, ptask->hdr.w0, +				ptask->hdr.w1);  			BUG();  		case RFC2374_HDR_FIRSTFRAG: @@ -953,8 +872,13 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  			datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);  			break;  		} -		skb = ptask->skb; -		skb_pull(skb, ptask->max_payload); + +		if (ptask->dest_node == IEEE1394_ALL_NODES) { +			skb_pull(skb, +				 ptask->max_payload + IEEE1394_GASP_HDR_SIZE); +		} else { +			skb_pull(skb, ptask->max_payload); +		}  		if (ptask->outstanding_pkts > 1) {  			fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,  					  dg_size, fg_off, datagram_label); @@ -970,18 +894,53 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)  		fwnet_free_ptask(ptask);  } +static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) +{ +	struct fwnet_device *dev = ptask->dev; +	unsigned long flags; +	bool free; + +	spin_lock_irqsave(&dev->lock, flags); + +	/* One fragment failed; don't try to send remaining fragments. */ +	ptask->outstanding_pkts = 0; + +	/* Check whether we or the networking TX soft-IRQ is last user. */ +	free = ptask->enqueued; +	if (free) +		dec_queued_datagrams(dev); + +	dev->netdev->stats.tx_dropped++; +	dev->netdev->stats.tx_errors++; + +	spin_unlock_irqrestore(&dev->lock, flags); + +	if (free) +		fwnet_free_ptask(ptask); +} +  static void fwnet_write_complete(struct fw_card *card, int rcode,  				 void *payload, size_t length, void *data)  { -	struct fwnet_packet_task *ptask; - -	ptask = data; +	struct fwnet_packet_task *ptask = data; +	static unsigned long j; +	static int last_rcode, errors_skipped; -	if (rcode == RCODE_COMPLETE) +	if (rcode == RCODE_COMPLETE) {  		fwnet_transmit_packet_done(ptask); -	else -		fw_error("fwnet_write_complete: failed: %x\n", rcode); -		/* ??? error recovery */ +	} else { +		if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) { +			dev_err(&ptask->dev->netdev->dev, +				"fwnet_write_complete failed: %x (skipped %d)\n", +				rcode, errors_skipped); + +			errors_skipped = 0; +			last_rcode = rcode; +		} else { +			errors_skipped++; +		} +		fwnet_transmit_packet_failed(ptask); +	}  }  static int fwnet_send_packet(struct fwnet_packet_task *ptask) @@ -1017,16 +976,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)  		u8 *p;  		int generation;  		int node_id; +		unsigned int sw_version;  		/* ptask->generation may not have been set yet */  		generation = dev->card->generation;  		smp_rmb();  		node_id = dev->card->node_id; -		p = skb_push(ptask->skb, 8); +		switch (ptask->skb->protocol) { +		default: +			sw_version = RFC2734_SW_VERSION; +			break; +#if IS_ENABLED(CONFIG_IPV6) +		case htons(ETH_P_IPV6): +			sw_version = RFC3146_SW_VERSION; +#endif +		} + +		p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE);  		put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);  		put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 -						| RFC2734_SW_VERSION, &p[4]); +						| sw_version, &p[4]);  		/* We should not transmit if broadcast_channel.valid == 0. */  		fw_send_request(dev->card, &ptask->transaction, @@ -1039,9 +1009,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)  		spin_lock_irqsave(&dev->lock, flags);  		/* If the AT tasklet already ran, we may be last user. */ -		free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); +		free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);  		if (!free) -			list_add_tail(&ptask->pt_link, &dev->broadcasted_list); +			ptask->enqueued = true; +		else +			dec_queued_datagrams(dev);  		spin_unlock_irqrestore(&dev->lock, flags); @@ -1056,9 +1028,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)  	spin_lock_irqsave(&dev->lock, flags);  	/* If the AT tasklet already ran, we may be last user. */ -	free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); +	free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);  	if (!free) -		list_add_tail(&ptask->pt_link, &dev->sent_list); +		ptask->enqueued = true; +	else +		dec_queued_datagrams(dev);  	spin_unlock_irqrestore(&dev->lock, flags); @@ -1070,6 +1044,62 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)  	return 0;  } +static void fwnet_fifo_stop(struct fwnet_device *dev) +{ +	if (dev->local_fifo == FWNET_NO_FIFO_ADDR) +		return; + +	fw_core_remove_address_handler(&dev->handler); +	dev->local_fifo = FWNET_NO_FIFO_ADDR; +} + +static int fwnet_fifo_start(struct fwnet_device *dev) +{ +	int retval; + +	if (dev->local_fifo != FWNET_NO_FIFO_ADDR) +		return 0; + +	dev->handler.length = 4096; +	dev->handler.address_callback = fwnet_receive_packet; +	dev->handler.callback_data = dev; + +	retval = fw_core_add_address_handler(&dev->handler, +					     &fw_high_memory_region); +	if (retval < 0) +		return retval; + +	dev->local_fifo = dev->handler.offset; + +	return 0; +} + +static void __fwnet_broadcast_stop(struct fwnet_device *dev) +{ +	unsigned u; + +	if (dev->broadcast_state != FWNET_BROADCAST_ERROR) { +		for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) +			kunmap(dev->broadcast_rcv_buffer.pages[u]); +		fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card); +	} +	if (dev->broadcast_rcv_context) { +		fw_iso_context_destroy(dev->broadcast_rcv_context); +		dev->broadcast_rcv_context = NULL; +	} +	kfree(dev->broadcast_rcv_buffer_ptrs); +	dev->broadcast_rcv_buffer_ptrs = NULL; +	dev->broadcast_state = FWNET_BROADCAST_ERROR; +} + +static void fwnet_broadcast_stop(struct fwnet_device *dev) +{ +	if (dev->broadcast_state == FWNET_BROADCAST_ERROR) +		return; +	fw_iso_context_stop(dev->broadcast_rcv_context); +	__fwnet_broadcast_stop(dev); +} +  static int fwnet_broadcast_start(struct fwnet_device *dev)  {  	struct fw_iso_context *context; @@ -1078,65 +1108,47 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)  	unsigned max_receive;  	struct fw_iso_packet packet;  	unsigned long offset; +	void **ptrptr;  	unsigned u; -	if (dev->local_fifo == FWNET_NO_FIFO_ADDR) { -		/* outside OHCI posted write area? */ -		static const struct fw_address_region region = { -			.start = 0xffff00000000ULL, -			.end   = CSR_REGISTER_BASE, -		}; - -		dev->handler.length = 4096; -		dev->handler.address_callback = fwnet_receive_packet; -		dev->handler.callback_data = dev; - -		retval = fw_core_add_address_handler(&dev->handler, ®ion); -		if (retval < 0) -			goto failed_initial; - -		dev->local_fifo = dev->handler.offset; -	} +	if (dev->broadcast_state != FWNET_BROADCAST_ERROR) +		return 0;  	max_receive = 1U << (dev->card->max_receive + 1);  	num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive; -	if (!dev->broadcast_rcv_context) { -		void **ptrptr; - -		context = fw_iso_context_create(dev->card, -		    FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL, -		    dev->card->link_speed, 8, fwnet_receive_broadcast, dev); -		if (IS_ERR(context)) { -			retval = PTR_ERR(context); -			goto failed_context_create; -		} +	ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); +	if (!ptrptr) { +		retval = -ENOMEM; +		goto failed; +	} +	dev->broadcast_rcv_buffer_ptrs = ptrptr; + +	context = fw_iso_context_create(dev->card, FW_ISO_CONTEXT_RECEIVE, +					IEEE1394_BROADCAST_CHANNEL, +					dev->card->link_speed, 8, +					fwnet_receive_broadcast, dev); +	if (IS_ERR(context)) { +		retval = PTR_ERR(context); +		goto failed; +	} -		retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, -		    dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE); -		if (retval < 0) -			goto failed_buffer_init; +	retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, dev->card, +				    FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE); +	if (retval < 0) +		goto failed; -		ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); -		if (!ptrptr) { -			retval = -ENOMEM; -			goto failed_ptrs_alloc; -		} +	dev->broadcast_state = FWNET_BROADCAST_STOPPED; -		dev->broadcast_rcv_buffer_ptrs = ptrptr; -		for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) { -			void *ptr; -			unsigned v; +	for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) { +		void *ptr; +		unsigned v; -			ptr = kmap(dev->broadcast_rcv_buffer.pages[u]); -			for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++) -				*ptrptr++ = (void *) -						((char *)ptr + v * max_receive); -		} -		dev->broadcast_rcv_context = context; -	} else { -		context = dev->broadcast_rcv_context; +		ptr = kmap(dev->broadcast_rcv_buffer.pages[u]); +		for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++) +			*ptrptr++ = (void *) ((char *)ptr + v * max_receive);  	} +	dev->broadcast_rcv_context = context;  	packet.payload_length = max_receive;  	packet.interrupt = 1; @@ -1150,7 +1162,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)  		retval = fw_iso_context_queue(context, &packet,  				&dev->broadcast_rcv_buffer, offset);  		if (retval < 0) -			goto failed_rcv_queue; +			goto failed;  		offset += max_receive;  	} @@ -1160,7 +1172,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)  	retval = fw_iso_context_start(context, -1, 0,  			FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */  	if (retval < 0) -		goto failed_rcv_queue; +		goto failed;  	/* FIXME: adjust it according to the min. speed of all known peers? */  	dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100 @@ -1169,44 +1181,45 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)  	return 0; - failed_rcv_queue: -	kfree(dev->broadcast_rcv_buffer_ptrs); -	dev->broadcast_rcv_buffer_ptrs = NULL; - failed_ptrs_alloc: -	fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card); - failed_buffer_init: -	fw_iso_context_destroy(context); -	dev->broadcast_rcv_context = NULL; - failed_context_create: -	fw_core_remove_address_handler(&dev->handler); - failed_initial: -	dev->local_fifo = FWNET_NO_FIFO_ADDR; - + failed: +	__fwnet_broadcast_stop(dev);  	return retval;  } +static void set_carrier_state(struct fwnet_device *dev) +{ +	if (dev->peer_count > 1) +		netif_carrier_on(dev->netdev); +	else +		netif_carrier_off(dev->netdev); +} +  /* ifup */  static int fwnet_open(struct net_device *net)  {  	struct fwnet_device *dev = netdev_priv(net);  	int ret; -	if (dev->broadcast_state == FWNET_BROADCAST_ERROR) { -		ret = fwnet_broadcast_start(dev); -		if (ret) -			return ret; -	} +	ret = fwnet_broadcast_start(dev); +	if (ret) +		return ret; +  	netif_start_queue(net); +	spin_lock_irq(&dev->lock); +	set_carrier_state(dev); +	spin_unlock_irq(&dev->lock); +  	return 0;  }  /* ifdown */  static int fwnet_stop(struct net_device *net)  { -	netif_stop_queue(net); +	struct fwnet_device *dev = netdev_priv(net); -	/* Deallocate iso context for use by other applications? */ +	netif_stop_queue(net); +	fwnet_broadcast_stop(dev);  	return 0;  } @@ -1224,6 +1237,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)  	struct fwnet_peer *peer;  	unsigned long flags; +	spin_lock_irqsave(&dev->lock, flags); + +	/* Can this happen? */ +	if (netif_queue_stopped(dev->netdev)) { +		spin_unlock_irqrestore(&dev->lock, flags); + +		return NETDEV_TX_BUSY; +	} +  	ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);  	if (ptask == NULL)  		goto fail; @@ -1237,22 +1259,27 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)  	 * We might need to rebuild the header on tx failure.  	 */  	memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); -	skb_pull(skb, sizeof(hdr_buf)); -  	proto = hdr_buf.h_proto; -	dg_size = skb->len; -	/* serialize access to peer, including peer->datagram_label */ -	spin_lock_irqsave(&dev->lock, flags); +	switch (proto) { +	case htons(ETH_P_ARP): +	case htons(ETH_P_IP): +#if IS_ENABLED(CONFIG_IPV6) +	case htons(ETH_P_IPV6): +#endif +		break; +	default: +		goto fail; +	} + +	skb_pull(skb, sizeof(hdr_buf)); +	dg_size = skb->len;  	/*  	 * Set the transmission type for the packet.  ARP packets and IP  	 * broadcast packets are sent via GASP.  	 */ -	if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0 -	    || proto == htons(ETH_P_ARP) -	    || (proto == htons(ETH_P_IP) -		&& IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { +	if (fwnet_hwaddr_is_multicast(hdr_buf.h_dest)) {  		max_payload        = dev->broadcast_xmt_max_payload;  		datagram_label_ptr = &dev->broadcast_xmt_datagramlabel; @@ -1261,44 +1288,25 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)  		ptask->dest_node   = IEEE1394_ALL_NODES;  		ptask->speed       = SCODE_100;  	} else { -		__be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest); +		union fwnet_hwaddr *ha = (union fwnet_hwaddr *)hdr_buf.h_dest; +		__be64 guid = get_unaligned(&ha->uc.uniq_id);  		u8 generation;  		peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); -		if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) -			goto fail_unlock; +		if (!peer) +			goto fail;  		generation         = peer->generation;  		dest_node          = peer->node_id;  		max_payload        = peer->max_payload;  		datagram_label_ptr = &peer->datagram_label; -		ptask->fifo_addr   = peer->fifo; +		ptask->fifo_addr   = fwnet_hwaddr_fifo(ha);  		ptask->generation  = generation;  		ptask->dest_node   = dest_node;  		ptask->speed       = peer->speed;  	} -	/* If this is an ARP packet, convert it */ -	if (proto == htons(ETH_P_ARP)) { -		struct arphdr *arp = (struct arphdr *)skb->data; -		unsigned char *arp_ptr = (unsigned char *)(arp + 1); -		struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data; -		__be32 ipaddr; - -		ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN)); - -		arp1394->hw_addr_len    = RFC2734_HW_ADDR_LEN; -		arp1394->max_rec        = dev->card->max_receive; -		arp1394->sspd		= dev->card->link_speed; - -		put_unaligned_be16(dev->local_fifo >> 32, -				   &arp1394->fifo_hi); -		put_unaligned_be32(dev->local_fifo & 0xffffffff, -				   &arp1394->fifo_lo); -		put_unaligned(ipaddr, &arp1394->sip); -	} -  	ptask->hdr.w0 = 0;  	ptask->hdr.w1 = 0;  	ptask->skb = skb; @@ -1320,18 +1328,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)  		max_payload += RFC2374_FRAG_HDR_SIZE;  	} +	if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS) +		netif_stop_queue(dev->netdev); +  	spin_unlock_irqrestore(&dev->lock, flags);  	ptask->max_payload = max_payload; -	INIT_LIST_HEAD(&ptask->pt_link); +	ptask->enqueued    = 0;  	fwnet_send_packet(ptask);  	return NETDEV_TX_OK; - fail_unlock: -	spin_unlock_irqrestore(&dev->lock, flags);   fail: +	spin_unlock_irqrestore(&dev->lock, flags); +  	if (ptask)  		kmem_cache_free(fwnet_packet_task_cache, ptask); @@ -1360,6 +1371,10 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)  	return 0;  } +static const struct ethtool_ops fwnet_ethtool_ops = { +	.get_link	= ethtool_op_get_link, +}; +  static const struct net_device_ops fwnet_netdev_ops = {  	.ndo_open       = fwnet_open,  	.ndo_stop	= fwnet_stop, @@ -1377,7 +1392,8 @@ static void fwnet_init_dev(struct net_device *net)  	net->addr_len		= FWNET_ALEN;  	net->hard_header_len	= FWNET_HLEN;  	net->type		= ARPHRD_IEEE1394; -	net->tx_queue_len	= 10; +	net->tx_queue_len	= FWNET_TX_QUEUE_LEN; +	net->ethtool_ops	= &fwnet_ethtool_ops;  }  /* caller must hold fwnet_device_mutex */ @@ -1405,7 +1421,6 @@ static int fwnet_add_peer(struct fwnet_device *dev,  	peer->dev = dev;  	peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; -	peer->fifo = FWNET_NO_FIFO_ADDR;  	INIT_LIST_HEAD(&peer->pd_list);  	peer->pdg_size = 0;  	peer->datagram_label = 0; @@ -1418,14 +1433,16 @@ static int fwnet_add_peer(struct fwnet_device *dev,  	spin_lock_irq(&dev->lock);  	list_add_tail(&peer->peer_link, &dev->peer_list); +	dev->peer_count++; +	set_carrier_state(dev);  	spin_unlock_irq(&dev->lock);  	return 0;  } -static int fwnet_probe(struct device *_dev) +static int fwnet_probe(struct fw_unit *unit, +		       const struct ieee1394_device_id *id)  { -	struct fw_unit *unit = fw_unit(_dev);  	struct fw_device *device = fw_parent_device(unit);  	struct fw_card *card = device->card;  	struct net_device *net; @@ -1433,6 +1450,7 @@ static int fwnet_probe(struct device *_dev)  	struct fwnet_device *dev;  	unsigned max_mtu;  	int ret; +	union fwnet_hwaddr *ha;  	mutex_lock(&fwnet_device_mutex); @@ -1444,8 +1462,8 @@ static int fwnet_probe(struct device *_dev)  	net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);  	if (net == NULL) { -		ret = -ENOMEM; -		goto out; +		mutex_unlock(&fwnet_device_mutex); +		return -ENOMEM;  	}  	allocated_netdev = true; @@ -1457,17 +1475,17 @@ static int fwnet_probe(struct device *_dev)  	dev->broadcast_rcv_context = NULL;  	dev->broadcast_xmt_max_payload = 0;  	dev->broadcast_xmt_datagramlabel = 0; -  	dev->local_fifo = FWNET_NO_FIFO_ADDR; - -	INIT_LIST_HEAD(&dev->packet_list); -	INIT_LIST_HEAD(&dev->broadcasted_list); -	INIT_LIST_HEAD(&dev->sent_list); +	dev->queued_datagrams = 0;  	INIT_LIST_HEAD(&dev->peer_list); -  	dev->card = card;  	dev->netdev = net; +	ret = fwnet_fifo_start(dev); +	if (ret < 0) +		goto out; +	dev->local_fifo = dev->handler.offset; +  	/*  	 * Use the RFC 2734 default 1500 octets or the maximum payload  	 * as initial MTU @@ -1477,39 +1495,64 @@ static int fwnet_probe(struct device *_dev)  	net->mtu = min(1500U, max_mtu);  	/* Set our hardware address while we're at it */ -	put_unaligned_be64(card->guid, net->dev_addr); -	put_unaligned_be64(~0ULL, net->broadcast); +	ha = (union fwnet_hwaddr *)net->dev_addr; +	put_unaligned_be64(card->guid, &ha->uc.uniq_id); +	ha->uc.max_rec = dev->card->max_receive; +	ha->uc.sspd = dev->card->link_speed; +	put_unaligned_be16(dev->local_fifo >> 32, &ha->uc.fifo_hi); +	put_unaligned_be32(dev->local_fifo & 0xffffffff, &ha->uc.fifo_lo); + +	memset(net->broadcast, -1, net->addr_len); +  	ret = register_netdev(net); -	if (ret) { -		fw_error("Cannot register the driver\n"); +	if (ret)  		goto out; -	}  	list_add_tail(&dev->dev_link, &fwnet_device_list); -	fw_notify("%s: IPv4 over FireWire on device %016llx\n", -		  net->name, (unsigned long long)card->guid); +	dev_notice(&net->dev, "IP over IEEE 1394 on card %s\n", +		   dev_name(card->device));   have_dev:  	ret = fwnet_add_peer(dev, unit, device);  	if (ret && allocated_netdev) {  		unregister_netdev(net);  		list_del(&dev->dev_link); -	}   out: -	if (ret && allocated_netdev) +		fwnet_fifo_stop(dev);  		free_netdev(net); +	}  	mutex_unlock(&fwnet_device_mutex);  	return ret;  } -static void fwnet_remove_peer(struct fwnet_peer *peer) +/* + * FIXME abort partially sent fragmented datagrams, + * discard partially received fragmented datagrams + */ +static void fwnet_update(struct fw_unit *unit)  { -	struct fwnet_partial_datagram *pd, *pd_next; +	struct fw_device *device = fw_parent_device(unit); +	struct fwnet_peer *peer = dev_get_drvdata(&unit->device); +	int generation; + +	generation = device->generation;  	spin_lock_irq(&peer->dev->lock); -	list_del(&peer->peer_link); +	peer->node_id    = device->node_id; +	peer->generation = generation;  	spin_unlock_irq(&peer->dev->lock); +} + +static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev) +{ +	struct fwnet_partial_datagram *pd, *pd_next; + +	spin_lock_irq(&dev->lock); +	list_del(&peer->peer_link); +	dev->peer_count--; +	set_carrier_state(dev); +	spin_unlock_irq(&dev->lock);  	list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)  		fwnet_pd_delete(pd); @@ -1517,70 +1560,33 @@ static void fwnet_remove_peer(struct fwnet_peer *peer)  	kfree(peer);  } -static int fwnet_remove(struct device *_dev) +static void fwnet_remove(struct fw_unit *unit)  { -	struct fwnet_peer *peer = dev_get_drvdata(_dev); +	struct fwnet_peer *peer = dev_get_drvdata(&unit->device);  	struct fwnet_device *dev = peer->dev;  	struct net_device *net; -	struct fwnet_packet_task *ptask, *pt_next; +	int i;  	mutex_lock(&fwnet_device_mutex); -	fwnet_remove_peer(peer); +	net = dev->netdev; + +	fwnet_remove_peer(peer, dev);  	if (list_empty(&dev->peer_list)) { -		net = dev->netdev;  		unregister_netdev(net); -		if (dev->local_fifo != FWNET_NO_FIFO_ADDR) -			fw_core_remove_address_handler(&dev->handler); -		if (dev->broadcast_rcv_context) { -			fw_iso_context_stop(dev->broadcast_rcv_context); -			fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, -					      dev->card); -			fw_iso_context_destroy(dev->broadcast_rcv_context); -		} -		list_for_each_entry_safe(ptask, pt_next, -					 &dev->packet_list, pt_link) { -			dev_kfree_skb_any(ptask->skb); -			kmem_cache_free(fwnet_packet_task_cache, ptask); -		} -		list_for_each_entry_safe(ptask, pt_next, -					 &dev->broadcasted_list, pt_link) { -			dev_kfree_skb_any(ptask->skb); -			kmem_cache_free(fwnet_packet_task_cache, ptask); -		} -		list_for_each_entry_safe(ptask, pt_next, -					 &dev->sent_list, pt_link) { -			dev_kfree_skb_any(ptask->skb); -			kmem_cache_free(fwnet_packet_task_cache, ptask); -		} +		fwnet_fifo_stop(dev); + +		for (i = 0; dev->queued_datagrams && i < 5; i++) +			ssleep(1); +		WARN_ON(dev->queued_datagrams);  		list_del(&dev->dev_link);  		free_netdev(net);  	}  	mutex_unlock(&fwnet_device_mutex); - -	return 0; -} - -/* - * FIXME abort partially sent fragmented datagrams, - * discard partially received fragmented datagrams - */ -static void fwnet_update(struct fw_unit *unit) -{ -	struct fw_device *device = fw_parent_device(unit); -	struct fwnet_peer *peer = dev_get_drvdata(&unit->device); -	int generation; - -	generation = device->generation; - -	spin_lock_irq(&peer->dev->lock); -	peer->node_id    = device->node_id; -	peer->generation = generation; -	spin_unlock_irq(&peer->dev->lock);  }  static const struct ieee1394_device_id fwnet_id_table[] = { @@ -1590,18 +1596,26 @@ static const struct ieee1394_device_id fwnet_id_table[] = {  		.specifier_id = IANA_SPECIFIER_ID,  		.version      = RFC2734_SW_VERSION,  	}, +#if IS_ENABLED(CONFIG_IPV6) +	{ +		.match_flags  = IEEE1394_MATCH_SPECIFIER_ID | +				IEEE1394_MATCH_VERSION, +		.specifier_id = IANA_SPECIFIER_ID, +		.version      = RFC3146_SW_VERSION, +	}, +#endif  	{ }  };  static struct fw_driver fwnet_driver = {  	.driver = {  		.owner  = THIS_MODULE, -		.name   = "net", +		.name   = KBUILD_MODNAME,  		.bus    = &fw_bus_type, -		.probe  = fwnet_probe, -		.remove = fwnet_remove,  	}, +	.probe    = fwnet_probe,  	.update   = fwnet_update, +	.remove   = fwnet_remove,  	.id_table = fwnet_id_table,  }; @@ -1627,6 +1641,30 @@ static struct fw_descriptor rfc2374_unit_directory = {  	.data   = rfc2374_unit_directory_data  }; +#if IS_ENABLED(CONFIG_IPV6) +static const u32 rfc3146_unit_directory_data[] = { +	0x00040000,	/* directory_length		*/ +	0x1200005e,	/* unit_specifier_id: IANA	*/ +	0x81000003,	/* textual descriptor offset	*/ +	0x13000002,	/* unit_sw_version: RFC 3146	*/ +	0x81000005,	/* textual descriptor offset	*/ +	0x00030000,	/* descriptor_length		*/ +	0x00000000,	/* text				*/ +	0x00000000,	/* minimal ASCII, en		*/ +	0x49414e41,	/* I A N A			*/ +	0x00030000,	/* descriptor_length		*/ +	0x00000000,	/* text				*/ +	0x00000000,	/* minimal ASCII, en		*/ +	0x49507636,	/* I P v 6			*/ +}; + +static struct fw_descriptor rfc3146_unit_directory = { +	.length = ARRAY_SIZE(rfc3146_unit_directory_data), +	.key    = (CSR_DIRECTORY | CSR_UNIT) << 24, +	.data   = rfc3146_unit_directory_data +}; +#endif +  static int __init fwnet_init(void)  {  	int err; @@ -1635,11 +1673,17 @@ static int __init fwnet_init(void)  	if (err)  		return err; +#if IS_ENABLED(CONFIG_IPV6) +	err = fw_core_add_descriptor(&rfc3146_unit_directory); +	if (err) +		goto out; +#endif +  	fwnet_packet_task_cache = kmem_cache_create("packet_task",  			sizeof(struct fwnet_packet_task), 0, 0, NULL);  	if (!fwnet_packet_task_cache) {  		err = -ENOMEM; -		goto out; +		goto out2;  	}  	err = driver_register(&fwnet_driver.driver); @@ -1647,7 +1691,11 @@ static int __init fwnet_init(void)  		return 0;  	kmem_cache_destroy(fwnet_packet_task_cache); +out2: +#if IS_ENABLED(CONFIG_IPV6) +	fw_core_remove_descriptor(&rfc3146_unit_directory);  out: +#endif  	fw_core_remove_descriptor(&rfc2374_unit_directory);  	return err; @@ -1658,11 +1706,14 @@ static void __exit fwnet_cleanup(void)  {  	driver_unregister(&fwnet_driver.driver);  	kmem_cache_destroy(fwnet_packet_task_cache); +#if IS_ENABLED(CONFIG_IPV6) +	fw_core_remove_descriptor(&rfc3146_unit_directory); +#endif  	fw_core_remove_descriptor(&rfc2374_unit_directory);  }  module_exit(fwnet_cleanup);  MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>"); -MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734"); +MODULE_DESCRIPTION("IP over IEEE1394 as per RFC 2734/3146");  MODULE_LICENSE("GPL");  MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table);  | 
