18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * USB Network driver infrastructure 48c2ecf20Sopenharmony_ci * Copyright (C) 2000-2005 by David Brownell 58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * This is a generic "USB networking" framework that works with several 108c2ecf20Sopenharmony_ci * kinds of full and high speed networking devices: host-to-host cables, 118c2ecf20Sopenharmony_ci * smart usb peripherals, and actual Ethernet adapters. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * These devices usually differ in terms of control protocols (if they 148c2ecf20Sopenharmony_ci * even have one!) and sometimes they define new framing to wrap or batch 158c2ecf20Sopenharmony_ci * Ethernet packets. Otherwise, they talk to USB pretty much the same, 168c2ecf20Sopenharmony_ci * so interface (un)binding, endpoint I/O queues, fault handling, and other 178c2ecf20Sopenharmony_ci * issues can usefully be addressed by this framework. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci// #define DEBUG // error path messages, extra info 218c2ecf20Sopenharmony_ci// #define VERBOSE // more; success messages 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 268c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/ctype.h> 288c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 298c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 308c2ecf20Sopenharmony_ci#include <linux/mii.h> 318c2ecf20Sopenharmony_ci#include <linux/usb.h> 328c2ecf20Sopenharmony_ci#include <linux/usb/usbnet.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. 418c2ecf20Sopenharmony_ci * Several dozen bytes of IPv4 data can fit in two such transactions. 428c2ecf20Sopenharmony_ci * One maximum size Ethernet packet takes twenty four of them. 438c2ecf20Sopenharmony_ci * For high speed, each frame comfortably fits almost 36 max size 448c2ecf20Sopenharmony_ci * Ethernet packets (so queues should be bigger). 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * The goal is to let the USB host controller be busy for 5msec or 478c2ecf20Sopenharmony_ci * more before an irq is required, under load. Jumbograms change 488c2ecf20Sopenharmony_ci * the equation. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci#define MAX_QUEUE_MEMORY (60 * 1518) 518c2ecf20Sopenharmony_ci#define RX_QLEN(dev) ((dev)->rx_qlen) 528c2ecf20Sopenharmony_ci#define TX_QLEN(dev) ((dev)->tx_qlen) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci// reawaken network queue this soon after stopping; else watchdog barks 558c2ecf20Sopenharmony_ci#define TX_TIMEOUT_JIFFIES (5*HZ) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* throttle rx/tx briefly after some faults, so hub_wq might disconnect() 588c2ecf20Sopenharmony_ci * us (it polls at HZ/4 usually) before we report too many false errors. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci#define THROTTLE_JIFFIES (HZ/8) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci// between wakeups 638c2ecf20Sopenharmony_ci#define UNLINK_TIMEOUT_MS 3 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci// randomly generated ethernet address 688c2ecf20Sopenharmony_cistatic u8 node_id [ETH_ALEN]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* use ethtool to change the level for any given device */ 718c2ecf20Sopenharmony_cistatic int msg_level = -1; 728c2ecf20Sopenharmony_cimodule_param (msg_level, int, 0); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC (msg_level, "Override default message level"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* handles CDC Ethernet and many other network "bulk data" interfaces */ 788c2ecf20Sopenharmony_ciint usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int tmp; 818c2ecf20Sopenharmony_ci struct usb_host_interface *alt = NULL; 828c2ecf20Sopenharmony_ci struct usb_host_endpoint *in = NULL, *out = NULL; 838c2ecf20Sopenharmony_ci struct usb_host_endpoint *status = NULL; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci for (tmp = 0; tmp < intf->num_altsetting; tmp++) { 868c2ecf20Sopenharmony_ci unsigned ep; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci in = out = status = NULL; 898c2ecf20Sopenharmony_ci alt = intf->altsetting + tmp; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* take the first altsetting with in-bulk + out-bulk; 928c2ecf20Sopenharmony_ci * remember any status endpoint, just in case; 938c2ecf20Sopenharmony_ci * ignore other endpoints and altsettings. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { 968c2ecf20Sopenharmony_ci struct usb_host_endpoint *e; 978c2ecf20Sopenharmony_ci int intr = 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci e = alt->endpoint + ep; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* ignore endpoints which cannot transfer data */ 1028c2ecf20Sopenharmony_ci if (!usb_endpoint_maxp(&e->desc)) 1038c2ecf20Sopenharmony_ci continue; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci switch (e->desc.bmAttributes) { 1068c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 1078c2ecf20Sopenharmony_ci if (!usb_endpoint_dir_in(&e->desc)) 1088c2ecf20Sopenharmony_ci continue; 1098c2ecf20Sopenharmony_ci intr = 1; 1108c2ecf20Sopenharmony_ci fallthrough; 1118c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci default: 1148c2ecf20Sopenharmony_ci continue; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci if (usb_endpoint_dir_in(&e->desc)) { 1178c2ecf20Sopenharmony_ci if (!intr && !in) 1188c2ecf20Sopenharmony_ci in = e; 1198c2ecf20Sopenharmony_ci else if (intr && !status) 1208c2ecf20Sopenharmony_ci status = e; 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci if (!out) 1238c2ecf20Sopenharmony_ci out = e; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if (in && out) 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci if (!alt || !in || !out) 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (alt->desc.bAlternateSetting != 0 || 1338c2ecf20Sopenharmony_ci !(dev->driver_info->flags & FLAG_NO_SETINT)) { 1348c2ecf20Sopenharmony_ci tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, 1358c2ecf20Sopenharmony_ci alt->desc.bAlternateSetting); 1368c2ecf20Sopenharmony_ci if (tmp < 0) 1378c2ecf20Sopenharmony_ci return tmp; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dev->in = usb_rcvbulkpipe (dev->udev, 1418c2ecf20Sopenharmony_ci in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 1428c2ecf20Sopenharmony_ci dev->out = usb_sndbulkpipe (dev->udev, 1438c2ecf20Sopenharmony_ci out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 1448c2ecf20Sopenharmony_ci dev->status = status; 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_endpoints); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciint usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int tmp = -1, ret; 1528c2ecf20Sopenharmony_ci unsigned char buf [13]; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); 1558c2ecf20Sopenharmony_ci if (ret == 12) 1568c2ecf20Sopenharmony_ci tmp = hex2bin(dev->net->dev_addr, buf, 6); 1578c2ecf20Sopenharmony_ci if (tmp < 0) { 1588c2ecf20Sopenharmony_ci dev_dbg(&dev->udev->dev, 1598c2ecf20Sopenharmony_ci "bad MAC string %d fetch, %d\n", iMACAddress, tmp); 1608c2ecf20Sopenharmony_ci if (ret >= 0) 1618c2ecf20Sopenharmony_ci ret = -EINVAL; 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void intr_complete (struct urb *urb) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct usbnet *dev = urb->context; 1718c2ecf20Sopenharmony_ci int status = urb->status; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci switch (status) { 1748c2ecf20Sopenharmony_ci /* success */ 1758c2ecf20Sopenharmony_ci case 0: 1768c2ecf20Sopenharmony_ci dev->driver_info->status(dev, urb); 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* software-driven interface shutdown */ 1808c2ecf20Sopenharmony_ci case -ENOENT: /* urb killed */ 1818c2ecf20Sopenharmony_ci case -ESHUTDOWN: /* hardware gone */ 1828c2ecf20Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 1838c2ecf20Sopenharmony_ci "intr shutdown, code %d\n", status); 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* NOTE: not throttling like RX/TX, since this endpoint 1878c2ecf20Sopenharmony_ci * already polls infrequently 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci default: 1908c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "intr status %d\n", status); 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci status = usb_submit_urb (urb, GFP_ATOMIC); 1958c2ecf20Sopenharmony_ci if (status != 0) 1968c2ecf20Sopenharmony_ci netif_err(dev, timer, dev->net, 1978c2ecf20Sopenharmony_ci "intr resubmit --> %d\n", status); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int init_status (struct usbnet *dev, struct usb_interface *intf) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci char *buf = NULL; 2038c2ecf20Sopenharmony_ci unsigned pipe = 0; 2048c2ecf20Sopenharmony_ci unsigned maxp; 2058c2ecf20Sopenharmony_ci unsigned period; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (!dev->driver_info->status) 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci pipe = usb_rcvintpipe (dev->udev, 2118c2ecf20Sopenharmony_ci dev->status->desc.bEndpointAddress 2128c2ecf20Sopenharmony_ci & USB_ENDPOINT_NUMBER_MASK); 2138c2ecf20Sopenharmony_ci maxp = usb_maxpacket (dev->udev, pipe, 0); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* avoid 1 msec chatter: min 8 msec poll rate */ 2168c2ecf20Sopenharmony_ci period = max ((int) dev->status->desc.bInterval, 2178c2ecf20Sopenharmony_ci (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci buf = kmalloc (maxp, GFP_KERNEL); 2208c2ecf20Sopenharmony_ci if (buf) { 2218c2ecf20Sopenharmony_ci dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); 2228c2ecf20Sopenharmony_ci if (!dev->interrupt) { 2238c2ecf20Sopenharmony_ci kfree (buf); 2248c2ecf20Sopenharmony_ci return -ENOMEM; 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci usb_fill_int_urb(dev->interrupt, dev->udev, pipe, 2278c2ecf20Sopenharmony_ci buf, maxp, intr_complete, dev, period); 2288c2ecf20Sopenharmony_ci dev->interrupt->transfer_flags |= URB_FREE_BUFFER; 2298c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, 2308c2ecf20Sopenharmony_ci "status ep%din, %d bytes period %d\n", 2318c2ecf20Sopenharmony_ci usb_pipeendpoint(pipe), maxp, period); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* Submit the interrupt URB if not previously submitted, increasing refcount */ 2388c2ecf20Sopenharmony_ciint usbnet_status_start(struct usbnet *dev, gfp_t mem_flags) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci int ret = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci WARN_ON_ONCE(dev->interrupt == NULL); 2438c2ecf20Sopenharmony_ci if (dev->interrupt) { 2448c2ecf20Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (++dev->interrupt_count == 1) 2478c2ecf20Sopenharmony_ci ret = usb_submit_urb(dev->interrupt, mem_flags); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci dev_dbg(&dev->udev->dev, "incremented interrupt URB count to %d\n", 2508c2ecf20Sopenharmony_ci dev->interrupt_count); 2518c2ecf20Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_status_start); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* For resume; submit interrupt URB if previously submitted */ 2588c2ecf20Sopenharmony_cistatic int __usbnet_status_start_force(struct usbnet *dev, gfp_t mem_flags) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci int ret = 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 2638c2ecf20Sopenharmony_ci if (dev->interrupt_count) { 2648c2ecf20Sopenharmony_ci ret = usb_submit_urb(dev->interrupt, mem_flags); 2658c2ecf20Sopenharmony_ci dev_dbg(&dev->udev->dev, 2668c2ecf20Sopenharmony_ci "submitted interrupt URB for resume\n"); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* Kill the interrupt URB if all submitters want it killed */ 2738c2ecf20Sopenharmony_civoid usbnet_status_stop(struct usbnet *dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci if (dev->interrupt) { 2768c2ecf20Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 2778c2ecf20Sopenharmony_ci WARN_ON(dev->interrupt_count == 0); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (dev->interrupt_count && --dev->interrupt_count == 0) 2808c2ecf20Sopenharmony_ci usb_kill_urb(dev->interrupt); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dev_dbg(&dev->udev->dev, 2838c2ecf20Sopenharmony_ci "decremented interrupt URB count to %d\n", 2848c2ecf20Sopenharmony_ci dev->interrupt_count); 2858c2ecf20Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_status_stop); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* For suspend; always kill interrupt URB */ 2918c2ecf20Sopenharmony_cistatic void __usbnet_status_stop_force(struct usbnet *dev) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci if (dev->interrupt) { 2948c2ecf20Sopenharmony_ci mutex_lock(&dev->interrupt_mutex); 2958c2ecf20Sopenharmony_ci usb_kill_urb(dev->interrupt); 2968c2ecf20Sopenharmony_ci dev_dbg(&dev->udev->dev, "killed interrupt URB for suspend\n"); 2978c2ecf20Sopenharmony_ci mutex_unlock(&dev->interrupt_mutex); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* Passes this packet up the stack, updating its accounting. 3028c2ecf20Sopenharmony_ci * Some link protocols batch packets, so their rx_fixup paths 3038c2ecf20Sopenharmony_ci * can return clones as well as just modify the original skb. 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_civoid usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); 3088c2ecf20Sopenharmony_ci unsigned long flags; 3098c2ecf20Sopenharmony_ci int status; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { 3128c2ecf20Sopenharmony_ci skb_queue_tail(&dev->rxq_pause, skb); 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* only update if unset to allow minidriver rx_fixup override */ 3178c2ecf20Sopenharmony_ci if (skb->protocol == 0) 3188c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans (skb, dev->net); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci flags = u64_stats_update_begin_irqsave(&stats64->syncp); 3218c2ecf20Sopenharmony_ci stats64->rx_packets++; 3228c2ecf20Sopenharmony_ci stats64->rx_bytes += skb->len; 3238c2ecf20Sopenharmony_ci u64_stats_update_end_irqrestore(&stats64->syncp, flags); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", 3268c2ecf20Sopenharmony_ci skb->len + sizeof (struct ethhdr), skb->protocol); 3278c2ecf20Sopenharmony_ci memset (skb->cb, 0, sizeof (struct skb_data)); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (skb_defer_rx_timestamp(skb)) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci status = netif_rx (skb); 3338c2ecf20Sopenharmony_ci if (status != NET_RX_SUCCESS) 3348c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, 3358c2ecf20Sopenharmony_ci "netif_rx status %d\n", status); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_skb_return); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* must be called if hard_mtu or rx_urb_size changed */ 3408c2ecf20Sopenharmony_civoid usbnet_update_max_qlen(struct usbnet *dev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci enum usb_device_speed speed = dev->udev->speed; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!dev->rx_urb_size || !dev->hard_mtu) 3458c2ecf20Sopenharmony_ci goto insanity; 3468c2ecf20Sopenharmony_ci switch (speed) { 3478c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 3488c2ecf20Sopenharmony_ci dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size; 3498c2ecf20Sopenharmony_ci dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu; 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 3528c2ecf20Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Not take default 5ms qlen for super speed HC to 3558c2ecf20Sopenharmony_ci * save memory, and iperf tests show 2.5ms qlen can 3568c2ecf20Sopenharmony_ci * work well 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size; 3598c2ecf20Sopenharmony_ci dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci default: 3628c2ecf20Sopenharmony_ciinsanity: 3638c2ecf20Sopenharmony_ci dev->rx_qlen = dev->tx_qlen = 4; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_update_max_qlen); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/*------------------------------------------------------------------------- 3708c2ecf20Sopenharmony_ci * 3718c2ecf20Sopenharmony_ci * Network Device Driver (peer link to "Host Device", from USB host) 3728c2ecf20Sopenharmony_ci * 3738c2ecf20Sopenharmony_ci *-------------------------------------------------------------------------*/ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciint usbnet_change_mtu (struct net_device *net, int new_mtu) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 3788c2ecf20Sopenharmony_ci int ll_mtu = new_mtu + net->hard_header_len; 3798c2ecf20Sopenharmony_ci int old_hard_mtu = dev->hard_mtu; 3808c2ecf20Sopenharmony_ci int old_rx_urb_size = dev->rx_urb_size; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci // no second zero-length packet read wanted after mtu-sized packets 3838c2ecf20Sopenharmony_ci if ((ll_mtu % dev->maxpacket) == 0) 3848c2ecf20Sopenharmony_ci return -EDOM; 3858c2ecf20Sopenharmony_ci net->mtu = new_mtu; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 3888c2ecf20Sopenharmony_ci if (dev->rx_urb_size == old_hard_mtu) { 3898c2ecf20Sopenharmony_ci dev->rx_urb_size = dev->hard_mtu; 3908c2ecf20Sopenharmony_ci if (dev->rx_urb_size > old_rx_urb_size) { 3918c2ecf20Sopenharmony_ci usbnet_pause_rx(dev); 3928c2ecf20Sopenharmony_ci usbnet_unlink_rx_urbs(dev); 3938c2ecf20Sopenharmony_ci usbnet_resume_rx(dev); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* max qlen depend on hard_mtu and rx_urb_size */ 3988c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_change_mtu); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* The caller must hold list->lock */ 4058c2ecf20Sopenharmony_cistatic void __usbnet_queue_skb(struct sk_buff_head *list, 4068c2ecf20Sopenharmony_ci struct sk_buff *newsk, enum skb_state state) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct skb_data *entry = (struct skb_data *) newsk->cb; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci __skb_queue_tail(list, newsk); 4118c2ecf20Sopenharmony_ci entry->state = state; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from 4178c2ecf20Sopenharmony_ci * completion callbacks. 2.5 should have fixed those bugs... 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, 4218c2ecf20Sopenharmony_ci struct sk_buff_head *list, enum skb_state state) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci unsigned long flags; 4248c2ecf20Sopenharmony_ci enum skb_state old_state; 4258c2ecf20Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 4288c2ecf20Sopenharmony_ci old_state = entry->state; 4298c2ecf20Sopenharmony_ci entry->state = state; 4308c2ecf20Sopenharmony_ci __skb_unlink(skb, list); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* defer_bh() is never called with list == &dev->done. 4338c2ecf20Sopenharmony_ci * spin_lock_nested() tells lockdep that it is OK to take 4348c2ecf20Sopenharmony_ci * dev->done.lock here with list->lock held. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci __skb_queue_tail(&dev->done, skb); 4398c2ecf20Sopenharmony_ci if (dev->done.qlen == 1) 4408c2ecf20Sopenharmony_ci tasklet_schedule(&dev->bh); 4418c2ecf20Sopenharmony_ci spin_unlock(&dev->done.lock); 4428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 4438c2ecf20Sopenharmony_ci return old_state; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* some work can't be done in tasklets, so we use keventd 4478c2ecf20Sopenharmony_ci * 4488c2ecf20Sopenharmony_ci * NOTE: annoying asymmetry: if it's active, schedule_work() fails, 4498c2ecf20Sopenharmony_ci * but tasklet_schedule() doesn't. hope the failure is rare. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_civoid usbnet_defer_kevent (struct usbnet *dev, int work) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci set_bit (work, &dev->flags); 4548c2ecf20Sopenharmony_ci if (!schedule_work (&dev->kevent)) 4558c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "kevent %d may have been dropped\n", work); 4568c2ecf20Sopenharmony_ci else 4578c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "kevent %d scheduled\n", work); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_defer_kevent); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void rx_complete (struct urb *urb); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct sk_buff *skb; 4688c2ecf20Sopenharmony_ci struct skb_data *entry; 4698c2ecf20Sopenharmony_ci int retval = 0; 4708c2ecf20Sopenharmony_ci unsigned long lockflags; 4718c2ecf20Sopenharmony_ci size_t size = dev->rx_urb_size; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* prevent rx skb allocation when error ratio is high */ 4748c2ecf20Sopenharmony_ci if (test_bit(EVENT_RX_KILL, &dev->flags)) { 4758c2ecf20Sopenharmony_ci usb_free_urb(urb); 4768c2ecf20Sopenharmony_ci return -ENOLINK; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (test_bit(EVENT_NO_IP_ALIGN, &dev->flags)) 4808c2ecf20Sopenharmony_ci skb = __netdev_alloc_skb(dev->net, size, flags); 4818c2ecf20Sopenharmony_ci else 4828c2ecf20Sopenharmony_ci skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); 4838c2ecf20Sopenharmony_ci if (!skb) { 4848c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); 4858c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_MEMORY); 4868c2ecf20Sopenharmony_ci usb_free_urb (urb); 4878c2ecf20Sopenharmony_ci return -ENOMEM; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci entry = (struct skb_data *) skb->cb; 4918c2ecf20Sopenharmony_ci entry->urb = urb; 4928c2ecf20Sopenharmony_ci entry->dev = dev; 4938c2ecf20Sopenharmony_ci entry->length = 0; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci usb_fill_bulk_urb (urb, dev->udev, dev->in, 4968c2ecf20Sopenharmony_ci skb->data, size, rx_complete, skb); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci spin_lock_irqsave (&dev->rxq.lock, lockflags); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (netif_running (dev->net) && 5018c2ecf20Sopenharmony_ci netif_device_present (dev->net) && 5028c2ecf20Sopenharmony_ci test_bit(EVENT_DEV_OPEN, &dev->flags) && 5038c2ecf20Sopenharmony_ci !test_bit (EVENT_RX_HALT, &dev->flags) && 5048c2ecf20Sopenharmony_ci !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { 5058c2ecf20Sopenharmony_ci switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { 5068c2ecf20Sopenharmony_ci case -EPIPE: 5078c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_HALT); 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci case -ENOMEM: 5108c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_MEMORY); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case -ENODEV: 5138c2ecf20Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, "device gone\n"); 5148c2ecf20Sopenharmony_ci netif_device_detach (dev->net); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci case -EHOSTUNREACH: 5178c2ecf20Sopenharmony_ci retval = -ENOLINK; 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci default: 5208c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, 5218c2ecf20Sopenharmony_ci "rx submit, %d\n", retval); 5228c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci case 0: 5258c2ecf20Sopenharmony_ci __usbnet_queue_skb(&dev->rxq, skb, rx_start); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } else { 5288c2ecf20Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); 5298c2ecf20Sopenharmony_ci retval = -ENOLINK; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&dev->rxq.lock, lockflags); 5328c2ecf20Sopenharmony_ci if (retval) { 5338c2ecf20Sopenharmony_ci dev_kfree_skb_any (skb); 5348c2ecf20Sopenharmony_ci usb_free_urb (urb); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci return retval; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic inline void rx_process (struct usbnet *dev, struct sk_buff *skb) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci if (dev->driver_info->rx_fixup && 5458c2ecf20Sopenharmony_ci !dev->driver_info->rx_fixup (dev, skb)) { 5468c2ecf20Sopenharmony_ci /* With RX_ASSEMBLE, rx_fixup() must update counters */ 5478c2ecf20Sopenharmony_ci if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) 5488c2ecf20Sopenharmony_ci dev->net->stats.rx_errors++; 5498c2ecf20Sopenharmony_ci goto done; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci // else network stack removes extra byte if we forced a short packet 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* all data was already cloned from skb inside the driver */ 5548c2ecf20Sopenharmony_ci if (dev->driver_info->flags & FLAG_MULTI_PACKET) 5558c2ecf20Sopenharmony_ci goto done; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (skb->len < ETH_HLEN) { 5588c2ecf20Sopenharmony_ci dev->net->stats.rx_errors++; 5598c2ecf20Sopenharmony_ci dev->net->stats.rx_length_errors++; 5608c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); 5618c2ecf20Sopenharmony_ci } else { 5628c2ecf20Sopenharmony_ci usbnet_skb_return(dev, skb); 5638c2ecf20Sopenharmony_ci return; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cidone: 5678c2ecf20Sopenharmony_ci skb_queue_tail(&dev->done, skb); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void rx_complete (struct urb *urb) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *) urb->context; 5758c2ecf20Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 5768c2ecf20Sopenharmony_ci struct usbnet *dev = entry->dev; 5778c2ecf20Sopenharmony_ci int urb_status = urb->status; 5788c2ecf20Sopenharmony_ci enum skb_state state; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci skb_put (skb, urb->actual_length); 5818c2ecf20Sopenharmony_ci state = rx_done; 5828c2ecf20Sopenharmony_ci entry->urb = NULL; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci switch (urb_status) { 5858c2ecf20Sopenharmony_ci /* success */ 5868c2ecf20Sopenharmony_ci case 0: 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* stalls need manual reset. this is rare ... except that 5908c2ecf20Sopenharmony_ci * when going through USB 2.0 TTs, unplug appears this way. 5918c2ecf20Sopenharmony_ci * we avoid the highspeed version of the ETIMEDOUT/EILSEQ 5928c2ecf20Sopenharmony_ci * storm, recovering as needed. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci case -EPIPE: 5958c2ecf20Sopenharmony_ci dev->net->stats.rx_errors++; 5968c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_RX_HALT); 5978c2ecf20Sopenharmony_ci fallthrough; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* software-driven interface shutdown */ 6008c2ecf20Sopenharmony_ci case -ECONNRESET: /* async unlink */ 6018c2ecf20Sopenharmony_ci case -ESHUTDOWN: /* hardware gone */ 6028c2ecf20Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 6038c2ecf20Sopenharmony_ci "rx shutdown, code %d\n", urb_status); 6048c2ecf20Sopenharmony_ci goto block; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* we get controller i/o faults during hub_wq disconnect() delays. 6078c2ecf20Sopenharmony_ci * throttle down resubmits, to avoid log floods; just temporarily, 6088c2ecf20Sopenharmony_ci * so we still recover when the fault isn't a hub_wq delay. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_ci case -EPROTO: 6118c2ecf20Sopenharmony_ci case -ETIME: 6128c2ecf20Sopenharmony_ci case -EILSEQ: 6138c2ecf20Sopenharmony_ci dev->net->stats.rx_errors++; 6148c2ecf20Sopenharmony_ci if (!timer_pending (&dev->delay)) { 6158c2ecf20Sopenharmony_ci mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); 6168c2ecf20Sopenharmony_ci netif_dbg(dev, link, dev->net, 6178c2ecf20Sopenharmony_ci "rx throttle %d\n", urb_status); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ciblock: 6208c2ecf20Sopenharmony_ci state = rx_cleanup; 6218c2ecf20Sopenharmony_ci entry->urb = urb; 6228c2ecf20Sopenharmony_ci urb = NULL; 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* data overrun ... flush fifo? */ 6268c2ecf20Sopenharmony_ci case -EOVERFLOW: 6278c2ecf20Sopenharmony_ci dev->net->stats.rx_over_errors++; 6288c2ecf20Sopenharmony_ci fallthrough; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci default: 6318c2ecf20Sopenharmony_ci state = rx_cleanup; 6328c2ecf20Sopenharmony_ci dev->net->stats.rx_errors++; 6338c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* stop rx if packet error rate is high */ 6388c2ecf20Sopenharmony_ci if (++dev->pkt_cnt > 30) { 6398c2ecf20Sopenharmony_ci dev->pkt_cnt = 0; 6408c2ecf20Sopenharmony_ci dev->pkt_err = 0; 6418c2ecf20Sopenharmony_ci } else { 6428c2ecf20Sopenharmony_ci if (state == rx_cleanup) 6438c2ecf20Sopenharmony_ci dev->pkt_err++; 6448c2ecf20Sopenharmony_ci if (dev->pkt_err > 20) 6458c2ecf20Sopenharmony_ci set_bit(EVENT_RX_KILL, &dev->flags); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci state = defer_bh(dev, skb, &dev->rxq, state); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (urb) { 6518c2ecf20Sopenharmony_ci if (netif_running (dev->net) && 6528c2ecf20Sopenharmony_ci !test_bit (EVENT_RX_HALT, &dev->flags) && 6538c2ecf20Sopenharmony_ci state != unlink_start) { 6548c2ecf20Sopenharmony_ci rx_submit (dev, urb, GFP_ATOMIC); 6558c2ecf20Sopenharmony_ci usb_mark_last_busy(dev->udev); 6568c2ecf20Sopenharmony_ci return; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci usb_free_urb (urb); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 6648c2ecf20Sopenharmony_civoid usbnet_pause_rx(struct usbnet *dev) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci set_bit(EVENT_RX_PAUSED, &dev->flags); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n"); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_pause_rx); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_civoid usbnet_resume_rx(struct usbnet *dev) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct sk_buff *skb; 6758c2ecf20Sopenharmony_ci int num = 0; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci clear_bit(EVENT_RX_PAUSED, &dev->flags); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { 6808c2ecf20Sopenharmony_ci usbnet_skb_return(dev, skb); 6818c2ecf20Sopenharmony_ci num++; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci tasklet_schedule(&dev->bh); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci netif_dbg(dev, rx_status, dev->net, 6878c2ecf20Sopenharmony_ci "paused rx queue disabled, %d skbs requeued\n", num); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_resume_rx); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_civoid usbnet_purge_paused_rxq(struct usbnet *dev) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci skb_queue_purge(&dev->rxq_pause); 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci// unlink pending rx/tx; completion handlers do all other cleanup 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci unsigned long flags; 7048c2ecf20Sopenharmony_ci struct sk_buff *skb; 7058c2ecf20Sopenharmony_ci int count = 0; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci spin_lock_irqsave (&q->lock, flags); 7088c2ecf20Sopenharmony_ci while (!skb_queue_empty(q)) { 7098c2ecf20Sopenharmony_ci struct skb_data *entry; 7108c2ecf20Sopenharmony_ci struct urb *urb; 7118c2ecf20Sopenharmony_ci int retval; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci skb_queue_walk(q, skb) { 7148c2ecf20Sopenharmony_ci entry = (struct skb_data *) skb->cb; 7158c2ecf20Sopenharmony_ci if (entry->state != unlink_start) 7168c2ecf20Sopenharmony_ci goto found; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_cifound: 7208c2ecf20Sopenharmony_ci entry->state = unlink_start; 7218c2ecf20Sopenharmony_ci urb = entry->urb; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* 7248c2ecf20Sopenharmony_ci * Get reference count of the URB to avoid it to be 7258c2ecf20Sopenharmony_ci * freed during usb_unlink_urb, which may trigger 7268c2ecf20Sopenharmony_ci * use-after-free problem inside usb_unlink_urb since 7278c2ecf20Sopenharmony_ci * usb_unlink_urb is always racing with .complete 7288c2ecf20Sopenharmony_ci * handler(include defer_bh). 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_ci usb_get_urb(urb); 7318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 7328c2ecf20Sopenharmony_ci // during some PM-driven resume scenarios, 7338c2ecf20Sopenharmony_ci // these (async) unlinks complete immediately 7348c2ecf20Sopenharmony_ci retval = usb_unlink_urb (urb); 7358c2ecf20Sopenharmony_ci if (retval != -EINPROGRESS && retval != 0) 7368c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "unlink urb err, %d\n", retval); 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci count++; 7398c2ecf20Sopenharmony_ci usb_put_urb(urb); 7408c2ecf20Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&q->lock, flags); 7438c2ecf20Sopenharmony_ci return count; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci// Flush all pending rx urbs 7478c2ecf20Sopenharmony_ci// minidrivers may need to do this when the MTU changes 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_civoid usbnet_unlink_rx_urbs(struct usbnet *dev) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci if (netif_running(dev->net)) { 7528c2ecf20Sopenharmony_ci (void) unlink_urbs (dev, &dev->rxq); 7538c2ecf20Sopenharmony_ci tasklet_schedule(&dev->bh); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void wait_skb_queue_empty(struct sk_buff_head *q) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci unsigned long flags; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 7658c2ecf20Sopenharmony_ci while (!skb_queue_empty(q)) { 7668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 7678c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); 7688c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 7698c2ecf20Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci// precondition: never called in_interrupt 7758c2ecf20Sopenharmony_cistatic void usbnet_terminate_urbs(struct usbnet *dev) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 7788c2ecf20Sopenharmony_ci int temp; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* ensure there are no more active urbs */ 7818c2ecf20Sopenharmony_ci add_wait_queue(&dev->wait, &wait); 7828c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 7838c2ecf20Sopenharmony_ci temp = unlink_urbs(dev, &dev->txq) + 7848c2ecf20Sopenharmony_ci unlink_urbs(dev, &dev->rxq); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* maybe wait for deletions to finish. */ 7878c2ecf20Sopenharmony_ci wait_skb_queue_empty(&dev->rxq); 7888c2ecf20Sopenharmony_ci wait_skb_queue_empty(&dev->txq); 7898c2ecf20Sopenharmony_ci wait_skb_queue_empty(&dev->done); 7908c2ecf20Sopenharmony_ci netif_dbg(dev, ifdown, dev->net, 7918c2ecf20Sopenharmony_ci "waited for %d urb completions\n", temp); 7928c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 7938c2ecf20Sopenharmony_ci remove_wait_queue(&dev->wait, &wait); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciint usbnet_stop (struct net_device *net) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 7998c2ecf20Sopenharmony_ci const struct driver_info *info = dev->driver_info; 8008c2ecf20Sopenharmony_ci int retval, pm, mpn; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci clear_bit(EVENT_DEV_OPEN, &dev->flags); 8038c2ecf20Sopenharmony_ci netif_stop_queue (net); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci netif_info(dev, ifdown, dev->net, 8068c2ecf20Sopenharmony_ci "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", 8078c2ecf20Sopenharmony_ci net->stats.rx_packets, net->stats.tx_packets, 8088c2ecf20Sopenharmony_ci net->stats.rx_errors, net->stats.tx_errors); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* to not race resume */ 8118c2ecf20Sopenharmony_ci pm = usb_autopm_get_interface(dev->intf); 8128c2ecf20Sopenharmony_ci /* allow minidriver to stop correctly (wireless devices to turn off 8138c2ecf20Sopenharmony_ci * radio etc) */ 8148c2ecf20Sopenharmony_ci if (info->stop) { 8158c2ecf20Sopenharmony_ci retval = info->stop(dev); 8168c2ecf20Sopenharmony_ci if (retval < 0) 8178c2ecf20Sopenharmony_ci netif_info(dev, ifdown, dev->net, 8188c2ecf20Sopenharmony_ci "stop fail (%d) usbnet usb-%s-%s, %s\n", 8198c2ecf20Sopenharmony_ci retval, 8208c2ecf20Sopenharmony_ci dev->udev->bus->bus_name, dev->udev->devpath, 8218c2ecf20Sopenharmony_ci info->description); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) 8258c2ecf20Sopenharmony_ci usbnet_terminate_urbs(dev); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci usbnet_status_stop(dev); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci usbnet_purge_paused_rxq(dev); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* deferred work (timer, softirq, task) must also stop */ 8348c2ecf20Sopenharmony_ci dev->flags = 0; 8358c2ecf20Sopenharmony_ci del_timer_sync (&dev->delay); 8368c2ecf20Sopenharmony_ci tasklet_kill (&dev->bh); 8378c2ecf20Sopenharmony_ci cancel_work_sync(&dev->kevent); 8388c2ecf20Sopenharmony_ci if (!pm) 8398c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (info->manage_power && mpn) 8428c2ecf20Sopenharmony_ci info->manage_power(dev, 0); 8438c2ecf20Sopenharmony_ci else 8448c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_stop); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci// posts reads, and enables write queuing 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci// precondition: never called in_interrupt 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ciint usbnet_open (struct net_device *net) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 8598c2ecf20Sopenharmony_ci int retval; 8608c2ecf20Sopenharmony_ci const struct driver_info *info = dev->driver_info; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { 8638c2ecf20Sopenharmony_ci netif_info(dev, ifup, dev->net, 8648c2ecf20Sopenharmony_ci "resumption fail (%d) usbnet usb-%s-%s, %s\n", 8658c2ecf20Sopenharmony_ci retval, 8668c2ecf20Sopenharmony_ci dev->udev->bus->bus_name, 8678c2ecf20Sopenharmony_ci dev->udev->devpath, 8688c2ecf20Sopenharmony_ci info->description); 8698c2ecf20Sopenharmony_ci goto done_nopm; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci // put into "known safe" state 8738c2ecf20Sopenharmony_ci if (info->reset && (retval = info->reset (dev)) < 0) { 8748c2ecf20Sopenharmony_ci netif_info(dev, ifup, dev->net, 8758c2ecf20Sopenharmony_ci "open reset fail (%d) usbnet usb-%s-%s, %s\n", 8768c2ecf20Sopenharmony_ci retval, 8778c2ecf20Sopenharmony_ci dev->udev->bus->bus_name, 8788c2ecf20Sopenharmony_ci dev->udev->devpath, 8798c2ecf20Sopenharmony_ci info->description); 8808c2ecf20Sopenharmony_ci goto done; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* hard_mtu or rx_urb_size may change in reset() */ 8848c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci // insist peer be connected 8878c2ecf20Sopenharmony_ci if (info->check_connect && (retval = info->check_connect (dev)) < 0) { 8888c2ecf20Sopenharmony_ci netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval); 8898c2ecf20Sopenharmony_ci goto done; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* start any status interrupt transfer */ 8938c2ecf20Sopenharmony_ci if (dev->interrupt) { 8948c2ecf20Sopenharmony_ci retval = usbnet_status_start(dev, GFP_KERNEL); 8958c2ecf20Sopenharmony_ci if (retval < 0) { 8968c2ecf20Sopenharmony_ci netif_err(dev, ifup, dev->net, 8978c2ecf20Sopenharmony_ci "intr submit %d\n", retval); 8988c2ecf20Sopenharmony_ci goto done; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci set_bit(EVENT_DEV_OPEN, &dev->flags); 9038c2ecf20Sopenharmony_ci netif_start_queue (net); 9048c2ecf20Sopenharmony_ci netif_info(dev, ifup, dev->net, 9058c2ecf20Sopenharmony_ci "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", 9068c2ecf20Sopenharmony_ci (int)RX_QLEN(dev), (int)TX_QLEN(dev), 9078c2ecf20Sopenharmony_ci dev->net->mtu, 9088c2ecf20Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" : 9098c2ecf20Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" : 9108c2ecf20Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" : 9118c2ecf20Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" : 9128c2ecf20Sopenharmony_ci (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : 9138c2ecf20Sopenharmony_ci "simple"); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* reset rx error state */ 9168c2ecf20Sopenharmony_ci dev->pkt_cnt = 0; 9178c2ecf20Sopenharmony_ci dev->pkt_err = 0; 9188c2ecf20Sopenharmony_ci clear_bit(EVENT_RX_KILL, &dev->flags); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci // delay posting reads until we're fully open 9218c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 9228c2ecf20Sopenharmony_ci if (info->manage_power) { 9238c2ecf20Sopenharmony_ci retval = info->manage_power(dev, 1); 9248c2ecf20Sopenharmony_ci if (retval < 0) { 9258c2ecf20Sopenharmony_ci retval = 0; 9268c2ecf20Sopenharmony_ci set_bit(EVENT_NO_RUNTIME_PM, &dev->flags); 9278c2ecf20Sopenharmony_ci } else { 9288c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci return retval; 9328c2ecf20Sopenharmony_cidone: 9338c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 9348c2ecf20Sopenharmony_cidone_nopm: 9358c2ecf20Sopenharmony_ci return retval; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_open); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci/* ethtool methods; minidrivers may need to add some more, but 9428c2ecf20Sopenharmony_ci * they'll probably want to use this base set. 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ciint usbnet_get_link_ksettings(struct net_device *net, 9468c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (!dev->mii.mdio_read) 9518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci mii_ethtool_get_link_ksettings(&dev->mii, cmd); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_link_ksettings); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ciint usbnet_set_link_ksettings(struct net_device *net, 9608c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 9638c2ecf20Sopenharmony_ci int retval; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (!dev->mii.mdio_write) 9668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci retval = mii_ethtool_set_link_ksettings(&dev->mii, cmd); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* link speed/duplex might have changed */ 9718c2ecf20Sopenharmony_ci if (dev->driver_info->link_reset) 9728c2ecf20Sopenharmony_ci dev->driver_info->link_reset(dev); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* hard_mtu or rx_urb_size may change in link_reset() */ 9758c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return retval; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_link_ksettings); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_civoid usbnet_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci netdev_stats_to_stats64(stats, &net->stats); 9868c2ecf20Sopenharmony_ci dev_fetch_sw_netstats(stats, dev->stats64); 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_stats64); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ciu32 usbnet_get_link (struct net_device *net) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* If a check_connect is defined, return its result */ 9958c2ecf20Sopenharmony_ci if (dev->driver_info->check_connect) 9968c2ecf20Sopenharmony_ci return dev->driver_info->check_connect (dev) == 0; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* if the device has mii operations, use those */ 9998c2ecf20Sopenharmony_ci if (dev->mii.mdio_read) 10008c2ecf20Sopenharmony_ci return mii_link_ok(&dev->mii); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */ 10038c2ecf20Sopenharmony_ci return ethtool_op_get_link(net); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_link); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ciint usbnet_nway_reset(struct net_device *net) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (!dev->mii.mdio_write) 10128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return mii_nway_restart(&dev->mii); 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_nway_reset); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_civoid usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci strlcpy (info->driver, dev->driver_name, sizeof info->driver); 10238c2ecf20Sopenharmony_ci strlcpy (info->fw_version, dev->driver_info->description, 10248c2ecf20Sopenharmony_ci sizeof info->fw_version); 10258c2ecf20Sopenharmony_ci usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_drvinfo); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ciu32 usbnet_get_msglevel (struct net_device *net) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return dev->msg_enable; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_get_msglevel); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_civoid usbnet_set_msglevel (struct net_device *net, u32 level) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci dev->msg_enable = level; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_msglevel); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci/* drivers may override default ethtool_ops in their bind() routine */ 10468c2ecf20Sopenharmony_cistatic const struct ethtool_ops usbnet_ethtool_ops = { 10478c2ecf20Sopenharmony_ci .get_link = usbnet_get_link, 10488c2ecf20Sopenharmony_ci .nway_reset = usbnet_nway_reset, 10498c2ecf20Sopenharmony_ci .get_drvinfo = usbnet_get_drvinfo, 10508c2ecf20Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 10518c2ecf20Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 10528c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 10538c2ecf20Sopenharmony_ci .get_link_ksettings = usbnet_get_link_ksettings, 10548c2ecf20Sopenharmony_ci .set_link_ksettings = usbnet_set_link_ksettings, 10558c2ecf20Sopenharmony_ci}; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic void __handle_link_change(struct usbnet *dev) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci if (!test_bit(EVENT_DEV_OPEN, &dev->flags)) 10628c2ecf20Sopenharmony_ci return; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev->net)) { 10658c2ecf20Sopenharmony_ci /* kill URBs for reading packets to save bus bandwidth */ 10668c2ecf20Sopenharmony_ci unlink_urbs(dev, &dev->rxq); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* 10698c2ecf20Sopenharmony_ci * tx_timeout will unlink URBs for sending packets and 10708c2ecf20Sopenharmony_ci * tx queue is stopped by netcore after link becomes off 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci } else { 10738c2ecf20Sopenharmony_ci /* submitting URBs for reading packets */ 10748c2ecf20Sopenharmony_ci tasklet_schedule(&dev->bh); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* hard_mtu or rx_urb_size may change during link change */ 10788c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci clear_bit(EVENT_LINK_CHANGE, &dev->flags); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_civoid usbnet_set_rx_mode(struct net_device *net) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_SET_RX_MODE); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_set_rx_mode); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic void __handle_set_rx_mode(struct usbnet *dev) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci if (dev->driver_info->set_rx_mode) 10948c2ecf20Sopenharmony_ci (dev->driver_info->set_rx_mode)(dev); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci clear_bit(EVENT_SET_RX_MODE, &dev->flags); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/* work that cannot be done in interrupt context uses keventd. 11008c2ecf20Sopenharmony_ci * 11018c2ecf20Sopenharmony_ci * NOTE: with 2.5 we could do more of this using completion callbacks, 11028c2ecf20Sopenharmony_ci * especially now that control transfers can be queued. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_cistatic void 11058c2ecf20Sopenharmony_ciusbnet_deferred_kevent (struct work_struct *work) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct usbnet *dev = 11088c2ecf20Sopenharmony_ci container_of(work, struct usbnet, kevent); 11098c2ecf20Sopenharmony_ci int status; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* usb_clear_halt() needs a thread context */ 11128c2ecf20Sopenharmony_ci if (test_bit (EVENT_TX_HALT, &dev->flags)) { 11138c2ecf20Sopenharmony_ci unlink_urbs (dev, &dev->txq); 11148c2ecf20Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 11158c2ecf20Sopenharmony_ci if (status < 0) 11168c2ecf20Sopenharmony_ci goto fail_pipe; 11178c2ecf20Sopenharmony_ci status = usb_clear_halt (dev->udev, dev->out); 11188c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 11198c2ecf20Sopenharmony_ci if (status < 0 && 11208c2ecf20Sopenharmony_ci status != -EPIPE && 11218c2ecf20Sopenharmony_ci status != -ESHUTDOWN) { 11228c2ecf20Sopenharmony_ci if (netif_msg_tx_err (dev)) 11238c2ecf20Sopenharmony_cifail_pipe: 11248c2ecf20Sopenharmony_ci netdev_err(dev->net, "can't clear tx halt, status %d\n", 11258c2ecf20Sopenharmony_ci status); 11268c2ecf20Sopenharmony_ci } else { 11278c2ecf20Sopenharmony_ci clear_bit (EVENT_TX_HALT, &dev->flags); 11288c2ecf20Sopenharmony_ci if (status != -ESHUTDOWN) 11298c2ecf20Sopenharmony_ci netif_wake_queue (dev->net); 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci if (test_bit (EVENT_RX_HALT, &dev->flags)) { 11338c2ecf20Sopenharmony_ci unlink_urbs (dev, &dev->rxq); 11348c2ecf20Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 11358c2ecf20Sopenharmony_ci if (status < 0) 11368c2ecf20Sopenharmony_ci goto fail_halt; 11378c2ecf20Sopenharmony_ci status = usb_clear_halt (dev->udev, dev->in); 11388c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 11398c2ecf20Sopenharmony_ci if (status < 0 && 11408c2ecf20Sopenharmony_ci status != -EPIPE && 11418c2ecf20Sopenharmony_ci status != -ESHUTDOWN) { 11428c2ecf20Sopenharmony_ci if (netif_msg_rx_err (dev)) 11438c2ecf20Sopenharmony_cifail_halt: 11448c2ecf20Sopenharmony_ci netdev_err(dev->net, "can't clear rx halt, status %d\n", 11458c2ecf20Sopenharmony_ci status); 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci clear_bit (EVENT_RX_HALT, &dev->flags); 11488c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* tasklet could resubmit itself forever if memory is tight */ 11538c2ecf20Sopenharmony_ci if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { 11548c2ecf20Sopenharmony_ci struct urb *urb = NULL; 11558c2ecf20Sopenharmony_ci int resched = 1; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci if (netif_running (dev->net)) 11588c2ecf20Sopenharmony_ci urb = usb_alloc_urb (0, GFP_KERNEL); 11598c2ecf20Sopenharmony_ci else 11608c2ecf20Sopenharmony_ci clear_bit (EVENT_RX_MEMORY, &dev->flags); 11618c2ecf20Sopenharmony_ci if (urb != NULL) { 11628c2ecf20Sopenharmony_ci clear_bit (EVENT_RX_MEMORY, &dev->flags); 11638c2ecf20Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 11648c2ecf20Sopenharmony_ci if (status < 0) { 11658c2ecf20Sopenharmony_ci usb_free_urb(urb); 11668c2ecf20Sopenharmony_ci goto fail_lowmem; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) 11698c2ecf20Sopenharmony_ci resched = 0; 11708c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 11718c2ecf20Sopenharmony_cifail_lowmem: 11728c2ecf20Sopenharmony_ci if (resched) 11738c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (test_bit (EVENT_LINK_RESET, &dev->flags)) { 11788c2ecf20Sopenharmony_ci const struct driver_info *info = dev->driver_info; 11798c2ecf20Sopenharmony_ci int retval = 0; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci clear_bit (EVENT_LINK_RESET, &dev->flags); 11828c2ecf20Sopenharmony_ci status = usb_autopm_get_interface(dev->intf); 11838c2ecf20Sopenharmony_ci if (status < 0) 11848c2ecf20Sopenharmony_ci goto skip_reset; 11858c2ecf20Sopenharmony_ci if(info->link_reset && (retval = info->link_reset(dev)) < 0) { 11868c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 11878c2ecf20Sopenharmony_ciskip_reset: 11888c2ecf20Sopenharmony_ci netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n", 11898c2ecf20Sopenharmony_ci retval, 11908c2ecf20Sopenharmony_ci dev->udev->bus->bus_name, 11918c2ecf20Sopenharmony_ci dev->udev->devpath, 11928c2ecf20Sopenharmony_ci info->description); 11938c2ecf20Sopenharmony_ci } else { 11948c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* handle link change from link resetting */ 11988c2ecf20Sopenharmony_ci __handle_link_change(dev); 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) 12028c2ecf20Sopenharmony_ci __handle_link_change(dev); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (test_bit (EVENT_SET_RX_MODE, &dev->flags)) 12058c2ecf20Sopenharmony_ci __handle_set_rx_mode(dev); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (dev->flags) 12098c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic void tx_complete (struct urb *urb) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *) urb->context; 12178c2ecf20Sopenharmony_ci struct skb_data *entry = (struct skb_data *) skb->cb; 12188c2ecf20Sopenharmony_ci struct usbnet *dev = entry->dev; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (urb->status == 0) { 12218c2ecf20Sopenharmony_ci struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); 12228c2ecf20Sopenharmony_ci unsigned long flags; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci flags = u64_stats_update_begin_irqsave(&stats64->syncp); 12258c2ecf20Sopenharmony_ci stats64->tx_packets += entry->packets; 12268c2ecf20Sopenharmony_ci stats64->tx_bytes += entry->length; 12278c2ecf20Sopenharmony_ci u64_stats_update_end_irqrestore(&stats64->syncp, flags); 12288c2ecf20Sopenharmony_ci } else { 12298c2ecf20Sopenharmony_ci dev->net->stats.tx_errors++; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci switch (urb->status) { 12328c2ecf20Sopenharmony_ci case -EPIPE: 12338c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_TX_HALT); 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* software-driven interface shutdown */ 12378c2ecf20Sopenharmony_ci case -ECONNRESET: // async unlink 12388c2ecf20Sopenharmony_ci case -ESHUTDOWN: // hardware gone 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* like rx, tx gets controller i/o faults during hub_wq 12428c2ecf20Sopenharmony_ci * delays and so it uses the same throttling mechanism. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci case -EPROTO: 12458c2ecf20Sopenharmony_ci case -ETIME: 12468c2ecf20Sopenharmony_ci case -EILSEQ: 12478c2ecf20Sopenharmony_ci usb_mark_last_busy(dev->udev); 12488c2ecf20Sopenharmony_ci if (!timer_pending (&dev->delay)) { 12498c2ecf20Sopenharmony_ci mod_timer (&dev->delay, 12508c2ecf20Sopenharmony_ci jiffies + THROTTLE_JIFFIES); 12518c2ecf20Sopenharmony_ci netif_dbg(dev, link, dev->net, 12528c2ecf20Sopenharmony_ci "tx throttle %d\n", urb->status); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci netif_stop_queue (dev->net); 12558c2ecf20Sopenharmony_ci break; 12568c2ecf20Sopenharmony_ci default: 12578c2ecf20Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, 12588c2ecf20Sopenharmony_ci "tx err %d\n", entry->urb->status); 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 12648c2ecf20Sopenharmony_ci (void) defer_bh(dev, skb, &dev->txq, tx_done); 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_civoid usbnet_tx_timeout (struct net_device *net, unsigned int txqueue) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci unlink_urbs (dev, &dev->txq); 12748c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 12758c2ecf20Sopenharmony_ci /* this needs to be handled individually because the generic layer 12768c2ecf20Sopenharmony_ci * doesn't know what is sufficient and could not restore private 12778c2ecf20Sopenharmony_ci * information if a remedy of an unconditional reset were used. 12788c2ecf20Sopenharmony_ci */ 12798c2ecf20Sopenharmony_ci if (dev->driver_info->recover) 12808c2ecf20Sopenharmony_ci (dev->driver_info->recover)(dev); 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_tx_timeout); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic int build_dma_sg(const struct sk_buff *skb, struct urb *urb) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci unsigned num_sgs, total_len = 0; 12898c2ecf20Sopenharmony_ci int i, s = 0; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci num_sgs = skb_shinfo(skb)->nr_frags + 1; 12928c2ecf20Sopenharmony_ci if (num_sgs == 1) 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* reserve one for zero packet */ 12968c2ecf20Sopenharmony_ci urb->sg = kmalloc_array(num_sgs + 1, sizeof(struct scatterlist), 12978c2ecf20Sopenharmony_ci GFP_ATOMIC); 12988c2ecf20Sopenharmony_ci if (!urb->sg) 12998c2ecf20Sopenharmony_ci return -ENOMEM; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci urb->num_sgs = num_sgs; 13028c2ecf20Sopenharmony_ci sg_init_table(urb->sg, urb->num_sgs + 1); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); 13058c2ecf20Sopenharmony_ci total_len += skb_headlen(skb); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 13088c2ecf20Sopenharmony_ci skb_frag_t *f = &skb_shinfo(skb)->frags[i]; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci total_len += skb_frag_size(f); 13118c2ecf20Sopenharmony_ci sg_set_page(&urb->sg[i + s], skb_frag_page(f), skb_frag_size(f), 13128c2ecf20Sopenharmony_ci skb_frag_off(f)); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci urb->transfer_buffer_length = total_len; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci return 1; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cinetdev_tx_t usbnet_start_xmit (struct sk_buff *skb, 13208c2ecf20Sopenharmony_ci struct net_device *net) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 13238c2ecf20Sopenharmony_ci unsigned int length; 13248c2ecf20Sopenharmony_ci struct urb *urb = NULL; 13258c2ecf20Sopenharmony_ci struct skb_data *entry; 13268c2ecf20Sopenharmony_ci const struct driver_info *info = dev->driver_info; 13278c2ecf20Sopenharmony_ci unsigned long flags; 13288c2ecf20Sopenharmony_ci int retval; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (skb) 13318c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci // some devices want funky USB-level framing, for 13348c2ecf20Sopenharmony_ci // win32 driver (usually) and/or hardware quirks 13358c2ecf20Sopenharmony_ci if (info->tx_fixup) { 13368c2ecf20Sopenharmony_ci skb = info->tx_fixup (dev, skb, GFP_ATOMIC); 13378c2ecf20Sopenharmony_ci if (!skb) { 13388c2ecf20Sopenharmony_ci /* packet collected; minidriver waiting for more */ 13398c2ecf20Sopenharmony_ci if (info->flags & FLAG_MULTI_PACKET) 13408c2ecf20Sopenharmony_ci goto not_drop; 13418c2ecf20Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); 13428c2ecf20Sopenharmony_ci goto drop; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { 13478c2ecf20Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "no urb\n"); 13488c2ecf20Sopenharmony_ci goto drop; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci entry = (struct skb_data *) skb->cb; 13528c2ecf20Sopenharmony_ci entry->urb = urb; 13538c2ecf20Sopenharmony_ci entry->dev = dev; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci usb_fill_bulk_urb (urb, dev->udev, dev->out, 13568c2ecf20Sopenharmony_ci skb->data, skb->len, tx_complete, skb); 13578c2ecf20Sopenharmony_ci if (dev->can_dma_sg) { 13588c2ecf20Sopenharmony_ci if (build_dma_sg(skb, urb) < 0) 13598c2ecf20Sopenharmony_ci goto drop; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci length = urb->transfer_buffer_length; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* don't assume the hardware handles USB_ZERO_PACKET 13648c2ecf20Sopenharmony_ci * NOTE: strictly conforming cdc-ether devices should expect 13658c2ecf20Sopenharmony_ci * the ZLP here, but ignore the one-byte packet. 13668c2ecf20Sopenharmony_ci * NOTE2: CDC NCM specification is different from CDC ECM when 13678c2ecf20Sopenharmony_ci * handling ZLP/short packets, so cdc_ncm driver will make short 13688c2ecf20Sopenharmony_ci * packet itself if needed. 13698c2ecf20Sopenharmony_ci */ 13708c2ecf20Sopenharmony_ci if (length % dev->maxpacket == 0) { 13718c2ecf20Sopenharmony_ci if (!(info->flags & FLAG_SEND_ZLP)) { 13728c2ecf20Sopenharmony_ci if (!(info->flags & FLAG_MULTI_PACKET)) { 13738c2ecf20Sopenharmony_ci length++; 13748c2ecf20Sopenharmony_ci if (skb_tailroom(skb) && !urb->num_sgs) { 13758c2ecf20Sopenharmony_ci skb->data[skb->len] = 0; 13768c2ecf20Sopenharmony_ci __skb_put(skb, 1); 13778c2ecf20Sopenharmony_ci } else if (urb->num_sgs) 13788c2ecf20Sopenharmony_ci sg_set_buf(&urb->sg[urb->num_sgs++], 13798c2ecf20Sopenharmony_ci dev->padding_pkt, 1); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci } else 13828c2ecf20Sopenharmony_ci urb->transfer_flags |= URB_ZERO_PACKET; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci urb->transfer_buffer_length = length; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (info->flags & FLAG_MULTI_PACKET) { 13878c2ecf20Sopenharmony_ci /* Driver has set number of packets and a length delta. 13888c2ecf20Sopenharmony_ci * Calculate the complete length and ensure that it's 13898c2ecf20Sopenharmony_ci * positive. 13908c2ecf20Sopenharmony_ci */ 13918c2ecf20Sopenharmony_ci entry->length += length; 13928c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(entry->length <= 0)) 13938c2ecf20Sopenharmony_ci entry->length = length; 13948c2ecf20Sopenharmony_ci } else { 13958c2ecf20Sopenharmony_ci usbnet_set_skb_tx_stats(skb, 1, length); 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->txq.lock, flags); 13998c2ecf20Sopenharmony_ci retval = usb_autopm_get_interface_async(dev->intf); 14008c2ecf20Sopenharmony_ci if (retval < 0) { 14018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 14028c2ecf20Sopenharmony_ci goto drop; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci if (netif_queue_stopped(net)) { 14058c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 14068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 14078c2ecf20Sopenharmony_ci goto drop; 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 14118c2ecf20Sopenharmony_ci /* if this triggers the device is still a sleep */ 14128c2ecf20Sopenharmony_ci if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { 14138c2ecf20Sopenharmony_ci /* transmission will be done in resume */ 14148c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &dev->deferred); 14158c2ecf20Sopenharmony_ci /* no use to process more packets */ 14168c2ecf20Sopenharmony_ci netif_stop_queue(net); 14178c2ecf20Sopenharmony_ci usb_put_urb(urb); 14188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->txq.lock, flags); 14198c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Delaying transmission for resumption\n"); 14208c2ecf20Sopenharmony_ci goto deferred; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci#endif 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { 14258c2ecf20Sopenharmony_ci case -EPIPE: 14268c2ecf20Sopenharmony_ci netif_stop_queue (net); 14278c2ecf20Sopenharmony_ci usbnet_defer_kevent (dev, EVENT_TX_HALT); 14288c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 14298c2ecf20Sopenharmony_ci break; 14308c2ecf20Sopenharmony_ci default: 14318c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 14328c2ecf20Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, 14338c2ecf20Sopenharmony_ci "tx: submit urb err %d\n", retval); 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case 0: 14368c2ecf20Sopenharmony_ci netif_trans_update(net); 14378c2ecf20Sopenharmony_ci __usbnet_queue_skb(&dev->txq, skb, tx_start); 14388c2ecf20Sopenharmony_ci if (dev->txq.qlen >= TX_QLEN (dev)) 14398c2ecf20Sopenharmony_ci netif_stop_queue (net); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&dev->txq.lock, flags); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (retval) { 14448c2ecf20Sopenharmony_ci netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); 14458c2ecf20Sopenharmony_cidrop: 14468c2ecf20Sopenharmony_ci dev->net->stats.tx_dropped++; 14478c2ecf20Sopenharmony_cinot_drop: 14488c2ecf20Sopenharmony_ci if (skb) 14498c2ecf20Sopenharmony_ci dev_kfree_skb_any (skb); 14508c2ecf20Sopenharmony_ci if (urb) { 14518c2ecf20Sopenharmony_ci kfree(urb->sg); 14528c2ecf20Sopenharmony_ci usb_free_urb(urb); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci } else 14558c2ecf20Sopenharmony_ci netif_dbg(dev, tx_queued, dev->net, 14568c2ecf20Sopenharmony_ci "> tx, len %u, type 0x%x\n", length, skb->protocol); 14578c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 14588c2ecf20Sopenharmony_cideferred: 14598c2ecf20Sopenharmony_ci#endif 14608c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_start_xmit); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic int rx_alloc_submit(struct usbnet *dev, gfp_t flags) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct urb *urb; 14678c2ecf20Sopenharmony_ci int i; 14688c2ecf20Sopenharmony_ci int ret = 0; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* don't refill the queue all at once */ 14718c2ecf20Sopenharmony_ci for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { 14728c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, flags); 14738c2ecf20Sopenharmony_ci if (urb != NULL) { 14748c2ecf20Sopenharmony_ci ret = rx_submit(dev, urb, flags); 14758c2ecf20Sopenharmony_ci if (ret) 14768c2ecf20Sopenharmony_ci goto err; 14778c2ecf20Sopenharmony_ci } else { 14788c2ecf20Sopenharmony_ci ret = -ENOMEM; 14798c2ecf20Sopenharmony_ci goto err; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_cierr: 14838c2ecf20Sopenharmony_ci return ret; 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci// tasklet (work deferred from completions, in_irq) or timer 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic void usbnet_bh (struct timer_list *t) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct usbnet *dev = from_timer(dev, t, delay); 14938c2ecf20Sopenharmony_ci struct sk_buff *skb; 14948c2ecf20Sopenharmony_ci struct skb_data *entry; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci while ((skb = skb_dequeue (&dev->done))) { 14978c2ecf20Sopenharmony_ci entry = (struct skb_data *) skb->cb; 14988c2ecf20Sopenharmony_ci switch (entry->state) { 14998c2ecf20Sopenharmony_ci case rx_done: 15008c2ecf20Sopenharmony_ci entry->state = rx_cleanup; 15018c2ecf20Sopenharmony_ci rx_process (dev, skb); 15028c2ecf20Sopenharmony_ci continue; 15038c2ecf20Sopenharmony_ci case tx_done: 15048c2ecf20Sopenharmony_ci kfree(entry->urb->sg); 15058c2ecf20Sopenharmony_ci fallthrough; 15068c2ecf20Sopenharmony_ci case rx_cleanup: 15078c2ecf20Sopenharmony_ci usb_free_urb (entry->urb); 15088c2ecf20Sopenharmony_ci dev_kfree_skb (skb); 15098c2ecf20Sopenharmony_ci continue; 15108c2ecf20Sopenharmony_ci default: 15118c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* restart RX again after disabling due to high error rate */ 15168c2ecf20Sopenharmony_ci clear_bit(EVENT_RX_KILL, &dev->flags); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* waiting for all pending urbs to complete? 15198c2ecf20Sopenharmony_ci * only then can we forgo submitting anew 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_ci if (waitqueue_active(&dev->wait)) { 15228c2ecf20Sopenharmony_ci if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0) 15238c2ecf20Sopenharmony_ci wake_up_all(&dev->wait); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci // or are we maybe short a few urbs? 15268c2ecf20Sopenharmony_ci } else if (netif_running (dev->net) && 15278c2ecf20Sopenharmony_ci netif_device_present (dev->net) && 15288c2ecf20Sopenharmony_ci netif_carrier_ok(dev->net) && 15298c2ecf20Sopenharmony_ci !timer_pending(&dev->delay) && 15308c2ecf20Sopenharmony_ci !test_bit(EVENT_RX_PAUSED, &dev->flags) && 15318c2ecf20Sopenharmony_ci !test_bit(EVENT_RX_HALT, &dev->flags)) { 15328c2ecf20Sopenharmony_ci int temp = dev->rxq.qlen; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (temp < RX_QLEN(dev)) { 15358c2ecf20Sopenharmony_ci if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK) 15368c2ecf20Sopenharmony_ci return; 15378c2ecf20Sopenharmony_ci if (temp != dev->rxq.qlen) 15388c2ecf20Sopenharmony_ci netif_dbg(dev, link, dev->net, 15398c2ecf20Sopenharmony_ci "rxqlen %d --> %d\n", 15408c2ecf20Sopenharmony_ci temp, dev->rxq.qlen); 15418c2ecf20Sopenharmony_ci if (dev->rxq.qlen < RX_QLEN(dev)) 15428c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci if (dev->txq.qlen < TX_QLEN (dev)) 15458c2ecf20Sopenharmony_ci netif_wake_queue (dev->net); 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_cistatic void usbnet_bh_tasklet(unsigned long data) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci struct timer_list *t = (struct timer_list *)data; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci usbnet_bh(t); 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci/*------------------------------------------------------------------------- 15588c2ecf20Sopenharmony_ci * 15598c2ecf20Sopenharmony_ci * USB Device Driver support 15608c2ecf20Sopenharmony_ci * 15618c2ecf20Sopenharmony_ci *-------------------------------------------------------------------------*/ 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci// precondition: never called in_interrupt 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_civoid usbnet_disconnect (struct usb_interface *intf) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct usbnet *dev; 15688c2ecf20Sopenharmony_ci struct usb_device *xdev; 15698c2ecf20Sopenharmony_ci struct net_device *net; 15708c2ecf20Sopenharmony_ci struct urb *urb; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci dev = usb_get_intfdata(intf); 15738c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 15748c2ecf20Sopenharmony_ci if (!dev) 15758c2ecf20Sopenharmony_ci return; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci xdev = interface_to_usbdev (intf); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n", 15808c2ecf20Sopenharmony_ci intf->dev.driver->name, 15818c2ecf20Sopenharmony_ci xdev->bus->bus_name, xdev->devpath, 15828c2ecf20Sopenharmony_ci dev->driver_info->description); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci net = dev->net; 15858c2ecf20Sopenharmony_ci unregister_netdev (net); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci while ((urb = usb_get_from_anchor(&dev->deferred))) { 15888c2ecf20Sopenharmony_ci dev_kfree_skb(urb->context); 15898c2ecf20Sopenharmony_ci kfree(urb->sg); 15908c2ecf20Sopenharmony_ci usb_free_urb(urb); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (dev->driver_info->unbind) 15948c2ecf20Sopenharmony_ci dev->driver_info->unbind (dev, intf); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci usb_kill_urb(dev->interrupt); 15978c2ecf20Sopenharmony_ci usb_free_urb(dev->interrupt); 15988c2ecf20Sopenharmony_ci kfree(dev->padding_pkt); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci free_percpu(dev->stats64); 16018c2ecf20Sopenharmony_ci free_netdev(net); 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_disconnect); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic const struct net_device_ops usbnet_netdev_ops = { 16068c2ecf20Sopenharmony_ci .ndo_open = usbnet_open, 16078c2ecf20Sopenharmony_ci .ndo_stop = usbnet_stop, 16088c2ecf20Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 16098c2ecf20Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 16108c2ecf20Sopenharmony_ci .ndo_set_rx_mode = usbnet_set_rx_mode, 16118c2ecf20Sopenharmony_ci .ndo_change_mtu = usbnet_change_mtu, 16128c2ecf20Sopenharmony_ci .ndo_get_stats64 = usbnet_get_stats64, 16138c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 16148c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 16158c2ecf20Sopenharmony_ci}; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci// precondition: never called in_interrupt 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic struct device_type wlan_type = { 16228c2ecf20Sopenharmony_ci .name = "wlan", 16238c2ecf20Sopenharmony_ci}; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cistatic struct device_type wwan_type = { 16268c2ecf20Sopenharmony_ci .name = "wwan", 16278c2ecf20Sopenharmony_ci}; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ciint 16308c2ecf20Sopenharmony_ciusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci struct usbnet *dev; 16338c2ecf20Sopenharmony_ci struct net_device *net; 16348c2ecf20Sopenharmony_ci struct usb_host_interface *interface; 16358c2ecf20Sopenharmony_ci const struct driver_info *info; 16368c2ecf20Sopenharmony_ci struct usb_device *xdev; 16378c2ecf20Sopenharmony_ci int status; 16388c2ecf20Sopenharmony_ci const char *name; 16398c2ecf20Sopenharmony_ci struct usb_driver *driver = to_usb_driver(udev->dev.driver); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci /* usbnet already took usb runtime pm, so have to enable the feature 16428c2ecf20Sopenharmony_ci * for usb interface, otherwise usb_autopm_get_interface may return 16438c2ecf20Sopenharmony_ci * failure if RUNTIME_PM is enabled. 16448c2ecf20Sopenharmony_ci */ 16458c2ecf20Sopenharmony_ci if (!driver->supports_autosuspend) { 16468c2ecf20Sopenharmony_ci driver->supports_autosuspend = 1; 16478c2ecf20Sopenharmony_ci pm_runtime_enable(&udev->dev); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci name = udev->dev.driver->name; 16518c2ecf20Sopenharmony_ci info = (const struct driver_info *) prod->driver_info; 16528c2ecf20Sopenharmony_ci if (!info) { 16538c2ecf20Sopenharmony_ci dev_dbg (&udev->dev, "blacklisted by %s\n", name); 16548c2ecf20Sopenharmony_ci return -ENODEV; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci xdev = interface_to_usbdev (udev); 16578c2ecf20Sopenharmony_ci interface = udev->cur_altsetting; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci status = -ENOMEM; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci // set up our own records 16628c2ecf20Sopenharmony_ci net = alloc_etherdev(sizeof(*dev)); 16638c2ecf20Sopenharmony_ci if (!net) 16648c2ecf20Sopenharmony_ci goto out; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* netdev_printk() needs this so do it as early as possible */ 16678c2ecf20Sopenharmony_ci SET_NETDEV_DEV(net, &udev->dev); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci dev = netdev_priv(net); 16708c2ecf20Sopenharmony_ci dev->udev = xdev; 16718c2ecf20Sopenharmony_ci dev->intf = udev; 16728c2ecf20Sopenharmony_ci dev->driver_info = info; 16738c2ecf20Sopenharmony_ci dev->driver_name = name; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci dev->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 16768c2ecf20Sopenharmony_ci if (!dev->stats64) 16778c2ecf20Sopenharmony_ci goto out0; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV 16808c2ecf20Sopenharmony_ci | NETIF_MSG_PROBE | NETIF_MSG_LINK); 16818c2ecf20Sopenharmony_ci init_waitqueue_head(&dev->wait); 16828c2ecf20Sopenharmony_ci skb_queue_head_init (&dev->rxq); 16838c2ecf20Sopenharmony_ci skb_queue_head_init (&dev->txq); 16848c2ecf20Sopenharmony_ci skb_queue_head_init (&dev->done); 16858c2ecf20Sopenharmony_ci skb_queue_head_init(&dev->rxq_pause); 16868c2ecf20Sopenharmony_ci dev->bh.func = usbnet_bh_tasklet; 16878c2ecf20Sopenharmony_ci dev->bh.data = (unsigned long)&dev->delay; 16888c2ecf20Sopenharmony_ci INIT_WORK (&dev->kevent, usbnet_deferred_kevent); 16898c2ecf20Sopenharmony_ci init_usb_anchor(&dev->deferred); 16908c2ecf20Sopenharmony_ci timer_setup(&dev->delay, usbnet_bh, 0); 16918c2ecf20Sopenharmony_ci mutex_init (&dev->phy_mutex); 16928c2ecf20Sopenharmony_ci mutex_init(&dev->interrupt_mutex); 16938c2ecf20Sopenharmony_ci dev->interrupt_count = 0; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci dev->net = net; 16968c2ecf20Sopenharmony_ci strcpy (net->name, "usb%d"); 16978c2ecf20Sopenharmony_ci memcpy (net->dev_addr, node_id, sizeof node_id); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* rx and tx sides can use different message sizes; 17008c2ecf20Sopenharmony_ci * bind() should set rx_urb_size in that case. 17018c2ecf20Sopenharmony_ci */ 17028c2ecf20Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 17038c2ecf20Sopenharmony_ci net->min_mtu = 0; 17048c2ecf20Sopenharmony_ci net->max_mtu = ETH_MAX_MTU; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci net->netdev_ops = &usbnet_netdev_ops; 17078c2ecf20Sopenharmony_ci net->watchdog_timeo = TX_TIMEOUT_JIFFIES; 17088c2ecf20Sopenharmony_ci net->ethtool_ops = &usbnet_ethtool_ops; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci // allow device-specific bind/init procedures 17118c2ecf20Sopenharmony_ci // NOTE net->name still not usable ... 17128c2ecf20Sopenharmony_ci if (info->bind) { 17138c2ecf20Sopenharmony_ci status = info->bind (dev, udev); 17148c2ecf20Sopenharmony_ci if (status < 0) 17158c2ecf20Sopenharmony_ci goto out1; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci // heuristic: "usb%d" for links we know are two-host, 17188c2ecf20Sopenharmony_ci // else "eth%d" when there's reasonable doubt. userspace 17198c2ecf20Sopenharmony_ci // can rename the link if it knows better. 17208c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_ETHER) != 0 && 17218c2ecf20Sopenharmony_ci ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || 17228c2ecf20Sopenharmony_ci (net->dev_addr [0] & 0x02) == 0)) 17238c2ecf20Sopenharmony_ci strcpy (net->name, "eth%d"); 17248c2ecf20Sopenharmony_ci /* WLAN devices should always be named "wlan%d" */ 17258c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WLAN) != 0) 17268c2ecf20Sopenharmony_ci strcpy(net->name, "wlan%d"); 17278c2ecf20Sopenharmony_ci /* WWAN devices should always be named "wwan%d" */ 17288c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WWAN) != 0) 17298c2ecf20Sopenharmony_ci strcpy(net->name, "wwan%d"); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* devices that cannot do ARP */ 17328c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_NOARP) != 0) 17338c2ecf20Sopenharmony_ci net->flags |= IFF_NOARP; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci /* maybe the remote can't receive an Ethernet MTU */ 17368c2ecf20Sopenharmony_ci if (net->mtu > (dev->hard_mtu - net->hard_header_len)) 17378c2ecf20Sopenharmony_ci net->mtu = dev->hard_mtu - net->hard_header_len; 17388c2ecf20Sopenharmony_ci } else if (!info->in || !info->out) 17398c2ecf20Sopenharmony_ci status = usbnet_get_endpoints (dev, udev); 17408c2ecf20Sopenharmony_ci else { 17418c2ecf20Sopenharmony_ci u8 ep_addrs[3] = { 17428c2ecf20Sopenharmony_ci info->in + USB_DIR_IN, info->out + USB_DIR_OUT, 0 17438c2ecf20Sopenharmony_ci }; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci dev->in = usb_rcvbulkpipe (xdev, info->in); 17468c2ecf20Sopenharmony_ci dev->out = usb_sndbulkpipe (xdev, info->out); 17478c2ecf20Sopenharmony_ci if (!(info->flags & FLAG_NO_SETINT)) 17488c2ecf20Sopenharmony_ci status = usb_set_interface (xdev, 17498c2ecf20Sopenharmony_ci interface->desc.bInterfaceNumber, 17508c2ecf20Sopenharmony_ci interface->desc.bAlternateSetting); 17518c2ecf20Sopenharmony_ci else 17528c2ecf20Sopenharmony_ci status = 0; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if (status == 0 && !usb_check_bulk_endpoints(udev, ep_addrs)) 17558c2ecf20Sopenharmony_ci status = -EINVAL; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci if (status >= 0 && dev->status) 17588c2ecf20Sopenharmony_ci status = init_status (dev, udev); 17598c2ecf20Sopenharmony_ci if (status < 0) 17608c2ecf20Sopenharmony_ci goto out3; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (!dev->rx_urb_size) 17638c2ecf20Sopenharmony_ci dev->rx_urb_size = dev->hard_mtu; 17648c2ecf20Sopenharmony_ci dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); 17658c2ecf20Sopenharmony_ci if (dev->maxpacket == 0) { 17668c2ecf20Sopenharmony_ci /* that is a broken device */ 17678c2ecf20Sopenharmony_ci status = -ENODEV; 17688c2ecf20Sopenharmony_ci goto out4; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* let userspace know we have a random address */ 17728c2ecf20Sopenharmony_ci if (ether_addr_equal(net->dev_addr, node_id)) 17738c2ecf20Sopenharmony_ci net->addr_assign_type = NET_ADDR_RANDOM; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WLAN) != 0) 17768c2ecf20Sopenharmony_ci SET_NETDEV_DEVTYPE(net, &wlan_type); 17778c2ecf20Sopenharmony_ci if ((dev->driver_info->flags & FLAG_WWAN) != 0) 17788c2ecf20Sopenharmony_ci SET_NETDEV_DEVTYPE(net, &wwan_type); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci /* initialize max rx_qlen and tx_qlen */ 17818c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) && 17848c2ecf20Sopenharmony_ci !(info->flags & FLAG_MULTI_PACKET)) { 17858c2ecf20Sopenharmony_ci dev->padding_pkt = kzalloc(1, GFP_KERNEL); 17868c2ecf20Sopenharmony_ci if (!dev->padding_pkt) { 17878c2ecf20Sopenharmony_ci status = -ENOMEM; 17888c2ecf20Sopenharmony_ci goto out4; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci status = register_netdev (net); 17938c2ecf20Sopenharmony_ci if (status) 17948c2ecf20Sopenharmony_ci goto out5; 17958c2ecf20Sopenharmony_ci netif_info(dev, probe, dev->net, 17968c2ecf20Sopenharmony_ci "register '%s' at usb-%s-%s, %s, %pM\n", 17978c2ecf20Sopenharmony_ci udev->dev.driver->name, 17988c2ecf20Sopenharmony_ci xdev->bus->bus_name, xdev->devpath, 17998c2ecf20Sopenharmony_ci dev->driver_info->description, 18008c2ecf20Sopenharmony_ci net->dev_addr); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci // ok, it's ready to go. 18038c2ecf20Sopenharmony_ci usb_set_intfdata (udev, dev); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci netif_device_attach (net); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (dev->driver_info->flags & FLAG_LINK_INTR) 18088c2ecf20Sopenharmony_ci usbnet_link_change(dev, 0, 0); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return 0; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ciout5: 18138c2ecf20Sopenharmony_ci kfree(dev->padding_pkt); 18148c2ecf20Sopenharmony_ciout4: 18158c2ecf20Sopenharmony_ci usb_free_urb(dev->interrupt); 18168c2ecf20Sopenharmony_ciout3: 18178c2ecf20Sopenharmony_ci if (info->unbind) 18188c2ecf20Sopenharmony_ci info->unbind (dev, udev); 18198c2ecf20Sopenharmony_ciout1: 18208c2ecf20Sopenharmony_ci /* subdrivers must undo all they did in bind() if they 18218c2ecf20Sopenharmony_ci * fail it, but we may fail later and a deferred kevent 18228c2ecf20Sopenharmony_ci * may trigger an error resubmitting itself and, worse, 18238c2ecf20Sopenharmony_ci * schedule a timer. So we kill it all just in case. 18248c2ecf20Sopenharmony_ci */ 18258c2ecf20Sopenharmony_ci cancel_work_sync(&dev->kevent); 18268c2ecf20Sopenharmony_ci del_timer_sync(&dev->delay); 18278c2ecf20Sopenharmony_ci free_percpu(dev->stats64); 18288c2ecf20Sopenharmony_ciout0: 18298c2ecf20Sopenharmony_ci free_netdev(net); 18308c2ecf20Sopenharmony_ciout: 18318c2ecf20Sopenharmony_ci return status; 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_probe); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci/* 18388c2ecf20Sopenharmony_ci * suspend the whole driver as soon as the first interface is suspended 18398c2ecf20Sopenharmony_ci * resume only when the last interface is resumed 18408c2ecf20Sopenharmony_ci */ 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ciint usbnet_suspend (struct usb_interface *intf, pm_message_t message) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci if (!dev->suspend_count++) { 18478c2ecf20Sopenharmony_ci spin_lock_irq(&dev->txq.lock); 18488c2ecf20Sopenharmony_ci /* don't autosuspend while transmitting */ 18498c2ecf20Sopenharmony_ci if (dev->txq.qlen && PMSG_IS_AUTO(message)) { 18508c2ecf20Sopenharmony_ci dev->suspend_count--; 18518c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 18528c2ecf20Sopenharmony_ci return -EBUSY; 18538c2ecf20Sopenharmony_ci } else { 18548c2ecf20Sopenharmony_ci set_bit(EVENT_DEV_ASLEEP, &dev->flags); 18558c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci /* 18588c2ecf20Sopenharmony_ci * accelerate emptying of the rx and queues, to avoid 18598c2ecf20Sopenharmony_ci * having everything error out. 18608c2ecf20Sopenharmony_ci */ 18618c2ecf20Sopenharmony_ci netif_device_detach (dev->net); 18628c2ecf20Sopenharmony_ci usbnet_terminate_urbs(dev); 18638c2ecf20Sopenharmony_ci __usbnet_status_stop_force(dev); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* 18668c2ecf20Sopenharmony_ci * reattach so runtime management can use and 18678c2ecf20Sopenharmony_ci * wake the device 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_ci netif_device_attach (dev->net); 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci return 0; 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_suspend); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ciint usbnet_resume (struct usb_interface *intf) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 18788c2ecf20Sopenharmony_ci struct sk_buff *skb; 18798c2ecf20Sopenharmony_ci struct urb *res; 18808c2ecf20Sopenharmony_ci int retval; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci if (!--dev->suspend_count) { 18838c2ecf20Sopenharmony_ci /* resume interrupt URB if it was previously submitted */ 18848c2ecf20Sopenharmony_ci __usbnet_status_start_force(dev, GFP_NOIO); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci spin_lock_irq(&dev->txq.lock); 18878c2ecf20Sopenharmony_ci while ((res = usb_get_from_anchor(&dev->deferred))) { 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci skb = (struct sk_buff *)res->context; 18908c2ecf20Sopenharmony_ci retval = usb_submit_urb(res, GFP_ATOMIC); 18918c2ecf20Sopenharmony_ci if (retval < 0) { 18928c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 18938c2ecf20Sopenharmony_ci kfree(res->sg); 18948c2ecf20Sopenharmony_ci usb_free_urb(res); 18958c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 18968c2ecf20Sopenharmony_ci } else { 18978c2ecf20Sopenharmony_ci netif_trans_update(dev->net); 18988c2ecf20Sopenharmony_ci __skb_queue_tail(&dev->txq, skb); 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci smp_mb(); 19038c2ecf20Sopenharmony_ci clear_bit(EVENT_DEV_ASLEEP, &dev->flags); 19048c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->txq.lock); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { 19078c2ecf20Sopenharmony_ci /* handle remote wakeup ASAP 19088c2ecf20Sopenharmony_ci * we cannot race against stop 19098c2ecf20Sopenharmony_ci */ 19108c2ecf20Sopenharmony_ci if (netif_device_present(dev->net) && 19118c2ecf20Sopenharmony_ci !timer_pending(&dev->delay) && 19128c2ecf20Sopenharmony_ci !test_bit(EVENT_RX_HALT, &dev->flags)) 19138c2ecf20Sopenharmony_ci rx_alloc_submit(dev, GFP_NOIO); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (!(dev->txq.qlen >= TX_QLEN(dev))) 19168c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(dev->net); 19178c2ecf20Sopenharmony_ci tasklet_schedule (&dev->bh); 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) 19228c2ecf20Sopenharmony_ci usb_autopm_get_interface_no_resume(intf); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci return 0; 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_resume); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci/* 19298c2ecf20Sopenharmony_ci * Either a subdriver implements manage_power, then it is assumed to always 19308c2ecf20Sopenharmony_ci * be ready to be suspended or it reports the readiness to be suspended 19318c2ecf20Sopenharmony_ci * explicitly 19328c2ecf20Sopenharmony_ci */ 19338c2ecf20Sopenharmony_civoid usbnet_device_suggests_idle(struct usbnet *dev) 19348c2ecf20Sopenharmony_ci{ 19358c2ecf20Sopenharmony_ci if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) { 19368c2ecf20Sopenharmony_ci dev->intf->needs_remote_wakeup = 1; 19378c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(dev->intf); 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(usbnet_device_suggests_idle); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci/* 19438c2ecf20Sopenharmony_ci * For devices that can do without special commands 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_ciint usbnet_manage_power(struct usbnet *dev, int on) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci dev->intf->needs_remote_wakeup = on; 19488c2ecf20Sopenharmony_ci return 0; 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(usbnet_manage_power); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_civoid usbnet_link_change(struct usbnet *dev, bool link, bool need_reset) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci /* update link after link is reseted */ 19558c2ecf20Sopenharmony_ci if (link && !need_reset) 19568c2ecf20Sopenharmony_ci netif_carrier_on(dev->net); 19578c2ecf20Sopenharmony_ci else 19588c2ecf20Sopenharmony_ci netif_carrier_off(dev->net); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (need_reset && link) 19618c2ecf20Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_LINK_RESET); 19628c2ecf20Sopenharmony_ci else 19638c2ecf20Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(usbnet_link_change); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 19688c2ecf20Sopenharmony_cistatic int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 19698c2ecf20Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci void *buf = NULL; 19728c2ecf20Sopenharmony_ci int err = -ENOMEM; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "usbnet_read_cmd cmd=0x%02x reqtype=%02x" 19758c2ecf20Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 19768c2ecf20Sopenharmony_ci cmd, reqtype, value, index, size); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (size) { 19798c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_NOIO); 19808c2ecf20Sopenharmony_ci if (!buf) 19818c2ecf20Sopenharmony_ci goto out; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci err = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), 19858c2ecf20Sopenharmony_ci cmd, reqtype, value, index, buf, size, 19868c2ecf20Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 19878c2ecf20Sopenharmony_ci if (err > 0 && err <= size) { 19888c2ecf20Sopenharmony_ci if (data) 19898c2ecf20Sopenharmony_ci memcpy(data, buf, err); 19908c2ecf20Sopenharmony_ci else 19918c2ecf20Sopenharmony_ci netdev_dbg(dev->net, 19928c2ecf20Sopenharmony_ci "Huh? Data requested but thrown away.\n"); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci kfree(buf); 19958c2ecf20Sopenharmony_ciout: 19968c2ecf20Sopenharmony_ci return err; 19978c2ecf20Sopenharmony_ci} 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_cistatic int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 20008c2ecf20Sopenharmony_ci u16 value, u16 index, const void *data, 20018c2ecf20Sopenharmony_ci u16 size) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci void *buf = NULL; 20048c2ecf20Sopenharmony_ci int err = -ENOMEM; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" 20078c2ecf20Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 20088c2ecf20Sopenharmony_ci cmd, reqtype, value, index, size); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (data) { 20118c2ecf20Sopenharmony_ci buf = kmemdup(data, size, GFP_NOIO); 20128c2ecf20Sopenharmony_ci if (!buf) 20138c2ecf20Sopenharmony_ci goto out; 20148c2ecf20Sopenharmony_ci } else { 20158c2ecf20Sopenharmony_ci if (size) { 20168c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 20178c2ecf20Sopenharmony_ci err = -EINVAL; 20188c2ecf20Sopenharmony_ci goto out; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 20238c2ecf20Sopenharmony_ci cmd, reqtype, value, index, buf, size, 20248c2ecf20Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 20258c2ecf20Sopenharmony_ci kfree(buf); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ciout: 20288c2ecf20Sopenharmony_ci return err; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci/* 20328c2ecf20Sopenharmony_ci * The function can't be called inside suspend/resume callback, 20338c2ecf20Sopenharmony_ci * otherwise deadlock will be caused. 20348c2ecf20Sopenharmony_ci */ 20358c2ecf20Sopenharmony_ciint usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 20368c2ecf20Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci int ret; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(dev->intf) < 0) 20418c2ecf20Sopenharmony_ci return -ENODEV; 20428c2ecf20Sopenharmony_ci ret = __usbnet_read_cmd(dev, cmd, reqtype, value, index, 20438c2ecf20Sopenharmony_ci data, size); 20448c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 20458c2ecf20Sopenharmony_ci return ret; 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_read_cmd); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci/* 20508c2ecf20Sopenharmony_ci * The function can't be called inside suspend/resume callback, 20518c2ecf20Sopenharmony_ci * otherwise deadlock will be caused. 20528c2ecf20Sopenharmony_ci */ 20538c2ecf20Sopenharmony_ciint usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 20548c2ecf20Sopenharmony_ci u16 value, u16 index, const void *data, u16 size) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci int ret; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(dev->intf) < 0) 20598c2ecf20Sopenharmony_ci return -ENODEV; 20608c2ecf20Sopenharmony_ci ret = __usbnet_write_cmd(dev, cmd, reqtype, value, index, 20618c2ecf20Sopenharmony_ci data, size); 20628c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 20638c2ecf20Sopenharmony_ci return ret; 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci/* 20688c2ecf20Sopenharmony_ci * The function can be called inside suspend/resume callback safely 20698c2ecf20Sopenharmony_ci * and should only be called by suspend/resume callback generally. 20708c2ecf20Sopenharmony_ci */ 20718c2ecf20Sopenharmony_ciint usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, 20728c2ecf20Sopenharmony_ci u16 value, u16 index, void *data, u16 size) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci return __usbnet_read_cmd(dev, cmd, reqtype, value, index, 20758c2ecf20Sopenharmony_ci data, size); 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_read_cmd_nopm); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci/* 20808c2ecf20Sopenharmony_ci * The function can be called inside suspend/resume callback safely 20818c2ecf20Sopenharmony_ci * and should only be called by suspend/resume callback generally. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ciint usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, 20848c2ecf20Sopenharmony_ci u16 value, u16 index, const void *data, 20858c2ecf20Sopenharmony_ci u16 size) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci return __usbnet_write_cmd(dev, cmd, reqtype, value, index, 20888c2ecf20Sopenharmony_ci data, size); 20898c2ecf20Sopenharmony_ci} 20908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd_nopm); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cistatic void usbnet_async_cmd_cb(struct urb *urb) 20938c2ecf20Sopenharmony_ci{ 20948c2ecf20Sopenharmony_ci struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; 20958c2ecf20Sopenharmony_ci int status = urb->status; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci if (status < 0) 20988c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s failed with %d", 20998c2ecf20Sopenharmony_ci __func__, status); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci kfree(req); 21028c2ecf20Sopenharmony_ci usb_free_urb(urb); 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci/* 21068c2ecf20Sopenharmony_ci * The caller must make sure that device can't be put into suspend 21078c2ecf20Sopenharmony_ci * state until the control URB completes. 21088c2ecf20Sopenharmony_ci */ 21098c2ecf20Sopenharmony_ciint usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, 21108c2ecf20Sopenharmony_ci u16 value, u16 index, const void *data, u16 size) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct usb_ctrlrequest *req; 21138c2ecf20Sopenharmony_ci struct urb *urb; 21148c2ecf20Sopenharmony_ci int err = -ENOMEM; 21158c2ecf20Sopenharmony_ci void *buf = NULL; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" 21188c2ecf20Sopenharmony_ci " value=0x%04x index=0x%04x size=%d\n", 21198c2ecf20Sopenharmony_ci cmd, reqtype, value, index, size); 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 21228c2ecf20Sopenharmony_ci if (!urb) 21238c2ecf20Sopenharmony_ci goto fail; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (data) { 21268c2ecf20Sopenharmony_ci buf = kmemdup(data, size, GFP_ATOMIC); 21278c2ecf20Sopenharmony_ci if (!buf) { 21288c2ecf20Sopenharmony_ci netdev_err(dev->net, "Error allocating buffer" 21298c2ecf20Sopenharmony_ci " in %s!\n", __func__); 21308c2ecf20Sopenharmony_ci goto fail_free_urb; 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 21358c2ecf20Sopenharmony_ci if (!req) 21368c2ecf20Sopenharmony_ci goto fail_free_buf; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci req->bRequestType = reqtype; 21398c2ecf20Sopenharmony_ci req->bRequest = cmd; 21408c2ecf20Sopenharmony_ci req->wValue = cpu_to_le16(value); 21418c2ecf20Sopenharmony_ci req->wIndex = cpu_to_le16(index); 21428c2ecf20Sopenharmony_ci req->wLength = cpu_to_le16(size); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci usb_fill_control_urb(urb, dev->udev, 21458c2ecf20Sopenharmony_ci usb_sndctrlpipe(dev->udev, 0), 21468c2ecf20Sopenharmony_ci (void *)req, buf, size, 21478c2ecf20Sopenharmony_ci usbnet_async_cmd_cb, req); 21488c2ecf20Sopenharmony_ci urb->transfer_flags |= URB_FREE_BUFFER; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci err = usb_submit_urb(urb, GFP_ATOMIC); 21518c2ecf20Sopenharmony_ci if (err < 0) { 21528c2ecf20Sopenharmony_ci netdev_err(dev->net, "Error submitting the control" 21538c2ecf20Sopenharmony_ci " message: status=%d\n", err); 21548c2ecf20Sopenharmony_ci goto fail_free_all; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci return 0; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_cifail_free_all: 21598c2ecf20Sopenharmony_ci kfree(req); 21608c2ecf20Sopenharmony_cifail_free_buf: 21618c2ecf20Sopenharmony_ci kfree(buf); 21628c2ecf20Sopenharmony_ci /* 21638c2ecf20Sopenharmony_ci * avoid a double free 21648c2ecf20Sopenharmony_ci * needed because the flag can be set only 21658c2ecf20Sopenharmony_ci * after filling the URB 21668c2ecf20Sopenharmony_ci */ 21678c2ecf20Sopenharmony_ci urb->transfer_flags = 0; 21688c2ecf20Sopenharmony_cifail_free_urb: 21698c2ecf20Sopenharmony_ci usb_free_urb(urb); 21708c2ecf20Sopenharmony_cifail: 21718c2ecf20Sopenharmony_ci return err; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usbnet_write_cmd_async); 21758c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_cistatic int __init usbnet_init(void) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci /* Compiler should optimize this out. */ 21808c2ecf20Sopenharmony_ci BUILD_BUG_ON( 21818c2ecf20Sopenharmony_ci sizeof_field(struct sk_buff, cb) < sizeof(struct skb_data)); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci eth_random_addr(node_id); 21848c2ecf20Sopenharmony_ci return 0; 21858c2ecf20Sopenharmony_ci} 21868c2ecf20Sopenharmony_cimodule_init(usbnet_init); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_cistatic void __exit usbnet_exit(void) 21898c2ecf20Sopenharmony_ci{ 21908c2ecf20Sopenharmony_ci} 21918c2ecf20Sopenharmony_cimodule_exit(usbnet_exit); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Brownell"); 21948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("USB network driver framework"); 21958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2196