diff options
| author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-11-14 08:35:40 -0500 |
|---|---|---|
| committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-11-16 18:08:49 -0500 |
| commit | b2268830f5cf29d94b3e4a2af0b795a8f28776fe (patch) | |
| tree | a52483756446f1e09dcd80b5243d899612cf5caa | |
| parent | 48553011cea504796e513350740781ac6745f556 (diff) | |
firewire: net: throttle TX queue before running out of tlabels
This prevents firewire-net from submitting write requests in fast
succession until failure due to all 64 transaction labels were used up
for unfinished split transactions. The netif_stop/wake_queue API is
used for this purpose.
Without this stop/wake mechanism, datagrams were simply lost whenever
the tlabel pool was exhausted. Plus, tlabel exhaustion by firewire-net
also prevented other unrelated outbound transactions to be initiated.
The chosen queue depth was checked by me to hit the maximum possible
throughput with an OS X peer whose receive DMA is good enough to never
reject requests due to busy inbound request FIFO. Current Linux peers
show a mixed picture of -5%...+15% change in bandwidth; their current
bottleneck are RCODE_BUSY situations (fewer or more, depending on TX
queue depth) due to too small AR buffer in firewire-ohci.
Maxim Levitsky tested this change with similar watermarks with a Linux
peer and some pending firewire-ohci improvements that address the
RCODE_BUSY problem and confirmed that these TX queue limits are good.
Note: This removes some netif_wake_queue from reception code paths.
They were apparently copy&paste artefacts from a nonsensical
netif_wake_queue use in the older eth1394 driver. This belongs only
into the transmit path.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Tested-by: Maxim Levitsky <maximlevitsky@gmail.com>
| -rw-r--r-- | drivers/firewire/net.c | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index d2d488b9cd96..1a467a91fb0b 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c | |||
| @@ -27,8 +27,14 @@ | |||
| 27 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
| 28 | #include <net/arp.h> | 28 | #include <net/arp.h> |
| 29 | 29 | ||
| 30 | #define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ | 30 | /* rx limits */ |
| 31 | #define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) | 31 | #define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ |
| 32 | #define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2) | ||
| 33 | |||
| 34 | /* tx limits */ | ||
| 35 | #define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */ | ||
| 36 | #define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */ | ||
| 37 | #define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */ | ||
| 32 | 38 | ||
| 33 | #define IEEE1394_BROADCAST_CHANNEL 31 | 39 | #define IEEE1394_BROADCAST_CHANNEL 31 |
| 34 | #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) | 40 | #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) |
| @@ -640,8 +646,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, | |||
| 640 | net->stats.rx_packets++; | 646 | net->stats.rx_packets++; |
| 641 | net->stats.rx_bytes += skb->len; | 647 | net->stats.rx_bytes += skb->len; |
| 642 | } | 648 | } |
| 643 | if (netif_queue_stopped(net)) | ||
| 644 | netif_wake_queue(net); | ||
| 645 | 649 | ||
| 646 | return 0; | 650 | return 0; |
| 647 | 651 | ||
| @@ -650,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, | |||
| 650 | net->stats.rx_dropped++; | 654 | net->stats.rx_dropped++; |
| 651 | 655 | ||
| 652 | dev_kfree_skb_any(skb); | 656 | dev_kfree_skb_any(skb); |
| 653 | if (netif_queue_stopped(net)) | ||
| 654 | netif_wake_queue(net); | ||
| 655 | 657 | ||
| 656 | return -ENOENT; | 658 | return -ENOENT; |
| 657 | } | 659 | } |
| @@ -783,15 +785,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, | |||
| 783 | * Datagram is not complete, we're done for the | 785 | * Datagram is not complete, we're done for the |
| 784 | * moment. | 786 | * moment. |
| 785 | */ | 787 | */ |
| 786 | spin_unlock_irqrestore(&dev->lock, flags); | 788 | retval = 0; |
| 787 | |||
| 788 | return 0; | ||
| 789 | fail: | 789 | fail: |
| 790 | spin_unlock_irqrestore(&dev->lock, flags); | 790 | spin_unlock_irqrestore(&dev->lock, flags); |
| 791 | 791 | ||
| 792 | if (netif_queue_stopped(net)) | ||
| 793 | netif_wake_queue(net); | ||
| 794 | |||
| 795 | return retval; | 792 | return retval; |
| 796 | } | 793 | } |
| 797 | 794 | ||
| @@ -891,6 +888,13 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask) | |||
| 891 | kmem_cache_free(fwnet_packet_task_cache, ptask); | 888 | kmem_cache_free(fwnet_packet_task_cache, ptask); |
| 892 | } | 889 | } |
| 893 | 890 | ||
| 891 | /* Caller must hold dev->lock. */ | ||
| 892 | static void dec_queued_datagrams(struct fwnet_device *dev) | ||
| 893 | { | ||
| 894 | if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS) | ||
| 895 | netif_wake_queue(dev->netdev); | ||
| 896 | } | ||
| 897 | |||
| 894 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); | 898 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); |
| 895 | 899 | ||
| 896 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | 900 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) |
| @@ -907,7 +911,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
| 907 | /* Check whether we or the networking TX soft-IRQ is last user. */ | 911 | /* Check whether we or the networking TX soft-IRQ is last user. */ |
| 908 | free = (ptask->outstanding_pkts == 0 && ptask->enqueued); | 912 | free = (ptask->outstanding_pkts == 0 && ptask->enqueued); |
| 909 | if (free) | 913 | if (free) |
| 910 | dev->queued_datagrams--; | 914 | dec_queued_datagrams(dev); |
| 911 | 915 | ||
| 912 | if (ptask->outstanding_pkts == 0) { | 916 | if (ptask->outstanding_pkts == 0) { |
| 913 | dev->netdev->stats.tx_packets++; | 917 | dev->netdev->stats.tx_packets++; |
| @@ -978,7 +982,7 @@ static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) | |||
| 978 | /* Check whether we or the networking TX soft-IRQ is last user. */ | 982 | /* Check whether we or the networking TX soft-IRQ is last user. */ |
| 979 | free = ptask->enqueued; | 983 | free = ptask->enqueued; |
| 980 | if (free) | 984 | if (free) |
| 981 | dev->queued_datagrams--; | 985 | dec_queued_datagrams(dev); |
| 982 | 986 | ||
| 983 | dev->netdev->stats.tx_dropped++; | 987 | dev->netdev->stats.tx_dropped++; |
| 984 | dev->netdev->stats.tx_errors++; | 988 | dev->netdev->stats.tx_errors++; |
| @@ -1063,7 +1067,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
| 1063 | if (!free) | 1067 | if (!free) |
| 1064 | ptask->enqueued = true; | 1068 | ptask->enqueued = true; |
| 1065 | else | 1069 | else |
| 1066 | dev->queued_datagrams--; | 1070 | dec_queued_datagrams(dev); |
| 1067 | 1071 | ||
| 1068 | spin_unlock_irqrestore(&dev->lock, flags); | 1072 | spin_unlock_irqrestore(&dev->lock, flags); |
| 1069 | 1073 | ||
| @@ -1082,7 +1086,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
| 1082 | if (!free) | 1086 | if (!free) |
| 1083 | ptask->enqueued = true; | 1087 | ptask->enqueued = true; |
| 1084 | else | 1088 | else |
| 1085 | dev->queued_datagrams--; | 1089 | dec_queued_datagrams(dev); |
| 1086 | 1090 | ||
| 1087 | spin_unlock_irqrestore(&dev->lock, flags); | 1091 | spin_unlock_irqrestore(&dev->lock, flags); |
| 1088 | 1092 | ||
| @@ -1248,6 +1252,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
| 1248 | struct fwnet_peer *peer; | 1252 | struct fwnet_peer *peer; |
| 1249 | unsigned long flags; | 1253 | unsigned long flags; |
| 1250 | 1254 | ||
| 1255 | spin_lock_irqsave(&dev->lock, flags); | ||
| 1256 | |||
| 1257 | /* Can this happen? */ | ||
| 1258 | if (netif_queue_stopped(dev->netdev)) { | ||
| 1259 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 1260 | |||
| 1261 | return NETDEV_TX_BUSY; | ||
| 1262 | } | ||
| 1263 | |||
| 1251 | ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); | 1264 | ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); |
| 1252 | if (ptask == NULL) | 1265 | if (ptask == NULL) |
| 1253 | goto fail; | 1266 | goto fail; |
| @@ -1266,9 +1279,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
| 1266 | proto = hdr_buf.h_proto; | 1279 | proto = hdr_buf.h_proto; |
| 1267 | dg_size = skb->len; | 1280 | dg_size = skb->len; |
| 1268 | 1281 | ||
| 1269 | /* serialize access to peer, including peer->datagram_label */ | ||
| 1270 | spin_lock_irqsave(&dev->lock, flags); | ||
| 1271 | |||
| 1272 | /* | 1282 | /* |
| 1273 | * Set the transmission type for the packet. ARP packets and IP | 1283 | * Set the transmission type for the packet. ARP packets and IP |
| 1274 | * broadcast packets are sent via GASP. | 1284 | * broadcast packets are sent via GASP. |
| @@ -1290,7 +1300,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
| 1290 | 1300 | ||
| 1291 | peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); | 1301 | peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); |
| 1292 | if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) | 1302 | if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) |
| 1293 | goto fail_unlock; | 1303 | goto fail; |
| 1294 | 1304 | ||
| 1295 | generation = peer->generation; | 1305 | generation = peer->generation; |
| 1296 | dest_node = peer->node_id; | 1306 | dest_node = peer->node_id; |
| @@ -1344,7 +1354,8 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
| 1344 | max_payload += RFC2374_FRAG_HDR_SIZE; | 1354 | max_payload += RFC2374_FRAG_HDR_SIZE; |
| 1345 | } | 1355 | } |
| 1346 | 1356 | ||
| 1347 | dev->queued_datagrams++; | 1357 | if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS) |
| 1358 | netif_stop_queue(dev->netdev); | ||
| 1348 | 1359 | ||
| 1349 | spin_unlock_irqrestore(&dev->lock, flags); | 1360 | spin_unlock_irqrestore(&dev->lock, flags); |
| 1350 | 1361 | ||
| @@ -1355,9 +1366,9 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
| 1355 | 1366 | ||
| 1356 | return NETDEV_TX_OK; | 1367 | return NETDEV_TX_OK; |
| 1357 | 1368 | ||
| 1358 | fail_unlock: | ||
| 1359 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 1360 | fail: | 1369 | fail: |
| 1370 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 1371 | |||
| 1361 | if (ptask) | 1372 | if (ptask) |
| 1362 | kmem_cache_free(fwnet_packet_task_cache, ptask); | 1373 | kmem_cache_free(fwnet_packet_task_cache, ptask); |
| 1363 | 1374 | ||
| @@ -1403,7 +1414,7 @@ static void fwnet_init_dev(struct net_device *net) | |||
| 1403 | net->addr_len = FWNET_ALEN; | 1414 | net->addr_len = FWNET_ALEN; |
| 1404 | net->hard_header_len = FWNET_HLEN; | 1415 | net->hard_header_len = FWNET_HLEN; |
| 1405 | net->type = ARPHRD_IEEE1394; | 1416 | net->type = ARPHRD_IEEE1394; |
| 1406 | net->tx_queue_len = 10; | 1417 | net->tx_queue_len = FWNET_TX_QUEUE_LEN; |
| 1407 | } | 1418 | } |
| 1408 | 1419 | ||
| 1409 | /* caller must hold fwnet_device_mutex */ | 1420 | /* caller must hold fwnet_device_mutex */ |
