Loading drivers/usb/gadget/function/u_ether.c +82 −40 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ * blocks and still have efficient handling. */ #define GETHER_MAX_ETH_FRAME_LEN 15412 static struct workqueue_struct *uether_wq; struct eth_dev { /* lock is held while accessing port_usb */ Loading @@ -80,6 +82,7 @@ struct eth_dev { struct sk_buff_head *list); struct work_struct work; struct work_struct rx_work; unsigned long todo; unsigned long flags; Loading Loading @@ -284,18 +287,16 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) DBG(dev, "rx submit --> %d\n", retval); if (skb) dev_kfree_skb_any(skb); spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } return retval; } static void rx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context, *skb2; struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; int status = req->status; bool queue = 0; switch (status) { Loading @@ -319,30 +320,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) } else { skb_queue_tail(&dev->rx_frames, skb); } skb = NULL; skb2 = skb_dequeue(&dev->rx_frames); while (skb2) { if (status < 0 || ETH_HLEN > skb2->len || skb2->len > GETHER_MAX_ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb2->len); dev_kfree_skb_any(skb2); goto next_frame; } skb2->protocol = eth_type_trans(skb2, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb2->len; /* no buffer copies needed, unless hardware can't * use skb buffers. */ status = netif_rx(skb2); next_frame: skb2 = skb_dequeue(&dev->rx_frames); } if (!status) queue = 1; break; /* software-driven interface shutdown */ Loading @@ -365,22 +344,20 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ default: queue = 1; dev_kfree_skb_any(skb); dev->net->stats.rx_errors++; DBG(dev, "rx status %d\n", status); break; } if (skb) dev_kfree_skb_any(skb); if (!netif_running(dev->net)) { clean: spin_lock(&dev->req_lock); list_add(&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); req = NULL; } if (req) rx_submit(dev, req, GFP_ATOMIC); if (queue) queue_work(uether_wq, &dev->rx_work); } static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) Loading Loading @@ -445,15 +422,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; int req_cnt = 0; /* fill unused rxq slots with some skb */ spin_lock_irqsave(&dev->req_lock, flags); while (!list_empty(&dev->rx_reqs)) { req = list_first_entry(&dev->rx_reqs, struct usb_request, list); /* break the link of continuous completion and re-submission*/ if (++req_cnt > qlen(dev->gadget, dev->qmult)) break; req = container_of(dev->rx_reqs.next, struct usb_request, list); list_del_init(&req->list); spin_unlock_irqrestore(&dev->req_lock, flags); if (rx_submit(dev, req, gfp_flags) < 0) { spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); defer_kevent(dev, WORK_RX_MEMORY); return; } Loading @@ -463,6 +449,36 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } static void process_rx_w(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, rx_work); struct sk_buff *skb; int status = 0; if (!dev->port_usb) return; while ((skb = skb_dequeue(&dev->rx_frames))) { if (status < 0 || ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb->len); dev_kfree_skb_any(skb); continue; } skb->protocol = eth_type_trans(skb, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; status = netif_rx_ni(skb); } if (netif_running(dev->net)) rx_fill(dev, GFP_KERNEL); } static void eth_work(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, work); Loading Loading @@ -963,6 +979,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); INIT_WORK(&dev->rx_work, process_rx_w); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->rx_reqs); Loading Loading @@ -1327,6 +1344,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; struct sk_buff *skb; WARN_ON(!dev); if (!dev) Loading Loading @@ -1365,6 +1383,12 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); spin_lock(&dev->rx_frames.lock); while ((skb = __skb_dequeue(&dev->rx_frames))) dev_kfree_skb_any(skb); spin_unlock(&dev->rx_frames.lock); link->out_ep->desc = NULL; /* finish forgetting about this USB link episode */ Loading @@ -1378,5 +1402,23 @@ void gether_disconnect(struct gether *link) } EXPORT_SYMBOL_GPL(gether_disconnect); MODULE_LICENSE("GPL"); static int __init gether_init(void) { uether_wq = create_singlethread_workqueue("uether"); if (!uether_wq) { pr_err("%s: Unable to create workqueue: uether\n", __func__); return -ENOMEM; } return 0; } module_init(gether_init); static void __exit gether_exit(void) { destroy_workqueue(uether_wq); } module_exit(gether_exit); MODULE_AUTHOR("David Brownell"); MODULE_DESCRIPTION("ethernet over USB driver"); MODULE_LICENSE("GPL v2"); Loading
drivers/usb/gadget/function/u_ether.c +82 −40 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ * blocks and still have efficient handling. */ #define GETHER_MAX_ETH_FRAME_LEN 15412 static struct workqueue_struct *uether_wq; struct eth_dev { /* lock is held while accessing port_usb */ Loading @@ -80,6 +82,7 @@ struct eth_dev { struct sk_buff_head *list); struct work_struct work; struct work_struct rx_work; unsigned long todo; unsigned long flags; Loading Loading @@ -284,18 +287,16 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) DBG(dev, "rx submit --> %d\n", retval); if (skb) dev_kfree_skb_any(skb); spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } return retval; } static void rx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context, *skb2; struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; int status = req->status; bool queue = 0; switch (status) { Loading @@ -319,30 +320,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) } else { skb_queue_tail(&dev->rx_frames, skb); } skb = NULL; skb2 = skb_dequeue(&dev->rx_frames); while (skb2) { if (status < 0 || ETH_HLEN > skb2->len || skb2->len > GETHER_MAX_ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb2->len); dev_kfree_skb_any(skb2); goto next_frame; } skb2->protocol = eth_type_trans(skb2, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb2->len; /* no buffer copies needed, unless hardware can't * use skb buffers. */ status = netif_rx(skb2); next_frame: skb2 = skb_dequeue(&dev->rx_frames); } if (!status) queue = 1; break; /* software-driven interface shutdown */ Loading @@ -365,22 +344,20 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ default: queue = 1; dev_kfree_skb_any(skb); dev->net->stats.rx_errors++; DBG(dev, "rx status %d\n", status); break; } if (skb) dev_kfree_skb_any(skb); if (!netif_running(dev->net)) { clean: spin_lock(&dev->req_lock); list_add(&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); req = NULL; } if (req) rx_submit(dev, req, GFP_ATOMIC); if (queue) queue_work(uether_wq, &dev->rx_work); } static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) Loading Loading @@ -445,15 +422,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; int req_cnt = 0; /* fill unused rxq slots with some skb */ spin_lock_irqsave(&dev->req_lock, flags); while (!list_empty(&dev->rx_reqs)) { req = list_first_entry(&dev->rx_reqs, struct usb_request, list); /* break the link of continuous completion and re-submission*/ if (++req_cnt > qlen(dev->gadget, dev->qmult)) break; req = container_of(dev->rx_reqs.next, struct usb_request, list); list_del_init(&req->list); spin_unlock_irqrestore(&dev->req_lock, flags); if (rx_submit(dev, req, gfp_flags) < 0) { spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); defer_kevent(dev, WORK_RX_MEMORY); return; } Loading @@ -463,6 +449,36 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } static void process_rx_w(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, rx_work); struct sk_buff *skb; int status = 0; if (!dev->port_usb) return; while ((skb = skb_dequeue(&dev->rx_frames))) { if (status < 0 || ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb->len); dev_kfree_skb_any(skb); continue; } skb->protocol = eth_type_trans(skb, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; status = netif_rx_ni(skb); } if (netif_running(dev->net)) rx_fill(dev, GFP_KERNEL); } static void eth_work(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, work); Loading Loading @@ -963,6 +979,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); INIT_WORK(&dev->rx_work, process_rx_w); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->rx_reqs); Loading Loading @@ -1327,6 +1344,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; struct sk_buff *skb; WARN_ON(!dev); if (!dev) Loading Loading @@ -1365,6 +1383,12 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); spin_lock(&dev->rx_frames.lock); while ((skb = __skb_dequeue(&dev->rx_frames))) dev_kfree_skb_any(skb); spin_unlock(&dev->rx_frames.lock); link->out_ep->desc = NULL; /* finish forgetting about this USB link episode */ Loading @@ -1378,5 +1402,23 @@ void gether_disconnect(struct gether *link) } EXPORT_SYMBOL_GPL(gether_disconnect); MODULE_LICENSE("GPL"); static int __init gether_init(void) { uether_wq = create_singlethread_workqueue("uether"); if (!uether_wq) { pr_err("%s: Unable to create workqueue: uether\n", __func__); return -ENOMEM; } return 0; } module_init(gether_init); static void __exit gether_exit(void) { destroy_workqueue(uether_wq); } module_exit(gether_exit); MODULE_AUTHOR("David Brownell"); MODULE_DESCRIPTION("ethernet over USB driver"); MODULE_LICENSE("GPL v2");