18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Wireless WiMAX Connection 2400m 48c2ecf20Sopenharmony_ci * Glue with the networking stack 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com> 78c2ecf20Sopenharmony_ci * Yanir Lubetkin <yanirx.lubetkin@intel.com> 88c2ecf20Sopenharmony_ci * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This implements an ethernet device for the i2400m. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * We fake being an ethernet device to simplify the support from user 138c2ecf20Sopenharmony_ci * space and from the other side. The world is (sadly) configured to 148c2ecf20Sopenharmony_ci * take in only Ethernet devices... 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Because of this, when using firmwares <= v1.3, there is an 178c2ecf20Sopenharmony_ci * copy-each-rxed-packet overhead on the RX path. Each IP packet has 188c2ecf20Sopenharmony_ci * to be reallocated to add an ethernet header (as there is no space 198c2ecf20Sopenharmony_ci * in what we get from the device). This is a known drawback and 208c2ecf20Sopenharmony_ci * firmwares >= 1.4 add header space that can be used to insert the 218c2ecf20Sopenharmony_ci * ethernet header without having to reallocate and copy. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * TX error handling is tricky; because we have to FIFO/queue the 248c2ecf20Sopenharmony_ci * buffers for transmission (as the hardware likes it aggregated), we 258c2ecf20Sopenharmony_ci * just give the skb to the TX subsystem and by the time it is 268c2ecf20Sopenharmony_ci * transmitted, we have long forgotten about it. So we just don't care 278c2ecf20Sopenharmony_ci * too much about it. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Note that when the device is in idle mode with the basestation, we 308c2ecf20Sopenharmony_ci * need to negotiate coming back up online. That involves negotiation 318c2ecf20Sopenharmony_ci * and possible user space interaction. Thus, we defer to a workqueue 328c2ecf20Sopenharmony_ci * to do all that. By default, we only queue a single packet and drop 338c2ecf20Sopenharmony_ci * the rest, as potentially the time to go back from idle to normal is 348c2ecf20Sopenharmony_ci * long. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * ROADMAP 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * i2400m_open Called on ifconfig up 398c2ecf20Sopenharmony_ci * i2400m_stop Called on ifconfig down 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * i2400m_hard_start_xmit Called by the network stack to send a packet 428c2ecf20Sopenharmony_ci * i2400m_net_wake_tx Wake up device from basestation-IDLE & TX 438c2ecf20Sopenharmony_ci * i2400m_wake_tx_work 448c2ecf20Sopenharmony_ci * i2400m_cmd_exit_idle 458c2ecf20Sopenharmony_ci * i2400m_tx 468c2ecf20Sopenharmony_ci * i2400m_net_tx TX a data frame 478c2ecf20Sopenharmony_ci * i2400m_tx 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * i2400m_change_mtu Called on ifconfig mtu XXX 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * i2400m_tx_timeout Called when the device times out 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * i2400m_net_rx Called by the RX code when a data frame is 548c2ecf20Sopenharmony_ci * available (firmware <= 1.3) 558c2ecf20Sopenharmony_ci * i2400m_net_erx Called by the RX code when a data frame is 568c2ecf20Sopenharmony_ci * available (firmware >= 1.4). 578c2ecf20Sopenharmony_ci * i2400m_netdev_setup Called to setup all the netdev stuff from 588c2ecf20Sopenharmony_ci * alloc_netdev. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 618c2ecf20Sopenharmony_ci#include <linux/slab.h> 628c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 638c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 648c2ecf20Sopenharmony_ci#include <linux/export.h> 658c2ecf20Sopenharmony_ci#include "i2400m.h" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define D_SUBMODULE netdev 698c2ecf20Sopenharmony_ci#include "debug-levels.h" 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cienum { 728c2ecf20Sopenharmony_ci/* netdev interface */ 738c2ecf20Sopenharmony_ci /* 20 secs? yep, this is the maximum timeout that the device 748c2ecf20Sopenharmony_ci * might take to get out of IDLE / negotiate it with the base 758c2ecf20Sopenharmony_ci * station. We add 1sec for good measure. */ 768c2ecf20Sopenharmony_ci I2400M_TX_TIMEOUT = 21 * HZ, 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * Experimentation has determined that, 20 to be a good value 798c2ecf20Sopenharmony_ci * for minimizing the jitter in the throughput. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci I2400M_TX_QLEN = 20, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic 868c2ecf20Sopenharmony_ciint i2400m_open(struct net_device *net_dev) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci int result; 898c2ecf20Sopenharmony_ci struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 908c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); 938c2ecf20Sopenharmony_ci /* Make sure we wait until init is complete... */ 948c2ecf20Sopenharmony_ci mutex_lock(&i2400m->init_mutex); 958c2ecf20Sopenharmony_ci if (i2400m->updown) 968c2ecf20Sopenharmony_ci result = 0; 978c2ecf20Sopenharmony_ci else 988c2ecf20Sopenharmony_ci result = -EBUSY; 998c2ecf20Sopenharmony_ci mutex_unlock(&i2400m->init_mutex); 1008c2ecf20Sopenharmony_ci d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", 1018c2ecf20Sopenharmony_ci net_dev, i2400m, result); 1028c2ecf20Sopenharmony_ci return result; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic 1078c2ecf20Sopenharmony_ciint i2400m_stop(struct net_device *net_dev) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 1108c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); 1138c2ecf20Sopenharmony_ci i2400m_net_wake_stop(i2400m); 1148c2ecf20Sopenharmony_ci d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m); 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Wake up the device and transmit a held SKB, then restart the net queue 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * When the device goes into basestation-idle mode, we need to tell it 1238c2ecf20Sopenharmony_ci * to exit that mode; it will negotiate with the base station, user 1248c2ecf20Sopenharmony_ci * space may have to intervene to rehandshake crypto and then tell us 1258c2ecf20Sopenharmony_ci * when it is ready to transmit the packet we have "queued". Still we 1268c2ecf20Sopenharmony_ci * need to give it sometime after it reports being ok. 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * On error, there is not much we can do. If the error was on TX, we 1298c2ecf20Sopenharmony_ci * still wake the queue up to see if the next packet will be luckier. 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * If _cmd_exit_idle() fails...well, it could be many things; most 1328c2ecf20Sopenharmony_ci * commonly it is that something else took the device out of IDLE mode 1338c2ecf20Sopenharmony_ci * (for example, the base station). In that case we get an -EILSEQ and 1348c2ecf20Sopenharmony_ci * we are just going to ignore that one. If the device is back to 1358c2ecf20Sopenharmony_ci * connected, then fine -- if it is someother state, the packet will 1368c2ecf20Sopenharmony_ci * be dropped anyway. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_civoid i2400m_wake_tx_work(struct work_struct *ws) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int result; 1418c2ecf20Sopenharmony_ci struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); 1428c2ecf20Sopenharmony_ci struct net_device *net_dev = i2400m->wimax_dev.net_dev; 1438c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 1448c2ecf20Sopenharmony_ci struct sk_buff *skb; 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2400m->tx_lock, flags); 1488c2ecf20Sopenharmony_ci skb = i2400m->wake_tx_skb; 1498c2ecf20Sopenharmony_ci i2400m->wake_tx_skb = NULL; 1508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2400m->tx_lock, flags); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb); 1538c2ecf20Sopenharmony_ci result = -EINVAL; 1548c2ecf20Sopenharmony_ci if (skb == NULL) { 1558c2ecf20Sopenharmony_ci dev_err(dev, "WAKE&TX: skb disappeared!\n"); 1568c2ecf20Sopenharmony_ci goto out_put; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci /* If we have, somehow, lost the connection after this was 1598c2ecf20Sopenharmony_ci * queued, don't do anything; this might be the device got 1608c2ecf20Sopenharmony_ci * reset or just disconnected. */ 1618c2ecf20Sopenharmony_ci if (unlikely(!netif_carrier_ok(net_dev))) 1628c2ecf20Sopenharmony_ci goto out_kfree; 1638c2ecf20Sopenharmony_ci result = i2400m_cmd_exit_idle(i2400m); 1648c2ecf20Sopenharmony_ci if (result == -EILSEQ) 1658c2ecf20Sopenharmony_ci result = 0; 1668c2ecf20Sopenharmony_ci if (result < 0) { 1678c2ecf20Sopenharmony_ci dev_err(dev, "WAKE&TX: device didn't get out of idle: " 1688c2ecf20Sopenharmony_ci "%d - resetting\n", result); 1698c2ecf20Sopenharmony_ci i2400m_reset(i2400m, I2400M_RT_BUS); 1708c2ecf20Sopenharmony_ci goto error; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci result = wait_event_timeout(i2400m->state_wq, 1738c2ecf20Sopenharmony_ci i2400m->state != I2400M_SS_IDLE, 1748c2ecf20Sopenharmony_ci net_dev->watchdog_timeo - HZ/2); 1758c2ecf20Sopenharmony_ci if (result == 0) 1768c2ecf20Sopenharmony_ci result = -ETIMEDOUT; 1778c2ecf20Sopenharmony_ci if (result < 0) { 1788c2ecf20Sopenharmony_ci dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: " 1798c2ecf20Sopenharmony_ci "%d - resetting\n", result); 1808c2ecf20Sopenharmony_ci i2400m_reset(i2400m, I2400M_RT_BUS); 1818c2ecf20Sopenharmony_ci goto error; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci msleep(20); /* device still needs some time or it drops it */ 1848c2ecf20Sopenharmony_ci result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); 1858c2ecf20Sopenharmony_cierror: 1868c2ecf20Sopenharmony_ci netif_wake_queue(net_dev); 1878c2ecf20Sopenharmony_ciout_kfree: 1888c2ecf20Sopenharmony_ci kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ 1898c2ecf20Sopenharmony_ciout_put: 1908c2ecf20Sopenharmony_ci i2400m_put(i2400m); 1918c2ecf20Sopenharmony_ci d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n", 1928c2ecf20Sopenharmony_ci ws, i2400m, skb, result); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * Prepare the data payload TX header 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * The i2400m expects a 4 byte header in front of a data packet. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * Because we pretend to be an ethernet device, this packet comes with 2028c2ecf20Sopenharmony_ci * an ethernet header. Pull it and push our header. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic 2058c2ecf20Sopenharmony_civoid i2400m_tx_prep_header(struct sk_buff *skb) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct i2400m_pl_data_hdr *pl_hdr; 2088c2ecf20Sopenharmony_ci skb_pull(skb, ETH_HLEN); 2098c2ecf20Sopenharmony_ci pl_hdr = skb_push(skb, sizeof(*pl_hdr)); 2108c2ecf20Sopenharmony_ci pl_hdr->reserved = 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* 2168c2ecf20Sopenharmony_ci * Cleanup resources acquired during i2400m_net_wake_tx() 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * This is called by __i2400m_dev_stop and means we have to make sure 2198c2ecf20Sopenharmony_ci * the workqueue is flushed from any pending work. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_civoid i2400m_net_wake_stop(struct i2400m *i2400m) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 2248c2ecf20Sopenharmony_ci struct sk_buff *wake_tx_skb; 2258c2ecf20Sopenharmony_ci unsigned long flags; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(i2400m %p)\n", i2400m); 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * See i2400m_hard_start_xmit(), references are taken there and 2308c2ecf20Sopenharmony_ci * here we release them if the packet was still pending. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci cancel_work_sync(&i2400m->wake_tx_ws); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2400m->tx_lock, flags); 2358c2ecf20Sopenharmony_ci wake_tx_skb = i2400m->wake_tx_skb; 2368c2ecf20Sopenharmony_ci i2400m->wake_tx_skb = NULL; 2378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2400m->tx_lock, flags); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (wake_tx_skb) { 2408c2ecf20Sopenharmony_ci i2400m_put(i2400m); 2418c2ecf20Sopenharmony_ci kfree_skb(wake_tx_skb); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* 2498c2ecf20Sopenharmony_ci * TX an skb to an idle device 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * When the device is in basestation-idle mode, we need to wake it up 2528c2ecf20Sopenharmony_ci * and then TX. So we queue a work_struct for doing so. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * We need to get an extra ref for the skb (so it is not dropped), as 2558c2ecf20Sopenharmony_ci * well as be careful not to queue more than one request (won't help 2568c2ecf20Sopenharmony_ci * at all). If more than one request comes or there are errors, we 2578c2ecf20Sopenharmony_ci * just drop the packets (see i2400m_hard_start_xmit()). 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_cistatic 2608c2ecf20Sopenharmony_ciint i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev, 2618c2ecf20Sopenharmony_ci struct sk_buff *skb) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci int result; 2648c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 2658c2ecf20Sopenharmony_ci unsigned long flags; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); 2688c2ecf20Sopenharmony_ci if (net_ratelimit()) { 2698c2ecf20Sopenharmony_ci d_printf(3, dev, "WAKE&NETTX: " 2708c2ecf20Sopenharmony_ci "skb %p sending %d bytes to radio\n", 2718c2ecf20Sopenharmony_ci skb, skb->len); 2728c2ecf20Sopenharmony_ci d_dump(4, dev, skb->data, skb->len); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci /* We hold a ref count for i2400m and skb, so when 2758c2ecf20Sopenharmony_ci * stopping() the device, we need to cancel that work 2768c2ecf20Sopenharmony_ci * and if pending, release those resources. */ 2778c2ecf20Sopenharmony_ci result = 0; 2788c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2400m->tx_lock, flags); 2798c2ecf20Sopenharmony_ci if (!i2400m->wake_tx_skb) { 2808c2ecf20Sopenharmony_ci netif_stop_queue(net_dev); 2818c2ecf20Sopenharmony_ci i2400m_get(i2400m); 2828c2ecf20Sopenharmony_ci i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */ 2838c2ecf20Sopenharmony_ci i2400m_tx_prep_header(skb); 2848c2ecf20Sopenharmony_ci result = schedule_work(&i2400m->wake_tx_ws); 2858c2ecf20Sopenharmony_ci WARN_ON(result == 0); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2400m->tx_lock, flags); 2888c2ecf20Sopenharmony_ci if (result == 0) { 2898c2ecf20Sopenharmony_ci /* Yes, this happens even if we stopped the 2908c2ecf20Sopenharmony_ci * queue -- blame the queue disciplines that 2918c2ecf20Sopenharmony_ci * queue without looking -- I guess there is a reason 2928c2ecf20Sopenharmony_ci * for that. */ 2938c2ecf20Sopenharmony_ci if (net_ratelimit()) 2948c2ecf20Sopenharmony_ci d_printf(1, dev, "NETTX: device exiting idle, " 2958c2ecf20Sopenharmony_ci "dropping skb %p, queue running %d\n", 2968c2ecf20Sopenharmony_ci skb, netif_queue_stopped(net_dev)); 2978c2ecf20Sopenharmony_ci result = -EBUSY; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); 3008c2ecf20Sopenharmony_ci return result; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* 3058c2ecf20Sopenharmony_ci * Transmit a packet to the base station on behalf of the network stack. 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Returns: 0 if ok, < 0 errno code on error. 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * We need to pull the ethernet header and add the hardware header, 3108c2ecf20Sopenharmony_ci * which is currently set to all zeroes and reserved. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_cistatic 3138c2ecf20Sopenharmony_ciint i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev, 3148c2ecf20Sopenharmony_ci struct sk_buff *skb) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci int result; 3178c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n", 3208c2ecf20Sopenharmony_ci i2400m, net_dev, skb); 3218c2ecf20Sopenharmony_ci /* FIXME: check eth hdr, only IPv4 is routed by the device as of now */ 3228c2ecf20Sopenharmony_ci netif_trans_update(net_dev); 3238c2ecf20Sopenharmony_ci i2400m_tx_prep_header(skb); 3248c2ecf20Sopenharmony_ci d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n", 3258c2ecf20Sopenharmony_ci skb, skb->len); 3268c2ecf20Sopenharmony_ci d_dump(4, dev, skb->data, skb->len); 3278c2ecf20Sopenharmony_ci result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); 3288c2ecf20Sopenharmony_ci d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n", 3298c2ecf20Sopenharmony_ci i2400m, net_dev, skb, result); 3308c2ecf20Sopenharmony_ci return result; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * Transmit a packet to the base station on behalf of the network stack 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * Returns: NETDEV_TX_OK (always, even in case of error) 3398c2ecf20Sopenharmony_ci * 3408c2ecf20Sopenharmony_ci * In case of error, we just drop it. Reasons: 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * - we add a hw header to each skb, and if the network stack 3438c2ecf20Sopenharmony_ci * retries, we have no way to know if that skb has it or not. 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * - network protocols have their own drop-recovery mechanisms 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * - there is not much else we can do 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * If the device is idle, we need to wake it up; that is an operation 3508c2ecf20Sopenharmony_ci * that will sleep. See i2400m_net_wake_tx() for details. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic 3538c2ecf20Sopenharmony_cinetdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, 3548c2ecf20Sopenharmony_ci struct net_device *net_dev) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 3578c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 3588c2ecf20Sopenharmony_ci int result = -1; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (skb_cow_head(skb, 0)) 3638c2ecf20Sopenharmony_ci goto drop; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (i2400m->state == I2400M_SS_IDLE) 3668c2ecf20Sopenharmony_ci result = i2400m_net_wake_tx(i2400m, net_dev, skb); 3678c2ecf20Sopenharmony_ci else 3688c2ecf20Sopenharmony_ci result = i2400m_net_tx(i2400m, net_dev, skb); 3698c2ecf20Sopenharmony_ci if (result < 0) { 3708c2ecf20Sopenharmony_cidrop: 3718c2ecf20Sopenharmony_ci net_dev->stats.tx_dropped++; 3728c2ecf20Sopenharmony_ci } else { 3738c2ecf20Sopenharmony_ci net_dev->stats.tx_packets++; 3748c2ecf20Sopenharmony_ci net_dev->stats.tx_bytes += skb->len; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3778c2ecf20Sopenharmony_ci d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); 3788c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic 3838c2ecf20Sopenharmony_civoid i2400m_tx_timeout(struct net_device *net_dev, unsigned int txqueue) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * We might want to kick the device 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * There is not much we can do though, as the device requires 3898c2ecf20Sopenharmony_ci * that we send the data aggregated. By the time we receive 3908c2ecf20Sopenharmony_ci * this, there might be data pending to be sent or not... 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci net_dev->stats.tx_errors++; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* 3978c2ecf20Sopenharmony_ci * Create a fake ethernet header 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * For emulating an ethernet device, every received IP header has to 4008c2ecf20Sopenharmony_ci * be prefixed with an ethernet header. Fake it with the given 4018c2ecf20Sopenharmony_ci * protocol. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_cistatic 4048c2ecf20Sopenharmony_civoid i2400m_rx_fake_eth_header(struct net_device *net_dev, 4058c2ecf20Sopenharmony_ci void *_eth_hdr, __be16 protocol) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 4088c2ecf20Sopenharmony_ci struct ethhdr *eth_hdr = _eth_hdr; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); 4118c2ecf20Sopenharmony_ci memcpy(eth_hdr->h_source, i2400m->src_mac_addr, 4128c2ecf20Sopenharmony_ci sizeof(eth_hdr->h_source)); 4138c2ecf20Sopenharmony_ci eth_hdr->h_proto = protocol; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* 4188c2ecf20Sopenharmony_ci * i2400m_net_rx - pass a network packet to the stack 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * @i2400m: device instance 4218c2ecf20Sopenharmony_ci * @skb_rx: the skb where the buffer pointed to by @buf is 4228c2ecf20Sopenharmony_ci * @i: 1 if payload is the only one 4238c2ecf20Sopenharmony_ci * @buf: pointer to the buffer containing the data 4248c2ecf20Sopenharmony_ci * @len: buffer's length 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * This is only used now for the v1.3 firmware. It will be deprecated 4278c2ecf20Sopenharmony_ci * in >= 2.6.31. 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * Note that due to firmware limitations, we don't have space to add 4308c2ecf20Sopenharmony_ci * an ethernet header, so we need to copy each packet. Firmware 4318c2ecf20Sopenharmony_ci * versions >= v1.4 fix this [see i2400m_net_erx()]. 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * We just clone the skb and set it up so that it's skb->data pointer 4348c2ecf20Sopenharmony_ci * points to "buf" and it's length. 4358c2ecf20Sopenharmony_ci * 4368c2ecf20Sopenharmony_ci * Note that if the payload is the last (or the only one) in a 4378c2ecf20Sopenharmony_ci * multi-payload message, we don't clone the SKB but just reuse it. 4388c2ecf20Sopenharmony_ci * 4398c2ecf20Sopenharmony_ci * This function is normally run from a thread context. However, we 4408c2ecf20Sopenharmony_ci * still use netif_rx() instead of netif_receive_skb() as was 4418c2ecf20Sopenharmony_ci * recommended in the mailing list. Reason is in some stress tests 4428c2ecf20Sopenharmony_ci * when sending/receiving a lot of data we seem to hit a softlock in 4438c2ecf20Sopenharmony_ci * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using 4448c2ecf20Sopenharmony_ci * netif_rx() took care of the issue. 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * This is, of course, still open to do more research on why running 4478c2ecf20Sopenharmony_ci * with netif_receive_skb() hits this softlock. FIXME. 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * FIXME: currently we don't do any efforts at distinguishing if what 4508c2ecf20Sopenharmony_ci * we got was an IPv4 or IPv6 header, to setup the protocol field 4518c2ecf20Sopenharmony_ci * correctly. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_civoid i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx, 4548c2ecf20Sopenharmony_ci unsigned i, const void *buf, int buf_len) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct net_device *net_dev = i2400m->wimax_dev.net_dev; 4578c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 4588c2ecf20Sopenharmony_ci struct sk_buff *skb; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci d_fnstart(2, dev, "(i2400m %p buf %p buf_len %d)\n", 4618c2ecf20Sopenharmony_ci i2400m, buf, buf_len); 4628c2ecf20Sopenharmony_ci if (i) { 4638c2ecf20Sopenharmony_ci skb = skb_get(skb_rx); 4648c2ecf20Sopenharmony_ci d_printf(2, dev, "RX: reusing first payload skb %p\n", skb); 4658c2ecf20Sopenharmony_ci skb_pull(skb, buf - (void *) skb->data); 4668c2ecf20Sopenharmony_ci skb_trim(skb, (void *) skb_end_pointer(skb) - buf); 4678c2ecf20Sopenharmony_ci } else { 4688c2ecf20Sopenharmony_ci /* Yes, this is bad -- a lot of overhead -- see 4698c2ecf20Sopenharmony_ci * comments at the top of the file */ 4708c2ecf20Sopenharmony_ci skb = __netdev_alloc_skb(net_dev, buf_len, GFP_KERNEL); 4718c2ecf20Sopenharmony_ci if (skb == NULL) { 4728c2ecf20Sopenharmony_ci dev_err(dev, "NETRX: no memory to realloc skb\n"); 4738c2ecf20Sopenharmony_ci net_dev->stats.rx_dropped++; 4748c2ecf20Sopenharmony_ci goto error_skb_realloc; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci skb_put_data(skb, buf, buf_len); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, 4798c2ecf20Sopenharmony_ci skb->data - ETH_HLEN, 4808c2ecf20Sopenharmony_ci cpu_to_be16(ETH_P_IP)); 4818c2ecf20Sopenharmony_ci skb_set_mac_header(skb, -ETH_HLEN); 4828c2ecf20Sopenharmony_ci skb->dev = i2400m->wimax_dev.net_dev; 4838c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_IP); 4848c2ecf20Sopenharmony_ci net_dev->stats.rx_packets++; 4858c2ecf20Sopenharmony_ci net_dev->stats.rx_bytes += buf_len; 4868c2ecf20Sopenharmony_ci d_printf(3, dev, "NETRX: receiving %d bytes to network stack\n", 4878c2ecf20Sopenharmony_ci buf_len); 4888c2ecf20Sopenharmony_ci d_dump(4, dev, buf, buf_len); 4898c2ecf20Sopenharmony_ci netif_rx_ni(skb); /* see notes in function header */ 4908c2ecf20Sopenharmony_cierror_skb_realloc: 4918c2ecf20Sopenharmony_ci d_fnend(2, dev, "(i2400m %p buf %p buf_len %d) = void\n", 4928c2ecf20Sopenharmony_ci i2400m, buf, buf_len); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/* 4978c2ecf20Sopenharmony_ci * i2400m_net_erx - pass a network packet to the stack (extended version) 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * @i2400m: device descriptor 5008c2ecf20Sopenharmony_ci * @skb: the skb where the packet is - the skb should be set to point 5018c2ecf20Sopenharmony_ci * at the IP packet; this function will add ethernet headers if 5028c2ecf20Sopenharmony_ci * needed. 5038c2ecf20Sopenharmony_ci * @cs: packet type 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci * This is only used now for firmware >= v1.4. Note it is quite 5068c2ecf20Sopenharmony_ci * similar to i2400m_net_rx() (used only for v1.3 firmware). 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This function is normally run from a thread context. However, we 5098c2ecf20Sopenharmony_ci * still use netif_rx() instead of netif_receive_skb() as was 5108c2ecf20Sopenharmony_ci * recommended in the mailing list. Reason is in some stress tests 5118c2ecf20Sopenharmony_ci * when sending/receiving a lot of data we seem to hit a softlock in 5128c2ecf20Sopenharmony_ci * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using 5138c2ecf20Sopenharmony_ci * netif_rx() took care of the issue. 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * This is, of course, still open to do more research on why running 5168c2ecf20Sopenharmony_ci * with netif_receive_skb() hits this softlock. FIXME. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_civoid i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb, 5198c2ecf20Sopenharmony_ci enum i2400m_cs cs) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct net_device *net_dev = i2400m->wimax_dev.net_dev; 5228c2ecf20Sopenharmony_ci struct device *dev = i2400m_dev(i2400m); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci d_fnstart(2, dev, "(i2400m %p skb %p [%u] cs %d)\n", 5258c2ecf20Sopenharmony_ci i2400m, skb, skb->len, cs); 5268c2ecf20Sopenharmony_ci switch(cs) { 5278c2ecf20Sopenharmony_ci case I2400M_CS_IPV4_0: 5288c2ecf20Sopenharmony_ci case I2400M_CS_IPV4: 5298c2ecf20Sopenharmony_ci i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, 5308c2ecf20Sopenharmony_ci skb->data - ETH_HLEN, 5318c2ecf20Sopenharmony_ci cpu_to_be16(ETH_P_IP)); 5328c2ecf20Sopenharmony_ci skb_set_mac_header(skb, -ETH_HLEN); 5338c2ecf20Sopenharmony_ci skb->dev = i2400m->wimax_dev.net_dev; 5348c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_IP); 5358c2ecf20Sopenharmony_ci net_dev->stats.rx_packets++; 5368c2ecf20Sopenharmony_ci net_dev->stats.rx_bytes += skb->len; 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci default: 5398c2ecf20Sopenharmony_ci dev_err(dev, "ERX: BUG? CS type %u unsupported\n", cs); 5408c2ecf20Sopenharmony_ci goto error; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci d_printf(3, dev, "ERX: receiving %d bytes to the network stack\n", 5448c2ecf20Sopenharmony_ci skb->len); 5458c2ecf20Sopenharmony_ci d_dump(4, dev, skb->data, skb->len); 5468c2ecf20Sopenharmony_ci netif_rx_ni(skb); /* see notes in function header */ 5478c2ecf20Sopenharmony_cierror: 5488c2ecf20Sopenharmony_ci d_fnend(2, dev, "(i2400m %p skb %p [%u] cs %d) = void\n", 5498c2ecf20Sopenharmony_ci i2400m, skb, skb->len, cs); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic const struct net_device_ops i2400m_netdev_ops = { 5538c2ecf20Sopenharmony_ci .ndo_open = i2400m_open, 5548c2ecf20Sopenharmony_ci .ndo_stop = i2400m_stop, 5558c2ecf20Sopenharmony_ci .ndo_start_xmit = i2400m_hard_start_xmit, 5568c2ecf20Sopenharmony_ci .ndo_tx_timeout = i2400m_tx_timeout, 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void i2400m_get_drvinfo(struct net_device *net_dev, 5608c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 5658c2ecf20Sopenharmony_ci strlcpy(info->fw_version, i2400m->fw_name ? : "", 5668c2ecf20Sopenharmony_ci sizeof(info->fw_version)); 5678c2ecf20Sopenharmony_ci if (net_dev->dev.parent) 5688c2ecf20Sopenharmony_ci strlcpy(info->bus_info, dev_name(net_dev->dev.parent), 5698c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic const struct ethtool_ops i2400m_ethtool_ops = { 5738c2ecf20Sopenharmony_ci .get_drvinfo = i2400m_get_drvinfo, 5748c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/** 5788c2ecf20Sopenharmony_ci * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * Called by alloc_netdev() 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_civoid i2400m_netdev_setup(struct net_device *net_dev) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci d_fnstart(3, NULL, "(net_dev %p)\n", net_dev); 5858c2ecf20Sopenharmony_ci ether_setup(net_dev); 5868c2ecf20Sopenharmony_ci net_dev->mtu = I2400M_MAX_MTU; 5878c2ecf20Sopenharmony_ci net_dev->min_mtu = 0; 5888c2ecf20Sopenharmony_ci net_dev->max_mtu = I2400M_MAX_MTU; 5898c2ecf20Sopenharmony_ci net_dev->tx_queue_len = I2400M_TX_QLEN; 5908c2ecf20Sopenharmony_ci net_dev->features = 5918c2ecf20Sopenharmony_ci NETIF_F_VLAN_CHALLENGED 5928c2ecf20Sopenharmony_ci | NETIF_F_HIGHDMA; 5938c2ecf20Sopenharmony_ci net_dev->flags = 5948c2ecf20Sopenharmony_ci IFF_NOARP /* i2400m is apure IP device */ 5958c2ecf20Sopenharmony_ci & (~IFF_BROADCAST /* i2400m is P2P */ 5968c2ecf20Sopenharmony_ci & ~IFF_MULTICAST); 5978c2ecf20Sopenharmony_ci net_dev->watchdog_timeo = I2400M_TX_TIMEOUT; 5988c2ecf20Sopenharmony_ci net_dev->netdev_ops = &i2400m_netdev_ops; 5998c2ecf20Sopenharmony_ci net_dev->ethtool_ops = &i2400m_ethtool_ops; 6008c2ecf20Sopenharmony_ci d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(i2400m_netdev_setup); 6038c2ecf20Sopenharmony_ci 604