Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a124d38 authored by Stefan Richter's avatar Stefan Richter
Browse files

firewire: net: allow for unordered unit discovery



Decouple the creation and destruction of the net_device from the order
of discovery and removal of nodes with RFC 2734 unit directories since
there is no reliable order.  The net_device is now created when the
first RFC 2734 unit on a card is discovered, and destroyed when the last
RFC 2734 unit on a card went away.  This includes all remote units as
well as the local unit, which is therefore tracked as a peer now too.

Also, locking around the list of peers is slightly extended to guard
against peer removal.  As a side effect, fwnet_peer.pdg_lock has become
superfluous and is deleted.

Peer data (max_rec, speed, node ID, generation) are updated more
carefully.

Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent f91e3bd8
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -429,8 +429,6 @@ void fw_card_initialize(struct fw_card *card,
	card->local_node = NULL;
	card->local_node = NULL;


	INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
	INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
	card->netdev = NULL;
	INIT_LIST_HEAD(&card->peer_list);
}
}
EXPORT_SYMBOL(fw_card_initialize);
EXPORT_SYMBOL(fw_card_initialize);


+207 −247
Original line number Original line Diff line number Diff line
@@ -18,8 +18,10 @@
#include <linux/mod_devicetable.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>


#include <asm/unaligned.h>
#include <asm/unaligned.h>
#include <net/arp.h>
#include <net/arp.h>
@@ -135,40 +137,11 @@ struct fwnet_partial_datagram {
	u16 datagram_size;
	u16 datagram_size;
};
};


/*
static DEFINE_MUTEX(fwnet_device_mutex);
 * We keep one of these for each IPv4 capable device attached to a fw_card.
static LIST_HEAD(fwnet_device_list);
 * The list of them is stored in the fw_card structure rather than in the
 * fwnet_device because the remote IPv4 nodes may be probed before the card is,
 * so we need a place to store them before the fwnet_device structure is
 * allocated.
 */
struct fwnet_peer {
	struct list_head peer_link;
	/* guid of the remote peer */
	u64 guid;
	/* FIFO address to transmit datagrams to, or FWNET_NO_FIFO_ADDR */
	u64 fifo;

	spinlock_t pdg_lock;	/* partial datagram lock		*/
	/* List of partial datagrams received from this peer */
	struct list_head pd_list;
	/* Number of entries in pd_list at the moment */
	unsigned pdg_size;

	/* max payload to transmit to this remote peer */
	/* This already includes the RFC2374_FRAG_HDR_SIZE overhead */
	u16 max_payload;
	/* outgoing datagram label */
	u16 datagram_label;
	/* Current node_id of the remote peer */
	u16 node_id;
	/* current generation of the remote peer */
	u8 generation;
	/* max speed that this peer can receive at */
	u8 xmt_speed;
};


struct fwnet_device {
struct fwnet_device {
	struct list_head dev_link;
	spinlock_t lock;
	spinlock_t lock;
	enum {
	enum {
		FWNET_BROADCAST_ERROR,
		FWNET_BROADCAST_ERROR,
@@ -206,7 +179,26 @@ struct fwnet_device {
	/* List of packets that have been sent but not yet acked */
	/* List of packets that have been sent but not yet acked */
	struct list_head sent_list;
	struct list_head sent_list;


	struct list_head peer_list;
	struct fw_card *card;
	struct fw_card *card;
	struct net_device *netdev;
};

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 */
	int node_id;
	int generation;
	unsigned speed;
};
};


/* This is our task struct. It's used for the packet complete callback.  */
/* This is our task struct. It's used for the packet complete callback.  */
@@ -479,102 +471,47 @@ static bool fwnet_pd_is_complete(struct fwnet_partial_datagram *pd)
	return fi->len == pd->datagram_size;
	return fi->len == pd->datagram_size;
}
}


static int fwnet_peer_new(struct fw_card *card, struct fw_device *device)
/* caller must hold dev->lock */
{
	struct fwnet_peer *peer;

	peer = kmalloc(sizeof(*peer), GFP_KERNEL);
	if (!peer) {
		fw_error("out of memory\n");

		return -ENOMEM;
	}
	peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
	peer->fifo = FWNET_NO_FIFO_ADDR;
	INIT_LIST_HEAD(&peer->pd_list);
	spin_lock_init(&peer->pdg_lock);
	peer->pdg_size = 0;
	peer->generation = device->generation;
	rmb();
	peer->node_id = device->node_id;
	 /* FIXME what should it really be? */
	peer->max_payload = IEEE1394_MAX_PAYLOAD_S100 - RFC2374_UNFRAG_HDR_SIZE;
	peer->datagram_label = 0U;
	peer->xmt_speed = device->max_speed;
	list_add_tail(&peer->peer_link, &card->peer_list);

	return 0;
}

/* FIXME caller must take the lock, or peer needs to be reference-counted */
static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev,
static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev,
						  u64 guid)
						  u64 guid)
{
{
	struct fwnet_peer *p, *peer = NULL;
	struct fwnet_peer *peer;
	unsigned long flags;

	spin_lock_irqsave(&dev->lock, flags);
	list_for_each_entry(p, &dev->card->peer_list, peer_link)
		if (p->guid == guid) {
			peer = p;
			break;
		}
	spin_unlock_irqrestore(&dev->lock, flags);


	list_for_each_entry(peer, &dev->peer_list, peer_link)
		if (peer->guid == guid)
			return peer;
			return peer;

	return NULL;
}
}


/* FIXME caller must take the lock, or peer needs to be reference-counted */
/* caller must hold dev->lock */
/* FIXME node_id doesn't mean anything without generation */
static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,
static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,
						     u16 node_id)
						int node_id, int generation)
{
{
	struct fwnet_peer *p, *peer = NULL;
	struct fwnet_peer *peer;
	unsigned long flags;

	spin_lock_irqsave(&dev->lock, flags);
	list_for_each_entry(p, &dev->card->peer_list, peer_link)
		if (p->node_id == node_id) {
			peer = p;
			break;
		}
	spin_unlock_irqrestore(&dev->lock, flags);


	list_for_each_entry(peer, &dev->peer_list, peer_link)
		if (peer->node_id    == node_id &&
		    peer->generation == generation)
			return peer;
			return peer;

	return NULL;
}
}


/* FIXME */
/* See IEEE 1394-2008 table 6-4, table 8-8, table 16-18. */
static void fwnet_peer_delete(struct fw_card *card, struct fw_device *device)
static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed)
{
{
	struct net_device *net;
	max_rec = min(max_rec, speed + 8);
	struct fwnet_device *dev;
	max_rec = min(max_rec, 0xbU); /* <= 4096 */
	struct fwnet_peer *peer;
	if (max_rec < 8) {
	u64 guid;
		fw_notify("max_rec %x out of range\n", max_rec);
	unsigned long flags;
		max_rec = 8;
	struct fwnet_partial_datagram *pd, *pd_next;

	guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
	net = card->netdev;
	if (net)
		dev = netdev_priv(net);
	else
		dev = NULL;
	if (dev)
		spin_lock_irqsave(&dev->lock, flags);

	list_for_each_entry(peer, &card->peer_list, peer_link) {
		if (peer->guid == guid) {
			list_del(&peer->peer_link);
			list_for_each_entry_safe(pd, pd_next, &peer->pd_list,
						 pd_link)
				fwnet_pd_delete(pd);
			break;
	}
	}
	}

	if (dev)
	return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE;
		spin_unlock_irqrestore(&dev->lock, flags);
}
}



static int fwnet_finish_incoming_packet(struct net_device *net,
static int fwnet_finish_incoming_packet(struct net_device *net,
					struct sk_buff *skb, u16 source_node_id,
					struct sk_buff *skb, u16 source_node_id,
					bool is_broadcast, u16 ether_type)
					bool is_broadcast, u16 ether_type)
@@ -606,71 +543,44 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
		unsigned char *arp_ptr;
		unsigned char *arp_ptr;
		u64 fifo_addr;
		u64 fifo_addr;
		u64 peer_guid;
		u64 peer_guid;
		u8 max_rec;
		unsigned sspd;
		u8 sspd;
		u16 max_payload;
		u16 max_payload;
		struct fwnet_peer *peer;
		struct fwnet_peer *peer;
		static const u16 fwnet_speed_to_max_payload[] = {
		unsigned long flags;
			/* S100, S200, S400, S800, S1600, S3200 */
			    512, 1024, 2048, 4096,  4096,  4096
		};


		arp1394   = (struct rfc2734_arp *)skb->data;
		arp1394   = (struct rfc2734_arp *)skb->data;
		arp       = (struct arphdr *)skb->data;
		arp       = (struct arphdr *)skb->data;
		arp_ptr   = (unsigned char *)(arp + 1);
		arp_ptr   = (unsigned char *)(arp + 1);
		fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32
		peer_guid = get_unaligned_be64(&arp1394->s_uniq_id);
				| ntohl(arp1394->fifo_lo);
		fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32
		max_rec = dev->card->max_receive;
				| get_unaligned_be32(&arp1394->fifo_lo);
		if (arp1394->max_rec < max_rec)

			max_rec = arp1394->max_rec;
		sspd = arp1394->sspd;
		sspd = arp1394->sspd;
		/* Sanity check.  OS X 10.3 PPC reportedly sends 131. */
		/* Sanity check.  OS X 10.3 PPC reportedly sends 131. */
		if (sspd > SCODE_3200) {
		if (sspd > SCODE_3200) {
			fw_notify("sspd %x out of range\n", sspd);
			fw_notify("sspd %x out of range\n", sspd);
			sspd = 0;
			sspd = SCODE_3200;
		}
		}
		max_payload = fwnet_max_payload(arp1394->max_rec, sspd);


		max_payload = min(fwnet_speed_to_max_payload[sspd],
		spin_lock_irqsave(&dev->lock, flags);
			(u16)(1 << (max_rec + 1))) - RFC2374_UNFRAG_HDR_SIZE;

		peer_guid = get_unaligned_be64(&arp1394->s_uniq_id);
		peer = fwnet_peer_find_by_guid(dev, peer_guid);
		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) {
		if (!peer) {
			fw_notify("No peer for ARP packet from %016llx\n",
			fw_notify("No peer for ARP packet from %016llx\n",
				  (unsigned long long)peer_guid);
				  (unsigned long long)peer_guid);
			goto failed_proto;
			goto failed_proto;
		}
		}


		/* FIXME don't use card->generation */
		if (peer->node_id != source_node_id ||
		    peer->generation != dev->card->generation) {
			fw_notify("Internal error: peer->node_id (%x) != "
				  "source_node_id (%x) or peer->generation (%x)"
				  " != dev->card->generation(%x)\n",
				  peer->node_id, source_node_id,
				  peer->generation, dev->card->generation);
			peer->node_id = source_node_id;
			peer->generation = dev->card->generation;
		}

		/* FIXME: for debugging */
		if (sspd > SCODE_400)
			sspd = SCODE_400;
		/* Update our speed/payload/fifo_offset table */
		/*
		 * FIXME: this does not handle cases where two high-speed endpoints must use a slower speed because of
		 * a lower speed hub between them.  We need to look at the actual topology map here.
		 */
		peer->fifo = fifo_addr;
		peer->max_payload = max_payload;
		/*
		 * Only allow speeds to go down from their initial value.
		 * Otherwise a local peer that can only do S400 or slower may
		 * be told to transmit at S800 to a faster remote peer.
		 */
		if (peer->xmt_speed > sspd)
			peer->xmt_speed = sspd;

		/*
		/*
		 * Now that we're done with the 1394 specific stuff, we'll
		 * Now that we're done with the 1394 specific stuff, we'll
		 * need to alter some of the data.  Believe it or not, all
		 * need to alter some of the data.  Believe it or not, all
@@ -764,10 +674,11 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
}
}


static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
				 u16 source_node_id, bool is_broadcast)
				 int source_node_id, int generation,
				 bool is_broadcast)
{
{
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct net_device *net;
	struct net_device *net = dev->netdev;
	struct rfc2734_header hdr;
	struct rfc2734_header hdr;
	unsigned lf;
	unsigned lf;
	unsigned long flags;
	unsigned long flags;
@@ -779,8 +690,6 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
	int retval;
	int retval;
	u16 ether_type;
	u16 ether_type;


	net = dev->card->netdev;

	hdr.w0 = be32_to_cpu(buf[0]);
	hdr.w0 = be32_to_cpu(buf[0]);
	lf = fwnet_get_hdr_lf(&hdr);
	lf = fwnet_get_hdr_lf(&hdr);
	if (lf == RFC2374_HDR_UNFRAG) {
	if (lf == RFC2374_HDR_UNFRAG) {
@@ -819,9 +728,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
	}
	}
	datagram_label = fwnet_get_hdr_dgl(&hdr);
	datagram_label = fwnet_get_hdr_dgl(&hdr);
	dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
	dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
	peer = fwnet_peer_find_by_node_id(dev, source_node_id);


	spin_lock_irqsave(&peer->pdg_lock, flags);
	spin_lock_irqsave(&dev->lock, flags);

	peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation);
	if (!peer)
		goto bad_proto;


	pd = fwnet_pd_find(peer, datagram_label);
	pd = fwnet_pd_find(peer, datagram_label);
	if (pd == NULL) {
	if (pd == NULL) {
@@ -876,7 +788,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
		skb = skb_get(pd->skb);
		skb = skb_get(pd->skb);
		fwnet_pd_delete(pd);
		fwnet_pd_delete(pd);


		spin_unlock_irqrestore(&peer->pdg_lock, flags);
		spin_unlock_irqrestore(&dev->lock, flags);


		return fwnet_finish_incoming_packet(net, skb, source_node_id,
		return fwnet_finish_incoming_packet(net, skb, source_node_id,
						    false, ether_type);
						    false, ether_type);
@@ -885,12 +797,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
	 * Datagram is not complete, we're done for the
	 * Datagram is not complete, we're done for the
	 * moment.
	 * moment.
	 */
	 */
	spin_unlock_irqrestore(&peer->pdg_lock, flags);
	spin_unlock_irqrestore(&dev->lock, flags);


	return 0;
	return 0;


 bad_proto:
 bad_proto:
	spin_unlock_irqrestore(&peer->pdg_lock, flags);
	spin_unlock_irqrestore(&dev->lock, flags);


	if (netif_queue_stopped(net))
	if (netif_queue_stopped(net))
		netif_wake_queue(net);
		netif_wake_queue(net);
@@ -916,7 +828,8 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
		return;
		return;
	}
	}


	status = fwnet_incoming_packet(dev, payload, length, source, false);
	status = fwnet_incoming_packet(dev, payload, length,
				       source, generation, false);
	if (status != 0) {
	if (status != 0) {
		fw_error("Incoming packet failure\n");
		fw_error("Incoming packet failure\n");
		fw_send_response(card, r, RCODE_CONFLICT_ERROR);
		fw_send_response(card, r, RCODE_CONFLICT_ERROR);
@@ -966,7 +879,7 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
		buf_ptr += 2;
		buf_ptr += 2;
		length -= IEEE1394_GASP_HDR_SIZE;
		length -= IEEE1394_GASP_HDR_SIZE;
		fwnet_incoming_packet(dev, buf_ptr, length,
		fwnet_incoming_packet(dev, buf_ptr, length,
				      source_node_id, true);
				      source_node_id, -1, true);
	}
	}


	packet.payload_length = dev->rcv_buffer_size;
	packet.payload_length = dev->rcv_buffer_size;
@@ -1073,7 +986,6 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
	unsigned tx_len;
	unsigned tx_len;
	struct rfc2734_header *bufhdr;
	struct rfc2734_header *bufhdr;
	unsigned long flags;
	unsigned long flags;
	struct net_device *net;


	dev = ptask->dev;
	dev = ptask->dev;
	tx_len = ptask->max_payload;
	tx_len = ptask->max_payload;
@@ -1137,8 +1049,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
	list_add_tail(&ptask->pt_link, &dev->sent_list);
	list_add_tail(&ptask->pt_link, &dev->sent_list);
	spin_unlock_irqrestore(&dev->lock, flags);
	spin_unlock_irqrestore(&dev->lock, flags);


	net = dev->card->netdev;
	dev->netdev->trans_start = jiffies;
	net->trans_start = jiffies;


	return 0;
	return 0;
}
}
@@ -1294,7 +1205,8 @@ static int fwnet_tx(struct sk_buff *skb, struct net_device *net)
	u16 dg_size;
	u16 dg_size;
	u16 *datagram_label_ptr;
	u16 *datagram_label_ptr;
	struct fwnet_packet_task *ptask;
	struct fwnet_packet_task *ptask;
	struct fwnet_peer *peer = NULL;
	struct fwnet_peer *peer;
	unsigned long flags;


	ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
	ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
	if (ptask == NULL)
	if (ptask == NULL)
@@ -1314,6 +1226,9 @@ static int fwnet_tx(struct sk_buff *skb, struct net_device *net)
	proto = hdr_buf.h_proto;
	proto = hdr_buf.h_proto;
	dg_size = skb->len;
	dg_size = skb->len;


	/* serialize access to peer, including peer->datagram_label */
	spin_lock_irqsave(&dev->lock, flags);

	/*
	/*
	 * Set the transmission type for the packet.  ARP packets and IP
	 * Set the transmission type for the packet.  ARP packets and IP
	 * broadcast packets are sent via GASP.
	 * broadcast packets are sent via GASP.
@@ -1334,23 +1249,18 @@ static int fwnet_tx(struct sk_buff *skb, struct net_device *net)
		u8 generation;
		u8 generation;


		peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
		peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
		if (!peer)
		if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
			goto fail;
			goto fail_unlock;

		if (peer->fifo == FWNET_NO_FIFO_ADDR)
			goto fail;


		generation         = peer->generation;
		generation         = peer->generation;
		smp_rmb();
		dest_node          = peer->node_id;
		dest_node          = peer->node_id;

		max_payload        = peer->max_payload;
		max_payload        = peer->max_payload;
		datagram_label_ptr = &peer->datagram_label;
		datagram_label_ptr = &peer->datagram_label;


		ptask->fifo_addr   = peer->fifo;
		ptask->fifo_addr   = peer->fifo;
		ptask->generation  = generation;
		ptask->generation  = generation;
		ptask->dest_node   = dest_node;
		ptask->dest_node   = dest_node;
		ptask->speed = peer->xmt_speed;
		ptask->speed       = peer->speed;
	}
	}


	/* If this is an ARP packet, convert it */
	/* If this is an ARP packet, convert it */
@@ -1393,11 +1303,16 @@ static int fwnet_tx(struct sk_buff *skb, struct net_device *net)
		ptask->outstanding_pkts = DIV_ROUND_UP(dg_size, max_payload);
		ptask->outstanding_pkts = DIV_ROUND_UP(dg_size, max_payload);
		max_payload += RFC2374_FRAG_HDR_SIZE;
		max_payload += RFC2374_FRAG_HDR_SIZE;
	}
	}

	spin_unlock_irqrestore(&dev->lock, flags);

	ptask->max_payload = max_payload;
	ptask->max_payload = max_payload;
	fwnet_send_packet(ptask);
	fwnet_send_packet(ptask);


	return NETDEV_TX_OK;
	return NETDEV_TX_OK;


 fail_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
 fail:
 fail:
	if (ptask)
	if (ptask)
		kmem_cache_free(fwnet_packet_task_cache, ptask);
		kmem_cache_free(fwnet_packet_task_cache, ptask);
@@ -1467,7 +1382,48 @@ static void fwnet_init_dev(struct net_device *net)
	SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
	SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
}
}


/* FIXME create netdev upon first fw_unit of a card, not upon local fw_unit */
/* caller must hold fwnet_device_mutex */
static struct fwnet_device *fwnet_dev_find(struct fw_card *card)
{
	struct fwnet_device *dev;

	list_for_each_entry(dev, &fwnet_device_list, dev_link)
		if (dev->card == card)
			return dev;

	return NULL;
}

static int fwnet_add_peer(struct fwnet_device *dev,
			  struct fw_unit *unit, struct fw_device *device)
{
	struct fwnet_peer *peer;

	peer = kmalloc(sizeof(*peer), GFP_KERNEL);
	if (!peer)
		return -ENOMEM;

	unit->device.driver_data = peer;
	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;
	peer->speed = device->max_speed;
	peer->max_payload = fwnet_max_payload(device->max_rec, peer->speed);

	peer->generation = device->generation;
	smp_rmb();
	peer->node_id = device->node_id;

	spin_lock_irq(&dev->lock);
	list_add_tail(&peer->peer_link, &dev->peer_list);
	spin_unlock_irq(&dev->lock);

	return 0;
}

static int fwnet_probe(struct device *_dev)
static int fwnet_probe(struct device *_dev)
{
{
	struct fw_unit *unit = fw_unit(_dev);
	struct fw_unit *unit = fw_unit(_dev);
@@ -1476,16 +1432,22 @@ static int fwnet_probe(struct device *_dev)
	struct net_device *net;
	struct net_device *net;
	struct fwnet_device *dev;
	struct fwnet_device *dev;
	unsigned max_mtu;
	unsigned max_mtu;
	bool new_netdev;
	int ret;


	if (!device->is_local) {
	mutex_lock(&fwnet_device_mutex);
		int added;


		added = fwnet_peer_new(card, device);
	dev = fwnet_dev_find(card);
		return added;
	if (dev) {
		new_netdev = false;
		net = dev->netdev;
		goto have_dev;
	}
	}

	new_netdev = true;
	net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);
	net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);
	if (net == NULL) {
	if (net == NULL) {
		fw_error("out of memory\n");
		ret = -ENOMEM;
		goto out;
		goto out;
	}
	}


@@ -1500,12 +1462,13 @@ static int fwnet_probe(struct device *_dev)


	dev->local_fifo = FWNET_NO_FIFO_ADDR;
	dev->local_fifo = FWNET_NO_FIFO_ADDR;


	/* INIT_WORK(&dev->wake, fwnet_handle_queue);*/
	INIT_LIST_HEAD(&dev->packet_list);
	INIT_LIST_HEAD(&dev->packet_list);
	INIT_LIST_HEAD(&dev->broadcasted_list);
	INIT_LIST_HEAD(&dev->broadcasted_list);
	INIT_LIST_HEAD(&dev->sent_list);
	INIT_LIST_HEAD(&dev->sent_list);
	INIT_LIST_HEAD(&dev->peer_list);


	dev->card = card;
	dev->card = card;
	dev->netdev = net;


	/*
	/*
	 * Use the RFC 2734 default 1500 octets or the maximum payload
	 * Use the RFC 2734 default 1500 octets or the maximum payload
@@ -1518,43 +1481,57 @@ static int fwnet_probe(struct device *_dev)
	/* Set our hardware address while we're at it */
	/* Set our hardware address while we're at it */
	put_unaligned_be64(card->guid, net->dev_addr);
	put_unaligned_be64(card->guid, net->dev_addr);
	put_unaligned_be64(~0ULL, net->broadcast);
	put_unaligned_be64(~0ULL, net->broadcast);
	if (register_netdev(net)) {
	ret = register_netdev(net);
	if (ret) {
		fw_error("Cannot register the driver\n");
		fw_error("Cannot register the driver\n");
		goto out;
		goto out;
	}
	}


	list_add_tail(&dev->dev_link, &fwnet_device_list);
	fw_notify("%s: IPv4 over FireWire on device %016llx\n",
	fw_notify("%s: IPv4 over FireWire on device %016llx\n",
		  net->name, (unsigned long long)card->guid);
		  net->name, (unsigned long long)card->guid);
	card->netdev = net;
 have_dev:

	ret = fwnet_add_peer(dev, unit, device);
	return 0;
	if (ret && new_netdev) {
		unregister_netdev(net);
		list_del(&dev->dev_link);
	}
 out:
 out:
	if (net)
	if (ret && new_netdev)
		free_netdev(net);
		free_netdev(net);


	return -ENOENT;
	mutex_unlock(&fwnet_device_mutex);

	return ret;
}

static void fwnet_remove_peer(struct fwnet_peer *peer)
{
	struct fwnet_partial_datagram *pd, *pd_next;

	spin_lock_irq(&peer->dev->lock);
	list_del(&peer->peer_link);
	spin_unlock_irq(&peer->dev->lock);

	list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
		fwnet_pd_delete(pd);

	kfree(peer);
}
}


static int fwnet_remove(struct device *_dev)
static int fwnet_remove(struct device *_dev)
{
{
	struct fw_unit *unit = fw_unit(_dev);
	struct fwnet_peer *peer = _dev->driver_data;
	struct fw_device *device = fw_parent_device(unit);
	struct fwnet_device *dev = peer->dev;
	struct fw_card *card = device->card;
	struct net_device *net;
	struct net_device *net;
	struct fwnet_device *dev;
	struct fwnet_peer *peer;
	struct fwnet_partial_datagram *pd, *pd_next;
	struct fwnet_packet_task *ptask, *pt_next;
	struct fwnet_packet_task *ptask, *pt_next;


	if (!device->is_local) {
	mutex_lock(&fwnet_device_mutex);
		fwnet_peer_delete(card, device);


		return 0;
	fwnet_remove_peer(peer);
	}


	net = card->netdev;
	if (list_empty(&dev->peer_list)) {
	if (net) {
		net = dev->netdev;
		dev = netdev_priv(net);
		unregister_netdev(net);
		unregister_netdev(net);


		if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
		if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
@@ -1580,19 +1557,11 @@ static int fwnet_remove(struct device *_dev)
			dev_kfree_skb_any(ptask->skb);
			dev_kfree_skb_any(ptask->skb);
			kmem_cache_free(fwnet_packet_task_cache, ptask);
			kmem_cache_free(fwnet_packet_task_cache, ptask);
		}
		}
		list_for_each_entry(peer, &card->peer_list, peer_link) {
			if (peer->pdg_size) {
				list_for_each_entry_safe(pd, pd_next,
						&peer->pd_list, pd_link)
					fwnet_pd_delete(pd);
				peer->pdg_size = 0;
			}
			peer->fifo = FWNET_NO_FIFO_ADDR;
		}
		free_netdev(net);
		free_netdev(net);
		card->netdev = NULL;
	}
	}


	mutex_unlock(&fwnet_device_mutex);

	return 0;
	return 0;
}
}


@@ -1603,24 +1572,15 @@ static int fwnet_remove(struct device *_dev)
static void fwnet_update(struct fw_unit *unit)
static void fwnet_update(struct fw_unit *unit)
{
{
	struct fw_device *device = fw_parent_device(unit);
	struct fw_device *device = fw_parent_device(unit);
	struct net_device *net = device->card->netdev;
	struct fwnet_peer *peer = unit->device.driver_data;
	struct fwnet_device *dev;
	int generation;
	struct fwnet_peer *peer;
	u64 guid;


	if (net && !device->is_local) {
	generation = device->generation;
		dev = netdev_priv(net);

		guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
	spin_lock_irq(&peer->dev->lock);
		peer = fwnet_peer_find_by_guid(dev, guid);
		if (!peer) {
			fw_error("fwnet_update: no peer for device %016llx\n",
				 (unsigned long long)guid);
			return;
		}
		peer->generation = device->generation;
		rmb();
	peer->node_id    = device->node_id;
	peer->node_id    = device->node_id;
	}
	peer->generation = generation;
	spin_unlock_irq(&peer->dev->lock);
}
}


static const struct ieee1394_device_id fwnet_id_table[] = {
static const struct ieee1394_device_id fwnet_id_table[] = {
+0 −4
Original line number Original line Diff line number Diff line
@@ -131,10 +131,6 @@ struct fw_card {
	bool broadcast_channel_allocated;
	bool broadcast_channel_allocated;
	u32 broadcast_channel;
	u32 broadcast_channel;
	u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
	u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];

	/* firewire-net driver data */
	void *netdev;
	struct list_head peer_list;
};
};


static inline struct fw_card *fw_card_get(struct fw_card *card)
static inline struct fw_card *fw_card_get(struct fw_card *card)