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

Commit 75f5d2c9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'fwnet' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  firewire: net: throttle TX queue before running out of tlabels
  firewire: net: replace lists by counters
  firewire: net: fix memory leaks
  firewire: net: count stats.tx_packets and stats.tx_bytes
parents 0f639a3c b2268830
Loading
Loading
Loading
Loading
+90 −70
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
@@ -26,9 +27,15 @@
#include <asm/unaligned.h>
#include <net/arp.h>

#define FWNET_MAX_FRAGMENTS	25	/* arbitrary limit */
/* 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)
#define IEEE1394_MAX_PAYLOAD_S100	512
@@ -169,15 +176,8 @@ 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;

	struct list_head peer_list;
	struct fw_card *card;
@@ -195,7 +195,7 @@ struct fwnet_peer {
	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,22 +203,18 @@ 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;
};

/*
@@ -650,8 +646,6 @@ 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;

@@ -660,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
	net->stats.rx_dropped++;

	dev_kfree_skb_any(skb);
	if (netif_queue_stopped(net))
		netif_wake_queue(net);

	return -ENOENT;
}
@@ -793,15 +785,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;
}

@@ -901,11 +888,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 +909,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 +925,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);
@@ -953,7 +951,7 @@ 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->outstanding_pkts > 1) {
			fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
@@ -970,6 +968,31 @@ 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)
{
@@ -977,11 +1000,12 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,

	ptask = data;

	if (rcode == RCODE_COMPLETE)
	if (rcode == RCODE_COMPLETE) {
		fwnet_transmit_packet_done(ptask);
	else
	} else {
		fw_error("fwnet_write_complete: failed: %x\n", rcode);
		/* ??? error recovery */
		fwnet_transmit_packet_failed(ptask);
	}
}

static int fwnet_send_packet(struct fwnet_packet_task *ptask)
@@ -1039,9 +1063,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 +1082,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);

@@ -1224,6 +1252,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;
@@ -1242,9 +1279,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
	proto = hdr_buf.h_proto;
	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
	 * broadcast packets are sent via GASP.
@@ -1266,7 +1300,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)

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

		generation         = peer->generation;
		dest_node          = peer->node_id;
@@ -1320,18 +1354,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);

@@ -1377,7 +1414,7 @@ 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;
}

/* caller must hold fwnet_device_mutex */
@@ -1457,14 +1494,9 @@ 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;

@@ -1522,7 +1554,7 @@ static int fwnet_remove(struct device *_dev)
	struct fwnet_peer *peer = dev_get_drvdata(_dev);
	struct fwnet_device *dev = peer->dev;
	struct net_device *net;
	struct fwnet_packet_task *ptask, *pt_next;
	int i;

	mutex_lock(&fwnet_device_mutex);

@@ -1540,21 +1572,9 @@ static int fwnet_remove(struct device *_dev)
					      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);
		}
		for (i = 0; dev->queued_datagrams && i < 5; i++)
			ssleep(1);
		WARN_ON(dev->queued_datagrams);
		list_del(&dev->dev_link);

		free_netdev(net);