Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2586b9ea authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "USB: gadget: rndis: Optimize tx path for better performance"

parents cef27954 153b8ef6
Loading
Loading
Loading
Loading
+29 −7
Original line number Diff line number Diff line
@@ -405,14 +405,36 @@ static struct sk_buff *rndis_add_header(struct gether *port,
					struct sk_buff *skb)
{
	struct sk_buff *skb2;

	skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
	struct rndis_packet_msg_type *header = NULL;
	struct f_rndis *rndis = func_to_rndis(&port->func);

	if (rndis->port.multi_pkt_xfer) {
		if (port->header) {
			header = port->header;
			memset(header, 0, sizeof(*header));
			header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
			header->MessageLength = cpu_to_le32(skb->len +
							sizeof(*header));
			header->DataOffset = cpu_to_le32(36);
			header->DataLength = cpu_to_le32(skb->len);
			pr_debug("MessageLength:%d DataLength:%d\n",
						header->MessageLength,
						header->DataLength);
			return skb;
		} else {
			pr_err("RNDIS header is NULL.\n");
			return NULL;
		}
	} else {
		skb2 = skb_realloc_headroom(skb,
				sizeof(struct rndis_packet_msg_type));
		if (skb2)
			rndis_add_hdr(skb2);

		dev_kfree_skb_any(skb);
		return skb2;
	}
}

static void rndis_response_available(void *_rndis)
{
+58 −23
Original line number Diff line number Diff line
@@ -229,6 +229,7 @@ static void defer_kevent(struct eth_dev *dev, int flag)
}

static void rx_complete(struct usb_ep *ep, struct usb_request *req);
static void tx_complete(struct usb_ep *ep, struct usb_request *req);

static int
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
@@ -295,7 +296,6 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)

	req->buf = skb->data;
	req->length = size;
	req->complete = rx_complete;
	req->context = skb;

	retval = usb_ep_queue(out, req, gfp_flags);
@@ -388,6 +388,7 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
{
	unsigned		i;
	struct usb_request	*req;
	bool			usb_in;

	if (!n)
		return -ENOMEM;
@@ -398,10 +399,22 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
		if (i-- == 0)
			goto extra;
	}

	if (ep->desc->bEndpointAddress & USB_DIR_IN)
		usb_in = true;
	else
		usb_in = false;

	while (i--) {
		req = usb_ep_alloc_request(ep, GFP_ATOMIC);
		if (!req)
			return list_empty(list) ? -ENOMEM : 0;
		/* update completion handler */
		if (usb_in)
			req->complete = tx_complete;
		else
			req->complete = rx_complete;

		list_add(&req->list, list);
	}
	return 0;
@@ -545,7 +558,7 @@ static void eth_work(struct work_struct *work)

static void tx_complete(struct usb_ep *ep, struct usb_request *req)
{
	struct sk_buff	*skb = req->context;
	struct sk_buff	*skb;
	struct eth_dev	*dev;
	struct net_device *net;
	struct usb_request *new_req;
@@ -619,7 +632,6 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
				}

				new_req->length = length;
				new_req->complete = tx_complete;
				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
				switch (retval) {
				default:
@@ -651,6 +663,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
			spin_unlock(&dev->req_lock);
		}
	} else {
		skb = req->context;
		spin_unlock(&dev->req_lock);
		dev_kfree_skb_any(skb);
	}
@@ -679,7 +692,7 @@ static int alloc_tx_buffer(struct eth_dev *dev)
	list_for_each(act, &dev->tx_reqs) {
		req = container_of(act, struct usb_request, list);
		if (!req->buf)
			req->buf = kmalloc(dev->tx_req_bufsize,
			req->buf = kzalloc(dev->tx_req_bufsize,
						GFP_ATOMIC);
			if (!req->buf)
				goto free_buf;
@@ -784,28 +797,37 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
	 * or the hardware can't use skb buffers.
	 * or there's not enough space for extra headers we need
	 */
	if (dev->wrap) {
		unsigned long	flags;

	spin_lock_irqsave(&dev->lock, flags);
	if (dev->wrap) {
		if (dev->port_usb)
			skb = dev->wrap(dev->port_usb, skb);
		if (!skb) {
			spin_unlock_irqrestore(&dev->lock, flags);
		if (!skb)
			goto drop;
		}

	spin_lock_irqsave(&dev->req_lock, flags);
	dev->tx_skb_hold_count++;
	spin_unlock_irqrestore(&dev->req_lock, flags);
	}

	if (multi_pkt_xfer) {

		pr_debug("req->length:%d header_len:%u\n"
				"skb->len:%d skb->data_len:%d\n",
				req->length, dev->header_len,
				skb->len, skb->data_len);
		/* Add RNDIS Header */
		memcpy(req->buf + req->length, dev->port_usb->header,
						dev->header_len);
		/* Increment req length by header size */
		req->length += dev->header_len;
		spin_unlock_irqrestore(&dev->lock, flags);
		/* Copy received IP data from SKB */
		memcpy(req->buf + req->length, skb->data, skb->len);
		req->length = req->length + skb->len;
		/* Increment req length by skb data length */
		req->length += skb->len;
		length = req->length;
		dev_kfree_skb_any(skb);

		spin_lock_irqsave(&dev->req_lock, flags);
		dev->tx_skb_hold_count++;
		if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
			if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
				list_add(&req->list, &dev->tx_reqs);
@@ -815,19 +837,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
		}

		dev->no_tx_req_used++;
		spin_unlock_irqrestore(&dev->req_lock, flags);

		spin_lock_irqsave(&dev->lock, flags);
		dev->tx_skb_hold_count = 0;
		spin_unlock_irqrestore(&dev->lock, flags);
		spin_unlock_irqrestore(&dev->req_lock, flags);
	} else {
		spin_unlock_irqrestore(&dev->lock, flags);
		length = skb->len;
		req->buf = skb->data;
		req->context = skb;
	}

	req->complete = tx_complete;

	/* NCM requires no zlp if transfer is dwNtbInMaxSize */
	if (dev->port_usb->is_fixed &&
	    length == dev->port_usb->fixed_in_len &&
@@ -880,7 +898,7 @@ drop:
		spin_lock_irqsave(&dev->req_lock, flags);
		if (list_empty(&dev->tx_reqs))
			netif_start_queue(net);
		list_add(&req->list, &dev->tx_reqs);
		list_add_tail(&req->list, &dev->tx_reqs);
		spin_unlock_irqrestore(&dev->req_lock, flags);
	}
success:
@@ -1240,6 +1258,14 @@ struct net_device *gether_connect(struct gether *link)
	if (!dev)
		return ERR_PTR(-EINVAL);

	link->header = kzalloc(sizeof(struct rndis_packet_msg_type),
							GFP_ATOMIC);
	if (!link->header) {
		pr_err("RNDIS header memory allocation failed.\n");
		result = -ENOMEM;
		goto fail;
	}

	link->in_ep->driver_data = dev;
	result = usb_ep_enable(link->in_ep);
	if (result != 0) {
@@ -1260,6 +1286,7 @@ struct net_device *gether_connect(struct gether *link)
		result = alloc_requests(dev, link, qlen(dev->gadget));

	if (result == 0) {

		dev->zlp = link->is_zlp_ok;
		DBG(dev, "qlen %d\n", qlen(dev->gadget));

@@ -1298,10 +1325,15 @@ struct net_device *gether_connect(struct gether *link)
fail1:
		(void) usb_ep_disable(link->in_ep);
	}
fail0:

	/* caller is responsible for cleanup on error */
	if (result < 0)
	if (result < 0) {
fail0:
		kfree(link->header);
fail:
		return ERR_PTR(result);
	}

	return dev->net;
}

@@ -1348,6 +1380,9 @@ void gether_disconnect(struct gether *link)
		usb_ep_free_request(link->in_ep, req);
		spin_lock(&dev->req_lock);
	}
	/* Free rndis header buffer memory */
	kfree(link->header);
	link->header = NULL;
	spin_unlock(&dev->req_lock);
	link->in_ep->driver_data = NULL;
	link->in_ep->desc = NULL;
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ struct gether {
	/* called on network open/close */
	void				(*open)(struct gether *);
	void				(*close)(struct gether *);
	struct rndis_packet_msg_type	*header;

};

#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \