提交 75f5d2c9 编写于 作者: L Linus Torvalds

Merge branch 'fwnet' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6

* '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
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/firewire.h> #include <linux/firewire.h>
#include <linux/firewire-constants.h> #include <linux/firewire-constants.h>
...@@ -26,8 +27,14 @@ ...@@ -26,8 +27,14 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <net/arp.h> #include <net/arp.h>
#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ /* rx limits */
#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) #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_BROADCAST_CHANNEL 31
#define IEEE1394_ALL_NODES (0xffc0 | 0x003f) #define IEEE1394_ALL_NODES (0xffc0 | 0x003f)
...@@ -169,15 +176,8 @@ struct fwnet_device { ...@@ -169,15 +176,8 @@ struct fwnet_device {
struct fw_address_handler handler; struct fw_address_handler handler;
u64 local_fifo; u64 local_fifo;
/* List of packets to be sent */ /* Number of tx datagrams that have been queued but not yet acked */
struct list_head packet_list; int queued_datagrams;
/*
* 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;
struct list_head peer_list; struct list_head peer_list;
struct fw_card *card; struct fw_card *card;
...@@ -195,7 +195,7 @@ struct fwnet_peer { ...@@ -195,7 +195,7 @@ struct fwnet_peer {
unsigned pdg_size; /* pd_list size */ unsigned pdg_size; /* pd_list size */
u16 datagram_label; /* outgoing datagram label */ 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 node_id;
int generation; int generation;
unsigned speed; unsigned speed;
...@@ -203,22 +203,18 @@ struct fwnet_peer { ...@@ -203,22 +203,18 @@ struct fwnet_peer {
/* 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. */
struct fwnet_packet_task { 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 fw_transaction transaction;
struct rfc2734_header hdr; struct rfc2734_header hdr;
struct sk_buff *skb; struct sk_buff *skb;
struct fwnet_device *dev; struct fwnet_device *dev;
int outstanding_pkts; int outstanding_pkts;
unsigned max_payload;
u64 fifo_addr; u64 fifo_addr;
u16 dest_node; u16 dest_node;
u16 max_payload;
u8 generation; u8 generation;
u8 speed; u8 speed;
u8 enqueued;
}; };
/* /*
...@@ -650,8 +646,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -650,8 +646,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
net->stats.rx_packets++; net->stats.rx_packets++;
net->stats.rx_bytes += skb->len; net->stats.rx_bytes += skb->len;
} }
if (netif_queue_stopped(net))
netif_wake_queue(net);
return 0; return 0;
...@@ -660,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -660,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
net->stats.rx_dropped++; net->stats.rx_dropped++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
if (netif_queue_stopped(net))
netif_wake_queue(net);
return -ENOENT; return -ENOENT;
} }
...@@ -793,15 +785,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, ...@@ -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 * Datagram is not complete, we're done for the
* moment. * moment.
*/ */
spin_unlock_irqrestore(&dev->lock, flags); retval = 0;
return 0;
fail: fail:
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
if (netif_queue_stopped(net))
netif_wake_queue(net);
return retval; return retval;
} }
...@@ -901,11 +888,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask) ...@@ -901,11 +888,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask)
kmem_cache_free(fwnet_packet_task_cache, 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 int fwnet_send_packet(struct fwnet_packet_task *ptask);
static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
{ {
struct fwnet_device *dev = ptask->dev; struct fwnet_device *dev = ptask->dev;
struct sk_buff *skb = ptask->skb;
unsigned long flags; unsigned long flags;
bool free; bool free;
...@@ -914,10 +909,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ...@@ -914,10 +909,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
ptask->outstanding_pkts--; ptask->outstanding_pkts--;
/* Check whether we or the networking TX soft-IRQ is last user. */ /* 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) if (ptask->outstanding_pkts == 0) {
list_del(&ptask->pt_link); dev->netdev->stats.tx_packets++;
dev->netdev->stats.tx_bytes += skb->len;
}
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -926,7 +925,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ...@@ -926,7 +925,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
u16 fg_off; u16 fg_off;
u16 datagram_label; u16 datagram_label;
u16 lf; u16 lf;
struct sk_buff *skb;
/* Update the ptask to point to the next fragment and send it */ /* Update the ptask to point to the next fragment and send it */
lf = fwnet_get_hdr_lf(&ptask->hdr); lf = fwnet_get_hdr_lf(&ptask->hdr);
...@@ -953,7 +951,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ...@@ -953,7 +951,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
break; break;
} }
skb = ptask->skb;
skb_pull(skb, ptask->max_payload); skb_pull(skb, ptask->max_payload);
if (ptask->outstanding_pkts > 1) { if (ptask->outstanding_pkts > 1) {
fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
...@@ -970,6 +968,31 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ...@@ -970,6 +968,31 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
fwnet_free_ptask(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, static void fwnet_write_complete(struct fw_card *card, int rcode,
void *payload, size_t length, void *data) void *payload, size_t length, void *data)
{ {
...@@ -977,11 +1000,12 @@ static void fwnet_write_complete(struct fw_card *card, int rcode, ...@@ -977,11 +1000,12 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
ptask = data; ptask = data;
if (rcode == RCODE_COMPLETE) if (rcode == RCODE_COMPLETE) {
fwnet_transmit_packet_done(ptask); fwnet_transmit_packet_done(ptask);
else } else {
fw_error("fwnet_write_complete: failed: %x\n", rcode); 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) static int fwnet_send_packet(struct fwnet_packet_task *ptask)
...@@ -1039,9 +1063,11 @@ 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); spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */ /* 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) 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); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -1056,9 +1082,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) ...@@ -1056,9 +1082,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */ /* 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) 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); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -1224,6 +1252,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1224,6 +1252,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
struct fwnet_peer *peer; struct fwnet_peer *peer;
unsigned long flags; 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); ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
if (ptask == NULL) if (ptask == NULL)
goto fail; goto fail;
...@@ -1242,9 +1279,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1242,9 +1279,6 @@ static netdev_tx_t 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.
...@@ -1266,7 +1300,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -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)); peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
goto fail_unlock; goto fail;
generation = peer->generation; generation = peer->generation;
dest_node = peer->node_id; dest_node = peer->node_id;
...@@ -1320,18 +1354,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1320,18 +1354,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
max_payload += RFC2374_FRAG_HDR_SIZE; 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); spin_unlock_irqrestore(&dev->lock, flags);
ptask->max_payload = max_payload; ptask->max_payload = max_payload;
INIT_LIST_HEAD(&ptask->pt_link); ptask->enqueued = 0;
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:
spin_unlock_irqrestore(&dev->lock, flags);
if (ptask) if (ptask)
kmem_cache_free(fwnet_packet_task_cache, ptask); kmem_cache_free(fwnet_packet_task_cache, ptask);
...@@ -1377,7 +1414,7 @@ static void fwnet_init_dev(struct net_device *net) ...@@ -1377,7 +1414,7 @@ static void fwnet_init_dev(struct net_device *net)
net->addr_len = FWNET_ALEN; net->addr_len = FWNET_ALEN;
net->hard_header_len = FWNET_HLEN; net->hard_header_len = FWNET_HLEN;
net->type = ARPHRD_IEEE1394; net->type = ARPHRD_IEEE1394;
net->tx_queue_len = 10; net->tx_queue_len = FWNET_TX_QUEUE_LEN;
} }
/* caller must hold fwnet_device_mutex */ /* caller must hold fwnet_device_mutex */
...@@ -1457,14 +1494,9 @@ static int fwnet_probe(struct device *_dev) ...@@ -1457,14 +1494,9 @@ static int fwnet_probe(struct device *_dev)
dev->broadcast_rcv_context = NULL; dev->broadcast_rcv_context = NULL;
dev->broadcast_xmt_max_payload = 0; dev->broadcast_xmt_max_payload = 0;
dev->broadcast_xmt_datagramlabel = 0; dev->broadcast_xmt_datagramlabel = 0;
dev->local_fifo = FWNET_NO_FIFO_ADDR; dev->local_fifo = FWNET_NO_FIFO_ADDR;
dev->queued_datagrams = 0;
INIT_LIST_HEAD(&dev->packet_list);
INIT_LIST_HEAD(&dev->broadcasted_list);
INIT_LIST_HEAD(&dev->sent_list);
INIT_LIST_HEAD(&dev->peer_list); INIT_LIST_HEAD(&dev->peer_list);
dev->card = card; dev->card = card;
dev->netdev = net; dev->netdev = net;
...@@ -1522,7 +1554,7 @@ static int fwnet_remove(struct device *_dev) ...@@ -1522,7 +1554,7 @@ static int fwnet_remove(struct device *_dev)
struct fwnet_peer *peer = dev_get_drvdata(_dev); struct fwnet_peer *peer = dev_get_drvdata(_dev);
struct fwnet_device *dev = peer->dev; struct fwnet_device *dev = peer->dev;
struct net_device *net; struct net_device *net;
struct fwnet_packet_task *ptask, *pt_next; int i;
mutex_lock(&fwnet_device_mutex); mutex_lock(&fwnet_device_mutex);
...@@ -1540,21 +1572,9 @@ static int fwnet_remove(struct device *_dev) ...@@ -1540,21 +1572,9 @@ static int fwnet_remove(struct device *_dev)
dev->card); dev->card);
fw_iso_context_destroy(dev->broadcast_rcv_context); fw_iso_context_destroy(dev->broadcast_rcv_context);
} }
list_for_each_entry_safe(ptask, pt_next, for (i = 0; dev->queued_datagrams && i < 5; i++)
&dev->packet_list, pt_link) { ssleep(1);
dev_kfree_skb_any(ptask->skb); WARN_ON(dev->queued_datagrams);
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);
}
list_del(&dev->dev_link); list_del(&dev->dev_link);
free_netdev(net); free_netdev(net);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册