aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2007-05-05 11:25:51 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-05-27 17:20:59 -0400
commit7a97bc03e089d1a75dc533f0fe69ec8dac672916 (patch)
treebfa5de17774786f4b0ef976fd645b2adc74bd4b7 /drivers/ieee1394
parent69c29fa7d142d65b13e366ae51e50944484b65ab (diff)
ieee1394: eth1394: handle tlabel exhaustion
When eth1394 was unable to acquire a transaction label, it just dropped outgoing packets without attempt to resend them later. The transmit queue is now halted if no tlabel is available to ->hard_start_xmit(). A workqueue job is then scheduled to catch the moment when ieee1394 recycled the next lot of tlabels. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=8402 Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/eth1394.c80
-rw-r--r--drivers/ieee1394/eth1394.h4
2 files changed, 67 insertions, 17 deletions
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 8e4c959e586a..d6b19c2780af 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -47,6 +47,7 @@
47#include <linux/types.h> 47#include <linux/types.h>
48#include <linux/delay.h> 48#include <linux/delay.h>
49#include <linux/init.h> 49#include <linux/init.h>
50#include <linux/workqueue.h>
50 51
51#include <linux/netdevice.h> 52#include <linux/netdevice.h>
52#include <linux/inetdevice.h> 53#include <linux/inetdevice.h>
@@ -235,6 +236,9 @@ static int ether1394_open(struct net_device *dev)
235/* This is called after an "ifdown" */ 236/* This is called after an "ifdown" */
236static int ether1394_stop(struct net_device *dev) 237static int ether1394_stop(struct net_device *dev)
237{ 238{
239 /* flush priv->wake */
240 flush_scheduled_work();
241
238 netif_stop_queue(dev); 242 netif_stop_queue(dev);
239 return 0; 243 return 0;
240} 244}
@@ -531,6 +535,37 @@ static void ether1394_init_dev(struct net_device *dev)
531} 535}
532 536
533/* 537/*
538 * Wake the queue up after commonly encountered transmit failure conditions are
539 * hopefully over. Currently only tlabel exhaustion is accounted for.
540 */
541static void ether1394_wake_queue(struct work_struct *work)
542{
543 struct eth1394_priv *priv;
544 struct hpsb_packet *packet;
545
546 priv = container_of(work, struct eth1394_priv, wake);
547 packet = hpsb_alloc_packet(0);
548
549 /* This is really bad, but unjam the queue anyway. */
550 if (!packet)
551 goto out;
552
553 packet->host = priv->host;
554 packet->node_id = priv->wake_node;
555 /*
556 * A transaction label is all we really want. If we get one, it almost
557 * always means we can get a lot more because the ieee1394 core recycled
558 * a whole batch of tlabels, at last.
559 */
560 if (hpsb_get_tlabel(packet) == 0)
561 hpsb_free_tlabel(packet);
562
563 hpsb_free_packet(packet);
564out:
565 netif_wake_queue(priv->wake_dev);
566}
567
568/*
534 * This function is called every time a card is found. It is generally called 569 * This function is called every time a card is found. It is generally called
535 * when the module is installed. This is where we add all of our ethernet 570 * when the module is installed. This is where we add all of our ethernet
536 * devices. One for each host. 571 * devices. One for each host.
@@ -574,6 +609,8 @@ static void ether1394_add_host(struct hpsb_host *host)
574 spin_lock_init(&priv->lock); 609 spin_lock_init(&priv->lock);
575 priv->host = host; 610 priv->host = host;
576 priv->local_fifo = fifo_addr; 611 priv->local_fifo = fifo_addr;
612 INIT_WORK(&priv->wake, ether1394_wake_queue);
613 priv->wake_dev = dev;
577 614
578 hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi)); 615 hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
579 if (hi == NULL) { 616 if (hi == NULL) {
@@ -1390,22 +1427,17 @@ static int ether1394_prep_write_packet(struct hpsb_packet *p,
1390 u64 addr, void *data, int tx_len) 1427 u64 addr, void *data, int tx_len)
1391{ 1428{
1392 p->node_id = node; 1429 p->node_id = node;
1393 p->data = NULL;
1394 1430
1395 p->tcode = TCODE_WRITEB; 1431 if (hpsb_get_tlabel(p))
1396 p->header[1] = host->node_id << 16 | addr >> 32; 1432 return -EAGAIN;
1397 p->header[2] = addr & 0xffffffff;
1398 1433
1434 p->tcode = TCODE_WRITEB;
1399 p->header_size = 16; 1435 p->header_size = 16;
1400 p->expect_response = 1; 1436 p->expect_response = 1;
1401
1402 if (hpsb_get_tlabel(p)) {
1403 ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
1404 return -1;
1405 }
1406 p->header[0] = 1437 p->header[0] =
1407 p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4; 1438 p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
1408 1439 p->header[1] = host->node_id << 16 | addr >> 32;
1440 p->header[2] = addr & 0xffffffff;
1409 p->header[3] = tx_len << 16; 1441 p->header[3] = tx_len << 16;
1410 p->data_size = (tx_len + 3) & ~3; 1442 p->data_size = (tx_len + 3) & ~3;
1411 p->data = data; 1443 p->data = data;
@@ -1451,7 +1483,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
1451 1483
1452 packet = ether1394_alloc_common_packet(priv->host); 1484 packet = ether1394_alloc_common_packet(priv->host);
1453 if (!packet) 1485 if (!packet)
1454 return -1; 1486 return -ENOMEM;
1455 1487
1456 if (ptask->tx_type == ETH1394_GASP) { 1488 if (ptask->tx_type == ETH1394_GASP) {
1457 int length = tx_len + 2 * sizeof(quadlet_t); 1489 int length = tx_len + 2 * sizeof(quadlet_t);
@@ -1462,7 +1494,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
1462 ptask->addr, ptask->skb->data, 1494 ptask->addr, ptask->skb->data,
1463 tx_len)) { 1495 tx_len)) {
1464 hpsb_free_packet(packet); 1496 hpsb_free_packet(packet);
1465 return -1; 1497 return -EAGAIN;
1466 } 1498 }
1467 1499
1468 ptask->packet = packet; 1500 ptask->packet = packet;
@@ -1471,7 +1503,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
1471 1503
1472 if (hpsb_send_packet(packet) < 0) { 1504 if (hpsb_send_packet(packet) < 0) {
1473 ether1394_free_packet(packet); 1505 ether1394_free_packet(packet);
1474 return -1; 1506 return -EIO;
1475 } 1507 }
1476 1508
1477 return 0; 1509 return 0;
@@ -1514,13 +1546,18 @@ static void ether1394_complete_cb(void *__ptask)
1514 1546
1515 ptask->outstanding_pkts--; 1547 ptask->outstanding_pkts--;
1516 if (ptask->outstanding_pkts > 0 && !fail) { 1548 if (ptask->outstanding_pkts > 0 && !fail) {
1517 int tx_len; 1549 int tx_len, err;
1518 1550
1519 /* Add the encapsulation header to the fragment */ 1551 /* Add the encapsulation header to the fragment */
1520 tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, 1552 tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
1521 &ptask->hdr); 1553 &ptask->hdr);
1522 if (ether1394_send_packet(ptask, tx_len)) 1554 err = ether1394_send_packet(ptask, tx_len);
1555 if (err) {
1556 if (err == -EAGAIN)
1557 ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
1558
1523 ether1394_dg_complete(ptask, 1); 1559 ether1394_dg_complete(ptask, 1);
1560 }
1524 } else { 1561 } else {
1525 ether1394_dg_complete(ptask, fail); 1562 ether1394_dg_complete(ptask, fail);
1526 } 1563 }
@@ -1633,8 +1670,17 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
1633 /* Add the encapsulation header to the fragment */ 1670 /* Add the encapsulation header to the fragment */
1634 tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); 1671 tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
1635 dev->trans_start = jiffies; 1672 dev->trans_start = jiffies;
1636 if (ether1394_send_packet(ptask, tx_len)) 1673 if (ether1394_send_packet(ptask, tx_len)) {
1637 goto fail; 1674 if (dest_node == (LOCAL_BUS | ALL_NODES))
1675 goto fail;
1676
1677 /* Most failures of ether1394_send_packet are recoverable. */
1678 netif_stop_queue(dev);
1679 priv->wake_node = dest_node;
1680 schedule_work(&priv->wake);
1681 kmem_cache_free(packet_task_cache, ptask);
1682 return NETDEV_TX_BUSY;
1683 }
1638 1684
1639 return NETDEV_TX_OK; 1685 return NETDEV_TX_OK;
1640fail: 1686fail:
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
index a3439ee7cb4e..4f3e2dd46f00 100644
--- a/drivers/ieee1394/eth1394.h
+++ b/drivers/ieee1394/eth1394.h
@@ -66,6 +66,10 @@ struct eth1394_priv {
66 int bc_dgl; /* Outgoing broadcast datagram label */ 66 int bc_dgl; /* Outgoing broadcast datagram label */
67 struct list_head ip_node_list; /* List of IP capable nodes */ 67 struct list_head ip_node_list; /* List of IP capable nodes */
68 struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */ 68 struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
69
70 struct work_struct wake; /* Wake up after xmit failure */
71 struct net_device *wake_dev; /* Stupid backlink for .wake */
72 nodeid_t wake_node; /* Destination of failed xmit */
69}; 73};
70 74
71 75