Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+67 -17
+63 -17
drivers/ieee1394/eth1394.c
··· 47 47 #include <linux/types.h> 48 48 #include <linux/delay.h> 49 49 #include <linux/init.h> 50 + #include <linux/workqueue.h> 50 51 51 52 #include <linux/netdevice.h> 52 53 #include <linux/inetdevice.h> ··· 236 235 /* This is called after an "ifdown" */ 237 236 static int ether1394_stop(struct net_device *dev) 238 237 { 238 + /* flush priv->wake */ 239 + flush_scheduled_work(); 240 + 239 241 netif_stop_queue(dev); 240 242 return 0; 241 243 } ··· 535 531 } 536 532 537 533 /* 534 + * Wake the queue up after commonly encountered transmit failure conditions are 535 + * hopefully over. Currently only tlabel exhaustion is accounted for. 536 + */ 537 + static void ether1394_wake_queue(struct work_struct *work) 538 + { 539 + struct eth1394_priv *priv; 540 + struct hpsb_packet *packet; 541 + 542 + priv = container_of(work, struct eth1394_priv, wake); 543 + packet = hpsb_alloc_packet(0); 544 + 545 + /* This is really bad, but unjam the queue anyway. */ 546 + if (!packet) 547 + goto out; 548 + 549 + packet->host = priv->host; 550 + packet->node_id = priv->wake_node; 551 + /* 552 + * A transaction label is all we really want. If we get one, it almost 553 + * always means we can get a lot more because the ieee1394 core recycled 554 + * a whole batch of tlabels, at last. 555 + */ 556 + if (hpsb_get_tlabel(packet) == 0) 557 + hpsb_free_tlabel(packet); 558 + 559 + hpsb_free_packet(packet); 560 + out: 561 + netif_wake_queue(priv->wake_dev); 562 + } 563 + 564 + /* 538 565 * This function is called every time a card is found. It is generally called 539 566 * when the module is installed. This is where we add all of our ethernet 540 567 * devices. One for each host. ··· 609 574 spin_lock_init(&priv->lock); 610 575 priv->host = host; 611 576 priv->local_fifo = fifo_addr; 577 + INIT_WORK(&priv->wake, ether1394_wake_queue); 578 + priv->wake_dev = dev; 612 579 613 580 hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi)); 614 581 if (hi == NULL) { ··· 1427 1390 u64 addr, void *data, int tx_len) 1428 1391 { 1429 1392 p->node_id = node; 1430 - p->data = NULL; 1393 + 1394 + if (hpsb_get_tlabel(p)) 1395 + return -EAGAIN; 1431 1396 1432 1397 p->tcode = TCODE_WRITEB; 1433 - p->header[1] = host->node_id << 16 | addr >> 32; 1434 - p->header[2] = addr & 0xffffffff; 1435 - 1436 1398 p->header_size = 16; 1437 1399 p->expect_response = 1; 1438 - 1439 - if (hpsb_get_tlabel(p)) { 1440 - ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n"); 1441 - return -1; 1442 - } 1443 1400 p->header[0] = 1444 1401 p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4; 1445 - 1402 + p->header[1] = host->node_id << 16 | addr >> 32; 1403 + p->header[2] = addr & 0xffffffff; 1446 1404 p->header[3] = tx_len << 16; 1447 1405 p->data_size = (tx_len + 3) & ~3; 1448 1406 p->data = data; ··· 1483 1451 1484 1452 packet = ether1394_alloc_common_packet(priv->host); 1485 1453 if (!packet) 1486 - return -1; 1454 + return -ENOMEM; 1487 1455 1488 1456 if (ptask->tx_type == ETH1394_GASP) { 1489 1457 int length = tx_len + 2 * sizeof(quadlet_t); ··· 1494 1462 ptask->addr, ptask->skb->data, 1495 1463 tx_len)) { 1496 1464 hpsb_free_packet(packet); 1497 - return -1; 1465 + return -EAGAIN; 1498 1466 } 1499 1467 1500 1468 ptask->packet = packet; ··· 1503 1471 1504 1472 if (hpsb_send_packet(packet) < 0) { 1505 1473 ether1394_free_packet(packet); 1506 - return -1; 1474 + return -EIO; 1507 1475 } 1508 1476 1509 1477 return 0; ··· 1546 1514 1547 1515 ptask->outstanding_pkts--; 1548 1516 if (ptask->outstanding_pkts > 0 && !fail) { 1549 - int tx_len; 1517 + int tx_len, err; 1550 1518 1551 1519 /* Add the encapsulation header to the fragment */ 1552 1520 tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, 1553 1521 &ptask->hdr); 1554 - if (ether1394_send_packet(ptask, tx_len)) 1522 + err = ether1394_send_packet(ptask, tx_len); 1523 + if (err) { 1524 + if (err == -EAGAIN) 1525 + ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n"); 1526 + 1555 1527 ether1394_dg_complete(ptask, 1); 1528 + } 1556 1529 } else { 1557 1530 ether1394_dg_complete(ptask, fail); 1558 1531 } ··· 1670 1633 /* Add the encapsulation header to the fragment */ 1671 1634 tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); 1672 1635 dev->trans_start = jiffies; 1673 - if (ether1394_send_packet(ptask, tx_len)) 1674 - goto fail; 1636 + if (ether1394_send_packet(ptask, tx_len)) { 1637 + if (dest_node == (LOCAL_BUS | ALL_NODES)) 1638 + goto fail; 1639 + 1640 + /* Most failures of ether1394_send_packet are recoverable. */ 1641 + netif_stop_queue(dev); 1642 + priv->wake_node = dest_node; 1643 + schedule_work(&priv->wake); 1644 + kmem_cache_free(packet_task_cache, ptask); 1645 + return NETDEV_TX_BUSY; 1646 + } 1675 1647 1676 1648 return NETDEV_TX_OK; 1677 1649 fail:
+4
drivers/ieee1394/eth1394.h
··· 66 66 int bc_dgl; /* Outgoing broadcast datagram label */ 67 67 struct list_head ip_node_list; /* List of IP capable nodes */ 68 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