.. | .. |
---|
56 | 56 | * @vq: pointer to the virtio virtqueue |
---|
57 | 57 | * @desc: current descriptor of the pending packet |
---|
58 | 58 | * @desc_head: head descriptor of the pending packet |
---|
| 59 | + * @drop_desc: dummy desc for packet dropping |
---|
59 | 60 | * @cur_len: processed length of the current descriptor |
---|
60 | 61 | * @rem_len: remaining length of the pending packet |
---|
61 | 62 | * @pkt_len: total length of the pending packet |
---|
.. | .. |
---|
72 | 73 | struct virtqueue *vq; |
---|
73 | 74 | struct vring_desc *desc; |
---|
74 | 75 | struct vring_desc *desc_head; |
---|
| 76 | + struct vring_desc drop_desc; |
---|
75 | 77 | int cur_len; |
---|
76 | 78 | int rem_len; |
---|
77 | 79 | u32 pkt_len; |
---|
.. | .. |
---|
82 | 84 | int vdev_id; |
---|
83 | 85 | struct mlxbf_tmfifo *fifo; |
---|
84 | 86 | }; |
---|
| 87 | + |
---|
| 88 | +/* Check whether vring is in drop mode. */ |
---|
| 89 | +#define IS_VRING_DROP(_r) ({ \ |
---|
| 90 | + typeof(_r) (r) = (_r); \ |
---|
| 91 | + (r->desc_head == &r->drop_desc ? true : false); }) |
---|
| 92 | + |
---|
| 93 | +/* A stub length to drop maximum length packet. */ |
---|
| 94 | +#define VRING_DROP_DESC_MAX_LEN GENMASK(15, 0) |
---|
85 | 95 | |
---|
86 | 96 | /* Interrupt types. */ |
---|
87 | 97 | enum { |
---|
.. | .. |
---|
195 | 205 | static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr"; |
---|
196 | 206 | |
---|
197 | 207 | /* Maximum L2 header length. */ |
---|
198 | | -#define MLXBF_TMFIFO_NET_L2_OVERHEAD 36 |
---|
| 208 | +#define MLXBF_TMFIFO_NET_L2_OVERHEAD (ETH_HLEN + VLAN_HLEN) |
---|
199 | 209 | |
---|
200 | 210 | /* Supported virtio-net features. */ |
---|
201 | 211 | #define MLXBF_TMFIFO_NET_FEATURES \ |
---|
.. | .. |
---|
243 | 253 | vring->align = SMP_CACHE_BYTES; |
---|
244 | 254 | vring->index = i; |
---|
245 | 255 | vring->vdev_id = tm_vdev->vdev.id.device; |
---|
| 256 | + vring->drop_desc.len = VRING_DROP_DESC_MAX_LEN; |
---|
246 | 257 | dev = &tm_vdev->vdev.dev; |
---|
247 | 258 | |
---|
248 | 259 | size = vring_size(vring->num, vring->align); |
---|
.. | .. |
---|
348 | 359 | return len; |
---|
349 | 360 | } |
---|
350 | 361 | |
---|
351 | | -static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring) |
---|
| 362 | +static void mlxbf_tmfifo_release_pkt(struct mlxbf_tmfifo_vring *vring) |
---|
352 | 363 | { |
---|
353 | 364 | struct vring_desc *desc_head; |
---|
354 | 365 | u32 len = 0; |
---|
.. | .. |
---|
577 | 588 | |
---|
578 | 589 | if (vring->cur_len + sizeof(u64) <= len) { |
---|
579 | 590 | /* The whole word. */ |
---|
580 | | - if (is_rx) |
---|
581 | | - memcpy(addr + vring->cur_len, &data, sizeof(u64)); |
---|
582 | | - else |
---|
583 | | - memcpy(&data, addr + vring->cur_len, sizeof(u64)); |
---|
| 591 | + if (!IS_VRING_DROP(vring)) { |
---|
| 592 | + if (is_rx) |
---|
| 593 | + memcpy(addr + vring->cur_len, &data, |
---|
| 594 | + sizeof(u64)); |
---|
| 595 | + else |
---|
| 596 | + memcpy(&data, addr + vring->cur_len, |
---|
| 597 | + sizeof(u64)); |
---|
| 598 | + } |
---|
584 | 599 | vring->cur_len += sizeof(u64); |
---|
585 | 600 | } else { |
---|
586 | 601 | /* Leftover bytes. */ |
---|
587 | | - if (is_rx) |
---|
588 | | - memcpy(addr + vring->cur_len, &data, |
---|
589 | | - len - vring->cur_len); |
---|
590 | | - else |
---|
591 | | - memcpy(&data, addr + vring->cur_len, |
---|
592 | | - len - vring->cur_len); |
---|
| 602 | + if (!IS_VRING_DROP(vring)) { |
---|
| 603 | + if (is_rx) |
---|
| 604 | + memcpy(addr + vring->cur_len, &data, |
---|
| 605 | + len - vring->cur_len); |
---|
| 606 | + else |
---|
| 607 | + memcpy(&data, addr + vring->cur_len, |
---|
| 608 | + len - vring->cur_len); |
---|
| 609 | + } |
---|
593 | 610 | vring->cur_len = len; |
---|
594 | 611 | } |
---|
595 | 612 | |
---|
.. | .. |
---|
606 | 623 | * flag is set. |
---|
607 | 624 | */ |
---|
608 | 625 | static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, |
---|
609 | | - struct vring_desc *desc, |
---|
| 626 | + struct vring_desc **desc, |
---|
610 | 627 | bool is_rx, bool *vring_change) |
---|
611 | 628 | { |
---|
612 | 629 | struct mlxbf_tmfifo *fifo = vring->fifo; |
---|
613 | 630 | struct virtio_net_config *config; |
---|
614 | 631 | struct mlxbf_tmfifo_msg_hdr hdr; |
---|
615 | 632 | int vdev_id, hdr_len; |
---|
| 633 | + bool drop_rx = false; |
---|
616 | 634 | |
---|
617 | 635 | /* Read/Write packet header. */ |
---|
618 | 636 | if (is_rx) { |
---|
.. | .. |
---|
632 | 650 | if (ntohs(hdr.len) > |
---|
633 | 651 | __virtio16_to_cpu(virtio_legacy_is_little_endian(), |
---|
634 | 652 | config->mtu) + |
---|
635 | | - MLXBF_TMFIFO_NET_L2_OVERHEAD) |
---|
636 | | - return; |
---|
| 653 | + MLXBF_TMFIFO_NET_L2_OVERHEAD) |
---|
| 654 | + drop_rx = true; |
---|
637 | 655 | } else { |
---|
638 | 656 | vdev_id = VIRTIO_ID_CONSOLE; |
---|
639 | 657 | hdr_len = 0; |
---|
.. | .. |
---|
648 | 666 | |
---|
649 | 667 | if (!tm_dev2) |
---|
650 | 668 | return; |
---|
651 | | - vring->desc = desc; |
---|
| 669 | + vring->desc = *desc; |
---|
652 | 670 | vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX]; |
---|
653 | 671 | *vring_change = true; |
---|
654 | 672 | } |
---|
| 673 | + |
---|
| 674 | + if (drop_rx && !IS_VRING_DROP(vring)) { |
---|
| 675 | + if (vring->desc_head) |
---|
| 676 | + mlxbf_tmfifo_release_pkt(vring); |
---|
| 677 | + *desc = &vring->drop_desc; |
---|
| 678 | + vring->desc_head = *desc; |
---|
| 679 | + vring->desc = *desc; |
---|
| 680 | + } |
---|
| 681 | + |
---|
655 | 682 | vring->pkt_len = ntohs(hdr.len) + hdr_len; |
---|
656 | 683 | } else { |
---|
657 | 684 | /* Network virtio has an extra header. */ |
---|
658 | 685 | hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ? |
---|
659 | 686 | sizeof(struct virtio_net_hdr) : 0; |
---|
660 | | - vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc); |
---|
| 687 | + vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, *desc); |
---|
661 | 688 | hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ? |
---|
662 | 689 | VIRTIO_ID_NET : VIRTIO_ID_CONSOLE; |
---|
663 | 690 | hdr.len = htons(vring->pkt_len - hdr_len); |
---|
.. | .. |
---|
690 | 717 | /* Get the descriptor of the next packet. */ |
---|
691 | 718 | if (!vring->desc) { |
---|
692 | 719 | desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx); |
---|
693 | | - if (!desc) |
---|
694 | | - return false; |
---|
| 720 | + if (!desc) { |
---|
| 721 | + /* Drop next Rx packet to avoid stuck. */ |
---|
| 722 | + if (is_rx) { |
---|
| 723 | + desc = &vring->drop_desc; |
---|
| 724 | + vring->desc_head = desc; |
---|
| 725 | + vring->desc = desc; |
---|
| 726 | + } else { |
---|
| 727 | + return false; |
---|
| 728 | + } |
---|
| 729 | + } |
---|
695 | 730 | } else { |
---|
696 | 731 | desc = vring->desc; |
---|
697 | 732 | } |
---|
698 | 733 | |
---|
699 | 734 | /* Beginning of a packet. Start to Rx/Tx packet header. */ |
---|
700 | 735 | if (vring->pkt_len == 0) { |
---|
701 | | - mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change); |
---|
| 736 | + mlxbf_tmfifo_rxtx_header(vring, &desc, is_rx, &vring_change); |
---|
702 | 737 | (*avail)--; |
---|
703 | 738 | |
---|
704 | 739 | /* Return if new packet is for another ring. */ |
---|
.. | .. |
---|
724 | 759 | vring->rem_len -= len; |
---|
725 | 760 | |
---|
726 | 761 | /* Get the next desc on the chain. */ |
---|
727 | | - if (vring->rem_len > 0 && |
---|
| 762 | + if (!IS_VRING_DROP(vring) && vring->rem_len > 0 && |
---|
728 | 763 | (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) { |
---|
729 | 764 | idx = virtio16_to_cpu(vdev, desc->next); |
---|
730 | 765 | desc = &vr->desc[idx]; |
---|
731 | 766 | goto mlxbf_tmfifo_desc_done; |
---|
732 | 767 | } |
---|
733 | 768 | |
---|
734 | | - /* Done and release the pending packet. */ |
---|
735 | | - mlxbf_tmfifo_release_pending_pkt(vring); |
---|
| 769 | + /* Done and release the packet. */ |
---|
736 | 770 | desc = NULL; |
---|
737 | 771 | fifo->vring[is_rx] = NULL; |
---|
| 772 | + if (!IS_VRING_DROP(vring)) { |
---|
| 773 | + mlxbf_tmfifo_release_pkt(vring); |
---|
| 774 | + } else { |
---|
| 775 | + vring->pkt_len = 0; |
---|
| 776 | + vring->desc_head = NULL; |
---|
| 777 | + vring->desc = NULL; |
---|
| 778 | + return false; |
---|
| 779 | + } |
---|
738 | 780 | |
---|
739 | 781 | /* |
---|
740 | 782 | * Make sure the load/store are in order before |
---|
.. | .. |
---|
868 | 910 | tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE]; |
---|
869 | 911 | mlxbf_tmfifo_console_output(tm_vdev, vring); |
---|
870 | 912 | spin_unlock_irqrestore(&fifo->spin_lock[0], flags); |
---|
| 913 | + set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events); |
---|
871 | 914 | } else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, |
---|
872 | 915 | &fifo->pend_events)) { |
---|
873 | 916 | return true; |
---|
.. | .. |
---|
913 | 956 | |
---|
914 | 957 | /* Release the pending packet. */ |
---|
915 | 958 | if (vring->desc) |
---|
916 | | - mlxbf_tmfifo_release_pending_pkt(vring); |
---|
| 959 | + mlxbf_tmfifo_release_pkt(vring); |
---|
917 | 960 | vq = vring->vq; |
---|
918 | 961 | if (vq) { |
---|
919 | 962 | vring->vq = NULL; |
---|