Loading drivers/usb/gadget/function/f_rndis.c +57 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ struct f_rndis { atomic_t notify_count; }; static struct f_rndis *__rndis; static spinlock_t _rndis_lock; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); Loading Loading @@ -422,10 +425,19 @@ static void rndis_response_available(void *_rndis) static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rndis *rndis = req->context; struct usb_composite_dev *cdev = rndis->port.func.config->cdev; struct f_rndis *rndis; struct usb_composite_dev *cdev; int status = req->status; struct usb_ep *notify_ep; spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* after TX: * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) * - RNDIS_RESPONSE_AVAILABLE (status/irq) Loading @@ -435,7 +447,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* connection gone */ atomic_set(&rndis->notify_count, 0); break; goto out; default: DBG(cdev, "RNDIS %s response error %d, %d/%d\n", ep->name, status, Loading @@ -443,29 +455,53 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ case 0: if (ep != rndis->notify) break; goto out; /* handle multiple pending RNDIS_RESPONSE_AVAILABLE * notifications by resending until we're done */ if (atomic_dec_and_test(&rndis->notify_count)) break; status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); goto out; notify_ep = rndis->notify; spin_unlock(&_rndis_lock); status = usb_ep_queue(notify_ep, req, GFP_ATOMIC); if (status) { atomic_dec(&rndis->notify_count); spin_lock(&_rndis_lock); if (!__rndis) goto out; atomic_dec(&__rndis->notify_count); DBG(cdev, "notify/1 --> %d\n", status); spin_unlock(&_rndis_lock); } break; } return; out: spin_unlock(&_rndis_lock); } static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rndis *rndis = req->context; struct usb_composite_dev *cdev = rndis->port.func.config->cdev; struct f_rndis *rndis; struct usb_composite_dev *cdev; int status; rndis_init_msg_type *buf; if (req->status != 0) { pr_err("%s: RNDIS command completion error:%d\n", __func__, req->status); return; } spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); status = rndis_msg_parser(rndis->params, (u8 *) req->buf); Loading @@ -488,6 +524,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) rndis->port.multi_pkt_xfer = 0; } // spin_unlock(&dev->lock); spin_unlock(&_rndis_lock); } static int Loading Loading @@ -639,13 +676,16 @@ static void rndis_disable(struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; unsigned long flags; if (!rndis->notify->enabled) return; DBG(cdev, "rndis deactivated\n"); spin_lock_irqsave(&_rndis_lock, flags); rndis_uninit(rndis->params); spin_unlock_irqrestore(&_rndis_lock, flags); gether_disconnect(&rndis->port); usb_ep_disable(rndis->notify); Loading Loading @@ -938,6 +978,7 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; mutex_init(&opts->lock); spin_lock_init(&_rndis_lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); if (IS_ERR(opts->net)) { Loading Loading @@ -967,11 +1008,15 @@ static void rndis_free(struct usb_function *f) { struct f_rndis *rndis; struct f_rndis_opts *opts; unsigned long flags; rndis = func_to_rndis(f); rndis_deregister(rndis->params); opts = container_of(f->fi, struct f_rndis_opts, func_inst); spin_lock_irqsave(&_rndis_lock, flags); kfree(rndis); __rndis = NULL; spin_unlock_irqrestore(&_rndis_lock, flags); mutex_lock(&opts->lock); opts->refcnt--; mutex_unlock(&opts->lock); Loading Loading @@ -1000,6 +1045,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) if (!rndis) return ERR_PTR(-ENOMEM); __rndis = rndis; opts = container_of(fi, struct f_rndis_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; Loading drivers/usb/gadget/function/u_ether.c +46 −4 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ static struct workqueue_struct *uether_wq; /* Extra buffer size to allocate for tx */ #define EXTRA_ALLOCATION_SIZE_U_ETH 128 struct eth_dev { /* lock is held while accessing port_usb */ Loading Loading @@ -104,6 +107,7 @@ struct eth_dev { unsigned long tx_throttle; unsigned long rx_throttle; unsigned int tx_pkts_rcvd; unsigned long skb_expand_cnt; struct dentry *uether_dent; struct dentry *uether_dfile; }; Loading @@ -125,7 +129,7 @@ static void uether_debugfs_exit(struct eth_dev *dev); * of interconnect, data can be very bursty. tx_qmult is the * additional multipler on qmult. */ static unsigned int tx_qmult = 1; static unsigned int tx_qmult = 2; module_param(tx_qmult, uint, 0644); MODULE_PARM_DESC(tx_qmult, "Additional queue length multiplier for tx"); Loading Loading @@ -748,17 +752,24 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, { struct eth_dev *dev = netdev_priv(net); int length = 0; int tail_room = 0; int extra_alloc = 0; int retval; struct usb_request *req = NULL; struct sk_buff *new_skb; unsigned long flags; struct usb_ep *in = NULL; u16 cdc_filter = 0; bool multi_pkt_xfer = false; u32 fixed_in_len = 0; bool is_fixed = false; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { in = dev->port_usb->in_ep; cdc_filter = dev->port_usb->cdc_filter; is_fixed = dev->port_usb->is_fixed; fixed_in_len = dev->port_usb->fixed_in_len; multi_pkt_xfer = dev->port_usb->multi_pkt_xfer; } spin_unlock_irqrestore(&dev->lock, flags); Loading Loading @@ -880,6 +891,35 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev->tx_skb_hold_count = 0; spin_unlock_irqrestore(&dev->lock, flags); } else { bool do_align = false; /* Check if TX buffer should be aligned before queuing to hw */ if (dev->gadget->is_chipidea && !IS_ALIGNED((size_t)skb->data, 4)) do_align = true; /* * Some UDC requires allocation of some extra bytes for * TX buffer due to hardware requirement. Check if extra * bytes are already there, otherwise allocate new buffer * with extra bytes and do memcpy to align skb as well. */ if (dev->gadget->extra_buf_alloc) extra_alloc = EXTRA_ALLOCATION_SIZE_U_ETH; tail_room = skb_tailroom(skb); if (do_align || tail_room < extra_alloc) { pr_debug("%s:align skb and update tail_room %d to %d\n", __func__, tail_room, extra_alloc); tail_room = extra_alloc; new_skb = skb_copy_expand(skb, 0, tail_room, GFP_ATOMIC); if (!new_skb) return -ENOMEM; dev_kfree_skb_any(skb); skb = new_skb; dev->skb_expand_cnt++; } length = skb->len; req->buf = skb->data; req->context = skb; Loading @@ -888,9 +928,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (dev->port_usb && dev->port_usb->is_fixed && length == dev->port_usb->fixed_in_len && if (is_fixed && length == fixed_in_len && (length % in->maxpacket) == 0) req->zero = 0; else Loading Loading @@ -1525,6 +1563,7 @@ void gether_cleanup(struct eth_dev *dev) uether_debugfs_exit(dev); unregister_netdev(dev->net); flush_work(&dev->work); cancel_work_sync(&dev->rx_work); free_netdev(dev->net); } EXPORT_SYMBOL_GPL(gether_cleanup); Loading Loading @@ -1721,6 +1760,8 @@ static int uether_stat_show(struct seq_file *s, void *unused) seq_printf(s, "tx_throttle = %lu\n", dev->tx_throttle); seq_printf(s, "tx_pkts_rcvd=%u\n", dev->tx_pkts_rcvd); seq_printf(s, "rx_throttle = %lu\n", dev->rx_throttle); seq_printf(s, "skb_expand_cnt = %lu\n", dev->skb_expand_cnt); } return ret; } Loading @@ -1741,6 +1782,7 @@ static ssize_t uether_stat_reset(struct file *file, /* Reset tx_throttle */ dev->tx_throttle = 0; dev->rx_throttle = 0; dev->skb_expand_cnt = 0; spin_unlock_irqrestore(&dev->lock, flags); return count; } Loading Loading
drivers/usb/gadget/function/f_rndis.c +57 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ struct f_rndis { atomic_t notify_count; }; static struct f_rndis *__rndis; static spinlock_t _rndis_lock; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); Loading Loading @@ -422,10 +425,19 @@ static void rndis_response_available(void *_rndis) static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rndis *rndis = req->context; struct usb_composite_dev *cdev = rndis->port.func.config->cdev; struct f_rndis *rndis; struct usb_composite_dev *cdev; int status = req->status; struct usb_ep *notify_ep; spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* after TX: * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) * - RNDIS_RESPONSE_AVAILABLE (status/irq) Loading @@ -435,7 +447,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* connection gone */ atomic_set(&rndis->notify_count, 0); break; goto out; default: DBG(cdev, "RNDIS %s response error %d, %d/%d\n", ep->name, status, Loading @@ -443,29 +455,53 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ case 0: if (ep != rndis->notify) break; goto out; /* handle multiple pending RNDIS_RESPONSE_AVAILABLE * notifications by resending until we're done */ if (atomic_dec_and_test(&rndis->notify_count)) break; status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); goto out; notify_ep = rndis->notify; spin_unlock(&_rndis_lock); status = usb_ep_queue(notify_ep, req, GFP_ATOMIC); if (status) { atomic_dec(&rndis->notify_count); spin_lock(&_rndis_lock); if (!__rndis) goto out; atomic_dec(&__rndis->notify_count); DBG(cdev, "notify/1 --> %d\n", status); spin_unlock(&_rndis_lock); } break; } return; out: spin_unlock(&_rndis_lock); } static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rndis *rndis = req->context; struct usb_composite_dev *cdev = rndis->port.func.config->cdev; struct f_rndis *rndis; struct usb_composite_dev *cdev; int status; rndis_init_msg_type *buf; if (req->status != 0) { pr_err("%s: RNDIS command completion error:%d\n", __func__, req->status); return; } spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); status = rndis_msg_parser(rndis->params, (u8 *) req->buf); Loading @@ -488,6 +524,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) rndis->port.multi_pkt_xfer = 0; } // spin_unlock(&dev->lock); spin_unlock(&_rndis_lock); } static int Loading Loading @@ -639,13 +676,16 @@ static void rndis_disable(struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; unsigned long flags; if (!rndis->notify->enabled) return; DBG(cdev, "rndis deactivated\n"); spin_lock_irqsave(&_rndis_lock, flags); rndis_uninit(rndis->params); spin_unlock_irqrestore(&_rndis_lock, flags); gether_disconnect(&rndis->port); usb_ep_disable(rndis->notify); Loading Loading @@ -938,6 +978,7 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; mutex_init(&opts->lock); spin_lock_init(&_rndis_lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); if (IS_ERR(opts->net)) { Loading Loading @@ -967,11 +1008,15 @@ static void rndis_free(struct usb_function *f) { struct f_rndis *rndis; struct f_rndis_opts *opts; unsigned long flags; rndis = func_to_rndis(f); rndis_deregister(rndis->params); opts = container_of(f->fi, struct f_rndis_opts, func_inst); spin_lock_irqsave(&_rndis_lock, flags); kfree(rndis); __rndis = NULL; spin_unlock_irqrestore(&_rndis_lock, flags); mutex_lock(&opts->lock); opts->refcnt--; mutex_unlock(&opts->lock); Loading Loading @@ -1000,6 +1045,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) if (!rndis) return ERR_PTR(-ENOMEM); __rndis = rndis; opts = container_of(fi, struct f_rndis_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; Loading
drivers/usb/gadget/function/u_ether.c +46 −4 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ static struct workqueue_struct *uether_wq; /* Extra buffer size to allocate for tx */ #define EXTRA_ALLOCATION_SIZE_U_ETH 128 struct eth_dev { /* lock is held while accessing port_usb */ Loading Loading @@ -104,6 +107,7 @@ struct eth_dev { unsigned long tx_throttle; unsigned long rx_throttle; unsigned int tx_pkts_rcvd; unsigned long skb_expand_cnt; struct dentry *uether_dent; struct dentry *uether_dfile; }; Loading @@ -125,7 +129,7 @@ static void uether_debugfs_exit(struct eth_dev *dev); * of interconnect, data can be very bursty. tx_qmult is the * additional multipler on qmult. */ static unsigned int tx_qmult = 1; static unsigned int tx_qmult = 2; module_param(tx_qmult, uint, 0644); MODULE_PARM_DESC(tx_qmult, "Additional queue length multiplier for tx"); Loading Loading @@ -748,17 +752,24 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, { struct eth_dev *dev = netdev_priv(net); int length = 0; int tail_room = 0; int extra_alloc = 0; int retval; struct usb_request *req = NULL; struct sk_buff *new_skb; unsigned long flags; struct usb_ep *in = NULL; u16 cdc_filter = 0; bool multi_pkt_xfer = false; u32 fixed_in_len = 0; bool is_fixed = false; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { in = dev->port_usb->in_ep; cdc_filter = dev->port_usb->cdc_filter; is_fixed = dev->port_usb->is_fixed; fixed_in_len = dev->port_usb->fixed_in_len; multi_pkt_xfer = dev->port_usb->multi_pkt_xfer; } spin_unlock_irqrestore(&dev->lock, flags); Loading Loading @@ -880,6 +891,35 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev->tx_skb_hold_count = 0; spin_unlock_irqrestore(&dev->lock, flags); } else { bool do_align = false; /* Check if TX buffer should be aligned before queuing to hw */ if (dev->gadget->is_chipidea && !IS_ALIGNED((size_t)skb->data, 4)) do_align = true; /* * Some UDC requires allocation of some extra bytes for * TX buffer due to hardware requirement. Check if extra * bytes are already there, otherwise allocate new buffer * with extra bytes and do memcpy to align skb as well. */ if (dev->gadget->extra_buf_alloc) extra_alloc = EXTRA_ALLOCATION_SIZE_U_ETH; tail_room = skb_tailroom(skb); if (do_align || tail_room < extra_alloc) { pr_debug("%s:align skb and update tail_room %d to %d\n", __func__, tail_room, extra_alloc); tail_room = extra_alloc; new_skb = skb_copy_expand(skb, 0, tail_room, GFP_ATOMIC); if (!new_skb) return -ENOMEM; dev_kfree_skb_any(skb); skb = new_skb; dev->skb_expand_cnt++; } length = skb->len; req->buf = skb->data; req->context = skb; Loading @@ -888,9 +928,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (dev->port_usb && dev->port_usb->is_fixed && length == dev->port_usb->fixed_in_len && if (is_fixed && length == fixed_in_len && (length % in->maxpacket) == 0) req->zero = 0; else Loading Loading @@ -1525,6 +1563,7 @@ void gether_cleanup(struct eth_dev *dev) uether_debugfs_exit(dev); unregister_netdev(dev->net); flush_work(&dev->work); cancel_work_sync(&dev->rx_work); free_netdev(dev->net); } EXPORT_SYMBOL_GPL(gether_cleanup); Loading Loading @@ -1721,6 +1760,8 @@ static int uether_stat_show(struct seq_file *s, void *unused) seq_printf(s, "tx_throttle = %lu\n", dev->tx_throttle); seq_printf(s, "tx_pkts_rcvd=%u\n", dev->tx_pkts_rcvd); seq_printf(s, "rx_throttle = %lu\n", dev->rx_throttle); seq_printf(s, "skb_expand_cnt = %lu\n", dev->skb_expand_cnt); } return ret; } Loading @@ -1741,6 +1782,7 @@ static ssize_t uether_stat_reset(struct file *file, /* Reset tx_throttle */ dev->tx_throttle = 0; dev->rx_throttle = 0; dev->skb_expand_cnt = 0; spin_unlock_irqrestore(&dev->lock, flags); return count; } Loading