162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Network driver infrastructure 462306a36Sopenharmony_ci * Copyright (C) 2000-2005 by David Brownell 562306a36Sopenharmony_ci * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * This is a generic "USB networking" framework that works with several 1062306a36Sopenharmony_ci * kinds of full and high speed networking devices: host-to-host cables, 1162306a36Sopenharmony_ci * smart usb peripherals, and actual Ethernet adapters. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * These devices usually differ in terms of control protocols (if they 1462306a36Sopenharmony_ci * even have one!) and sometimes they define new framing to wrap or batch 1562306a36Sopenharmony_ci * Ethernet packets. Otherwise, they talk to USB pretty much the same, 1662306a36Sopenharmony_ci * so interface (un)binding, endpoint I/O queues, fault handling, and other 1762306a36Sopenharmony_ci * issues can usefully be addressed by this framework. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/netdevice.h> 2362306a36Sopenharmony_ci#include <linux/etherdevice.h> 2462306a36Sopenharmony_ci#include <linux/ctype.h> 2562306a36Sopenharmony_ci#include <linux/ethtool.h> 2662306a36Sopenharmony_ci#include <linux/workqueue.h> 2762306a36Sopenharmony_ci#include <linux/mii.h> 2862306a36Sopenharmony_ci#include <linux/usb.h> 2962306a36Sopenharmony_ci#include <linux/usb/usbnet.h> 3062306a36Sopenharmony_ci#include <linux/slab.h> 3162306a36Sopenharmony_ci#include <linux/kernel.h> 3262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. 3862306a36Sopenharmony_ci * Several dozen bytes of IPv4 data can fit in two such transactions. 3962306a36Sopenharmony_ci * One maximum size Ethernet packet takes twenty four of them. 4062306a36Sopenharmony_ci * For high speed, each frame comfortably fits almost 36 max size 4162306a36Sopenharmony_ci * Ethernet packets (so queues should be bigger). 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * The goal is to let the USB host controller be busy for 5msec or 4462306a36Sopenharmony_ci * more before an irq is required, under load. Jumbograms change 4562306a36Sopenharmony_ci * the equation. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci#define MAX_QUEUE_MEMORY (60 * 1518) 4862306a36Sopenharmony_ci#define RX_QLEN(dev) ((dev)->rx_qlen) 4962306a36Sopenharmony_ci#define TX_QLEN(dev) ((dev)->tx_qlen) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci// reawaken network queue this soon after stopping; else watchdog barks 5262306a36Sopenharmony_ci#define TX_TIMEOUT_JIFFIES (5*HZ) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* throttle rx/tx briefly after some faults, so hub_wq might disconnect() 5562306a36Sopenharmony_ci * us (it polls at HZ/4 usually) before we report too many false errors. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define THROTTLE_JIFFIES (HZ/8) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci// between wakeups 6062306a36Sopenharmony_ci#define UNLINK_TIMEOUT_MS 3 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci// randomly generated ethernet address 6562306a36Sopenharmony_cistatic u8 node_id [ETH_ALEN]; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* use ethtool to change the level for any given device */ 6862306a36Sopenharmony_cistatic int msg_level = -1; 6962306a36Sopenharmony_cimodule_param (msg_level, int, 0); 7062306a36Sopenharmony_ciMODULE_PARM_DESC (msg_level, "Override default message level"); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const char * const usbnet_event_names[] = { 7562306a36Sopenharmony_ci [EVENT_TX_HALT] = "EVENT_TX_HALT", 7662306a36Sopenharmony_ci [EVENT_RX_HALT] = "EVENT_RX_HALT", 7762306a36Sopenharmony_ci [EVENT_RX_MEMORY] = "EVENT_RX_MEMORY", 7862306a36Sopenharmony_ci [EVENT_STS_SPLIT] = "EVENT_STS_SPLIT", 7962306a36Sopenharmony_ci [EVENT_LINK_RESET] = "EVENT_LINK_RESET", 8062306a36Sopenharmony_ci [EVENT_RX_PAUSED] = "EVENT_RX_PAUSED", 8162306a36Sopenharmony_ci [EVENT_DEV_ASLEEP] = "EVENT_DEV_ASLEEP", 8262306a36Sopenharmony_ci [EVENT_DEV_OPEN] = "EVENT_DEV_OPEN", 8362306a36Sopenharmony_ci [EVENT_DEVICE_REPORT_IDLE] = "EVENT_DEVICE_REPORT_IDLE", 8462306a36Sopenharmony_ci [EVENT_NO_RUNTIME_PM] = "EVENT_NO_RUNTIME_PM", 8562306a36Sopenharmony_ci [EVENT_RX_KILL] = "EVENT_RX_KILL", 8662306a36Sopenharmony_ci [EVENT_LINK_CHANGE] = "EVENT_LINK_CHANGE", 8762306a36Sopenharmony_ci [EVENT_SET_RX_MODE] = "EVENT_SET_RX_MODE", 8862306a36Sopenharmony_ci [EVENT_NO_IP_ALIGN] = "EVENT_NO_IP_ALIGN", 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* handles CDC Ethernet and many other network "bulk data" interfaces */ 9262306a36Sopenharmony_ciint usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci int tmp; 9562306a36Sopenharmony_ci struct usb_host_interface *alt = NULL; 9662306a36Sopenharmony_ci struct usb_host_endpoint *in = NULL, *out = NULL; 9762306a36Sopenharmony_ci struct usb_host_endpoint *status = NULL; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci for (tmp = 0; tmp < intf->num_altsetting; tmp++) { 10062306a36Sopenharmony_ci unsigned ep; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci in = out = status = NULL; 10362306a36Sopenharmony_ci alt = intf->altsetting + tmp; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* take the first altsetting with in-bulk + out-bulk; 10662306a36Sopenharmony_ci * remember any status endpoint, just in case; 10762306a36Sopenharmony_ci * ignore other endpoints and altsettings. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { 11062306a36Sopenharmony_ci struct usb_host_endpoint *e; 11162306a36Sopenharmony_ci int intr = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci e = alt->endpoint + ep; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* ignore endpoints which cannot transfer data */ 11662306a36Sopenharmony_ci if (!usb_endpoint_maxp(&e->desc)) 11762306a36Sopenharmony_ci continue; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci switch (e->desc.bmAttributes) { 12062306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 12162306a36Sopenharmony_ci if (!usb_endpoint_dir_in(&e->desc)) 12262306a36Sopenharmony_ci continue; 12362306a36Sopenharmony_ci intr = 1; 12462306a36Sopenharmony_ci fallthrough; 12562306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci default: 12862306a36Sopenharmony_ci continue; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if (usb_endpoint_dir_in(&e->desc)) { 13162306a36Sopenharmony_ci if (!intr && !in) 13262306a36Sopenharmony_ci in = e; 13362306a36Sopenharmony_ci else if (intr && !status) 13462306a36Sopenharmony_ci status = e; 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci if (!out) 13762306a36Sopenharmony_ci out = e; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci if (in && out) 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci if (!alt || !in || !out) 14462306a36Sopenharmony_ci return -EINVAL; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (alt->desc.bAlternateSetting != 0 || 14762306a36Sopenharmony_ci !(dev->driver_info->flags & FLAG_NO_SETINT)) { 14862306a36Sopenharmony_ci tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, 14962306a36Sopenharmony_ci alt->desc.bAlternateSetting); 15062306a36Sopenharmony_ci if (tmp < 0) 15162306a36Sopenharmony_ci return tmp; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci dev->in = usb_rcvbulkpipe (dev->udev, 15562306a36Sopenharmony_ci in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 15662306a36Sopenharmony_ci dev->out = usb_sndbulkpipe (dev->udev, 15762306a36Sopenharmony_ci out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 15862306a36Sopenharmony_ci dev->status = status; 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_endpoints); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciint usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 16662306a36Sopenharmony_ci int tmp = -1, ret; 16762306a36Sopenharmony_ci unsigned char buf [13]; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); 17062306a36Sopenharmony_ci if (ret == 12) 17162306a36Sopenharmony_ci tmp = hex2bin(addr, buf, 6); 17262306a36Sopenharmony_ci if (tmp < 0) { 17362306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, 17462306a36Sopenharmony_ci "bad MAC string %d fetch, %d\n", iMACAddress, tmp); 17562306a36Sopenharmony_ci if (ret >= 0) 17662306a36Sopenharmony_ci ret = -EINVAL; 17762306a36Sopenharmony_ci return ret; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci eth_hw_addr_set(dev->net, addr); 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void intr_complete (struct urb *urb) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct usbnet *dev = urb->context; 18762306a36Sopenharmony_ci int status = urb->status; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci switch (status) { 19062306a36Sopenharmony_ci /* success */ 19162306a36Sopenharmony_ci case 0: 19262306a36Sopenharmony_ci dev->driver_info->status(dev, urb); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* software-driven interface shutdown */ 19662306a36Sopenharmony_ci case -ENOENT: /* urb killed */ 19762306a36Sopenharmony_ci case -ESHUTDOWN: /* hardware gone */ 19862306a36Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 19962306a36Sopenharmony_ci "intr shutdown, code %d\n", status); 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* NOTE: not throttling like RX/TX, since this endpoint 20362306a36Sopenharmony_ci * already polls infrequently 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci default: 20662306a36Sopenharmony_ci netdev_dbg(dev->net, "intr status %d\n", status); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci status = usb_submit_urb (urb, GFP_ATOMIC); 21162306a36Sopenharmony_ci if (status != 0) 21262306a36Sopenharmony_ci netif_err(dev, timer, dev->net, 21362306a36Sopenharmony_ci "intr resubmit --> %d\n", status); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int init_status (struct usbnet *dev, struct usb_interface *intf) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci char *buf = NULL; 21962306a36Sopenharmony_ci unsigned pipe = 0; 22062306a36Sopenharmony_ci unsigned maxp; 22162306a36Sopenharmony_ci unsigned period; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!dev->driver_info->status) 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci pipe = usb_rcvintpipe (dev->udev, 22762306a36Sopenharmony_ci dev->status->desc.bEndpointAddress 22862306a36Sopenharmony_ci & USB_ENDPOINT_NUMBER_MASK); 22962306a36Sopenharmony_ci maxp = usb_maxpacket(dev->udev, pipe); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* avoid 1 msec chatter: min 8 msec poll rate */ 23262306a36Sopenharmony_ci period = max ((int) dev->status->desc.bInterval, 23362306a36Sopenharmony_ci (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci buf = kmalloc (maxp, GFP_KERNEL); 23662306a36Sopenharmony_ci if (buf) { 23762306a36Sopenharmony_ci dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); 23862306a36Sopenharmony_ci if (!dev->interrupt) { 23962306a36Sopenharmony_ci kfree (buf); 24062306a36Sopenharmony_ci return -ENOMEM; 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci usb_fill_int_urb(dev->interrupt, dev->udev, pipe, 24362306a36Sopenharmony_ci buf, maxp, intr_complete, dev, period); 24462306a36Sopenharmony_ci dev->interrupt->transfer_flags |= URB_FREE_BUFFER; 24562306a36Sopenharmony_ci dev_dbg(&intf->dev, 24662306a36Sopenharmony_ci "status ep%din, %d bytes period %d\n", 24762306a36Sopenharmony_ci usb_pipeendpoint(pipe), maxp, period); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* Submit the interrupt URB if not previously submitted, increasing refcount */ 25462306a36Sopenharmony_ciint usbnet_status_start(struct usbnet *dev, gfp_t mem_flags) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci int ret = 0; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci WARN_ON_ONCE(dev->interrupt == NULL); 25962306a36Sopenharmony_ci if (dev->interrupt) { 26062306a36Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (++dev->interrupt_count == 1) 26362306a36Sopenharmony_ci ret = usb_submit_urb(dev->interrupt, mem_flags); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, "incremented interrupt URB count to %d\n", 26662306a36Sopenharmony_ci dev->interrupt_count); 26762306a36Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return ret; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_status_start); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* For resume; submit interrupt URB if previously submitted */ 27462306a36Sopenharmony_cistatic int __usbnet_status_start_force(struct usbnet *dev, gfp_t mem_flags) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci int ret = 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 27962306a36Sopenharmony_ci if (dev->interrupt_count) { 28062306a36Sopenharmony_ci ret = usb_submit_urb(dev->interrupt, mem_flags); 28162306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, 28262306a36Sopenharmony_ci "submitted interrupt URB for resume\n"); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* Kill the interrupt URB if all submitters want it killed */ 28962306a36Sopenharmony_civoid usbnet_status_stop(struct usbnet *dev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci if (dev->interrupt) { 29262306a36Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 29362306a36Sopenharmony_ci WARN_ON(dev->interrupt_count == 0); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (dev->interrupt_count && --dev->interrupt_count == 0) 29662306a36Sopenharmony_ci usb_kill_urb(dev->interrupt); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, 29962306a36Sopenharmony_ci "decremented interrupt URB count to %d\n", 30062306a36Sopenharmony_ci dev->interrupt_count); 30162306a36Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_status_stop); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* For suspend; always kill interrupt URB */ 30762306a36Sopenharmony_cistatic void __usbnet_status_stop_force(struct usbnet *dev) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci if (dev->interrupt) { 31062306a36Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 31162306a36Sopenharmony_ci usb_kill_urb(dev->interrupt); 31262306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, "killed interrupt URB for suspend\n"); 31362306a36Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/* Passes this packet up the stack, updating its accounting. 31862306a36Sopenharmony_ci * Some link protocols batch packets, so their rx_fixup paths 31962306a36Sopenharmony_ci * can return clones as well as just modify the original skb. 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_civoid usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->net->tstats); 32462306a36Sopenharmony_ci unsigned long flags; 32562306a36Sopenharmony_ci int status; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { 32862306a36Sopenharmony_ci skb_queue_tail(&dev->rxq_pause, skb); 32962306a36Sopenharmony_ci return; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* only update if unset to allow minidriver rx_fixup override */ 33362306a36Sopenharmony_ci if (skb->protocol == 0) 33462306a36Sopenharmony_ci skb->protocol = eth_type_trans (skb, dev->net); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci flags = u64_stats_update_begin_irqsave(&stats64->syncp); 33762306a36Sopenharmony_ci u64_stats_inc(&stats64->rx_packets); 33862306a36Sopenharmony_ci u64_stats_add(&stats64->rx_bytes, skb->len); 33962306a36Sopenharmony_ci u64_stats_update_end_irqrestore(&stats64->syncp, flags); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", 34262306a36Sopenharmony_ci skb->len + sizeof (struct ethhdr), skb->protocol); 34362306a36Sopenharmony_ci memset (skb->cb, 0, sizeof (struct skb_data)); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (skb_defer_rx_timestamp(skb)) 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci status = netif_rx (skb); 34962306a36Sopenharmony_ci if (status != NET_RX_SUCCESS) 35062306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, 35162306a36Sopenharmony_ci "netif_rx status %d\n", status); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_skb_return); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/* must be called if hard_mtu or rx_urb_size changed */ 35662306a36Sopenharmony_civoid usbnet_update_max_qlen(struct usbnet *dev) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci enum usb_device_speed speed = dev->udev->speed; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (!dev->rx_urb_size || !dev->hard_mtu) 36162306a36Sopenharmony_ci goto insanity; 36262306a36Sopenharmony_ci switch (speed) { 36362306a36Sopenharmony_ci case USB_SPEED_HIGH: 36462306a36Sopenharmony_ci dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size; 36562306a36Sopenharmony_ci dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case USB_SPEED_SUPER: 36862306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Not take default 5ms qlen for super speed HC to 37162306a36Sopenharmony_ci * save memory, and iperf tests show 2.5ms qlen can 37262306a36Sopenharmony_ci * work well 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size; 37562306a36Sopenharmony_ci dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci default: 37862306a36Sopenharmony_ciinsanity: 37962306a36Sopenharmony_ci dev->rx_qlen = dev->tx_qlen = 4; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_update_max_qlen); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/*------------------------------------------------------------------------- 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Network Device Driver (peer link to "Host Device", from USB host) 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci *-------------------------------------------------------------------------*/ 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciint usbnet_change_mtu (struct net_device *net, int new_mtu) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 39462306a36Sopenharmony_ci int ll_mtu = new_mtu + net->hard_header_len; 39562306a36Sopenharmony_ci int old_hard_mtu = dev->hard_mtu; 39662306a36Sopenharmony_ci int old_rx_urb_size = dev->rx_urb_size; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci // no second zero-length packet read wanted after mtu-sized packets 39962306a36Sopenharmony_ci if ((ll_mtu % dev->maxpacket) == 0) 40062306a36Sopenharmony_ci return -EDOM; 40162306a36Sopenharmony_ci net->mtu = new_mtu; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 40462306a36Sopenharmony_ci if (dev->rx_urb_size == old_hard_mtu) { 40562306a36Sopenharmony_ci dev->rx_urb_size = dev->hard_mtu; 40662306a36Sopenharmony_ci if (dev->rx_urb_size > old_rx_urb_size) { 40762306a36Sopenharmony_ci usbnet_pause_rx(dev); 40862306a36Sopenharmony_ci usbnet_unlink_rx_urbs(dev); 40962306a36Sopenharmony_ci usbnet_resume_rx(dev); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* max qlen depend on hard_mtu and rx_urb_size */ 41462306a36Sopenharmony_ci usbnet_update_max_qlen(dev); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_change_mtu); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/* The caller must hold list->lock */ 42162306a36Sopenharmony_cistatic void __usbnet_queue_skb(struct sk_buff_head *list, 42262306a36Sopenharmony_ci struct sk_buff *newsk, enum skb_state state) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct skb_data *entry = (struct skb_data *) newsk->cb; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci __skb_queue_tail(list, newsk); 42762306a36Sopenharmony_ci entry->state = state; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from 43362306a36Sopenharmony_ci * completion callbacks. 2.5 should have fixed those bugs... 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, 43762306a36Sopenharmony_ci struct sk_buff_head *list, enum skb_state state) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci unsigned long flags; 44062306a36Sopenharmony_ci enum skb_state old_state; 44162306a36Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 44462306a36Sopenharmony_ci old_state = entry->state; 44562306a36Sopenharmony_ci entry->state = state; 44662306a36Sopenharmony_ci __skb_unlink(skb, list); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* defer_bh() is never called with list == &dev->done. 44962306a36Sopenharmony_ci * spin_lock_nested() tells lockdep that it is OK to take 45062306a36Sopenharmony_ci * dev->done.lock here with list->lock held. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci __skb_queue_tail(&dev->done, skb); 45562306a36Sopenharmony_ci if (dev->done.qlen == 1) 45662306a36Sopenharmony_ci tasklet_schedule(&dev->bh); 45762306a36Sopenharmony_ci spin_unlock(&dev->done.lock); 45862306a36Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 45962306a36Sopenharmony_ci return old_state; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* some work can't be done in tasklets, so we use keventd 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * NOTE: annoying asymmetry: if it's active, schedule_work() fails, 46562306a36Sopenharmony_ci * but tasklet_schedule() doesn't. hope the failure is rare. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_civoid usbnet_defer_kevent (struct usbnet *dev, int work) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci set_bit (work, &dev->flags); 47062306a36Sopenharmony_ci if (!schedule_work (&dev->kevent)) 47162306a36Sopenharmony_ci netdev_dbg(dev->net, "kevent %s may have been dropped\n", usbnet_event_names[work]); 47262306a36Sopenharmony_ci else 47362306a36Sopenharmony_ci netdev_dbg(dev->net, "kevent %s scheduled\n", usbnet_event_names[work]); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_defer_kevent); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void rx_complete (struct urb *urb); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct sk_buff *skb; 48462306a36Sopenharmony_ci struct skb_data *entry; 48562306a36Sopenharmony_ci int retval = 0; 48662306a36Sopenharmony_ci unsigned long lockflags; 48762306a36Sopenharmony_ci size_t size = dev->rx_urb_size; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* prevent rx skb allocation when error ratio is high */ 49062306a36Sopenharmony_ci if (test_bit(EVENT_RX_KILL, &dev->flags)) { 49162306a36Sopenharmony_ci usb_free_urb(urb); 49262306a36Sopenharmony_ci return -ENOLINK; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (test_bit(EVENT_NO_IP_ALIGN, &dev->flags)) 49662306a36Sopenharmony_ci skb = __netdev_alloc_skb(dev->net, size, flags); 49762306a36Sopenharmony_ci else 49862306a36Sopenharmony_ci skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); 49962306a36Sopenharmony_ci if (!skb) { 50062306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); 50162306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_MEMORY); 50262306a36Sopenharmony_ci usb_free_urb (urb); 50362306a36Sopenharmony_ci return -ENOMEM; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci entry = (struct skb_data *) skb->cb; 50762306a36Sopenharmony_ci entry->urb = urb; 50862306a36Sopenharmony_ci entry->dev = dev; 50962306a36Sopenharmony_ci entry->length = 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci usb_fill_bulk_urb (urb, dev->udev, dev->in, 51262306a36Sopenharmony_ci skb->data, size, rx_complete, skb); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci spin_lock_irqsave (&dev->rxq.lock, lockflags); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (netif_running (dev->net) && 51762306a36Sopenharmony_ci netif_device_present (dev->net) && 51862306a36Sopenharmony_ci test_bit(EVENT_DEV_OPEN, &dev->flags) && 51962306a36Sopenharmony_ci !test_bit (EVENT_RX_HALT, &dev->flags) && 52062306a36Sopenharmony_ci !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { 52162306a36Sopenharmony_ci switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { 52262306a36Sopenharmony_ci case -EPIPE: 52362306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_HALT); 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case -ENOMEM: 52662306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_MEMORY); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case -ENODEV: 52962306a36Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, "device gone\n"); 53062306a36Sopenharmony_ci netif_device_detach (dev->net); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case -EHOSTUNREACH: 53362306a36Sopenharmony_ci retval = -ENOLINK; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci default: 53662306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, 53762306a36Sopenharmony_ci "rx submit, %d\n", retval); 53862306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 53962306a36Sopenharmony_ci break; 54062306a36Sopenharmony_ci case 0: 54162306a36Sopenharmony_ci __usbnet_queue_skb(&dev->rxq, skb, rx_start); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); 54562306a36Sopenharmony_ci retval = -ENOLINK; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci spin_unlock_irqrestore (&dev->rxq.lock, lockflags); 54862306a36Sopenharmony_ci if (retval) { 54962306a36Sopenharmony_ci dev_kfree_skb_any (skb); 55062306a36Sopenharmony_ci usb_free_urb (urb); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci return retval; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic inline int rx_process(struct usbnet *dev, struct sk_buff *skb) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci if (dev->driver_info->rx_fixup && 56162306a36Sopenharmony_ci !dev->driver_info->rx_fixup (dev, skb)) { 56262306a36Sopenharmony_ci /* With RX_ASSEMBLE, rx_fixup() must update counters */ 56362306a36Sopenharmony_ci if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) 56462306a36Sopenharmony_ci dev->net->stats.rx_errors++; 56562306a36Sopenharmony_ci return -EPROTO; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci // else network stack removes extra byte if we forced a short packet 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* all data was already cloned from skb inside the driver */ 57062306a36Sopenharmony_ci if (dev->driver_info->flags & FLAG_MULTI_PACKET) 57162306a36Sopenharmony_ci return -EALREADY; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (skb->len < ETH_HLEN) { 57462306a36Sopenharmony_ci dev->net->stats.rx_errors++; 57562306a36Sopenharmony_ci dev->net->stats.rx_length_errors++; 57662306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); 57762306a36Sopenharmony_ci return -EPROTO; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci usbnet_skb_return(dev, skb); 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void rx_complete (struct urb *urb) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *) urb->context; 58962306a36Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 59062306a36Sopenharmony_ci struct usbnet *dev = entry->dev; 59162306a36Sopenharmony_ci int urb_status = urb->status; 59262306a36Sopenharmony_ci enum skb_state state; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci skb_put (skb, urb->actual_length); 59562306a36Sopenharmony_ci state = rx_done; 59662306a36Sopenharmony_ci entry->urb = NULL; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci switch (urb_status) { 59962306a36Sopenharmony_ci /* success */ 60062306a36Sopenharmony_ci case 0: 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* stalls need manual reset. this is rare ... except that 60462306a36Sopenharmony_ci * when going through USB 2.0 TTs, unplug appears this way. 60562306a36Sopenharmony_ci * we avoid the highspeed version of the ETIMEDOUT/EILSEQ 60662306a36Sopenharmony_ci * storm, recovering as needed. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ci case -EPIPE: 60962306a36Sopenharmony_ci dev->net->stats.rx_errors++; 61062306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_HALT); 61162306a36Sopenharmony_ci fallthrough; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* software-driven interface shutdown */ 61462306a36Sopenharmony_ci case -ECONNRESET: /* async unlink */ 61562306a36Sopenharmony_ci case -ESHUTDOWN: /* hardware gone */ 61662306a36Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 61762306a36Sopenharmony_ci "rx shutdown, code %d\n", urb_status); 61862306a36Sopenharmony_ci goto block; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* we get controller i/o faults during hub_wq disconnect() delays. 62162306a36Sopenharmony_ci * throttle down resubmits, to avoid log floods; just temporarily, 62262306a36Sopenharmony_ci * so we still recover when the fault isn't a hub_wq delay. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci case -EPROTO: 62562306a36Sopenharmony_ci case -ETIME: 62662306a36Sopenharmony_ci case -EILSEQ: 62762306a36Sopenharmony_ci dev->net->stats.rx_errors++; 62862306a36Sopenharmony_ci if (!timer_pending (&dev->delay)) { 62962306a36Sopenharmony_ci mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); 63062306a36Sopenharmony_ci netif_dbg(dev, link, dev->net, 63162306a36Sopenharmony_ci "rx throttle %d\n", urb_status); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ciblock: 63462306a36Sopenharmony_ci state = rx_cleanup; 63562306a36Sopenharmony_ci entry->urb = urb; 63662306a36Sopenharmony_ci urb = NULL; 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* data overrun ... flush fifo? */ 64062306a36Sopenharmony_ci case -EOVERFLOW: 64162306a36Sopenharmony_ci dev->net->stats.rx_over_errors++; 64262306a36Sopenharmony_ci fallthrough; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci default: 64562306a36Sopenharmony_ci state = rx_cleanup; 64662306a36Sopenharmony_ci dev->net->stats.rx_errors++; 64762306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* stop rx if packet error rate is high */ 65262306a36Sopenharmony_ci if (++dev->pkt_cnt > 30) { 65362306a36Sopenharmony_ci dev->pkt_cnt = 0; 65462306a36Sopenharmony_ci dev->pkt_err = 0; 65562306a36Sopenharmony_ci } else { 65662306a36Sopenharmony_ci if (state == rx_cleanup) 65762306a36Sopenharmony_ci dev->pkt_err++; 65862306a36Sopenharmony_ci if (dev->pkt_err > 20) 65962306a36Sopenharmony_ci set_bit(EVENT_RX_KILL, &dev->flags); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci state = defer_bh(dev, skb, &dev->rxq, state); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (urb) { 66562306a36Sopenharmony_ci if (netif_running (dev->net) && 66662306a36Sopenharmony_ci !test_bit (EVENT_RX_HALT, &dev->flags) && 66762306a36Sopenharmony_ci state != unlink_start) { 66862306a36Sopenharmony_ci rx_submit (dev, urb, GFP_ATOMIC); 66962306a36Sopenharmony_ci usb_mark_last_busy(dev->udev); 67062306a36Sopenharmony_ci return; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci usb_free_urb (urb); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 67862306a36Sopenharmony_civoid usbnet_pause_rx(struct usbnet *dev) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci set_bit(EVENT_RX_PAUSED, &dev->flags); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n"); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_pause_rx); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_civoid usbnet_resume_rx(struct usbnet *dev) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct sk_buff *skb; 68962306a36Sopenharmony_ci int num = 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci clear_bit(EVENT_RX_PAUSED, &dev->flags); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { 69462306a36Sopenharmony_ci usbnet_skb_return(dev, skb); 69562306a36Sopenharmony_ci num++; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci tasklet_schedule(&dev->bh); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, 70162306a36Sopenharmony_ci "paused rx queue disabled, %d skbs requeued\n", num); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_resume_rx); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_civoid usbnet_purge_paused_rxq(struct usbnet *dev) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci skb_queue_purge(&dev->rxq_pause); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci// unlink pending rx/tx; completion handlers do all other cleanup 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci unsigned long flags; 71862306a36Sopenharmony_ci struct sk_buff *skb; 71962306a36Sopenharmony_ci int count = 0; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci spin_lock_irqsave (&q->lock, flags); 72262306a36Sopenharmony_ci while (!skb_queue_empty(q)) { 72362306a36Sopenharmony_ci struct skb_data *entry; 72462306a36Sopenharmony_ci struct urb *urb; 72562306a36Sopenharmony_ci int retval; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci skb_queue_walk(q, skb) { 72862306a36Sopenharmony_ci entry = (struct skb_data *) skb->cb; 72962306a36Sopenharmony_ci if (entry->state != unlink_start) 73062306a36Sopenharmony_ci goto found; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_cifound: 73462306a36Sopenharmony_ci entry->state = unlink_start; 73562306a36Sopenharmony_ci urb = entry->urb; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * Get reference count of the URB to avoid it to be 73962306a36Sopenharmony_ci * freed during usb_unlink_urb, which may trigger 74062306a36Sopenharmony_ci * use-after-free problem inside usb_unlink_urb since 74162306a36Sopenharmony_ci * usb_unlink_urb is always racing with .complete 74262306a36Sopenharmony_ci * handler(include defer_bh). 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci usb_get_urb(urb); 74562306a36Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 74662306a36Sopenharmony_ci // during some PM-driven resume scenarios, 74762306a36Sopenharmony_ci // these (async) unlinks complete immediately 74862306a36Sopenharmony_ci retval = usb_unlink_urb (urb); 74962306a36Sopenharmony_ci if (retval != -EINPROGRESS && retval != 0) 75062306a36Sopenharmony_ci netdev_dbg(dev->net, "unlink urb err, %d\n", retval); 75162306a36Sopenharmony_ci else 75262306a36Sopenharmony_ci count++; 75362306a36Sopenharmony_ci usb_put_urb(urb); 75462306a36Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci spin_unlock_irqrestore (&q->lock, flags); 75762306a36Sopenharmony_ci return count; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci// Flush all pending rx urbs 76162306a36Sopenharmony_ci// minidrivers may need to do this when the MTU changes 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_civoid usbnet_unlink_rx_urbs(struct usbnet *dev) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci if (netif_running(dev->net)) { 76662306a36Sopenharmony_ci (void) unlink_urbs (dev, &dev->rxq); 76762306a36Sopenharmony_ci tasklet_schedule(&dev->bh); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic void wait_skb_queue_empty(struct sk_buff_head *q) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci unsigned long flags; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 77962306a36Sopenharmony_ci while (!skb_queue_empty(q)) { 78062306a36Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 78162306a36Sopenharmony_ci schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); 78262306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 78362306a36Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci// precondition: never called in_interrupt 78962306a36Sopenharmony_cistatic void usbnet_terminate_urbs(struct usbnet *dev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 79262306a36Sopenharmony_ci int temp; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* ensure there are no more active urbs */ 79562306a36Sopenharmony_ci add_wait_queue(&dev->wait, &wait); 79662306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 79762306a36Sopenharmony_ci temp = unlink_urbs(dev, &dev->txq) + 79862306a36Sopenharmony_ci unlink_urbs(dev, &dev->rxq); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* maybe wait for deletions to finish. */ 80162306a36Sopenharmony_ci wait_skb_queue_empty(&dev->rxq); 80262306a36Sopenharmony_ci wait_skb_queue_empty(&dev->txq); 80362306a36Sopenharmony_ci wait_skb_queue_empty(&dev->done); 80462306a36Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 80562306a36Sopenharmony_ci "waited for %d urb completions\n", temp); 80662306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 80762306a36Sopenharmony_ci remove_wait_queue(&dev->wait, &wait); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ciint usbnet_stop (struct net_device *net) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 81362306a36Sopenharmony_ci const struct driver_info *info = dev->driver_info; 81462306a36Sopenharmony_ci int retval, pm, mpn; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci clear_bit(EVENT_DEV_OPEN, &dev->flags); 81762306a36Sopenharmony_ci netif_stop_queue (net); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci netif_info(dev, ifdown, dev->net, 82062306a36Sopenharmony_ci "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", 82162306a36Sopenharmony_ci net->stats.rx_packets, net->stats.tx_packets, 82262306a36Sopenharmony_ci net->stats.rx_errors, net->stats.tx_errors); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* to not race resume */ 82562306a36Sopenharmony_ci pm = usb_autopm_get_interface(dev->intf); 82662306a36Sopenharmony_ci /* allow minidriver to stop correctly (wireless devices to turn off 82762306a36Sopenharmony_ci * radio etc) */ 82862306a36Sopenharmony_ci if (info->stop) { 82962306a36Sopenharmony_ci retval = info->stop(dev); 83062306a36Sopenharmony_ci if (retval < 0) 83162306a36Sopenharmony_ci netif_info(dev, ifdown, dev->net, 83262306a36Sopenharmony_ci "stop fail (%d) usbnet usb-%s-%s, %s\n", 83362306a36Sopenharmony_ci retval, 83462306a36Sopenharmony_ci dev->udev->bus->bus_name, dev->udev->devpath, 83562306a36Sopenharmony_ci info->description); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) 83962306a36Sopenharmony_ci usbnet_terminate_urbs(dev); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci usbnet_status_stop(dev); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci usbnet_purge_paused_rxq(dev); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* deferred work (timer, softirq, task) must also stop */ 84862306a36Sopenharmony_ci dev->flags = 0; 84962306a36Sopenharmony_ci del_timer_sync (&dev->delay); 85062306a36Sopenharmony_ci tasklet_kill (&dev->bh); 85162306a36Sopenharmony_ci cancel_work_sync(&dev->kevent); 85262306a36Sopenharmony_ci if (!pm) 85362306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (info->manage_power && mpn) 85662306a36Sopenharmony_ci info->manage_power(dev, 0); 85762306a36Sopenharmony_ci else 85862306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_stop); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci// posts reads, and enables write queuing 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci// precondition: never called in_interrupt 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciint usbnet_open (struct net_device *net) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 87362306a36Sopenharmony_ci int retval; 87462306a36Sopenharmony_ci const struct driver_info *info = dev->driver_info; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { 87762306a36Sopenharmony_ci netif_info(dev, ifup, dev->net, 87862306a36Sopenharmony_ci "resumption fail (%d) usbnet usb-%s-%s, %s\n", 87962306a36Sopenharmony_ci retval, 88062306a36Sopenharmony_ci dev->udev->bus->bus_name, 88162306a36Sopenharmony_ci dev->udev->devpath, 88262306a36Sopenharmony_ci info->description); 88362306a36Sopenharmony_ci goto done_nopm; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci // put into "known safe" state 88762306a36Sopenharmony_ci if (info->reset && (retval = info->reset (dev)) < 0) { 88862306a36Sopenharmony_ci netif_info(dev, ifup, dev->net, 88962306a36Sopenharmony_ci "open reset fail (%d) usbnet usb-%s-%s, %s\n", 89062306a36Sopenharmony_ci retval, 89162306a36Sopenharmony_ci dev->udev->bus->bus_name, 89262306a36Sopenharmony_ci dev->udev->devpath, 89362306a36Sopenharmony_ci info->description); 89462306a36Sopenharmony_ci goto done; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* hard_mtu or rx_urb_size may change in reset() */ 89862306a36Sopenharmony_ci usbnet_update_max_qlen(dev); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci // insist peer be connected 90162306a36Sopenharmony_ci if (info->check_connect && (retval = info->check_connect (dev)) < 0) { 90262306a36Sopenharmony_ci netif_err(dev, ifup, dev->net, "can't open; %d\n", retval); 90362306a36Sopenharmony_ci goto done; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* start any status interrupt transfer */ 90762306a36Sopenharmony_ci if (dev->interrupt) { 90862306a36Sopenharmony_ci retval = usbnet_status_start(dev, GFP_KERNEL); 90962306a36Sopenharmony_ci if (retval < 0) { 91062306a36Sopenharmony_ci netif_err(dev, ifup, dev->net, 91162306a36Sopenharmony_ci "intr submit %d\n", retval); 91262306a36Sopenharmony_ci goto done; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci set_bit(EVENT_DEV_OPEN, &dev->flags); 91762306a36Sopenharmony_ci netif_start_queue (net); 91862306a36Sopenharmony_ci netif_info(dev, ifup, dev->net, 91962306a36Sopenharmony_ci "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", 92062306a36Sopenharmony_ci (int)RX_QLEN(dev), (int)TX_QLEN(dev), 92162306a36Sopenharmony_ci dev->net->mtu, 92262306a36Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" : 92362306a36Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" : 92462306a36Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" : 92562306a36Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" : 92662306a36Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : 92762306a36Sopenharmony_ci "simple"); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* reset rx error state */ 93062306a36Sopenharmony_ci dev->pkt_cnt = 0; 93162306a36Sopenharmony_ci dev->pkt_err = 0; 93262306a36Sopenharmony_ci clear_bit(EVENT_RX_KILL, &dev->flags); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci // delay posting reads until we're fully open 93562306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 93662306a36Sopenharmony_ci if (info->manage_power) { 93762306a36Sopenharmony_ci retval = info->manage_power(dev, 1); 93862306a36Sopenharmony_ci if (retval < 0) { 93962306a36Sopenharmony_ci retval = 0; 94062306a36Sopenharmony_ci set_bit(EVENT_NO_RUNTIME_PM, &dev->flags); 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci return retval; 94662306a36Sopenharmony_cidone: 94762306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 94862306a36Sopenharmony_cidone_nopm: 94962306a36Sopenharmony_ci return retval; 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_open); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/* ethtool methods; minidrivers may need to add some more, but 95662306a36Sopenharmony_ci * they'll probably want to use this base set. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/* These methods are written on the assumption that the device 96062306a36Sopenharmony_ci * uses MII 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ciint usbnet_get_link_ksettings_mii(struct net_device *net, 96362306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (!dev->mii.mdio_read) 96862306a36Sopenharmony_ci return -EOPNOTSUPP; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci mii_ethtool_get_link_ksettings(&dev->mii, cmd); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_link_ksettings_mii); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ciint usbnet_get_link_ksettings_internal(struct net_device *net, 97762306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* the assumption that speed is equal on tx and rx 98262306a36Sopenharmony_ci * is deeply engrained into the networking layer. 98362306a36Sopenharmony_ci * For wireless stuff it is not true. 98462306a36Sopenharmony_ci * We assume that rx_speed matters more. 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci if (dev->rx_speed != SPEED_UNSET) 98762306a36Sopenharmony_ci cmd->base.speed = dev->rx_speed / 1000000; 98862306a36Sopenharmony_ci else if (dev->tx_speed != SPEED_UNSET) 98962306a36Sopenharmony_ci cmd->base.speed = dev->tx_speed / 1000000; 99062306a36Sopenharmony_ci else 99162306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_link_ksettings_internal); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ciint usbnet_set_link_ksettings_mii(struct net_device *net, 99862306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 100162306a36Sopenharmony_ci int retval; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (!dev->mii.mdio_write) 100462306a36Sopenharmony_ci return -EOPNOTSUPP; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci retval = mii_ethtool_set_link_ksettings(&dev->mii, cmd); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* link speed/duplex might have changed */ 100962306a36Sopenharmony_ci if (dev->driver_info->link_reset) 101062306a36Sopenharmony_ci dev->driver_info->link_reset(dev); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci /* hard_mtu or rx_urb_size may change in link_reset() */ 101362306a36Sopenharmony_ci usbnet_update_max_qlen(dev); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci return retval; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_link_ksettings_mii); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ciu32 usbnet_get_link (struct net_device *net) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* If a check_connect is defined, return its result */ 102462306a36Sopenharmony_ci if (dev->driver_info->check_connect) 102562306a36Sopenharmony_ci return dev->driver_info->check_connect (dev) == 0; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* if the device has mii operations, use those */ 102862306a36Sopenharmony_ci if (dev->mii.mdio_read) 102962306a36Sopenharmony_ci return mii_link_ok(&dev->mii); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */ 103262306a36Sopenharmony_ci return ethtool_op_get_link(net); 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_link); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ciint usbnet_nway_reset(struct net_device *net) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (!dev->mii.mdio_write) 104162306a36Sopenharmony_ci return -EOPNOTSUPP; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return mii_nway_restart(&dev->mii); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_nway_reset); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_civoid usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci strscpy(info->driver, dev->driver_name, sizeof(info->driver)); 105262306a36Sopenharmony_ci strscpy(info->fw_version, dev->driver_info->description, 105362306a36Sopenharmony_ci sizeof(info->fw_version)); 105462306a36Sopenharmony_ci usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_drvinfo); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ciu32 usbnet_get_msglevel (struct net_device *net) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return dev->msg_enable; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_msglevel); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_civoid usbnet_set_msglevel (struct net_device *net, u32 level) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci dev->msg_enable = level; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_msglevel); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci/* drivers may override default ethtool_ops in their bind() routine */ 107562306a36Sopenharmony_cistatic const struct ethtool_ops usbnet_ethtool_ops = { 107662306a36Sopenharmony_ci .get_link = usbnet_get_link, 107762306a36Sopenharmony_ci .nway_reset = usbnet_nway_reset, 107862306a36Sopenharmony_ci .get_drvinfo = usbnet_get_drvinfo, 107962306a36Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 108062306a36Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 108162306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 108262306a36Sopenharmony_ci .get_link_ksettings = usbnet_get_link_ksettings_mii, 108362306a36Sopenharmony_ci .set_link_ksettings = usbnet_set_link_ksettings_mii, 108462306a36Sopenharmony_ci}; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic void __handle_link_change(struct usbnet *dev) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci if (!test_bit(EVENT_DEV_OPEN, &dev->flags)) 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (!netif_carrier_ok(dev->net)) { 109462306a36Sopenharmony_ci /* kill URBs for reading packets to save bus bandwidth */ 109562306a36Sopenharmony_ci unlink_urbs(dev, &dev->rxq); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * tx_timeout will unlink URBs for sending packets and 109962306a36Sopenharmony_ci * tx queue is stopped by netcore after link becomes off 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci } else { 110262306a36Sopenharmony_ci /* submitting URBs for reading packets */ 110362306a36Sopenharmony_ci tasklet_schedule(&dev->bh); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* hard_mtu or rx_urb_size may change during link change */ 110762306a36Sopenharmony_ci usbnet_update_max_qlen(dev); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci clear_bit(EVENT_LINK_CHANGE, &dev->flags); 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_civoid usbnet_set_rx_mode(struct net_device *net) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_SET_RX_MODE); 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_rx_mode); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic void __handle_set_rx_mode(struct usbnet *dev) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci if (dev->driver_info->set_rx_mode) 112362306a36Sopenharmony_ci (dev->driver_info->set_rx_mode)(dev); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci clear_bit(EVENT_SET_RX_MODE, &dev->flags); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci/* work that cannot be done in interrupt context uses keventd. 112962306a36Sopenharmony_ci * 113062306a36Sopenharmony_ci * NOTE: with 2.5 we could do more of this using completion callbacks, 113162306a36Sopenharmony_ci * especially now that control transfers can be queued. 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_cistatic void 113462306a36Sopenharmony_ciusbnet_deferred_kevent (struct work_struct *work) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct usbnet *dev = 113762306a36Sopenharmony_ci container_of(work, struct usbnet, kevent); 113862306a36Sopenharmony_ci int status; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* usb_clear_halt() needs a thread context */ 114162306a36Sopenharmony_ci if (test_bit (EVENT_TX_HALT, &dev->flags)) { 114262306a36Sopenharmony_ci unlink_urbs (dev, &dev->txq); 114362306a36Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 114462306a36Sopenharmony_ci if (status < 0) 114562306a36Sopenharmony_ci goto fail_pipe; 114662306a36Sopenharmony_ci status = usb_clear_halt (dev->udev, dev->out); 114762306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 114862306a36Sopenharmony_ci if (status < 0 && 114962306a36Sopenharmony_ci status != -EPIPE && 115062306a36Sopenharmony_ci status != -ESHUTDOWN) { 115162306a36Sopenharmony_ci if (netif_msg_tx_err (dev)) 115262306a36Sopenharmony_cifail_pipe: 115362306a36Sopenharmony_ci netdev_err(dev->net, "can't clear tx halt, status %d\n", 115462306a36Sopenharmony_ci status); 115562306a36Sopenharmony_ci } else { 115662306a36Sopenharmony_ci clear_bit (EVENT_TX_HALT, &dev->flags); 115762306a36Sopenharmony_ci if (status != -ESHUTDOWN) 115862306a36Sopenharmony_ci netif_wake_queue (dev->net); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci if (test_bit (EVENT_RX_HALT, &dev->flags)) { 116262306a36Sopenharmony_ci unlink_urbs (dev, &dev->rxq); 116362306a36Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 116462306a36Sopenharmony_ci if (status < 0) 116562306a36Sopenharmony_ci goto fail_halt; 116662306a36Sopenharmony_ci status = usb_clear_halt (dev->udev, dev->in); 116762306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 116862306a36Sopenharmony_ci if (status < 0 && 116962306a36Sopenharmony_ci status != -EPIPE && 117062306a36Sopenharmony_ci status != -ESHUTDOWN) { 117162306a36Sopenharmony_ci if (netif_msg_rx_err (dev)) 117262306a36Sopenharmony_cifail_halt: 117362306a36Sopenharmony_ci netdev_err(dev->net, "can't clear rx halt, status %d\n", 117462306a36Sopenharmony_ci status); 117562306a36Sopenharmony_ci } else { 117662306a36Sopenharmony_ci clear_bit (EVENT_RX_HALT, &dev->flags); 117762306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* tasklet could resubmit itself forever if memory is tight */ 118262306a36Sopenharmony_ci if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { 118362306a36Sopenharmony_ci struct urb *urb = NULL; 118462306a36Sopenharmony_ci int resched = 1; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (netif_running (dev->net)) 118762306a36Sopenharmony_ci urb = usb_alloc_urb (0, GFP_KERNEL); 118862306a36Sopenharmony_ci else 118962306a36Sopenharmony_ci clear_bit (EVENT_RX_MEMORY, &dev->flags); 119062306a36Sopenharmony_ci if (urb != NULL) { 119162306a36Sopenharmony_ci clear_bit (EVENT_RX_MEMORY, &dev->flags); 119262306a36Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 119362306a36Sopenharmony_ci if (status < 0) { 119462306a36Sopenharmony_ci usb_free_urb(urb); 119562306a36Sopenharmony_ci goto fail_lowmem; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) 119862306a36Sopenharmony_ci resched = 0; 119962306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 120062306a36Sopenharmony_cifail_lowmem: 120162306a36Sopenharmony_ci if (resched) 120262306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (test_bit (EVENT_LINK_RESET, &dev->flags)) { 120762306a36Sopenharmony_ci const struct driver_info *info = dev->driver_info; 120862306a36Sopenharmony_ci int retval = 0; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci clear_bit (EVENT_LINK_RESET, &dev->flags); 121162306a36Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 121262306a36Sopenharmony_ci if (status < 0) 121362306a36Sopenharmony_ci goto skip_reset; 121462306a36Sopenharmony_ci if(info->link_reset && (retval = info->link_reset(dev)) < 0) { 121562306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 121662306a36Sopenharmony_ciskip_reset: 121762306a36Sopenharmony_ci netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n", 121862306a36Sopenharmony_ci retval, 121962306a36Sopenharmony_ci dev->udev->bus->bus_name, 122062306a36Sopenharmony_ci dev->udev->devpath, 122162306a36Sopenharmony_ci info->description); 122262306a36Sopenharmony_ci } else { 122362306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* handle link change from link resetting */ 122762306a36Sopenharmony_ci __handle_link_change(dev); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) 123162306a36Sopenharmony_ci __handle_link_change(dev); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (test_bit (EVENT_SET_RX_MODE, &dev->flags)) 123462306a36Sopenharmony_ci __handle_set_rx_mode(dev); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (dev->flags) 123862306a36Sopenharmony_ci netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic void tx_complete (struct urb *urb) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *) urb->context; 124662306a36Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 124762306a36Sopenharmony_ci struct usbnet *dev = entry->dev; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (urb->status == 0) { 125062306a36Sopenharmony_ci struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->net->tstats); 125162306a36Sopenharmony_ci unsigned long flags; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci flags = u64_stats_update_begin_irqsave(&stats64->syncp); 125462306a36Sopenharmony_ci u64_stats_add(&stats64->tx_packets, entry->packets); 125562306a36Sopenharmony_ci u64_stats_add(&stats64->tx_bytes, entry->length); 125662306a36Sopenharmony_ci u64_stats_update_end_irqrestore(&stats64->syncp, flags); 125762306a36Sopenharmony_ci } else { 125862306a36Sopenharmony_ci dev->net->stats.tx_errors++; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci switch (urb->status) { 126162306a36Sopenharmony_ci case -EPIPE: 126262306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_TX_HALT); 126362306a36Sopenharmony_ci break; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* software-driven interface shutdown */ 126662306a36Sopenharmony_ci case -ECONNRESET: // async unlink 126762306a36Sopenharmony_ci case -ESHUTDOWN: // hardware gone 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* like rx, tx gets controller i/o faults during hub_wq 127162306a36Sopenharmony_ci * delays and so it uses the same throttling mechanism. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci case -EPROTO: 127462306a36Sopenharmony_ci case -ETIME: 127562306a36Sopenharmony_ci case -EILSEQ: 127662306a36Sopenharmony_ci usb_mark_last_busy(dev->udev); 127762306a36Sopenharmony_ci if (!timer_pending (&dev->delay)) { 127862306a36Sopenharmony_ci mod_timer (&dev->delay, 127962306a36Sopenharmony_ci jiffies + THROTTLE_JIFFIES); 128062306a36Sopenharmony_ci netif_dbg(dev, link, dev->net, 128162306a36Sopenharmony_ci "tx throttle %d\n", urb->status); 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci netif_stop_queue (dev->net); 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci default: 128662306a36Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, 128762306a36Sopenharmony_ci "tx err %d\n", entry->urb->status); 128862306a36Sopenharmony_ci break; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 129362306a36Sopenharmony_ci (void) defer_bh(dev, skb, &dev->txq, tx_done); 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_civoid usbnet_tx_timeout (struct net_device *net, unsigned int txqueue) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci unlink_urbs (dev, &dev->txq); 130362306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 130462306a36Sopenharmony_ci /* this needs to be handled individually because the generic layer 130562306a36Sopenharmony_ci * doesn't know what is sufficient and could not restore private 130662306a36Sopenharmony_ci * information if a remedy of an unconditional reset were used. 130762306a36Sopenharmony_ci */ 130862306a36Sopenharmony_ci if (dev->driver_info->recover) 130962306a36Sopenharmony_ci (dev->driver_info->recover)(dev); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_tx_timeout); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_cistatic int build_dma_sg(const struct sk_buff *skb, struct urb *urb) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci unsigned num_sgs, total_len = 0; 131862306a36Sopenharmony_ci int i, s = 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci num_sgs = skb_shinfo(skb)->nr_frags + 1; 132162306a36Sopenharmony_ci if (num_sgs == 1) 132262306a36Sopenharmony_ci return 0; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* reserve one for zero packet */ 132562306a36Sopenharmony_ci urb->sg = kmalloc_array(num_sgs + 1, sizeof(struct scatterlist), 132662306a36Sopenharmony_ci GFP_ATOMIC); 132762306a36Sopenharmony_ci if (!urb->sg) 132862306a36Sopenharmony_ci return -ENOMEM; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci urb->num_sgs = num_sgs; 133162306a36Sopenharmony_ci sg_init_table(urb->sg, urb->num_sgs + 1); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); 133462306a36Sopenharmony_ci total_len += skb_headlen(skb); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 133762306a36Sopenharmony_ci skb_frag_t *f = &skb_shinfo(skb)->frags[i]; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci total_len += skb_frag_size(f); 134062306a36Sopenharmony_ci sg_set_page(&urb->sg[i + s], skb_frag_page(f), skb_frag_size(f), 134162306a36Sopenharmony_ci skb_frag_off(f)); 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci urb->transfer_buffer_length = total_len; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci return 1; 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cinetdev_tx_t usbnet_start_xmit (struct sk_buff *skb, 134962306a36Sopenharmony_ci struct net_device *net) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 135262306a36Sopenharmony_ci unsigned int length; 135362306a36Sopenharmony_ci struct urb *urb = NULL; 135462306a36Sopenharmony_ci struct skb_data *entry; 135562306a36Sopenharmony_ci const struct driver_info *info = dev->driver_info; 135662306a36Sopenharmony_ci unsigned long flags; 135762306a36Sopenharmony_ci int retval; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (skb) 136062306a36Sopenharmony_ci skb_tx_timestamp(skb); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci // some devices want funky USB-level framing, for 136362306a36Sopenharmony_ci // win32 driver (usually) and/or hardware quirks 136462306a36Sopenharmony_ci if (info->tx_fixup) { 136562306a36Sopenharmony_ci skb = info->tx_fixup (dev, skb, GFP_ATOMIC); 136662306a36Sopenharmony_ci if (!skb) { 136762306a36Sopenharmony_ci /* packet collected; minidriver waiting for more */ 136862306a36Sopenharmony_ci if (info->flags & FLAG_MULTI_PACKET) 136962306a36Sopenharmony_ci goto not_drop; 137062306a36Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); 137162306a36Sopenharmony_ci goto drop; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { 137662306a36Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "no urb\n"); 137762306a36Sopenharmony_ci goto drop; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci entry = (struct skb_data *) skb->cb; 138162306a36Sopenharmony_ci entry->urb = urb; 138262306a36Sopenharmony_ci entry->dev = dev; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci usb_fill_bulk_urb (urb, dev->udev, dev->out, 138562306a36Sopenharmony_ci skb->data, skb->len, tx_complete, skb); 138662306a36Sopenharmony_ci if (dev->can_dma_sg) { 138762306a36Sopenharmony_ci if (build_dma_sg(skb, urb) < 0) 138862306a36Sopenharmony_ci goto drop; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci length = urb->transfer_buffer_length; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* don't assume the hardware handles USB_ZERO_PACKET 139362306a36Sopenharmony_ci * NOTE: strictly conforming cdc-ether devices should expect 139462306a36Sopenharmony_ci * the ZLP here, but ignore the one-byte packet. 139562306a36Sopenharmony_ci * NOTE2: CDC NCM specification is different from CDC ECM when 139662306a36Sopenharmony_ci * handling ZLP/short packets, so cdc_ncm driver will make short 139762306a36Sopenharmony_ci * packet itself if needed. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_ci if (length % dev->maxpacket == 0) { 140062306a36Sopenharmony_ci if (!(info->flags & FLAG_SEND_ZLP)) { 140162306a36Sopenharmony_ci if (!(info->flags & FLAG_MULTI_PACKET)) { 140262306a36Sopenharmony_ci length++; 140362306a36Sopenharmony_ci if (skb_tailroom(skb) && !urb->num_sgs) { 140462306a36Sopenharmony_ci skb->data[skb->len] = 0; 140562306a36Sopenharmony_ci __skb_put(skb, 1); 140662306a36Sopenharmony_ci } else if (urb->num_sgs) 140762306a36Sopenharmony_ci sg_set_buf(&urb->sg[urb->num_sgs++], 140862306a36Sopenharmony_ci dev->padding_pkt, 1); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } else 141162306a36Sopenharmony_ci urb->transfer_flags |= URB_ZERO_PACKET; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci urb->transfer_buffer_length = length; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (info->flags & FLAG_MULTI_PACKET) { 141662306a36Sopenharmony_ci /* Driver has set number of packets and a length delta. 141762306a36Sopenharmony_ci * Calculate the complete length and ensure that it's 141862306a36Sopenharmony_ci * positive. 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_ci entry->length += length; 142162306a36Sopenharmony_ci if (WARN_ON_ONCE(entry->length <= 0)) 142262306a36Sopenharmony_ci entry->length = length; 142362306a36Sopenharmony_ci } else { 142462306a36Sopenharmony_ci usbnet_set_skb_tx_stats(skb, 1, length); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci spin_lock_irqsave(&dev->txq.lock, flags); 142862306a36Sopenharmony_ci retval = usb_autopm_get_interface_async(dev->intf); 142962306a36Sopenharmony_ci if (retval < 0) { 143062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 143162306a36Sopenharmony_ci goto drop; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci if (netif_queue_stopped(net)) { 143462306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 143562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 143662306a36Sopenharmony_ci goto drop; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci#ifdef CONFIG_PM 144062306a36Sopenharmony_ci /* if this triggers the device is still a sleep */ 144162306a36Sopenharmony_ci if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { 144262306a36Sopenharmony_ci /* transmission will be done in resume */ 144362306a36Sopenharmony_ci usb_anchor_urb(urb, &dev->deferred); 144462306a36Sopenharmony_ci /* no use to process more packets */ 144562306a36Sopenharmony_ci netif_stop_queue(net); 144662306a36Sopenharmony_ci usb_put_urb(urb); 144762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 144862306a36Sopenharmony_ci netdev_dbg(dev->net, "Delaying transmission for resumption\n"); 144962306a36Sopenharmony_ci goto deferred; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci#endif 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { 145462306a36Sopenharmony_ci case -EPIPE: 145562306a36Sopenharmony_ci netif_stop_queue (net); 145662306a36Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_TX_HALT); 145762306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 145862306a36Sopenharmony_ci break; 145962306a36Sopenharmony_ci default: 146062306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 146162306a36Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, 146262306a36Sopenharmony_ci "tx: submit urb err %d\n", retval); 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci case 0: 146562306a36Sopenharmony_ci netif_trans_update(net); 146662306a36Sopenharmony_ci __usbnet_queue_skb(&dev->txq, skb, tx_start); 146762306a36Sopenharmony_ci if (dev->txq.qlen >= TX_QLEN (dev)) 146862306a36Sopenharmony_ci netif_stop_queue (net); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci spin_unlock_irqrestore (&dev->txq.lock, flags); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (retval) { 147362306a36Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); 147462306a36Sopenharmony_cidrop: 147562306a36Sopenharmony_ci dev->net->stats.tx_dropped++; 147662306a36Sopenharmony_cinot_drop: 147762306a36Sopenharmony_ci if (skb) 147862306a36Sopenharmony_ci dev_kfree_skb_any (skb); 147962306a36Sopenharmony_ci if (urb) { 148062306a36Sopenharmony_ci kfree(urb->sg); 148162306a36Sopenharmony_ci usb_free_urb(urb); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci } else 148462306a36Sopenharmony_ci netif_dbg(dev, tx_queued, dev->net, 148562306a36Sopenharmony_ci "> tx, len %u, type 0x%x\n", length, skb->protocol); 148662306a36Sopenharmony_ci#ifdef CONFIG_PM 148762306a36Sopenharmony_cideferred: 148862306a36Sopenharmony_ci#endif 148962306a36Sopenharmony_ci return NETDEV_TX_OK; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_start_xmit); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic int rx_alloc_submit(struct usbnet *dev, gfp_t flags) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct urb *urb; 149662306a36Sopenharmony_ci int i; 149762306a36Sopenharmony_ci int ret = 0; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci /* don't refill the queue all at once */ 150062306a36Sopenharmony_ci for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { 150162306a36Sopenharmony_ci urb = usb_alloc_urb(0, flags); 150262306a36Sopenharmony_ci if (urb != NULL) { 150362306a36Sopenharmony_ci ret = rx_submit(dev, urb, flags); 150462306a36Sopenharmony_ci if (ret) 150562306a36Sopenharmony_ci goto err; 150662306a36Sopenharmony_ci } else { 150762306a36Sopenharmony_ci ret = -ENOMEM; 150862306a36Sopenharmony_ci goto err; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_cierr: 151262306a36Sopenharmony_ci return ret; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic inline void usb_free_skb(struct sk_buff *skb) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct skb_data *entry = (struct skb_data *)skb->cb; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci usb_free_urb(entry->urb); 152062306a36Sopenharmony_ci dev_kfree_skb(skb); 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci// tasklet (work deferred from completions, in_irq) or timer 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic void usbnet_bh (struct timer_list *t) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct usbnet *dev = from_timer(dev, t, delay); 153062306a36Sopenharmony_ci struct sk_buff *skb; 153162306a36Sopenharmony_ci struct skb_data *entry; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci while ((skb = skb_dequeue (&dev->done))) { 153462306a36Sopenharmony_ci entry = (struct skb_data *) skb->cb; 153562306a36Sopenharmony_ci switch (entry->state) { 153662306a36Sopenharmony_ci case rx_done: 153762306a36Sopenharmony_ci if (rx_process(dev, skb)) 153862306a36Sopenharmony_ci usb_free_skb(skb); 153962306a36Sopenharmony_ci continue; 154062306a36Sopenharmony_ci case tx_done: 154162306a36Sopenharmony_ci kfree(entry->urb->sg); 154262306a36Sopenharmony_ci fallthrough; 154362306a36Sopenharmony_ci case rx_cleanup: 154462306a36Sopenharmony_ci usb_free_skb(skb); 154562306a36Sopenharmony_ci continue; 154662306a36Sopenharmony_ci default: 154762306a36Sopenharmony_ci netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* restart RX again after disabling due to high error rate */ 155262306a36Sopenharmony_ci clear_bit(EVENT_RX_KILL, &dev->flags); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* waiting for all pending urbs to complete? 155562306a36Sopenharmony_ci * only then can we forgo submitting anew 155662306a36Sopenharmony_ci */ 155762306a36Sopenharmony_ci if (waitqueue_active(&dev->wait)) { 155862306a36Sopenharmony_ci if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0) 155962306a36Sopenharmony_ci wake_up_all(&dev->wait); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci // or are we maybe short a few urbs? 156262306a36Sopenharmony_ci } else if (netif_running (dev->net) && 156362306a36Sopenharmony_ci netif_device_present (dev->net) && 156462306a36Sopenharmony_ci netif_carrier_ok(dev->net) && 156562306a36Sopenharmony_ci !timer_pending(&dev->delay) && 156662306a36Sopenharmony_ci !test_bit(EVENT_RX_PAUSED, &dev->flags) && 156762306a36Sopenharmony_ci !test_bit(EVENT_RX_HALT, &dev->flags)) { 156862306a36Sopenharmony_ci int temp = dev->rxq.qlen; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (temp < RX_QLEN(dev)) { 157162306a36Sopenharmony_ci if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK) 157262306a36Sopenharmony_ci return; 157362306a36Sopenharmony_ci if (temp != dev->rxq.qlen) 157462306a36Sopenharmony_ci netif_dbg(dev, link, dev->net, 157562306a36Sopenharmony_ci "rxqlen %d --> %d\n", 157662306a36Sopenharmony_ci temp, dev->rxq.qlen); 157762306a36Sopenharmony_ci if (dev->rxq.qlen < RX_QLEN(dev)) 157862306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci if (dev->txq.qlen < TX_QLEN (dev)) 158162306a36Sopenharmony_ci netif_wake_queue (dev->net); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic void usbnet_bh_tasklet(struct tasklet_struct *t) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct usbnet *dev = from_tasklet(dev, t, bh); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci usbnet_bh(&dev->delay); 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci/*------------------------------------------------------------------------- 159462306a36Sopenharmony_ci * 159562306a36Sopenharmony_ci * USB Device Driver support 159662306a36Sopenharmony_ci * 159762306a36Sopenharmony_ci *-------------------------------------------------------------------------*/ 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci// precondition: never called in_interrupt 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_civoid usbnet_disconnect (struct usb_interface *intf) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci struct usbnet *dev; 160462306a36Sopenharmony_ci struct usb_device *xdev; 160562306a36Sopenharmony_ci struct net_device *net; 160662306a36Sopenharmony_ci struct urb *urb; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci dev = usb_get_intfdata(intf); 160962306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 161062306a36Sopenharmony_ci if (!dev) 161162306a36Sopenharmony_ci return; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci xdev = interface_to_usbdev (intf); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n", 161662306a36Sopenharmony_ci intf->dev.driver->name, 161762306a36Sopenharmony_ci xdev->bus->bus_name, xdev->devpath, 161862306a36Sopenharmony_ci dev->driver_info->description); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci net = dev->net; 162162306a36Sopenharmony_ci unregister_netdev (net); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci while ((urb = usb_get_from_anchor(&dev->deferred))) { 162462306a36Sopenharmony_ci dev_kfree_skb(urb->context); 162562306a36Sopenharmony_ci kfree(urb->sg); 162662306a36Sopenharmony_ci usb_free_urb(urb); 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (dev->driver_info->unbind) 163062306a36Sopenharmony_ci dev->driver_info->unbind(dev, intf); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci usb_kill_urb(dev->interrupt); 163362306a36Sopenharmony_ci usb_free_urb(dev->interrupt); 163462306a36Sopenharmony_ci kfree(dev->padding_pkt); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci free_percpu(net->tstats); 163762306a36Sopenharmony_ci free_netdev(net); 163862306a36Sopenharmony_ci} 163962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_disconnect); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_cistatic const struct net_device_ops usbnet_netdev_ops = { 164262306a36Sopenharmony_ci .ndo_open = usbnet_open, 164362306a36Sopenharmony_ci .ndo_stop = usbnet_stop, 164462306a36Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 164562306a36Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 164662306a36Sopenharmony_ci .ndo_set_rx_mode = usbnet_set_rx_mode, 164762306a36Sopenharmony_ci .ndo_change_mtu = usbnet_change_mtu, 164862306a36Sopenharmony_ci .ndo_get_stats64 = dev_get_tstats64, 164962306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 165062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 165162306a36Sopenharmony_ci}; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci// precondition: never called in_interrupt 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic struct device_type wlan_type = { 165862306a36Sopenharmony_ci .name = "wlan", 165962306a36Sopenharmony_ci}; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic struct device_type wwan_type = { 166262306a36Sopenharmony_ci .name = "wwan", 166362306a36Sopenharmony_ci}; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ciint 166662306a36Sopenharmony_ciusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) 166762306a36Sopenharmony_ci{ 166862306a36Sopenharmony_ci struct usbnet *dev; 166962306a36Sopenharmony_ci struct net_device *net; 167062306a36Sopenharmony_ci struct usb_host_interface *interface; 167162306a36Sopenharmony_ci const struct driver_info *info; 167262306a36Sopenharmony_ci struct usb_device *xdev; 167362306a36Sopenharmony_ci int status; 167462306a36Sopenharmony_ci const char *name; 167562306a36Sopenharmony_ci struct usb_driver *driver = to_usb_driver(udev->dev.driver); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* usbnet already took usb runtime pm, so have to enable the feature 167862306a36Sopenharmony_ci * for usb interface, otherwise usb_autopm_get_interface may return 167962306a36Sopenharmony_ci * failure if RUNTIME_PM is enabled. 168062306a36Sopenharmony_ci */ 168162306a36Sopenharmony_ci if (!driver->supports_autosuspend) { 168262306a36Sopenharmony_ci driver->supports_autosuspend = 1; 168362306a36Sopenharmony_ci pm_runtime_enable(&udev->dev); 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci name = udev->dev.driver->name; 168762306a36Sopenharmony_ci info = (const struct driver_info *) prod->driver_info; 168862306a36Sopenharmony_ci if (!info) { 168962306a36Sopenharmony_ci dev_dbg (&udev->dev, "blacklisted by %s\n", name); 169062306a36Sopenharmony_ci return -ENODEV; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci xdev = interface_to_usbdev (udev); 169362306a36Sopenharmony_ci interface = udev->cur_altsetting; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci status = -ENOMEM; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci // set up our own records 169862306a36Sopenharmony_ci net = alloc_etherdev(sizeof(*dev)); 169962306a36Sopenharmony_ci if (!net) 170062306a36Sopenharmony_ci goto out; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* netdev_printk() needs this so do it as early as possible */ 170362306a36Sopenharmony_ci SET_NETDEV_DEV(net, &udev->dev); 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci dev = netdev_priv(net); 170662306a36Sopenharmony_ci dev->udev = xdev; 170762306a36Sopenharmony_ci dev->intf = udev; 170862306a36Sopenharmony_ci dev->driver_info = info; 170962306a36Sopenharmony_ci dev->driver_name = name; 171062306a36Sopenharmony_ci dev->rx_speed = SPEED_UNSET; 171162306a36Sopenharmony_ci dev->tx_speed = SPEED_UNSET; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci net->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 171462306a36Sopenharmony_ci if (!net->tstats) 171562306a36Sopenharmony_ci goto out0; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV 171862306a36Sopenharmony_ci | NETIF_MSG_PROBE | NETIF_MSG_LINK); 171962306a36Sopenharmony_ci init_waitqueue_head(&dev->wait); 172062306a36Sopenharmony_ci skb_queue_head_init (&dev->rxq); 172162306a36Sopenharmony_ci skb_queue_head_init (&dev->txq); 172262306a36Sopenharmony_ci skb_queue_head_init (&dev->done); 172362306a36Sopenharmony_ci skb_queue_head_init(&dev->rxq_pause); 172462306a36Sopenharmony_ci tasklet_setup(&dev->bh, usbnet_bh_tasklet); 172562306a36Sopenharmony_ci INIT_WORK (&dev->kevent, usbnet_deferred_kevent); 172662306a36Sopenharmony_ci init_usb_anchor(&dev->deferred); 172762306a36Sopenharmony_ci timer_setup(&dev->delay, usbnet_bh, 0); 172862306a36Sopenharmony_ci mutex_init (&dev->phy_mutex); 172962306a36Sopenharmony_ci mutex_init(&dev->interrupt_mutex); 173062306a36Sopenharmony_ci dev->interrupt_count = 0; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci dev->net = net; 173362306a36Sopenharmony_ci strscpy(net->name, "usb%d", sizeof(net->name)); 173462306a36Sopenharmony_ci eth_hw_addr_set(net, node_id); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* rx and tx sides can use different message sizes; 173762306a36Sopenharmony_ci * bind() should set rx_urb_size in that case. 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 174062306a36Sopenharmony_ci net->min_mtu = 0; 174162306a36Sopenharmony_ci net->max_mtu = ETH_MAX_MTU; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci net->netdev_ops = &usbnet_netdev_ops; 174462306a36Sopenharmony_ci net->watchdog_timeo = TX_TIMEOUT_JIFFIES; 174562306a36Sopenharmony_ci net->ethtool_ops = &usbnet_ethtool_ops; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci // allow device-specific bind/init procedures 174862306a36Sopenharmony_ci // NOTE net->name still not usable ... 174962306a36Sopenharmony_ci if (info->bind) { 175062306a36Sopenharmony_ci status = info->bind (dev, udev); 175162306a36Sopenharmony_ci if (status < 0) 175262306a36Sopenharmony_ci goto out1; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci // heuristic: "usb%d" for links we know are two-host, 175562306a36Sopenharmony_ci // else "eth%d" when there's reasonable doubt. userspace 175662306a36Sopenharmony_ci // can rename the link if it knows better. 175762306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_ETHER) != 0 && 175862306a36Sopenharmony_ci ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || 175962306a36Sopenharmony_ci (net->dev_addr [0] & 0x02) == 0)) 176062306a36Sopenharmony_ci strscpy(net->name, "eth%d", sizeof(net->name)); 176162306a36Sopenharmony_ci /* WLAN devices should always be named "wlan%d" */ 176262306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WLAN) != 0) 176362306a36Sopenharmony_ci strscpy(net->name, "wlan%d", sizeof(net->name)); 176462306a36Sopenharmony_ci /* WWAN devices should always be named "wwan%d" */ 176562306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WWAN) != 0) 176662306a36Sopenharmony_ci strscpy(net->name, "wwan%d", sizeof(net->name)); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci /* devices that cannot do ARP */ 176962306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_NOARP) != 0) 177062306a36Sopenharmony_ci net->flags |= IFF_NOARP; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci /* maybe the remote can't receive an Ethernet MTU */ 177362306a36Sopenharmony_ci if (net->mtu > (dev->hard_mtu - net->hard_header_len)) 177462306a36Sopenharmony_ci net->mtu = dev->hard_mtu - net->hard_header_len; 177562306a36Sopenharmony_ci } else if (!info->in || !info->out) 177662306a36Sopenharmony_ci status = usbnet_get_endpoints (dev, udev); 177762306a36Sopenharmony_ci else { 177862306a36Sopenharmony_ci u8 ep_addrs[3] = { 177962306a36Sopenharmony_ci info->in + USB_DIR_IN, info->out + USB_DIR_OUT, 0 178062306a36Sopenharmony_ci }; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci dev->in = usb_rcvbulkpipe (xdev, info->in); 178362306a36Sopenharmony_ci dev->out = usb_sndbulkpipe (xdev, info->out); 178462306a36Sopenharmony_ci if (!(info->flags & FLAG_NO_SETINT)) 178562306a36Sopenharmony_ci status = usb_set_interface (xdev, 178662306a36Sopenharmony_ci interface->desc.bInterfaceNumber, 178762306a36Sopenharmony_ci interface->desc.bAlternateSetting); 178862306a36Sopenharmony_ci else 178962306a36Sopenharmony_ci status = 0; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (status == 0 && !usb_check_bulk_endpoints(udev, ep_addrs)) 179262306a36Sopenharmony_ci status = -EINVAL; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci if (status >= 0 && dev->status) 179562306a36Sopenharmony_ci status = init_status (dev, udev); 179662306a36Sopenharmony_ci if (status < 0) 179762306a36Sopenharmony_ci goto out3; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (!dev->rx_urb_size) 180062306a36Sopenharmony_ci dev->rx_urb_size = dev->hard_mtu; 180162306a36Sopenharmony_ci dev->maxpacket = usb_maxpacket(dev->udev, dev->out); 180262306a36Sopenharmony_ci if (dev->maxpacket == 0) { 180362306a36Sopenharmony_ci /* that is a broken device */ 180462306a36Sopenharmony_ci status = -ENODEV; 180562306a36Sopenharmony_ci goto out4; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci /* let userspace know we have a random address */ 180962306a36Sopenharmony_ci if (ether_addr_equal(net->dev_addr, node_id)) 181062306a36Sopenharmony_ci net->addr_assign_type = NET_ADDR_RANDOM; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WLAN) != 0) 181362306a36Sopenharmony_ci SET_NETDEV_DEVTYPE(net, &wlan_type); 181462306a36Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WWAN) != 0) 181562306a36Sopenharmony_ci SET_NETDEV_DEVTYPE(net, &wwan_type); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci /* initialize max rx_qlen and tx_qlen */ 181862306a36Sopenharmony_ci usbnet_update_max_qlen(dev); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) && 182162306a36Sopenharmony_ci !(info->flags & FLAG_MULTI_PACKET)) { 182262306a36Sopenharmony_ci dev->padding_pkt = kzalloc(1, GFP_KERNEL); 182362306a36Sopenharmony_ci if (!dev->padding_pkt) { 182462306a36Sopenharmony_ci status = -ENOMEM; 182562306a36Sopenharmony_ci goto out4; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci status = register_netdev (net); 183062306a36Sopenharmony_ci if (status) 183162306a36Sopenharmony_ci goto out5; 183262306a36Sopenharmony_ci netif_info(dev, probe, dev->net, 183362306a36Sopenharmony_ci "register '%s' at usb-%s-%s, %s, %pM\n", 183462306a36Sopenharmony_ci udev->dev.driver->name, 183562306a36Sopenharmony_ci xdev->bus->bus_name, xdev->devpath, 183662306a36Sopenharmony_ci dev->driver_info->description, 183762306a36Sopenharmony_ci net->dev_addr); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci // ok, it's ready to go. 184062306a36Sopenharmony_ci usb_set_intfdata (udev, dev); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci netif_device_attach (net); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci if (dev->driver_info->flags & FLAG_LINK_INTR) 184562306a36Sopenharmony_ci usbnet_link_change(dev, 0, 0); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci return 0; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ciout5: 185062306a36Sopenharmony_ci kfree(dev->padding_pkt); 185162306a36Sopenharmony_ciout4: 185262306a36Sopenharmony_ci usb_free_urb(dev->interrupt); 185362306a36Sopenharmony_ciout3: 185462306a36Sopenharmony_ci if (info->unbind) 185562306a36Sopenharmony_ci info->unbind (dev, udev); 185662306a36Sopenharmony_ciout1: 185762306a36Sopenharmony_ci /* subdrivers must undo all they did in bind() if they 185862306a36Sopenharmony_ci * fail it, but we may fail later and a deferred kevent 185962306a36Sopenharmony_ci * may trigger an error resubmitting itself and, worse, 186062306a36Sopenharmony_ci * schedule a timer. So we kill it all just in case. 186162306a36Sopenharmony_ci */ 186262306a36Sopenharmony_ci cancel_work_sync(&dev->kevent); 186362306a36Sopenharmony_ci del_timer_sync(&dev->delay); 186462306a36Sopenharmony_ci free_percpu(net->tstats); 186562306a36Sopenharmony_ciout0: 186662306a36Sopenharmony_ci free_netdev(net); 186762306a36Sopenharmony_ciout: 186862306a36Sopenharmony_ci return status; 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_probe); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci/* 187562306a36Sopenharmony_ci * suspend the whole driver as soon as the first interface is suspended 187662306a36Sopenharmony_ci * resume only when the last interface is resumed 187762306a36Sopenharmony_ci */ 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ciint usbnet_suspend (struct usb_interface *intf, pm_message_t message) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (!dev->suspend_count++) { 188462306a36Sopenharmony_ci spin_lock_irq(&dev->txq.lock); 188562306a36Sopenharmony_ci /* don't autosuspend while transmitting */ 188662306a36Sopenharmony_ci if (dev->txq.qlen && PMSG_IS_AUTO(message)) { 188762306a36Sopenharmony_ci dev->suspend_count--; 188862306a36Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 188962306a36Sopenharmony_ci return -EBUSY; 189062306a36Sopenharmony_ci } else { 189162306a36Sopenharmony_ci set_bit(EVENT_DEV_ASLEEP, &dev->flags); 189262306a36Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci /* 189562306a36Sopenharmony_ci * accelerate emptying of the rx and queues, to avoid 189662306a36Sopenharmony_ci * having everything error out. 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_ci netif_device_detach (dev->net); 189962306a36Sopenharmony_ci usbnet_terminate_urbs(dev); 190062306a36Sopenharmony_ci __usbnet_status_stop_force(dev); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* 190362306a36Sopenharmony_ci * reattach so runtime management can use and 190462306a36Sopenharmony_ci * wake the device 190562306a36Sopenharmony_ci */ 190662306a36Sopenharmony_ci netif_device_attach (dev->net); 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci return 0; 190962306a36Sopenharmony_ci} 191062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_suspend); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ciint usbnet_resume (struct usb_interface *intf) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 191562306a36Sopenharmony_ci struct sk_buff *skb; 191662306a36Sopenharmony_ci struct urb *res; 191762306a36Sopenharmony_ci int retval; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (!--dev->suspend_count) { 192062306a36Sopenharmony_ci /* resume interrupt URB if it was previously submitted */ 192162306a36Sopenharmony_ci __usbnet_status_start_force(dev, GFP_NOIO); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci spin_lock_irq(&dev->txq.lock); 192462306a36Sopenharmony_ci while ((res = usb_get_from_anchor(&dev->deferred))) { 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci skb = (struct sk_buff *)res->context; 192762306a36Sopenharmony_ci retval = usb_submit_urb(res, GFP_ATOMIC); 192862306a36Sopenharmony_ci if (retval < 0) { 192962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 193062306a36Sopenharmony_ci kfree(res->sg); 193162306a36Sopenharmony_ci usb_free_urb(res); 193262306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 193362306a36Sopenharmony_ci } else { 193462306a36Sopenharmony_ci netif_trans_update(dev->net); 193562306a36Sopenharmony_ci __skb_queue_tail(&dev->txq, skb); 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci smp_mb(); 194062306a36Sopenharmony_ci clear_bit(EVENT_DEV_ASLEEP, &dev->flags); 194162306a36Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { 194462306a36Sopenharmony_ci /* handle remote wakeup ASAP 194562306a36Sopenharmony_ci * we cannot race against stop 194662306a36Sopenharmony_ci */ 194762306a36Sopenharmony_ci if (netif_device_present(dev->net) && 194862306a36Sopenharmony_ci !timer_pending(&dev->delay) && 194962306a36Sopenharmony_ci !test_bit(EVENT_RX_HALT, &dev->flags)) 195062306a36Sopenharmony_ci rx_alloc_submit(dev, GFP_NOIO); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci if (!(dev->txq.qlen >= TX_QLEN(dev))) 195362306a36Sopenharmony_ci netif_tx_wake_all_queues(dev->net); 195462306a36Sopenharmony_ci tasklet_schedule (&dev->bh); 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) 195962306a36Sopenharmony_ci usb_autopm_get_interface_no_resume(intf); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci return 0; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_resume); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci/* 196662306a36Sopenharmony_ci * Either a subdriver implements manage_power, then it is assumed to always 196762306a36Sopenharmony_ci * be ready to be suspended or it reports the readiness to be suspended 196862306a36Sopenharmony_ci * explicitly 196962306a36Sopenharmony_ci */ 197062306a36Sopenharmony_civoid usbnet_device_suggests_idle(struct usbnet *dev) 197162306a36Sopenharmony_ci{ 197262306a36Sopenharmony_ci if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) { 197362306a36Sopenharmony_ci dev->intf->needs_remote_wakeup = 1; 197462306a36Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ciEXPORT_SYMBOL(usbnet_device_suggests_idle); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci/* 198062306a36Sopenharmony_ci * For devices that can do without special commands 198162306a36Sopenharmony_ci */ 198262306a36Sopenharmony_ciint usbnet_manage_power(struct usbnet *dev, int on) 198362306a36Sopenharmony_ci{ 198462306a36Sopenharmony_ci dev->intf->needs_remote_wakeup = on; 198562306a36Sopenharmony_ci return 0; 198662306a36Sopenharmony_ci} 198762306a36Sopenharmony_ciEXPORT_SYMBOL(usbnet_manage_power); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_civoid usbnet_link_change(struct usbnet *dev, bool link, bool need_reset) 199062306a36Sopenharmony_ci{ 199162306a36Sopenharmony_ci /* update link after link is reseted */ 199262306a36Sopenharmony_ci if (link && !need_reset) 199362306a36Sopenharmony_ci netif_carrier_on(dev->net); 199462306a36Sopenharmony_ci else 199562306a36Sopenharmony_ci netif_carrier_off(dev->net); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (need_reset && link) 199862306a36Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_LINK_RESET); 199962306a36Sopenharmony_ci else 200062306a36Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ciEXPORT_SYMBOL(usbnet_link_change); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 200562306a36Sopenharmony_cistatic int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 200662306a36Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 200762306a36Sopenharmony_ci{ 200862306a36Sopenharmony_ci void *buf = NULL; 200962306a36Sopenharmony_ci int err = -ENOMEM; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci netdev_dbg(dev->net, "usbnet_read_cmd cmd=0x%02x reqtype=%02x" 201262306a36Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 201362306a36Sopenharmony_ci cmd, reqtype, value, index, size); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci if (size) { 201662306a36Sopenharmony_ci buf = kmalloc(size, GFP_NOIO); 201762306a36Sopenharmony_ci if (!buf) 201862306a36Sopenharmony_ci goto out; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci err = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), 202262306a36Sopenharmony_ci cmd, reqtype, value, index, buf, size, 202362306a36Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 202462306a36Sopenharmony_ci if (err > 0 && err <= size) { 202562306a36Sopenharmony_ci if (data) 202662306a36Sopenharmony_ci memcpy(data, buf, err); 202762306a36Sopenharmony_ci else 202862306a36Sopenharmony_ci netdev_dbg(dev->net, 202962306a36Sopenharmony_ci "Huh? Data requested but thrown away.\n"); 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci kfree(buf); 203262306a36Sopenharmony_ciout: 203362306a36Sopenharmony_ci return err; 203462306a36Sopenharmony_ci} 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_cistatic int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 203762306a36Sopenharmony_ci u16 value, u16 index, const void *data, 203862306a36Sopenharmony_ci u16 size) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci void *buf = NULL; 204162306a36Sopenharmony_ci int err = -ENOMEM; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" 204462306a36Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 204562306a36Sopenharmony_ci cmd, reqtype, value, index, size); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (data) { 204862306a36Sopenharmony_ci buf = kmemdup(data, size, GFP_NOIO); 204962306a36Sopenharmony_ci if (!buf) 205062306a36Sopenharmony_ci goto out; 205162306a36Sopenharmony_ci } else { 205262306a36Sopenharmony_ci if (size) { 205362306a36Sopenharmony_ci WARN_ON_ONCE(1); 205462306a36Sopenharmony_ci err = -EINVAL; 205562306a36Sopenharmony_ci goto out; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 206062306a36Sopenharmony_ci cmd, reqtype, value, index, buf, size, 206162306a36Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 206262306a36Sopenharmony_ci kfree(buf); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ciout: 206562306a36Sopenharmony_ci return err; 206662306a36Sopenharmony_ci} 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci/* 206962306a36Sopenharmony_ci * The function can't be called inside suspend/resume callback, 207062306a36Sopenharmony_ci * otherwise deadlock will be caused. 207162306a36Sopenharmony_ci */ 207262306a36Sopenharmony_ciint usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 207362306a36Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 207462306a36Sopenharmony_ci{ 207562306a36Sopenharmony_ci int ret; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci if (usb_autopm_get_interface(dev->intf) < 0) 207862306a36Sopenharmony_ci return -ENODEV; 207962306a36Sopenharmony_ci ret = __usbnet_read_cmd(dev, cmd, reqtype, value, index, 208062306a36Sopenharmony_ci data, size); 208162306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 208262306a36Sopenharmony_ci return ret; 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_read_cmd); 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci/* 208762306a36Sopenharmony_ci * The function can't be called inside suspend/resume callback, 208862306a36Sopenharmony_ci * otherwise deadlock will be caused. 208962306a36Sopenharmony_ci */ 209062306a36Sopenharmony_ciint usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 209162306a36Sopenharmony_ci u16 value, u16 index, const void *data, u16 size) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci int ret; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci if (usb_autopm_get_interface(dev->intf) < 0) 209662306a36Sopenharmony_ci return -ENODEV; 209762306a36Sopenharmony_ci ret = __usbnet_write_cmd(dev, cmd, reqtype, value, index, 209862306a36Sopenharmony_ci data, size); 209962306a36Sopenharmony_ci usb_autopm_put_interface(dev->intf); 210062306a36Sopenharmony_ci return ret; 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci/* 210562306a36Sopenharmony_ci * The function can be called inside suspend/resume callback safely 210662306a36Sopenharmony_ci * and should only be called by suspend/resume callback generally. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_ciint usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, 210962306a36Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci return __usbnet_read_cmd(dev, cmd, reqtype, value, index, 211262306a36Sopenharmony_ci data, size); 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_read_cmd_nopm); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci/* 211762306a36Sopenharmony_ci * The function can be called inside suspend/resume callback safely 211862306a36Sopenharmony_ci * and should only be called by suspend/resume callback generally. 211962306a36Sopenharmony_ci */ 212062306a36Sopenharmony_ciint usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, 212162306a36Sopenharmony_ci u16 value, u16 index, const void *data, 212262306a36Sopenharmony_ci u16 size) 212362306a36Sopenharmony_ci{ 212462306a36Sopenharmony_ci return __usbnet_write_cmd(dev, cmd, reqtype, value, index, 212562306a36Sopenharmony_ci data, size); 212662306a36Sopenharmony_ci} 212762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd_nopm); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_cistatic void usbnet_async_cmd_cb(struct urb *urb) 213062306a36Sopenharmony_ci{ 213162306a36Sopenharmony_ci struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; 213262306a36Sopenharmony_ci int status = urb->status; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci if (status < 0) 213562306a36Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s failed with %d", 213662306a36Sopenharmony_ci __func__, status); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci kfree(req); 213962306a36Sopenharmony_ci usb_free_urb(urb); 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci/* 214362306a36Sopenharmony_ci * The caller must make sure that device can't be put into suspend 214462306a36Sopenharmony_ci * state until the control URB completes. 214562306a36Sopenharmony_ci */ 214662306a36Sopenharmony_ciint usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, 214762306a36Sopenharmony_ci u16 value, u16 index, const void *data, u16 size) 214862306a36Sopenharmony_ci{ 214962306a36Sopenharmony_ci struct usb_ctrlrequest *req; 215062306a36Sopenharmony_ci struct urb *urb; 215162306a36Sopenharmony_ci int err = -ENOMEM; 215262306a36Sopenharmony_ci void *buf = NULL; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" 215562306a36Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 215662306a36Sopenharmony_ci cmd, reqtype, value, index, size); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 215962306a36Sopenharmony_ci if (!urb) 216062306a36Sopenharmony_ci goto fail; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci if (data) { 216362306a36Sopenharmony_ci buf = kmemdup(data, size, GFP_ATOMIC); 216462306a36Sopenharmony_ci if (!buf) { 216562306a36Sopenharmony_ci netdev_err(dev->net, "Error allocating buffer" 216662306a36Sopenharmony_ci " in %s!\n", __func__); 216762306a36Sopenharmony_ci goto fail_free_urb; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 217262306a36Sopenharmony_ci if (!req) 217362306a36Sopenharmony_ci goto fail_free_buf; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci req->bRequestType = reqtype; 217662306a36Sopenharmony_ci req->bRequest = cmd; 217762306a36Sopenharmony_ci req->wValue = cpu_to_le16(value); 217862306a36Sopenharmony_ci req->wIndex = cpu_to_le16(index); 217962306a36Sopenharmony_ci req->wLength = cpu_to_le16(size); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci usb_fill_control_urb(urb, dev->udev, 218262306a36Sopenharmony_ci usb_sndctrlpipe(dev->udev, 0), 218362306a36Sopenharmony_ci (void *)req, buf, size, 218462306a36Sopenharmony_ci usbnet_async_cmd_cb, req); 218562306a36Sopenharmony_ci urb->transfer_flags |= URB_FREE_BUFFER; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci err = usb_submit_urb(urb, GFP_ATOMIC); 218862306a36Sopenharmony_ci if (err < 0) { 218962306a36Sopenharmony_ci netdev_err(dev->net, "Error submitting the control" 219062306a36Sopenharmony_ci " message: status=%d\n", err); 219162306a36Sopenharmony_ci goto fail_free_all; 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci return 0; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_cifail_free_all: 219662306a36Sopenharmony_ci kfree(req); 219762306a36Sopenharmony_cifail_free_buf: 219862306a36Sopenharmony_ci kfree(buf); 219962306a36Sopenharmony_ci /* 220062306a36Sopenharmony_ci * avoid a double free 220162306a36Sopenharmony_ci * needed because the flag can be set only 220262306a36Sopenharmony_ci * after filling the URB 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ci urb->transfer_flags = 0; 220562306a36Sopenharmony_cifail_free_urb: 220662306a36Sopenharmony_ci usb_free_urb(urb); 220762306a36Sopenharmony_cifail: 220862306a36Sopenharmony_ci return err; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci} 221162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd_async); 221262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic int __init usbnet_init(void) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci /* Compiler should optimize this out. */ 221762306a36Sopenharmony_ci BUILD_BUG_ON( 221862306a36Sopenharmony_ci sizeof_field(struct sk_buff, cb) < sizeof(struct skb_data)); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci eth_random_addr(node_id); 222162306a36Sopenharmony_ci return 0; 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_cimodule_init(usbnet_init); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_cistatic void __exit usbnet_exit(void) 222662306a36Sopenharmony_ci{ 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_cimodule_exit(usbnet_exit); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ciMODULE_AUTHOR("David Brownell"); 223162306a36Sopenharmony_ciMODULE_DESCRIPTION("USB network driver framework"); 223262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2233