diff options
author | Bjørn Mork <bjorn@mork.no> | 2012-10-22 06:56:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-23 02:40:11 -0400 |
commit | c78b7c58665748aa775e86e0e49798b9f34a1dc9 (patch) | |
tree | 81c298292d1ca721ab130a16d6c13f1a305af587 /drivers/net/usb/cdc_ncm.c | |
parent | ff06ab13a4ccae4acb44a2d4e3ece367b616ab50 (diff) |
net: cdc_ncm: refactoring for tx multiplexing
Adding multiplexed NDP support to cdc_ncm_fill_tx_frame, allowing
transmissions of multiple independent sessions within the same NTB.
Refactoring the code quite a bit to avoid having to store copies
of multiple NDPs being prepared for tx. The old code would still
reserve enough room for a maximum sized NDP in the skb so we might
as well keep them in the skb while they are being prepared.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/cdc_ncm.c')
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 247 |
1 files changed, 102 insertions, 145 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 6688a15e044d..2dd27346cb39 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
@@ -88,14 +88,11 @@ | |||
88 | (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ | 88 | (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ |
89 | (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) | 89 | (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) |
90 | 90 | ||
91 | struct cdc_ncm_data { | 91 | #define CDC_NCM_NDP_SIZE \ |
92 | struct usb_cdc_ncm_nth16 nth16; | 92 | (sizeof(struct usb_cdc_ncm_ndp16) + \ |
93 | struct usb_cdc_ncm_ndp16 ndp16; | 93 | (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) |
94 | struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1]; | ||
95 | }; | ||
96 | 94 | ||
97 | struct cdc_ncm_ctx { | 95 | struct cdc_ncm_ctx { |
98 | struct cdc_ncm_data tx_ncm; | ||
99 | struct usb_cdc_ncm_ntb_parameters ncm_parm; | 96 | struct usb_cdc_ncm_ntb_parameters ncm_parm; |
100 | struct hrtimer tx_timer; | 97 | struct hrtimer tx_timer; |
101 | struct tasklet_struct bh; | 98 | struct tasklet_struct bh; |
@@ -117,13 +114,12 @@ struct cdc_ncm_ctx { | |||
117 | 114 | ||
118 | struct sk_buff *tx_curr_skb; | 115 | struct sk_buff *tx_curr_skb; |
119 | struct sk_buff *tx_rem_skb; | 116 | struct sk_buff *tx_rem_skb; |
117 | __le32 tx_rem_sign; | ||
120 | 118 | ||
121 | spinlock_t mtx; | 119 | spinlock_t mtx; |
122 | atomic_t stop; | 120 | atomic_t stop; |
123 | 121 | ||
124 | u32 tx_timer_pending; | 122 | u32 tx_timer_pending; |
125 | u32 tx_curr_offset; | ||
126 | u32 tx_curr_last_offset; | ||
127 | u32 tx_curr_frame_num; | 123 | u32 tx_curr_frame_num; |
128 | u32 rx_speed; | 124 | u32 rx_speed; |
129 | u32 tx_speed; | 125 | u32 tx_speed; |
@@ -658,51 +654,75 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) | |||
658 | return ret; | 654 | return ret; |
659 | } | 655 | } |
660 | 656 | ||
661 | static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max) | 657 | static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) |
662 | { | 658 | { |
663 | if (first >= max) | 659 | size_t align = ALIGN(skb->len, modulus) - skb->len + remainder; |
664 | return; | 660 | |
665 | if (first >= end) | 661 | if (skb->len + align > max) |
666 | return; | 662 | align = max - skb->len; |
667 | if (end > max) | 663 | if (align && skb_tailroom(skb) >= align) |
668 | end = max; | 664 | memset(skb_put(skb, align), 0, align); |
669 | memset(ptr + first, 0, end - first); | 665 | } |
666 | |||
667 | /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly | ||
668 | * allocating a new one within skb | ||
669 | */ | ||
670 | static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve) | ||
671 | { | ||
672 | struct usb_cdc_ncm_ndp16 *ndp16 = NULL; | ||
673 | struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; | ||
674 | size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); | ||
675 | |||
676 | /* follow the chain of NDPs, looking for a match */ | ||
677 | while (ndpoffset) { | ||
678 | ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); | ||
679 | if (ndp16->dwSignature == sign) | ||
680 | return ndp16; | ||
681 | ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex); | ||
682 | } | ||
683 | |||
684 | /* align new NDP */ | ||
685 | cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); | ||
686 | |||
687 | /* verify that there is room for the NDP and the datagram (reserve) */ | ||
688 | if ((ctx->tx_max - skb->len - reserve) < CDC_NCM_NDP_SIZE) | ||
689 | return NULL; | ||
690 | |||
691 | /* link to it */ | ||
692 | if (ndp16) | ||
693 | ndp16->wNextNdpIndex = cpu_to_le16(skb->len); | ||
694 | else | ||
695 | nth16->wNdpIndex = cpu_to_le16(skb->len); | ||
696 | |||
697 | /* push a new empty NDP */ | ||
698 | ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, CDC_NCM_NDP_SIZE), 0, CDC_NCM_NDP_SIZE); | ||
699 | ndp16->dwSignature = sign; | ||
700 | ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); | ||
701 | return ndp16; | ||
670 | } | 702 | } |
671 | 703 | ||
672 | static struct sk_buff * | 704 | static struct sk_buff * |
673 | cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | 705 | cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) |
674 | { | 706 | { |
707 | struct usb_cdc_ncm_nth16 *nth16; | ||
708 | struct usb_cdc_ncm_ndp16 *ndp16; | ||
675 | struct sk_buff *skb_out; | 709 | struct sk_buff *skb_out; |
676 | u32 rem; | 710 | u16 n = 0, index, ndplen; |
677 | u32 offset; | ||
678 | u32 last_offset; | ||
679 | u16 n = 0, index; | ||
680 | u8 ready2send = 0; | 711 | u8 ready2send = 0; |
681 | 712 | ||
682 | /* if there is a remaining skb, it gets priority */ | 713 | /* if there is a remaining skb, it gets priority */ |
683 | if (skb != NULL) | 714 | if (skb != NULL) { |
684 | swap(skb, ctx->tx_rem_skb); | 715 | swap(skb, ctx->tx_rem_skb); |
685 | else | 716 | swap(sign, ctx->tx_rem_sign); |
717 | } else { | ||
686 | ready2send = 1; | 718 | ready2send = 1; |
687 | 719 | } | |
688 | /* | ||
689 | * +----------------+ | ||
690 | * | skb_out | | ||
691 | * +----------------+ | ||
692 | * ^ offset | ||
693 | * ^ last_offset | ||
694 | */ | ||
695 | 720 | ||
696 | /* check if we are resuming an OUT skb */ | 721 | /* check if we are resuming an OUT skb */ |
697 | if (ctx->tx_curr_skb != NULL) { | 722 | skb_out = ctx->tx_curr_skb; |
698 | /* pop variables */ | ||
699 | skb_out = ctx->tx_curr_skb; | ||
700 | offset = ctx->tx_curr_offset; | ||
701 | last_offset = ctx->tx_curr_last_offset; | ||
702 | n = ctx->tx_curr_frame_num; | ||
703 | 723 | ||
704 | } else { | 724 | /* allocate a new OUT skb */ |
705 | /* reset variables */ | 725 | if (!skb_out) { |
706 | skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); | 726 | skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); |
707 | if (skb_out == NULL) { | 727 | if (skb_out == NULL) { |
708 | if (skb != NULL) { | 728 | if (skb != NULL) { |
@@ -711,35 +731,21 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
711 | } | 731 | } |
712 | goto exit_no_skb; | 732 | goto exit_no_skb; |
713 | } | 733 | } |
734 | /* fill out the initial 16-bit NTB header */ | ||
735 | nth16 = (struct usb_cdc_ncm_nth16 *)memset(skb_put(skb_out, sizeof(struct usb_cdc_ncm_nth16)), 0, sizeof(struct usb_cdc_ncm_nth16)); | ||
736 | nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); | ||
737 | nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16)); | ||
738 | nth16->wSequence = cpu_to_le16(ctx->tx_seq++); | ||
714 | 739 | ||
715 | /* make room for NTH and NDP */ | 740 | /* count total number of frames in this NTB */ |
716 | offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16), | ||
717 | ctx->tx_ndp_modulus) + | ||
718 | sizeof(struct usb_cdc_ncm_ndp16) + | ||
719 | (ctx->tx_max_datagrams + 1) * | ||
720 | sizeof(struct usb_cdc_ncm_dpe16); | ||
721 | |||
722 | /* store last valid offset before alignment */ | ||
723 | last_offset = offset; | ||
724 | /* align first Datagram offset correctly */ | ||
725 | offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; | ||
726 | /* zero buffer till the first IP datagram */ | ||
727 | cdc_ncm_zero_fill(skb_out->data, 0, offset, offset); | ||
728 | n = 0; | ||
729 | ctx->tx_curr_frame_num = 0; | 741 | ctx->tx_curr_frame_num = 0; |
730 | } | 742 | } |
731 | 743 | ||
732 | for (; n < ctx->tx_max_datagrams; n++) { | 744 | for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) { |
733 | /* check if end of transmit buffer is reached */ | 745 | /* send any remaining skb first */ |
734 | if (offset >= ctx->tx_max) { | ||
735 | ready2send = 1; | ||
736 | break; | ||
737 | } | ||
738 | /* compute maximum buffer size */ | ||
739 | rem = ctx->tx_max - offset; | ||
740 | |||
741 | if (skb == NULL) { | 746 | if (skb == NULL) { |
742 | skb = ctx->tx_rem_skb; | 747 | skb = ctx->tx_rem_skb; |
748 | sign = ctx->tx_rem_sign; | ||
743 | ctx->tx_rem_skb = NULL; | 749 | ctx->tx_rem_skb = NULL; |
744 | 750 | ||
745 | /* check for end of skb */ | 751 | /* check for end of skb */ |
@@ -747,7 +753,14 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
747 | break; | 753 | break; |
748 | } | 754 | } |
749 | 755 | ||
750 | if (skb->len > rem) { | 756 | /* get the appropriate NDP for this skb */ |
757 | ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder); | ||
758 | |||
759 | /* align beginning of next frame */ | ||
760 | cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); | ||
761 | |||
762 | /* check if we had enough room left for both NDP and frame */ | ||
763 | if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { | ||
751 | if (n == 0) { | 764 | if (n == 0) { |
752 | /* won't fit, MTU problem? */ | 765 | /* won't fit, MTU problem? */ |
753 | dev_kfree_skb_any(skb); | 766 | dev_kfree_skb_any(skb); |
@@ -760,31 +773,30 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
760 | ctx->netdev->stats.tx_dropped++; | 773 | ctx->netdev->stats.tx_dropped++; |
761 | } | 774 | } |
762 | ctx->tx_rem_skb = skb; | 775 | ctx->tx_rem_skb = skb; |
776 | ctx->tx_rem_sign = sign; | ||
763 | skb = NULL; | 777 | skb = NULL; |
764 | ready2send = 1; | 778 | ready2send = 1; |
765 | } | 779 | } |
766 | break; | 780 | break; |
767 | } | 781 | } |
768 | 782 | ||
769 | memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len); | 783 | /* calculate frame number withing this NDP */ |
770 | 784 | ndplen = le16_to_cpu(ndp16->wLength); | |
771 | ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len); | 785 | index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1; |
772 | ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset); | ||
773 | |||
774 | /* update offset */ | ||
775 | offset += skb->len; | ||
776 | 786 | ||
777 | /* store last valid offset before alignment */ | 787 | /* OK, add this skb */ |
778 | last_offset = offset; | 788 | ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len); |
779 | 789 | ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len); | |
780 | /* align offset correctly */ | 790 | ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16)); |
781 | offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; | 791 | memcpy(skb_put(skb_out, skb->len), skb->data, skb->len); |
782 | |||
783 | /* zero padding */ | ||
784 | cdc_ncm_zero_fill(skb_out->data, last_offset, offset, | ||
785 | ctx->tx_max); | ||
786 | dev_kfree_skb_any(skb); | 792 | dev_kfree_skb_any(skb); |
787 | skb = NULL; | 793 | skb = NULL; |
794 | |||
795 | /* send now if this NDP is full */ | ||
796 | if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) { | ||
797 | ready2send = 1; | ||
798 | break; | ||
799 | } | ||
788 | } | 800 | } |
789 | 801 | ||
790 | /* free up any dangling skb */ | 802 | /* free up any dangling skb */ |
@@ -800,16 +812,12 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
800 | /* wait for more frames */ | 812 | /* wait for more frames */ |
801 | /* push variables */ | 813 | /* push variables */ |
802 | ctx->tx_curr_skb = skb_out; | 814 | ctx->tx_curr_skb = skb_out; |
803 | ctx->tx_curr_offset = offset; | ||
804 | ctx->tx_curr_last_offset = last_offset; | ||
805 | goto exit_no_skb; | 815 | goto exit_no_skb; |
806 | 816 | ||
807 | } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { | 817 | } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { |
808 | /* wait for more frames */ | 818 | /* wait for more frames */ |
809 | /* push variables */ | 819 | /* push variables */ |
810 | ctx->tx_curr_skb = skb_out; | 820 | ctx->tx_curr_skb = skb_out; |
811 | ctx->tx_curr_offset = offset; | ||
812 | ctx->tx_curr_last_offset = last_offset; | ||
813 | /* set the pending count */ | 821 | /* set the pending count */ |
814 | if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) | 822 | if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) |
815 | ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; | 823 | ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; |
@@ -820,75 +828,24 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
820 | /* variables will be reset at next call */ | 828 | /* variables will be reset at next call */ |
821 | } | 829 | } |
822 | 830 | ||
823 | /* check for overflow */ | ||
824 | if (last_offset > ctx->tx_max) | ||
825 | last_offset = ctx->tx_max; | ||
826 | |||
827 | /* revert offset */ | ||
828 | offset = last_offset; | ||
829 | |||
830 | /* | 831 | /* |
831 | * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, | 832 | * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, |
832 | * we send buffers as it is. If we get more data, it would be more | 833 | * we send buffers as it is. If we get more data, it would be more |
833 | * efficient for USB HS mobile device with DMA engine to receive a full | 834 | * efficient for USB HS mobile device with DMA engine to receive a full |
834 | * size NTB, than canceling DMA transfer and receiving a short packet. | 835 | * size NTB, than canceling DMA transfer and receiving a short packet. |
835 | */ | 836 | */ |
836 | if (offset > CDC_NCM_MIN_TX_PKT) | 837 | if (skb_out->len > CDC_NCM_MIN_TX_PKT) |
837 | offset = ctx->tx_max; | 838 | /* final zero padding */ |
838 | 839 | memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0, ctx->tx_max - skb_out->len); | |
839 | /* final zero padding */ | ||
840 | cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max); | ||
841 | |||
842 | /* store last offset */ | ||
843 | last_offset = offset; | ||
844 | |||
845 | if (((last_offset < ctx->tx_max) && ((last_offset % | ||
846 | le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || | ||
847 | (((last_offset == ctx->tx_max) && ((ctx->tx_max % | ||
848 | le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && | ||
849 | (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { | ||
850 | /* force short packet */ | ||
851 | *(((u8 *)skb_out->data) + last_offset) = 0; | ||
852 | last_offset++; | ||
853 | } | ||
854 | 840 | ||
855 | /* zero the rest of the DPEs plus the last NULL entry */ | 841 | /* do we need to prevent a ZLP? */ |
856 | for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) { | 842 | if (((skb_out->len % le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0) && |
857 | ctx->tx_ncm.dpe16[n].wDatagramLength = 0; | 843 | (skb_out->len < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)) && skb_tailroom(skb_out)) |
858 | ctx->tx_ncm.dpe16[n].wDatagramIndex = 0; | 844 | *skb_put(skb_out, 1) = 0; /* force short packet */ |
859 | } | ||
860 | |||
861 | /* fill out 16-bit NTB header */ | ||
862 | ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); | ||
863 | ctx->tx_ncm.nth16.wHeaderLength = | ||
864 | cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); | ||
865 | ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); | ||
866 | ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); | ||
867 | index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); | ||
868 | ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); | ||
869 | |||
870 | memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); | ||
871 | ctx->tx_seq++; | ||
872 | |||
873 | /* fill out 16-bit NDP table */ | ||
874 | ctx->tx_ncm.ndp16.dwSignature = | ||
875 | cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN); | ||
876 | rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) * | ||
877 | sizeof(struct usb_cdc_ncm_dpe16)); | ||
878 | ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); | ||
879 | ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ | ||
880 | |||
881 | memcpy(((u8 *)skb_out->data) + index, | ||
882 | &(ctx->tx_ncm.ndp16), | ||
883 | sizeof(ctx->tx_ncm.ndp16)); | ||
884 | |||
885 | memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), | ||
886 | &(ctx->tx_ncm.dpe16), | ||
887 | (ctx->tx_curr_frame_num + 1) * | ||
888 | sizeof(struct usb_cdc_ncm_dpe16)); | ||
889 | 845 | ||
890 | /* set frame length */ | 846 | /* set final frame length */ |
891 | skb_put(skb_out, last_offset); | 847 | nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; |
848 | nth16->wBlockLength = cpu_to_le16(skb_out->len); | ||
892 | 849 | ||
893 | /* return skb */ | 850 | /* return skb */ |
894 | ctx->tx_curr_skb = NULL; | 851 | ctx->tx_curr_skb = NULL; |
@@ -955,7 +912,7 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |||
955 | goto error; | 912 | goto error; |
956 | 913 | ||
957 | spin_lock_bh(&ctx->mtx); | 914 | spin_lock_bh(&ctx->mtx); |
958 | skb_out = cdc_ncm_fill_tx_frame(ctx, skb); | 915 | skb_out = cdc_ncm_fill_tx_frame(ctx, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)); |
959 | spin_unlock_bh(&ctx->mtx); | 916 | spin_unlock_bh(&ctx->mtx); |
960 | return skb_out; | 917 | return skb_out; |
961 | 918 | ||