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

thunderbolt: Add support for end-to-end flow control

USB4 spec defines end-to-end (E2E) flow control that can be used between
hosts to prevent overflow of a RX ring. We previously had this partially
implemented but that code was removed with commit 53f13319d131
("thunderbolt: Get rid of E2E workaround") with the idea that we add it
back properly if there ever is need. Now that we are going to add DMA
traffic test driver (in subsequent patches) this can be useful.

For this reason we modify tb_ring_alloc_rx/tx() so that they accept
RING_FLAG_E2E and configure the hardware ring accordingly. The RX side
also requires passing TX HopID (e2e_tx_hop) used in the credit grant
packets.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Yehezkel Bernat <YehezkelShB@gmail.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

+42 -8
+1 -1
drivers/net/thunderbolt.c
··· 866 866 eof_mask = BIT(TBIP_PDF_FRAME_END); 867 867 868 868 ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, 869 - RING_FLAG_FRAME, sof_mask, eof_mask, 869 + RING_FLAG_FRAME, 0, sof_mask, eof_mask, 870 870 tbnet_start_poll, net); 871 871 if (!ring) { 872 872 netdev_err(dev, "failed to allocate Rx ring\n");
+2 -2
drivers/thunderbolt/ctl.c
··· 628 628 if (!ctl->tx) 629 629 goto err; 630 630 631 - ctl->rx = tb_ring_alloc_rx(nhi, 0, 10, RING_FLAG_NO_SUSPEND, 0xffff, 632 - 0xffff, NULL, NULL); 631 + ctl->rx = tb_ring_alloc_rx(nhi, 0, 10, RING_FLAG_NO_SUSPEND, 0, 0xffff, 632 + 0xffff, NULL, NULL); 633 633 if (!ctl->rx) 634 634 goto err; 635 635
+32 -4
drivers/thunderbolt/nhi.c
··· 483 483 484 484 static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, 485 485 bool transmit, unsigned int flags, 486 - u16 sof_mask, u16 eof_mask, 486 + int e2e_tx_hop, u16 sof_mask, u16 eof_mask, 487 487 void (*start_poll)(void *), 488 488 void *poll_data) 489 489 { ··· 506 506 ring->is_tx = transmit; 507 507 ring->size = size; 508 508 ring->flags = flags; 509 + ring->e2e_tx_hop = e2e_tx_hop; 509 510 ring->sof_mask = sof_mask; 510 511 ring->eof_mask = eof_mask; 511 512 ring->head = 0; ··· 551 550 struct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size, 552 551 unsigned int flags) 553 552 { 554 - return tb_ring_alloc(nhi, hop, size, true, flags, 0, 0, NULL, NULL); 553 + return tb_ring_alloc(nhi, hop, size, true, flags, 0, 0, 0, NULL, NULL); 555 554 } 556 555 EXPORT_SYMBOL_GPL(tb_ring_alloc_tx); 557 556 ··· 561 560 * @hop: HopID (ring) to allocate. Pass %-1 for automatic allocation. 562 561 * @size: Number of entries in the ring 563 562 * @flags: Flags for the ring 563 + * @e2e_tx_hop: Transmit HopID when E2E is enabled in @flags 564 564 * @sof_mask: Mask of PDF values that start a frame 565 565 * @eof_mask: Mask of PDF values that end a frame 566 566 * @start_poll: If not %NULL the ring will call this function when an ··· 570 568 * @poll_data: Optional data passed to @start_poll 571 569 */ 572 570 struct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size, 573 - unsigned int flags, u16 sof_mask, u16 eof_mask, 571 + unsigned int flags, int e2e_tx_hop, 572 + u16 sof_mask, u16 eof_mask, 574 573 void (*start_poll)(void *), void *poll_data) 575 574 { 576 - return tb_ring_alloc(nhi, hop, size, false, flags, sof_mask, eof_mask, 575 + return tb_ring_alloc(nhi, hop, size, false, flags, e2e_tx_hop, sof_mask, eof_mask, 577 576 start_poll, poll_data); 578 577 } 579 578 EXPORT_SYMBOL_GPL(tb_ring_alloc_rx); ··· 621 618 ring_iowrite32options(ring, sof_eof_mask, 4); 622 619 ring_iowrite32options(ring, flags, 0); 623 620 } 621 + 622 + /* 623 + * Now that the ring valid bit is set we can configure E2E if 624 + * enabled for the ring. 625 + */ 626 + if (ring->flags & RING_FLAG_E2E) { 627 + if (!ring->is_tx) { 628 + u32 hop; 629 + 630 + hop = ring->e2e_tx_hop << REG_RX_OPTIONS_E2E_HOP_SHIFT; 631 + hop &= REG_RX_OPTIONS_E2E_HOP_MASK; 632 + flags |= hop; 633 + 634 + dev_dbg(&ring->nhi->pdev->dev, 635 + "enabling E2E for %s %d with TX HopID %d\n", 636 + RING_TYPE(ring), ring->hop, ring->e2e_tx_hop); 637 + } else { 638 + dev_dbg(&ring->nhi->pdev->dev, "enabling E2E for %s %d\n", 639 + RING_TYPE(ring), ring->hop); 640 + } 641 + 642 + flags |= RING_FLAG_E2E_FLOW_CONTROL; 643 + ring_iowrite32options(ring, flags, 0); 644 + } 645 + 624 646 ring_interrupt_active(ring, true); 625 647 ring->running = true; 626 648 err:
+7 -1
include/linux/thunderbolt.h
··· 481 481 * @irq: MSI-X irq number if the ring uses MSI-X. %0 otherwise. 482 482 * @vector: MSI-X vector number the ring uses (only set if @irq is > 0) 483 483 * @flags: Ring specific flags 484 + * @e2e_tx_hop: Transmit HopID when E2E is enabled. Only applicable to 485 + * RX ring. For TX ring this should be set to %0. 484 486 * @sof_mask: Bit mask used to detect start of frame PDF 485 487 * @eof_mask: Bit mask used to detect end of frame PDF 486 488 * @start_poll: Called when ring interrupt is triggered to start ··· 506 504 int irq; 507 505 u8 vector; 508 506 unsigned int flags; 507 + int e2e_tx_hop; 509 508 u16 sof_mask; 510 509 u16 eof_mask; 511 510 void (*start_poll)(void *data); ··· 517 514 #define RING_FLAG_NO_SUSPEND BIT(0) 518 515 /* Configure the ring to be in frame mode */ 519 516 #define RING_FLAG_FRAME BIT(1) 517 + /* Enable end-to-end flow control */ 518 + #define RING_FLAG_E2E BIT(2) 520 519 521 520 struct ring_frame; 522 521 typedef void (*ring_cb)(struct tb_ring *, struct ring_frame *, bool canceled); ··· 567 562 struct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size, 568 563 unsigned int flags); 569 564 struct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size, 570 - unsigned int flags, u16 sof_mask, u16 eof_mask, 565 + unsigned int flags, int e2e_tx_hop, 566 + u16 sof_mask, u16 eof_mask, 571 567 void (*start_poll)(void *), void *poll_data); 572 568 void tb_ring_start(struct tb_ring *ring); 573 569 void tb_ring_stop(struct tb_ring *ring);