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

Commit b91cd144 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont Committed by David S. Miller
Browse files

f_phonet: use page-sized rather than MTU-sized RX buffers



Instead of a large (physically) linear buffer, we generate a set of
paged sk_buff, so no extra memory copy is involved. This removes
high-order allocations and saves quite a bit of memory. Phonet MTU is
65541 bytes, so the two buffers were padded to 128 kilo-bytes each.
Now, we create 17 page buffers, almost a 75% memory use reduction.

Signed-off-by: default avatarRémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5da63cc4
Loading
Loading
Loading
Loading
+51 −26
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@
#include "u_phonet.h"

#define PN_MEDIA_USB	0x1B
#define MAXPACKET	512
#if (PAGE_SIZE % MAXPACKET)
#error MAXPACKET must divide PAGE_SIZE!
#endif

/*-------------------------------------------------------------------------*/

@@ -45,6 +49,10 @@ struct phonet_port {

struct f_phonet {
	struct usb_function		function;
	struct {
		struct sk_buff		*skb;
		spinlock_t		lock;
	} rx;
	struct net_device		*dev;
	struct usb_ep			*in_ep, *out_ep;

@@ -52,7 +60,7 @@ struct f_phonet {
	struct usb_request		*out_reqv[0];
};

static int phonet_rxq_size = 2;
static int phonet_rxq_size = 17;

static inline struct f_phonet *func_to_pn(struct usb_function *f)
{
@@ -138,7 +146,7 @@ pn_hs_sink_desc = {

	.bEndpointAddress =	USB_DIR_OUT,
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
	.wMaxPacketSize =	cpu_to_le16(512),
	.wMaxPacketSize =	cpu_to_le16(MAXPACKET),
};

static struct usb_endpoint_descriptor
@@ -298,21 +306,21 @@ static void pn_net_setup(struct net_device *dev)
static int
pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)
{
	struct sk_buff *skb;
	const size_t size = fp->dev->mtu;
	struct net_device *dev = fp->dev;
	struct page *page;
	int err;

	skb = alloc_skb(size, gfp_flags);
	if (!skb)
	page = __netdev_alloc_page(dev, gfp_flags);
	if (!page)
		return -ENOMEM;

	req->buf = skb->data;
	req->length = size;
	req->context = skb;
	req->buf = page_address(page);
	req->length = PAGE_SIZE;
	req->context = page;

	err = usb_ep_queue(fp->out_ep, req, gfp_flags);
	if (unlikely(err))
		dev_kfree_skb_any(skb);
		netdev_free_page(dev, page);
	return err;
}

@@ -320,25 +328,37 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
{
	struct f_phonet *fp = ep->driver_data;
	struct net_device *dev = fp->dev;
	struct sk_buff *skb = req->context;
	struct page *page = req->context;
	struct sk_buff *skb;
	unsigned long flags;
	int status = req->status;

	switch (status) {
	case 0:
		if (unlikely(!netif_running(dev)))
			break;
		if (unlikely(req->actual < 1))
		spin_lock_irqsave(&fp->rx.lock, flags);
		skb = fp->rx.skb;
		if (!skb)
			skb = fp->rx.skb = netdev_alloc_skb(dev, 12);
		if (req->actual < req->length) /* Last fragment */
			fp->rx.skb = NULL;
		spin_unlock_irqrestore(&fp->rx.lock, flags);

		if (unlikely(!skb))
			break;
		skb_put(skb, req->actual);
		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0,
				req->actual);
		page = NULL;

		if (req->actual < req->length) { /* Last fragment */
			skb->protocol = htons(ETH_P_PHONET);
			skb_reset_mac_header(skb);
		__skb_pull(skb, 1);
			pskb_pull(skb, 1);
			skb->dev = dev;
			dev->stats.rx_packets++;
			dev->stats.rx_bytes += skb->len;

			netif_rx(skb);
		skb = NULL;
		}
		break;

	/* Do not resubmit in these cases: */
@@ -356,8 +376,8 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
		break;
	}

	if (skb)
		dev_kfree_skb_any(skb);
	if (page)
		netdev_free_page(dev, page);
	if (req)
		pn_rx_submit(fp, req, GFP_ATOMIC);
}
@@ -375,6 +395,10 @@ static void __pn_reset(struct usb_function *f)

	usb_ep_disable(fp->out_ep);
	usb_ep_disable(fp->in_ep);
	if (fp->rx.skb) {
		dev_kfree_skb_irq(fp->rx.skb);
		fp->rx.skb = NULL;
	}
}

static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -573,6 +597,7 @@ int __init phonet_bind_config(struct usb_configuration *c)
	fp->function.set_alt = pn_set_alt;
	fp->function.get_alt = pn_get_alt;
	fp->function.disable = pn_disconnect;
	spin_lock_init(&fp->rx.lock);

	err = usb_add_function(c, &fp->function);
	if (err)