[PATCH 2/2] usb: gadget: f_ncm: add support for scatter/gather SKB to enable GSO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Enabling SG allows enabling GSO (generic segmentation offload) feature
of linux networking layer. This increases TCP throughput with NCM
on Cortex-A15+USB3380 based device from 300 Mbit/s to 1.1 Gbit/s.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@xxxxxxxxxxx>
---
 drivers/usb/gadget/Kconfig          |  2 ++
 drivers/usb/gadget/function/f_ncm.c | 47 +++++++++++++++++++++++++++++++------
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3c3f31c..3a8b874 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -277,6 +277,8 @@ config USB_CONFIGFS_NCM
 	depends on NET
 	select USB_U_ETHER
 	select USB_F_NCM
+	select CRYPTO
+	select CRYPTO_CRC32
 	help
 	  NCM is an advanced protocol for Ethernet encapsulation, allows
 	  grouping of several ethernet frames into one USB transfer and
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 08cff49..1f4f724 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -20,6 +20,8 @@
 #include <linux/device.h>
 #include <linux/etherdevice.h>
 #include <linux/crc32.h>
+#include <crypto/hash.h>
+#include <linux/scatterlist.h>
 
 #include <linux/usb/cdc.h>
 
@@ -80,6 +82,10 @@ struct f_ncm {
 	struct hrtimer			task_timer;
 
 	bool				timer_stopping;
+
+	/* For scatter/gather crc32 */
+	struct crypto_ahash		*tfm;
+	struct scatterlist		sg[MAX_SKB_FRAGS + 1];
 };
 
 static inline struct f_ncm *func_to_ncm(struct usb_function *f)
@@ -1017,6 +1023,25 @@ static struct sk_buff *package_for_tx(struct f_ncm *ncm)
 	return skb2;
 }
 
+static u32 skb_crc(struct f_ncm *ncm, struct sk_buff *skb)
+{
+	AHASH_REQUEST_ON_STACK(req, ncm->tfm);
+	__le32 crc = cpu_to_le32(~(u32)0);
+
+	sg_init_table(ncm->sg, MAX_SKB_FRAGS + 1);
+	skb_to_sgvec(skb, ncm->sg, 0, skb->len);
+
+	crypto_ahash_setkey(ncm->tfm, (void *)&crc, sizeof(crc));
+
+	ahash_request_set_tfm(req, ncm->tfm);
+	ahash_request_set_callback(req, 0, NULL, NULL);
+	ahash_request_set_crypt(req, ncm->sg, (void *)&crc, skb->len);
+
+	crypto_ahash_digest(req);
+
+	return ~le32_to_cpu(crc);
+}
+
 static struct sk_buff *ncm_wrap_ntb(struct gether *port,
 				    struct sk_buff *skb)
 {
@@ -1040,13 +1065,11 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
 	if (skb) {
 		/* Add the CRC if required up front */
 		if (ncm->is_crc) {
-			uint32_t	crc;
-			__le16		*crc_pos;
+			u32	crc;
+			__le32	*crc_pos;
 
-			crc = ~crc32_le(~0,
-					skb->data,
-					skb->len);
-			crc_pos = (void *) skb_put(skb, sizeof(uint32_t));
+			crc = skb_crc(ncm, skb);
+			crc_pos = (void *) skb_put(skb, sizeof(u32));
 			put_unaligned_le32(crc, crc_pos);
 		}
 
@@ -1130,7 +1153,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
 		ntb_data = (void *) skb_put(ncm->skb_tx_data, dgram_pad);
 		memset(ntb_data, 0, dgram_pad);
 		ntb_data = (void *) skb_put(ncm->skb_tx_data, skb->len);
-		memcpy(ntb_data, skb->data, skb->len);
+		skb_copy_bits(skb, 0, ntb_data, skb->len);
 		dev_kfree_skb_any(skb);
 		skb = NULL;
 
@@ -1513,6 +1536,12 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (status)
 		goto fail;
 
+	ncm->tfm = crypto_alloc_ahash("crc32", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ncm->tfm)) {
+		usb_free_all_descriptors(f);
+		goto fail;
+	}
+
 	/*
 	 * NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
@@ -1607,6 +1636,8 @@ static struct usb_function_instance *ncm_alloc_inst(void)
 		return ERR_CAST(net);
 	}
 
+	opts->net->features |= NETIF_F_SG;
+
 	config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
 
 	return &opts->func_inst;
@@ -1634,6 +1665,8 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
 	hrtimer_cancel(&ncm->task_timer);
 	tasklet_kill(&ncm->tx_tasklet);
 
+	crypto_free_ahash(ncm->tfm);
+
 	ncm_string_defs[0].id = 0;
 	usb_free_all_descriptors(f);
 
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux