diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-05-05 11:25:51 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-05-27 17:20:59 -0400 |
commit | 7a97bc03e089d1a75dc533f0fe69ec8dac672916 (patch) | |
tree | bfa5de17774786f4b0ef976fd645b2adc74bd4b7 /drivers/ieee1394 | |
parent | 69c29fa7d142d65b13e366ae51e50944484b65ab (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.c | 80 | ||||
-rw-r--r-- | drivers/ieee1394/eth1394.h | 4 |
2 files changed, 67 insertions, 17 deletions
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 8e4c959e586..d6b19c2780a 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" */ |
236 | static int ether1394_stop(struct net_device *dev) | 237 | static 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 | */ | ||
541 | static 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); | ||
564 | out: | ||
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(ð1394_highlevel, host, sizeof(*hi)); | 615 | hi = hpsb_create_hostinfo(ð1394_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; |
1640 | fail: | 1686 | fail: |
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h index a3439ee7cb4..4f3e2dd46f0 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 | ||