blob: ad23d8202ddaf0400e4ffb33430834de4c67956e [file] [log] [blame]
Mohammed Javid060c9c22018-02-01 20:42:17 +05301/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Amir Levya7146102016-11-08 14:10:58 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Amir Levya7146102016-11-08 14:10:58 +020012#include <linux/atomic.h>
13#include <linux/errno.h>
14#include <linux/etherdevice.h>
Amir Levy2da9d452017-12-12 10:09:46 +020015#include <linux/if_vlan.h>
Amir Levya7146102016-11-08 14:10:58 +020016#include <linux/debugfs.h>
17#include <linux/in.h>
18#include <linux/stddef.h>
19#include <linux/ip.h>
20#include <linux/fs.h>
21#include <linux/module.h>
22#include <linux/msm_ipa.h>
23#include <linux/netdevice.h>
24#include <linux/skbuff.h>
25#include <linux/sched.h>
26#include <linux/ipa.h>
27#include <linux/random.h>
28#include <linux/rndis_ipa.h>
29#include <linux/workqueue.h>
Michael Adisumarta3e350812017-09-18 14:54:36 -070030#include "../ipa_common_i.h"
Mohammed Javid4c4037e2017-11-27 16:23:35 +053031#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -070032#include "../ipa_v3/ipa_pm.h"
Mohammed Javid4c4037e2017-11-27 16:23:35 +053033#endif
Amir Levya7146102016-11-08 14:10:58 +020034
35#define CREATE_TRACE_POINTS
36#include "rndis_ipa_trace.h"
37
38#define DRV_NAME "RNDIS_IPA"
39#define DEBUGFS_DIR_NAME "rndis_ipa"
40#define DEBUGFS_AGGR_DIR_NAME "rndis_ipa_aggregation"
41#define NETDEV_NAME "rndis"
42#define DRV_RESOURCE_ID IPA_RM_RESOURCE_RNDIS_PROD
43#define IPV4_HDR_NAME "rndis_eth_ipv4"
44#define IPV6_HDR_NAME "rndis_eth_ipv6"
45#define IPA_TO_USB_CLIENT IPA_CLIENT_USB_CONS
46#define INACTIVITY_MSEC_DELAY 100
47#define DEFAULT_OUTSTANDING_HIGH 64
48#define DEFAULT_OUTSTANDING_LOW 32
49#define DEBUGFS_TEMP_BUF_SIZE 4
50#define RNDIS_IPA_PKT_TYPE 0x00000001
51#define RNDIS_IPA_DFLT_RT_HDL 0
52#define FROM_IPA_TO_USB_BAMDMA 4
53#define FROM_USB_TO_IPA_BAMDMA 5
54#define BAM_DMA_MAX_PKT_NUMBER 10
55#define BAM_DMA_DATA_FIFO_SIZE \
56 (BAM_DMA_MAX_PKT_NUMBER * \
57 (ETH_FRAME_LEN + sizeof(struct rndis_pkt_hdr)))
58#define BAM_DMA_DESC_FIFO_SIZE \
59 (BAM_DMA_MAX_PKT_NUMBER * (sizeof(struct sps_iovec)))
60#define TX_TIMEOUT (5 * HZ)
61#define MIN_TX_ERROR_SLEEP_PERIOD 500
62#define DEFAULT_AGGR_TIME_LIMIT 1
63#define DEFAULT_AGGR_PKT_LIMIT 0
64
65#define RNDIS_IPA_ERROR(fmt, args...) \
66 pr_err(DRV_NAME "@%s@%d@ctx:%s: "\
67 fmt, __func__, __LINE__, current->comm, ## args)
68#define RNDIS_IPA_DEBUG(fmt, args...) \
69 pr_debug("ctx: %s, "fmt, current->comm, ## args)
70
71#define NULL_CHECK_RETVAL(ptr) \
72 do { \
73 if (!(ptr)) { \
74 RNDIS_IPA_ERROR("null pointer #ptr\n"); \
75 ret = -EINVAL; \
76 } \
77 } \
78 while (0)
79
80#define RNDIS_HDR_OFST(field) offsetof(struct rndis_pkt_hdr, field)
81#define RNDIS_IPA_LOG_ENTRY() RNDIS_IPA_DEBUG("begin\n")
82#define RNDIS_IPA_LOG_EXIT() RNDIS_IPA_DEBUG("end\n")
83
84/**
85 * enum rndis_ipa_state - specify the current driver internal state
86 * which is guarded by a state machine.
87 *
88 * The driver internal state changes due to its external API usage.
89 * The driver saves its internal state to guard from caller illegal
90 * call sequence.
91 * states:
92 * UNLOADED is the first state which is the default one and is also the state
93 * after the driver gets unloaded(cleanup).
94 * INITIALIZED is the driver state once it finished registering
95 * the network device and all internal data struct were initialized
96 * CONNECTED is the driver state once the USB pipes were connected to IPA
97 * UP is the driver state after the interface mode was set to UP but the
98 * pipes are not connected yet - this state is meta-stable state.
99 * CONNECTED_AND_UP is the driver state when the pipe were connected and
100 * the interface got UP request from the network stack. this is the driver
101 * idle operation state which allows it to transmit/receive data.
102 * INVALID is a state which is not allowed.
103 */
104enum rndis_ipa_state {
105 RNDIS_IPA_UNLOADED = 0,
106 RNDIS_IPA_INITIALIZED = 1,
107 RNDIS_IPA_CONNECTED = 2,
108 RNDIS_IPA_UP = 3,
109 RNDIS_IPA_CONNECTED_AND_UP = 4,
110 RNDIS_IPA_INVALID = 5,
111};
112
113/**
114 * enum rndis_ipa_operation - enumerations used to describe the API operation
115 *
116 * Those enums are used as input for the driver state machine.
117 */
118enum rndis_ipa_operation {
119 RNDIS_IPA_INITIALIZE,
120 RNDIS_IPA_CONNECT,
121 RNDIS_IPA_OPEN,
122 RNDIS_IPA_STOP,
123 RNDIS_IPA_DISCONNECT,
124 RNDIS_IPA_CLEANUP,
125};
126
127#define RNDIS_IPA_STATE_DEBUG(ctx) \
Ghanim Fodi6a3d23f2017-03-07 14:44:58 +0200128 RNDIS_IPA_DEBUG("Driver state: %s\n",\
129 rndis_ipa_state_string((ctx)->state))
Amir Levya7146102016-11-08 14:10:58 +0200130
Amir Levya7146102016-11-08 14:10:58 +0200131
132/**
133 * struct rndis_ipa_dev - main driver context parameters
134 *
135 * @net: network interface struct implemented by this driver
136 * @directory: debugfs directory for various debugging switches
137 * @tx_filter: flag that enable/disable Tx path to continue to IPA
138 * @tx_dropped: number of filtered out Tx packets
139 * @tx_dump_enable: dump all Tx packets
140 * @rx_filter: flag that enable/disable Rx path to continue to IPA
141 * @rx_dropped: number of filtered out Rx packets
142 * @rx_dump_enable: dump all Rx packets
143 * @icmp_filter: allow all ICMP packet to pass through the filters
144 * @rm_enable: flag that enable/disable Resource manager request prior to Tx
Amir Levya7146102016-11-08 14:10:58 +0200145 * @deaggregation_enable: enable/disable IPA HW deaggregation logic
146 * @during_xmit_error: flags that indicate that the driver is in a middle
147 * of error handling in Tx path
Amir Levya7146102016-11-08 14:10:58 +0200148 * @directory: holds all debug flags used by the driver to allow cleanup
149 * for driver unload
150 * @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
151 * @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
152 * @usb_to_ipa_hdl: save handle for IPA pipe operations
153 * @ipa_to_usb_hdl: save handle for IPA pipe operations
154 * @outstanding_pkts: number of packets sent to IPA without TX complete ACKed
155 * @outstanding_high: number of outstanding packets allowed
156 * @outstanding_low: number of outstanding packets which shall cause
157 * to netdev queue start (after stopped due to outstanding_high reached)
158 * @error_msec_sleep_time: number of msec for sleeping in case of Tx error
159 * @state: current state of the driver
160 * @host_ethaddr: holds the tethered PC ethernet address
161 * @device_ethaddr: holds the device ethernet address
162 * @device_ready_notify: callback supplied by USB core driver
163 * This callback shall be called by the Netdev once the Netdev internal
164 * state is changed to RNDIS_IPA_CONNECTED_AND_UP
165 * @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530166 * @state_lock: used to protect the state variable.
Michael Adisumarta3e350812017-09-18 14:54:36 -0700167 * @pm_hdl: handle for IPA PM framework
Amir Levy2da9d452017-12-12 10:09:46 +0200168 * @is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +0200169 */
170struct rndis_ipa_dev {
171 struct net_device *net;
172 bool tx_filter;
173 u32 tx_dropped;
174 bool tx_dump_enable;
175 bool rx_filter;
176 u32 rx_dropped;
177 bool rx_dump_enable;
178 bool icmp_filter;
179 bool rm_enable;
Amir Levya7146102016-11-08 14:10:58 +0200180 bool deaggregation_enable;
181 bool during_xmit_error;
Amir Levya7146102016-11-08 14:10:58 +0200182 struct dentry *directory;
183 u32 eth_ipv4_hdr_hdl;
184 u32 eth_ipv6_hdr_hdl;
185 u32 usb_to_ipa_hdl;
186 u32 ipa_to_usb_hdl;
187 atomic_t outstanding_pkts;
188 u32 outstanding_high;
189 u32 outstanding_low;
190 u32 error_msec_sleep_time;
191 enum rndis_ipa_state state;
192 u8 host_ethaddr[ETH_ALEN];
193 u8 device_ethaddr[ETH_ALEN];
194 void (*device_ready_notify)(void);
195 struct delayed_work xmit_error_delayed_work;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530196 spinlock_t state_lock; /* Spinlock for the state variable.*/
Michael Adisumarta3e350812017-09-18 14:54:36 -0700197 u32 pm_hdl;
Amir Levy2da9d452017-12-12 10:09:46 +0200198 bool is_vlan_mode;
Amir Levya7146102016-11-08 14:10:58 +0200199};
200
201/**
202 * rndis_pkt_hdr - RNDIS_IPA representation of REMOTE_NDIS_PACKET_MSG
203 * @msg_type: for REMOTE_NDIS_PACKET_MSG this value should be 1
204 * @msg_len: total message length in bytes, including RNDIS header an payload
205 * @data_ofst: offset in bytes from start of the data_ofst to payload
206 * @data_len: payload size in bytes
207 * @zeroes: OOB place holder - not used for RNDIS_IPA.
208 */
209struct rndis_pkt_hdr {
210 __le32 msg_type;
211 __le32 msg_len;
212 __le32 data_ofst;
213 __le32 data_len;
214 __le32 zeroes[7];
215} __packed__;
216
217static int rndis_ipa_open(struct net_device *net);
218static void rndis_ipa_packet_receive_notify
219 (void *private, enum ipa_dp_evt_type evt, unsigned long data);
220static void rndis_ipa_tx_complete_notify
221 (void *private, enum ipa_dp_evt_type evt, unsigned long data);
222static void rndis_ipa_tx_timeout(struct net_device *net);
223static int rndis_ipa_stop(struct net_device *net);
224static void rndis_ipa_enable_data_path(struct rndis_ipa_dev *rndis_ipa_ctx);
Amir Levy2da9d452017-12-12 10:09:46 +0200225static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
226 struct rndis_ipa_dev *rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200227static void rndis_ipa_xmit_error(struct sk_buff *skb);
228static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work);
229static void rndis_ipa_prepare_header_insertion
230 (int eth_type,
231 const char *hdr_name, struct ipa_hdr_add *add_hdr,
Amir Levy2da9d452017-12-12 10:09:46 +0200232 const void *dst_mac, const void *src_mac, bool is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200233static int rndis_ipa_hdrs_cfg
234 (struct rndis_ipa_dev *rndis_ipa_ctx,
235 const void *dst_mac, const void *src_mac);
236static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
237static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net);
Amir Levy2da9d452017-12-12 10:09:46 +0200238static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200239static int rndis_ipa_deregister_properties(char *netdev_name);
240static void rndis_ipa_rm_notify
241 (void *user_data, enum ipa_rm_event event,
242 unsigned long data);
243static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
244static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530245#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -0700246static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
247static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530248#endif
Amir Levya7146102016-11-08 14:10:58 +0200249static bool rx_filter(struct sk_buff *skb);
250static bool tx_filter(struct sk_buff *skb);
251static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx);
252static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx);
253static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx);
254static netdev_tx_t rndis_ipa_start_xmit
255 (struct sk_buff *skb, struct net_device *net);
Amir Levya7146102016-11-08 14:10:58 +0200256static int rndis_ipa_debugfs_atomic_open
257 (struct inode *inode, struct file *file);
258static int rndis_ipa_debugfs_aggr_open
259 (struct inode *inode, struct file *file);
260static ssize_t rndis_ipa_debugfs_aggr_write
261 (struct file *file,
262 const char __user *buf, size_t count, loff_t *ppos);
Amir Levya7146102016-11-08 14:10:58 +0200263static ssize_t rndis_ipa_debugfs_atomic_read
264 (struct file *file,
265 char __user *ubuf, size_t count, loff_t *ppos);
266static void rndis_ipa_dump_skb(struct sk_buff *skb);
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +0530267static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200268static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
269static int rndis_ipa_ep_registers_cfg
270 (u32 usb_to_ipa_hdl,
271 u32 ipa_to_usb_hdl, u32 max_xfer_size_bytes_to_dev,
272 u32 max_xfer_size_bytes_to_host, u32 mtu,
Amir Levy2da9d452017-12-12 10:09:46 +0200273 bool deaggr_enable,
274 bool is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200275static int rndis_ipa_set_device_ethernet_addr
276 (u8 *dev_ethaddr,
277 u8 device_ethaddr[]);
278static enum rndis_ipa_state rndis_ipa_next_state
279 (enum rndis_ipa_state current_state,
280 enum rndis_ipa_operation operation);
281static const char *rndis_ipa_state_string(enum rndis_ipa_state state);
282static int rndis_ipa_init_module(void);
283static void rndis_ipa_cleanup_module(void);
284
285struct rndis_ipa_dev *rndis_ipa;
286
287static const struct net_device_ops rndis_ipa_netdev_ops = {
288 .ndo_open = rndis_ipa_open,
289 .ndo_stop = rndis_ipa_stop,
290 .ndo_start_xmit = rndis_ipa_start_xmit,
291 .ndo_tx_timeout = rndis_ipa_tx_timeout,
292 .ndo_get_stats = rndis_ipa_get_stats,
293 .ndo_set_mac_address = eth_mac_addr,
294};
295
296const struct file_operations rndis_ipa_debugfs_atomic_ops = {
297 .open = rndis_ipa_debugfs_atomic_open,
298 .read = rndis_ipa_debugfs_atomic_read,
299};
300
Amir Levya7146102016-11-08 14:10:58 +0200301const struct file_operations rndis_ipa_aggr_ops = {
302 .open = rndis_ipa_debugfs_aggr_open,
303 .write = rndis_ipa_debugfs_aggr_write,
304};
305
306static struct ipa_ep_cfg ipa_to_usb_ep_cfg = {
307 .mode = {
308 .mode = IPA_BASIC,
309 .dst = IPA_CLIENT_APPS_LAN_CONS,
310 },
311 .hdr = {
312 .hdr_len = ETH_HLEN + sizeof(struct rndis_pkt_hdr),
313 .hdr_ofst_metadata_valid = false,
314 .hdr_ofst_metadata = 0,
315 .hdr_additional_const_len = ETH_HLEN,
316 .hdr_ofst_pkt_size_valid = true,
317 .hdr_ofst_pkt_size = 3 * sizeof(u32),
318 .hdr_a5_mux = false,
319 .hdr_remove_additional = false,
320 .hdr_metadata_reg_valid = false,
321 },
322 .hdr_ext = {
323 .hdr_pad_to_alignment = 0,
324 .hdr_total_len_or_pad_offset = 1 * sizeof(u32),
325 .hdr_payload_len_inc_padding = false,
326 .hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN,
327 .hdr_total_len_or_pad_valid = true,
328 .hdr_little_endian = true,
329 },
330 .aggr = {
331 .aggr_en = IPA_ENABLE_AGGR,
332 .aggr = IPA_GENERIC,
333 .aggr_byte_limit = 4,
334 .aggr_time_limit = DEFAULT_AGGR_TIME_LIMIT,
335 .aggr_pkt_limit = DEFAULT_AGGR_PKT_LIMIT
336 },
337 .deaggr = {
338 .deaggr_hdr_len = 0,
339 .packet_offset_valid = 0,
340 .packet_offset_location = 0,
341 .max_packet_len = 0,
342 },
343 .route = {
344 .rt_tbl_hdl = RNDIS_IPA_DFLT_RT_HDL,
345 },
346 .nat = {
347 .nat_en = IPA_SRC_NAT,
348 },
349};
350
351static struct ipa_ep_cfg usb_to_ipa_ep_cfg_deaggr_dis = {
352 .mode = {
353 .mode = IPA_BASIC,
354 .dst = IPA_CLIENT_APPS_LAN_CONS,
355 },
356 .hdr = {
357 .hdr_len = ETH_HLEN + sizeof(struct rndis_pkt_hdr),
358 .hdr_ofst_metadata_valid = false,
359 .hdr_ofst_metadata = 0,
360 .hdr_additional_const_len = 0,
361 .hdr_ofst_pkt_size_valid = true,
362 .hdr_ofst_pkt_size = 3 * sizeof(u32) +
363 sizeof(struct rndis_pkt_hdr),
364 .hdr_a5_mux = false,
365 .hdr_remove_additional = false,
366 .hdr_metadata_reg_valid = false,
367 },
368 .hdr_ext = {
369 .hdr_pad_to_alignment = 0,
370 .hdr_total_len_or_pad_offset = 1 * sizeof(u32),
371 .hdr_payload_len_inc_padding = false,
372 .hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN,
373 .hdr_total_len_or_pad_valid = true,
374 .hdr_little_endian = true,
375 },
376
377 .aggr = {
378 .aggr_en = IPA_BYPASS_AGGR,
379 .aggr = 0,
380 .aggr_byte_limit = 0,
381 .aggr_time_limit = 0,
382 .aggr_pkt_limit = 0,
383 },
384 .deaggr = {
385 .deaggr_hdr_len = 0,
386 .packet_offset_valid = false,
387 .packet_offset_location = 0,
388 .max_packet_len = 0,
389 },
390
391 .route = {
392 .rt_tbl_hdl = RNDIS_IPA_DFLT_RT_HDL,
393 },
394 .nat = {
395 .nat_en = IPA_BYPASS_NAT,
396 },
397};
398
399static struct ipa_ep_cfg usb_to_ipa_ep_cfg_deaggr_en = {
400 .mode = {
401 .mode = IPA_BASIC,
402 .dst = IPA_CLIENT_APPS_LAN_CONS,
403 },
404 .hdr = {
405 .hdr_len = ETH_HLEN,
406 .hdr_ofst_metadata_valid = false,
407 .hdr_ofst_metadata = 0,
408 .hdr_additional_const_len = 0,
409 .hdr_ofst_pkt_size_valid = true,
410 .hdr_ofst_pkt_size = 3 * sizeof(u32),
411 .hdr_a5_mux = false,
412 .hdr_remove_additional = false,
413 .hdr_metadata_reg_valid = false,
414 },
415 .hdr_ext = {
416 .hdr_pad_to_alignment = 0,
417 .hdr_total_len_or_pad_offset = 1 * sizeof(u32),
418 .hdr_payload_len_inc_padding = false,
419 .hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN,
420 .hdr_total_len_or_pad_valid = true,
421 .hdr_little_endian = true,
422 },
423 .aggr = {
424 .aggr_en = IPA_ENABLE_DEAGGR,
425 .aggr = IPA_GENERIC,
426 .aggr_byte_limit = 0,
427 .aggr_time_limit = 0,
428 .aggr_pkt_limit = 0,
429 },
430 .deaggr = {
431 .deaggr_hdr_len = sizeof(struct rndis_pkt_hdr),
432 .packet_offset_valid = true,
433 .packet_offset_location = 8,
434 .max_packet_len = 8192, /* Will be overridden*/
435 },
436 .route = {
437 .rt_tbl_hdl = RNDIS_IPA_DFLT_RT_HDL,
438 },
439 .nat = {
440 .nat_en = IPA_BYPASS_NAT,
441 },
442};
443
444/**
445 * rndis_template_hdr - RNDIS template structure for RNDIS_IPA SW insertion
446 * @msg_type: set for REMOTE_NDIS_PACKET_MSG (0x00000001)
447 * this value will be used for all data packets
448 * @msg_len: will add the skb length to get final size
449 * @data_ofst: this field value will not be changed
450 * @data_len: set as skb length to get final size
451 * @zeroes: make sure all OOB data is not used
452 */
453struct rndis_pkt_hdr rndis_template_hdr = {
454 .msg_type = RNDIS_IPA_PKT_TYPE,
455 .msg_len = sizeof(struct rndis_pkt_hdr),
456 .data_ofst = sizeof(struct rndis_pkt_hdr) - RNDIS_HDR_OFST(data_ofst),
457 .data_len = 0,
458 .zeroes = {0},
459};
460
461/**
462 * rndis_ipa_init() - create network device and initialize internal
463 * data structures
464 * @params: in/out parameters required for initialization,
465 * see "struct ipa_usb_init_params" for more details
466 *
467 * Shall be called prior to pipe connection.
468 * Detailed description:
469 * - allocate the network device
470 * - set default values for driver internal switches and stash them inside
471 * the netdev private field
472 * - set needed headroom for RNDIS header
473 * - create debugfs folder and files
474 * - create IPA resource manager client
475 * - set the ethernet address for the netdev to be added on SW Tx path
476 * - add header insertion rules for IPA driver (based on host/device Ethernet
477 * addresses given in input params and on RNDIS data template struct)
478 * - register tx/rx properties to IPA driver (will be later used
479 * by IPA configuration manager to configure rest of the IPA rules)
480 * - set the carrier state to "off" (until connect is called)
481 * - register the network device
482 * - set the out parameters
483 * - change driver internal state to INITIALIZED
484 *
485 * Returns negative errno, or zero on success
486 */
487int rndis_ipa_init(struct ipa_usb_init_params *params)
488{
489 int result = 0;
490 struct net_device *net;
491 struct rndis_ipa_dev *rndis_ipa_ctx;
492 int ret;
493
494 RNDIS_IPA_LOG_ENTRY();
495 RNDIS_IPA_DEBUG("%s initializing\n", DRV_NAME);
496 ret = 0;
497 NULL_CHECK_RETVAL(params);
498 if (ret)
499 return ret;
500
501 RNDIS_IPA_DEBUG
502 ("host_ethaddr=%pM, device_ethaddr=%pM\n",
503 params->host_ethaddr,
504 params->device_ethaddr);
505
506 net = alloc_etherdev(sizeof(struct rndis_ipa_dev));
507 if (!net) {
508 result = -ENOMEM;
509 RNDIS_IPA_ERROR("fail to allocate Ethernet device\n");
510 goto fail_alloc_etherdev;
511 }
512 RNDIS_IPA_DEBUG("network device was successfully allocated\n");
513
514 rndis_ipa_ctx = netdev_priv(net);
515 if (!rndis_ipa_ctx) {
516 result = -ENOMEM;
517 RNDIS_IPA_ERROR("fail to extract netdev priv\n");
518 goto fail_netdev_priv;
519 }
520 memset(rndis_ipa_ctx, 0, sizeof(*rndis_ipa_ctx));
521 RNDIS_IPA_DEBUG("rndis_ipa_ctx (private)=%p\n", rndis_ipa_ctx);
522
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530523 spin_lock_init(&rndis_ipa_ctx->state_lock);
524
Amir Levya7146102016-11-08 14:10:58 +0200525 rndis_ipa_ctx->net = net;
526 rndis_ipa_ctx->tx_filter = false;
527 rndis_ipa_ctx->rx_filter = false;
528 rndis_ipa_ctx->icmp_filter = true;
529 rndis_ipa_ctx->rm_enable = true;
530 rndis_ipa_ctx->tx_dropped = 0;
531 rndis_ipa_ctx->rx_dropped = 0;
532 rndis_ipa_ctx->tx_dump_enable = false;
533 rndis_ipa_ctx->rx_dump_enable = false;
534 rndis_ipa_ctx->deaggregation_enable = false;
535 rndis_ipa_ctx->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
536 rndis_ipa_ctx->outstanding_low = DEFAULT_OUTSTANDING_LOW;
537 atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);
538 memcpy
539 (rndis_ipa_ctx->device_ethaddr, params->device_ethaddr,
540 sizeof(rndis_ipa_ctx->device_ethaddr));
541 memcpy
542 (rndis_ipa_ctx->host_ethaddr, params->host_ethaddr,
543 sizeof(rndis_ipa_ctx->host_ethaddr));
544 INIT_DELAYED_WORK
545 (&rndis_ipa_ctx->xmit_error_delayed_work,
546 rndis_ipa_xmit_error_aftercare_wq);
547 rndis_ipa_ctx->error_msec_sleep_time =
548 MIN_TX_ERROR_SLEEP_PERIOD;
549 RNDIS_IPA_DEBUG("internal data structures were set\n");
550
551 if (!params->device_ready_notify)
552 RNDIS_IPA_DEBUG("device_ready_notify() was not supplied\n");
553 rndis_ipa_ctx->device_ready_notify = params->device_ready_notify;
554
555 snprintf(net->name, sizeof(net->name), "%s%%d", NETDEV_NAME);
556 RNDIS_IPA_DEBUG
557 ("Setting network interface driver name to: %s\n",
558 net->name);
559
560 net->netdev_ops = &rndis_ipa_netdev_ops;
561 net->watchdog_timeo = TX_TIMEOUT;
562
563 net->needed_headroom = sizeof(rndis_template_hdr);
564 RNDIS_IPA_DEBUG
565 ("Needed headroom for RNDIS header set to %d\n",
566 net->needed_headroom);
567
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +0530568 rndis_ipa_debugfs_init(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200569
570 result = rndis_ipa_set_device_ethernet_addr
571 (net->dev_addr, rndis_ipa_ctx->device_ethaddr);
572 if (result) {
573 RNDIS_IPA_ERROR("set device MAC failed\n");
574 goto fail_set_device_ethernet;
575 }
576 RNDIS_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);
Mohammed Javid060c9c22018-02-01 20:42:17 +0530577#ifdef CONFIG_IPA3
Amir Levy2da9d452017-12-12 10:09:46 +0200578 if (ipa_is_vlan_mode(IPA_VLAN_IF_RNDIS,
579 &rndis_ipa_ctx->is_vlan_mode)) {
580 RNDIS_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
Mohammed Javid060c9c22018-02-01 20:42:17 +0530581 goto fail_hdrs_cfg;
Amir Levy2da9d452017-12-12 10:09:46 +0200582 }
Mohammed Javid060c9c22018-02-01 20:42:17 +0530583#else
584 rndis_ipa_ctx->is_vlan_mode = 0;
585#endif
Amir Levy2da9d452017-12-12 10:09:46 +0200586 RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);
587
Amir Levya7146102016-11-08 14:10:58 +0200588 result = rndis_ipa_hdrs_cfg
589 (rndis_ipa_ctx,
590 params->host_ethaddr,
591 params->device_ethaddr);
592 if (result) {
593 RNDIS_IPA_ERROR("fail on ipa hdrs set\n");
594 goto fail_hdrs_cfg;
595 }
596 RNDIS_IPA_DEBUG("IPA header-insertion configed for Ethernet+RNDIS\n");
597
Amir Levy2da9d452017-12-12 10:09:46 +0200598 result = rndis_ipa_register_properties(net->name,
599 rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200600 if (result) {
601 RNDIS_IPA_ERROR("fail on properties set\n");
602 goto fail_register_tx;
603 }
604 RNDIS_IPA_DEBUG("2 TX and 2 RX properties were registered\n");
605
606 netif_carrier_off(net);
607 RNDIS_IPA_DEBUG("set carrier off until pipes are connected\n");
608
609 result = register_netdev(net);
610 if (result) {
611 RNDIS_IPA_ERROR("register_netdev failed: %d\n", result);
612 goto fail_register_netdev;
613 }
614 RNDIS_IPA_DEBUG
615 ("netdev:%s registration succeeded, index=%d\n",
616 net->name, net->ifindex);
617
618 rndis_ipa = rndis_ipa_ctx;
619 params->ipa_rx_notify = rndis_ipa_packet_receive_notify;
620 params->ipa_tx_notify = rndis_ipa_tx_complete_notify;
621 params->private = rndis_ipa_ctx;
622 params->skip_ep_cfg = false;
623 rndis_ipa_ctx->state = RNDIS_IPA_INITIALIZED;
624 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
625 pr_info("RNDIS_IPA NetDev was initialized");
626
627 RNDIS_IPA_LOG_EXIT();
628
629 return 0;
630
631fail_register_netdev:
632 rndis_ipa_deregister_properties(net->name);
633fail_register_tx:
634 rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200635fail_hdrs_cfg:
Amir Levy2da9d452017-12-12 10:09:46 +0200636fail_set_device_ethernet:
Amir Levya7146102016-11-08 14:10:58 +0200637 rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200638fail_netdev_priv:
639 free_netdev(net);
640fail_alloc_etherdev:
641 return result;
642}
643EXPORT_SYMBOL(rndis_ipa_init);
644
645/**
646 * rndis_ipa_pipe_connect_notify() - notify rndis_ipa Netdev that the USB pipes
647 * were connected
648 * @usb_to_ipa_hdl: handle from IPA driver client for USB->IPA
649 * @ipa_to_usb_hdl: handle from IPA driver client for IPA->USB
650 * @private: same value that was set by init(), this parameter holds the
651 * network device pointer.
652 * @max_transfer_byte_size: RNDIS protocol specific, the maximum size that
653 * the host expect
654 * @max_packet_number: RNDIS protocol specific, the maximum packet number
655 * that the host expects
656 *
657 * Once USB driver finishes the pipe connection between IPA core
658 * and USB core this method shall be called in order to
659 * allow the driver to complete the data path configurations.
660 * Detailed description:
661 * - configure the IPA end-points register
662 * - notify the Linux kernel for "carrier_on"
663 * - change the driver internal state
664 *
665 * After this function is done the driver state changes to "Connected" or
666 * Connected and Up.
667 * This API is expected to be called after initialization() or
668 * after a call to disconnect().
669 *
670 * Returns negative errno, or zero on success
671 */
672int rndis_ipa_pipe_connect_notify(
673 u32 usb_to_ipa_hdl,
674 u32 ipa_to_usb_hdl,
675 u32 max_xfer_size_bytes_to_dev,
676 u32 max_packet_number_to_dev,
677 u32 max_xfer_size_bytes_to_host,
678 void *private)
679{
680 struct rndis_ipa_dev *rndis_ipa_ctx = private;
681 int next_state;
682 int result;
683 int ret;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530684 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +0200685
686 RNDIS_IPA_LOG_ENTRY();
687
688 ret = 0;
689 NULL_CHECK_RETVAL(private);
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530690
Amir Levya7146102016-11-08 14:10:58 +0200691 if (ret)
692 return ret;
693
694 RNDIS_IPA_DEBUG
695 ("usb_to_ipa_hdl=%d, ipa_to_usb_hdl=%d, private=0x%p\n",
696 usb_to_ipa_hdl, ipa_to_usb_hdl, private);
697 RNDIS_IPA_DEBUG
698 ("max_xfer_sz_to_dev=%d, max_pkt_num_to_dev=%d\n",
699 max_xfer_size_bytes_to_dev,
700 max_packet_number_to_dev);
701 RNDIS_IPA_DEBUG
702 ("max_xfer_sz_to_host=%d\n",
703 max_xfer_size_bytes_to_host);
704
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530705 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200706 next_state = rndis_ipa_next_state
707 (rndis_ipa_ctx->state,
708 RNDIS_IPA_CONNECT);
709 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530710 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200711 RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
712 return -EPERM;
713 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530714 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200715
716 if (usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
717 RNDIS_IPA_ERROR
718 ("usb_to_ipa_hdl(%d) - not valid ipa handle\n",
719 usb_to_ipa_hdl);
720 return -EINVAL;
721 }
722 if (ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
723 RNDIS_IPA_ERROR
724 ("ipa_to_usb_hdl(%d) - not valid ipa handle\n",
725 ipa_to_usb_hdl);
726 return -EINVAL;
727 }
728
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530729#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -0700730 if (ipa_pm_is_used())
731 result = rndis_ipa_register_pm_client(rndis_ipa_ctx);
732 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530733#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -0700734 result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200735 if (result) {
736 RNDIS_IPA_ERROR("fail on RM create\n");
737 goto fail_create_rm;
738 }
739 RNDIS_IPA_DEBUG("RM resource was created\n");
740
741 rndis_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
742 rndis_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
743 if (max_packet_number_to_dev > 1)
744 rndis_ipa_ctx->deaggregation_enable = true;
745 else
746 rndis_ipa_ctx->deaggregation_enable = false;
747 result = rndis_ipa_ep_registers_cfg
748 (usb_to_ipa_hdl,
749 ipa_to_usb_hdl,
750 max_xfer_size_bytes_to_dev,
751 max_xfer_size_bytes_to_host,
752 rndis_ipa_ctx->net->mtu,
Amir Levy2da9d452017-12-12 10:09:46 +0200753 rndis_ipa_ctx->deaggregation_enable,
754 rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200755 if (result) {
756 RNDIS_IPA_ERROR("fail on ep cfg\n");
757 goto fail;
758 }
759 RNDIS_IPA_DEBUG("end-points configured\n");
760
761 netif_stop_queue(rndis_ipa_ctx->net);
762 RNDIS_IPA_DEBUG("netif_stop_queue() was called\n");
763
764 netif_carrier_on(rndis_ipa_ctx->net);
765 if (!netif_carrier_ok(rndis_ipa_ctx->net)) {
766 RNDIS_IPA_ERROR("netif_carrier_ok error\n");
767 result = -EBUSY;
768 goto fail;
769 }
770 RNDIS_IPA_DEBUG("netif_carrier_on() was called\n");
771
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530772 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
773 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
774 RNDIS_IPA_CONNECT);
775 if (next_state == RNDIS_IPA_INVALID) {
776 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
777 RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
778 return -EPERM;
779 }
Amir Levya7146102016-11-08 14:10:58 +0200780 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530781 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
782
Amir Levya7146102016-11-08 14:10:58 +0200783 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
784
785 if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
786 rndis_ipa_enable_data_path(rndis_ipa_ctx);
787 else
788 RNDIS_IPA_DEBUG("queue shall be started after open()\n");
789
790 pr_info("RNDIS_IPA NetDev pipes were connected\n");
791
792 RNDIS_IPA_LOG_EXIT();
793
794 return 0;
795
796fail:
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530797#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -0700798 if (ipa_pm_is_used())
799 rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
800 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530801#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -0700802 rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200803fail_create_rm:
804 return result;
805}
806EXPORT_SYMBOL(rndis_ipa_pipe_connect_notify);
807
808/**
809 * rndis_ipa_open() - notify Linux network stack to start sending packets
810 * @net: the network interface supplied by the network stack
811 *
812 * Linux uses this API to notify the driver that the network interface
813 * transitions to the up state.
814 * The driver will instruct the Linux network stack to start
815 * delivering data packets.
816 * The driver internal state shall be changed to Up or Connected and Up
817 *
818 * Returns negative errno, or zero on success
819 */
820static int rndis_ipa_open(struct net_device *net)
821{
822 struct rndis_ipa_dev *rndis_ipa_ctx;
823 int next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530824 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +0200825
826 RNDIS_IPA_LOG_ENTRY();
827
828 rndis_ipa_ctx = netdev_priv(net);
829
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530830 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
831
Amir Levya7146102016-11-08 14:10:58 +0200832 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_OPEN);
833 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530834 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200835 RNDIS_IPA_ERROR("can't bring driver up before initialize\n");
836 return -EPERM;
837 }
838
839 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530840
841 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
842
Amir Levya7146102016-11-08 14:10:58 +0200843 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
844
845 if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
846 rndis_ipa_enable_data_path(rndis_ipa_ctx);
847 else
848 RNDIS_IPA_DEBUG("queue shall be started after connect()\n");
849
850 pr_info("RNDIS_IPA NetDev was opened\n");
851
852 RNDIS_IPA_LOG_EXIT();
853
854 return 0;
855}
856
857/**
858 * rndis_ipa_start_xmit() - send data from APPs to USB core via IPA core
859 * using SW path (Tx data path)
860 * Tx path for this Netdev is Apps-processor->IPA->USB
861 * @skb: packet received from Linux network stack destined for tethered PC
862 * @net: the network device being used to send this packet (rndis0)
863 *
864 * Several conditions needed in order to send the packet to IPA:
865 * - Transmit queue for the network driver is currently
866 * in "started" state
867 * - The driver internal state is in Connected and Up state.
868 * - Filters Tx switch are turned off
869 * - The IPA resource manager state for the driver producer client
870 * is "Granted" which implies that all the resources in the dependency
871 * graph are valid for data flow.
872 * - outstanding high boundary was not reached.
873 *
874 * In case the outstanding packets high boundary is reached, the driver will
875 * stop the send queue until enough packets are processed by
876 * the IPA core (based on calls to rndis_ipa_tx_complete_notify).
877 *
878 * In case all of the conditions are met, the network driver shall:
879 * - encapsulate the Ethernet packet with RNDIS header (REMOTE_NDIS_PACKET_MSG)
880 * - send the packet by using IPA Driver SW path (IP_PACKET_INIT)
881 * - Netdev status fields shall be updated based on the current Tx packet
882 *
883 * Returns NETDEV_TX_BUSY if retry should be made later,
884 * or NETDEV_TX_OK on success.
885 */
886static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
887 struct net_device *net)
888{
889 int ret;
890 netdev_tx_t status = NETDEV_TX_BUSY;
891 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
892
Ghanim Fodi6a3d23f2017-03-07 14:44:58 +0200893 netif_trans_update(net);
Amir Levya7146102016-11-08 14:10:58 +0200894
895 RNDIS_IPA_DEBUG
896 ("Tx, len=%d, skb->protocol=%d, outstanding=%d\n",
897 skb->len, skb->protocol,
898 atomic_read(&rndis_ipa_ctx->outstanding_pkts));
899
900 if (unlikely(netif_queue_stopped(net))) {
901 RNDIS_IPA_ERROR("interface queue is stopped\n");
902 goto out;
903 }
904
905 if (unlikely(rndis_ipa_ctx->tx_dump_enable))
906 rndis_ipa_dump_skb(skb);
907
908 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
909 RNDIS_IPA_ERROR("Missing pipe connected and/or iface up\n");
910 return NETDEV_TX_BUSY;
911 }
912
913 if (unlikely(tx_filter(skb))) {
914 dev_kfree_skb_any(skb);
915 RNDIS_IPA_DEBUG("packet got filtered out on Tx path\n");
916 rndis_ipa_ctx->tx_dropped++;
917 status = NETDEV_TX_OK;
918 goto out;
919 }
920
921 ret = resource_request(rndis_ipa_ctx);
922 if (ret) {
923 RNDIS_IPA_DEBUG("Waiting to resource\n");
924 netif_stop_queue(net);
925 goto resource_busy;
926 }
927
928 if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) >=
929 rndis_ipa_ctx->outstanding_high) {
930 RNDIS_IPA_DEBUG("Outstanding high boundary reached (%d)\n",
931 rndis_ipa_ctx->outstanding_high);
932 netif_stop_queue(net);
933 RNDIS_IPA_DEBUG("send queue was stopped\n");
934 status = NETDEV_TX_BUSY;
935 goto out;
936 }
937
Amir Levy2da9d452017-12-12 10:09:46 +0200938 skb = rndis_encapsulate_skb(skb, rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200939 trace_rndis_tx_dp(skb->protocol);
940 ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
941 if (ret) {
942 RNDIS_IPA_ERROR("ipa transmit failed (%d)\n", ret);
943 goto fail_tx_packet;
944 }
945
946 atomic_inc(&rndis_ipa_ctx->outstanding_pkts);
947
948 status = NETDEV_TX_OK;
949 goto out;
950
951fail_tx_packet:
952 rndis_ipa_xmit_error(skb);
953out:
954 resource_release(rndis_ipa_ctx);
955resource_busy:
956 RNDIS_IPA_DEBUG
957 ("packet Tx done - %s\n",
958 (status == NETDEV_TX_OK) ? "OK" : "FAIL");
959
960 return status;
961}
962
963/**
964 * rndis_ipa_tx_complete_notify() - notification for Netdev that the
965 * last packet was successfully sent
966 * @private: driver context stashed by IPA driver upon pipe connect
967 * @evt: event type (expected to be write-done event)
968 * @data: data provided with event (this is actually the skb that
969 * holds the sent packet)
970 *
971 * This function will be called on interrupt bottom halve deferred context.
972 * outstanding packets counter shall be decremented.
973 * Network stack send queue will be re-started in case low outstanding
974 * boundary is reached and queue was stopped before.
975 * At the end the skb shall be freed.
976 */
977static void rndis_ipa_tx_complete_notify(
978 void *private,
979 enum ipa_dp_evt_type evt,
980 unsigned long data)
981{
982 struct sk_buff *skb = (struct sk_buff *)data;
983 struct rndis_ipa_dev *rndis_ipa_ctx = private;
984 int ret;
985
986 ret = 0;
987 NULL_CHECK_RETVAL(private);
988 if (ret)
989 return;
990
991 trace_rndis_status_rcvd(skb->protocol);
992
993 RNDIS_IPA_DEBUG
994 ("Tx-complete, len=%d, skb->prot=%d, outstanding=%d\n",
995 skb->len, skb->protocol,
996 atomic_read(&rndis_ipa_ctx->outstanding_pkts));
997
998 if (unlikely((evt != IPA_WRITE_DONE))) {
999 RNDIS_IPA_ERROR("unsupported event on TX call-back\n");
1000 return;
1001 }
1002
1003 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1004 RNDIS_IPA_DEBUG
1005 ("dropping Tx-complete pkt, state=%s\n",
1006 rndis_ipa_state_string(rndis_ipa_ctx->state));
1007 goto out;
1008 }
1009
1010 rndis_ipa_ctx->net->stats.tx_packets++;
1011 rndis_ipa_ctx->net->stats.tx_bytes += skb->len;
1012
1013 atomic_dec(&rndis_ipa_ctx->outstanding_pkts);
1014 if
1015 (netif_queue_stopped(rndis_ipa_ctx->net) &&
1016 netif_carrier_ok(rndis_ipa_ctx->net) &&
1017 atomic_read(&rndis_ipa_ctx->outstanding_pkts) <
1018 (rndis_ipa_ctx->outstanding_low)) {
1019 RNDIS_IPA_DEBUG("outstanding low boundary reached (%d)n",
1020 rndis_ipa_ctx->outstanding_low);
1021 netif_wake_queue(rndis_ipa_ctx->net);
1022 RNDIS_IPA_DEBUG("send queue was awaken\n");
1023 }
1024
1025out:
1026 dev_kfree_skb_any(skb);
1027}
1028
1029static void rndis_ipa_tx_timeout(struct net_device *net)
1030{
1031 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
1032 int outstanding = atomic_read(&rndis_ipa_ctx->outstanding_pkts);
1033
1034 RNDIS_IPA_ERROR
1035 ("possible IPA stall was detected, %d outstanding\n",
1036 outstanding);
1037
1038 net->stats.tx_errors++;
1039}
1040
1041/**
1042 * rndis_ipa_rm_notify() - callback supplied to IPA resource manager
1043 * for grant/release events
1044 * user_data: the driver context supplied to IPA resource manager during call
1045 * to ipa_rm_create_resource().
1046 * event: the event notified to us by IPA resource manager (Release/Grant)
1047 * data: reserved field supplied by IPA resource manager
1048 *
1049 * This callback shall be called based on resource request/release sent
1050 * to the IPA resource manager.
1051 * In case the queue was stopped during EINPROGRESS for Tx path and the
1052 * event received is Grant then the queue shall be restarted.
1053 * In case the event notified is a release notification the netdev discard it.
1054 */
1055static void rndis_ipa_rm_notify(
1056 void *user_data, enum ipa_rm_event event,
1057 unsigned long data)
1058{
1059 struct rndis_ipa_dev *rndis_ipa_ctx = user_data;
1060
1061 RNDIS_IPA_LOG_ENTRY();
1062
1063 if (event == IPA_RM_RESOURCE_RELEASED) {
1064 RNDIS_IPA_DEBUG("Resource Released\n");
1065 return;
1066 }
1067
1068 if (event != IPA_RM_RESOURCE_GRANTED) {
1069 RNDIS_IPA_ERROR
1070 ("Unexceoted event receieved from RM (%d\n)", event);
1071 return;
1072 }
1073 RNDIS_IPA_DEBUG("Resource Granted\n");
1074
1075 if (netif_queue_stopped(rndis_ipa_ctx->net)) {
1076 RNDIS_IPA_DEBUG("starting queue\n");
1077 netif_start_queue(rndis_ipa_ctx->net);
1078 } else {
1079 RNDIS_IPA_DEBUG("queue already awake\n");
1080 }
1081
1082 RNDIS_IPA_LOG_EXIT();
1083}
1084
1085/**
1086 * rndis_ipa_packet_receive_notify() - Rx notify for packet sent from
1087 * tethered PC (USB->IPA).
1088 * is USB->IPA->Apps-processor
1089 * @private: driver context
1090 * @evt: event type
1091 * @data: data provided with event
1092 *
1093 * Once IPA driver receives a packet from USB client this callback will be
1094 * called from bottom-half interrupt handling context (ipa Rx workqueue).
1095 *
1096 * Packets that shall be sent to Apps processor may be of two types:
1097 * 1) Packets that are destined for Apps (e.g: WEBSERVER running on Apps)
1098 * 2) Exception packets that need special handling (based on IPA core
1099 * configuration, e.g: new TCP session or any other packets that IPA core
1100 * can't handle)
1101 * If the next conditions are met, the packet shall be sent up to the
1102 * Linux network stack:
1103 * - Driver internal state is Connected and Up
1104 * - Notification received from IPA driver meets the expected type
1105 * for Rx packet
1106 * -Filters Rx switch are turned off
1107 *
1108 * Prior to the sending to the network stack:
1109 * - Netdev struct shall be stashed to the skb as required by the network stack
1110 * - Ethernet header shall be removed (skb->data shall point to the Ethernet
1111 * payload, Ethernet still stashed under MAC header).
1112 * - The skb->pkt_protocol shall be set based on the ethernet destination
1113 * address, Can be Broadcast, Multicast or Other-Host, The later
1114 * pkt-types packets shall be dropped in case the Netdev is not
1115 * in promisc mode.
1116 * - Set the skb protocol field based on the EtherType field
1117 *
1118 * Netdev status fields shall be updated based on the current Rx packet
1119 */
1120static void rndis_ipa_packet_receive_notify(
1121 void *private,
1122 enum ipa_dp_evt_type evt,
1123 unsigned long data)
1124{
1125 struct sk_buff *skb = (struct sk_buff *)data;
1126 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1127 int result;
1128 unsigned int packet_len = skb->len;
1129
1130 RNDIS_IPA_DEBUG
1131 ("packet Rx, len=%d\n",
1132 skb->len);
1133
1134 if (unlikely(rndis_ipa_ctx->rx_dump_enable))
1135 rndis_ipa_dump_skb(skb);
1136
1137 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1138 RNDIS_IPA_DEBUG("use connect()/up() before receive()\n");
1139 RNDIS_IPA_DEBUG("packet dropped (length=%d)\n",
1140 skb->len);
1141 return;
1142 }
1143
1144 if (evt != IPA_RECEIVE) {
1145 RNDIS_IPA_ERROR("a none IPA_RECEIVE event in driver RX\n");
1146 return;
1147 }
1148
1149 if (!rndis_ipa_ctx->deaggregation_enable)
1150 skb_pull(skb, sizeof(struct rndis_pkt_hdr));
1151
1152 skb->dev = rndis_ipa_ctx->net;
1153 skb->protocol = eth_type_trans(skb, rndis_ipa_ctx->net);
1154
1155 if (rx_filter(skb)) {
1156 RNDIS_IPA_DEBUG("packet got filtered out on RX path\n");
1157 rndis_ipa_ctx->rx_dropped++;
1158 dev_kfree_skb_any(skb);
1159 return;
1160 }
1161
1162 trace_rndis_netif_ni(skb->protocol);
1163 result = netif_rx_ni(skb);
1164 if (result)
1165 RNDIS_IPA_ERROR("fail on netif_rx_ni\n");
1166 rndis_ipa_ctx->net->stats.rx_packets++;
1167 rndis_ipa_ctx->net->stats.rx_bytes += packet_len;
1168}
1169
1170/** rndis_ipa_stop() - notify the network interface to stop
1171 * sending/receiving data
1172 * @net: the network device being stopped.
1173 *
1174 * This API is used by Linux network stack to notify the network driver that
1175 * its state was changed to "down"
1176 * The driver will stop the "send" queue and change its internal
1177 * state to "Connected".
1178 * The Netdev shall be returned to be "Up" after rndis_ipa_open().
1179 */
1180static int rndis_ipa_stop(struct net_device *net)
1181{
1182 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
1183 int next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301184 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001185
1186 RNDIS_IPA_LOG_ENTRY();
1187
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301188 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1189
Amir Levya7146102016-11-08 14:10:58 +02001190 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_STOP);
1191 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301192 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001193 RNDIS_IPA_DEBUG("can't do network interface down without up\n");
1194 return -EPERM;
1195 }
1196
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301197 rndis_ipa_ctx->state = next_state;
1198
1199 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1200
Amir Levya7146102016-11-08 14:10:58 +02001201 netif_stop_queue(net);
1202 pr_info("RNDIS_IPA NetDev queue is stopped\n");
1203
Amir Levya7146102016-11-08 14:10:58 +02001204 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1205
1206 RNDIS_IPA_LOG_EXIT();
1207
1208 return 0;
1209}
1210
1211/** rndis_ipa_disconnect() - notify rndis_ipa Netdev that the USB pipes
1212 * were disconnected
1213 * @private: same value that was set by init(), this parameter holds the
1214 * network device pointer.
1215 *
1216 * USB shall notify the Netdev after disconnecting the pipe.
1217 * - The internal driver state shall returned to its previous
1218 * state (Up or Initialized).
1219 * - Linux network stack shall be informed for carrier off to notify
1220 * user space for pipe disconnect
1221 * - send queue shall be stopped
1222 * During the transition between the pipe disconnection to
1223 * the Netdev notification packets
1224 * are expected to be dropped by IPA driver or IPA core.
1225 */
1226int rndis_ipa_pipe_disconnect_notify(void *private)
1227{
1228 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1229 int next_state;
1230 int outstanding_dropped_pkts;
1231 int retval;
1232 int ret;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301233 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001234
1235 RNDIS_IPA_LOG_ENTRY();
1236
1237 ret = 0;
1238 NULL_CHECK_RETVAL(rndis_ipa_ctx);
1239 if (ret)
1240 return ret;
1241 RNDIS_IPA_DEBUG("private=0x%p\n", private);
1242
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301243 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1244
Amir Levya7146102016-11-08 14:10:58 +02001245 next_state = rndis_ipa_next_state
1246 (rndis_ipa_ctx->state,
1247 RNDIS_IPA_DISCONNECT);
1248 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301249 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001250 RNDIS_IPA_ERROR("can't disconnect before connect\n");
1251 return -EPERM;
1252 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301253 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001254
1255 if (rndis_ipa_ctx->during_xmit_error) {
1256 RNDIS_IPA_DEBUG("canceling xmit-error delayed work\n");
1257 cancel_delayed_work_sync(
1258 &rndis_ipa_ctx->xmit_error_delayed_work);
1259 rndis_ipa_ctx->during_xmit_error = false;
1260 }
1261
1262 netif_carrier_off(rndis_ipa_ctx->net);
1263 RNDIS_IPA_DEBUG("carrier_off notification was sent\n");
1264
1265 netif_stop_queue(rndis_ipa_ctx->net);
1266 RNDIS_IPA_DEBUG("queue stopped\n");
1267
1268 outstanding_dropped_pkts =
1269 atomic_read(&rndis_ipa_ctx->outstanding_pkts);
1270
1271 rndis_ipa_ctx->net->stats.tx_dropped += outstanding_dropped_pkts;
1272 atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);
1273
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301274#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001275 if (ipa_pm_is_used())
1276 retval = rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
1277 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301278#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001279 retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +02001280 if (retval) {
1281 RNDIS_IPA_ERROR("Fail to clean RM\n");
1282 return retval;
1283 }
1284 RNDIS_IPA_DEBUG("RM was successfully destroyed\n");
1285
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301286 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1287 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
1288 RNDIS_IPA_DISCONNECT);
1289 if (next_state == RNDIS_IPA_INVALID) {
1290 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1291 RNDIS_IPA_ERROR("can't disconnect before connect\n");
1292 return -EPERM;
1293 }
Amir Levya7146102016-11-08 14:10:58 +02001294 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301295 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1296
Amir Levya7146102016-11-08 14:10:58 +02001297 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1298
1299 pr_info("RNDIS_IPA NetDev pipes disconnected (%d outstanding clr)\n",
1300 outstanding_dropped_pkts);
1301
1302 RNDIS_IPA_LOG_EXIT();
1303
1304 return 0;
1305}
1306EXPORT_SYMBOL(rndis_ipa_pipe_disconnect_notify);
1307
1308/**
1309 * rndis_ipa_cleanup() - unregister the network interface driver and free
1310 * internal data structs.
1311 * @private: same value that was set by init(), this
1312 * parameter holds the network device pointer.
1313 *
1314 * This function shall be called once the network interface is not
1315 * needed anymore, e.g: when the USB composition does not support it.
1316 * This function shall be called after the pipes were disconnected.
1317 * Detailed description:
1318 * - remove header-insertion headers from IPA core
1319 * - delete the driver dependency defined for IPA resource manager and
1320 * destroy the producer resource.
1321 * - remove the debugfs entries
1322 * - deregister the network interface from Linux network stack
1323 * - free all internal data structs
1324 *
1325 * It is assumed that no packets shall be sent through HW bridging
1326 * during cleanup to avoid packets trying to add an header that is
1327 * removed during cleanup (IPA configuration manager should have
1328 * removed them at this point)
1329 */
1330void rndis_ipa_cleanup(void *private)
1331{
1332 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1333 int next_state;
1334 int retval;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301335 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001336
1337 RNDIS_IPA_LOG_ENTRY();
1338
1339 RNDIS_IPA_DEBUG("private=0x%p\n", private);
1340
1341 if (!rndis_ipa_ctx) {
1342 RNDIS_IPA_ERROR("rndis_ipa_ctx NULL pointer\n");
1343 return;
1344 }
1345
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301346 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001347 next_state = rndis_ipa_next_state
1348 (rndis_ipa_ctx->state,
1349 RNDIS_IPA_CLEANUP);
1350 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301351 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001352 RNDIS_IPA_ERROR("use disconnect()before clean()\n");
1353 return;
1354 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301355 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1356
Amir Levya7146102016-11-08 14:10:58 +02001357 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1358
1359 retval = rndis_ipa_deregister_properties(rndis_ipa_ctx->net->name);
1360 if (retval) {
1361 RNDIS_IPA_ERROR("Fail to deregister Tx/Rx properties\n");
1362 return;
1363 }
1364 RNDIS_IPA_DEBUG("deregister Tx/Rx properties was successful\n");
1365
1366 retval = rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
1367 if (retval)
1368 RNDIS_IPA_ERROR(
1369 "Failed removing RNDIS headers from IPA core. Continue anyway\n");
1370 else
1371 RNDIS_IPA_DEBUG("RNDIS headers were removed from IPA core\n");
1372
1373 rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
1374 RNDIS_IPA_DEBUG("debugfs remove was done\n");
1375
1376 unregister_netdev(rndis_ipa_ctx->net);
1377 RNDIS_IPA_DEBUG("netdev unregistered\n");
1378
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301379 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1380 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
1381 RNDIS_IPA_CLEANUP);
1382 if (next_state == RNDIS_IPA_INVALID) {
1383 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1384 RNDIS_IPA_ERROR("use disconnect()before clean()\n");
1385 return;
1386 }
Amir Levya7146102016-11-08 14:10:58 +02001387 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301388 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001389 free_netdev(rndis_ipa_ctx->net);
1390 pr_info("RNDIS_IPA NetDev was cleaned\n");
1391
1392 RNDIS_IPA_LOG_EXIT();
1393}
1394EXPORT_SYMBOL(rndis_ipa_cleanup);
1395
1396static void rndis_ipa_enable_data_path(struct rndis_ipa_dev *rndis_ipa_ctx)
1397{
1398 if (rndis_ipa_ctx->device_ready_notify) {
1399 rndis_ipa_ctx->device_ready_notify();
1400 RNDIS_IPA_DEBUG("USB device_ready_notify() was called\n");
1401 } else {
1402 RNDIS_IPA_DEBUG("device_ready_notify() not supplied\n");
1403 }
1404
1405 netif_start_queue(rndis_ipa_ctx->net);
1406 RNDIS_IPA_DEBUG("netif_start_queue() was called\n");
1407}
1408
1409static void rndis_ipa_xmit_error(struct sk_buff *skb)
1410{
1411 bool retval;
1412 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
1413 unsigned long delay_jiffies;
1414 u8 rand_dealy_msec;
1415
1416 RNDIS_IPA_LOG_ENTRY();
1417
1418 RNDIS_IPA_DEBUG("starting Tx-queue backoff\n");
1419
1420 netif_stop_queue(rndis_ipa_ctx->net);
1421 RNDIS_IPA_DEBUG("netif_stop_queue was called\n");
1422
1423 skb_pull(skb, sizeof(rndis_template_hdr));
1424 rndis_ipa_ctx->net->stats.tx_errors++;
1425
1426 get_random_bytes(&rand_dealy_msec, sizeof(rand_dealy_msec));
1427 delay_jiffies = msecs_to_jiffies(
1428 rndis_ipa_ctx->error_msec_sleep_time + rand_dealy_msec);
1429
1430 retval = schedule_delayed_work(
1431 &rndis_ipa_ctx->xmit_error_delayed_work, delay_jiffies);
1432 if (!retval) {
1433 RNDIS_IPA_ERROR("fail to schedule delayed work\n");
1434 netif_start_queue(rndis_ipa_ctx->net);
1435 } else {
1436 RNDIS_IPA_DEBUG
1437 ("work scheduled to start Tx-queue in %d msec\n",
1438 rndis_ipa_ctx->error_msec_sleep_time +
1439 rand_dealy_msec);
1440 rndis_ipa_ctx->during_xmit_error = true;
1441 }
1442
1443 RNDIS_IPA_LOG_EXIT();
1444}
1445
1446static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work)
1447{
1448 struct rndis_ipa_dev *rndis_ipa_ctx;
1449 struct delayed_work *delayed_work;
1450
1451 RNDIS_IPA_LOG_ENTRY();
1452
1453 RNDIS_IPA_DEBUG("Starting queue after xmit error\n");
1454
1455 delayed_work = to_delayed_work(work);
1456 rndis_ipa_ctx = container_of
1457 (delayed_work, struct rndis_ipa_dev,
1458 xmit_error_delayed_work);
1459
1460 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1461 RNDIS_IPA_ERROR
1462 ("error aftercare handling in bad state (%d)",
1463 rndis_ipa_ctx->state);
1464 return;
1465 }
1466
1467 rndis_ipa_ctx->during_xmit_error = false;
1468
1469 netif_start_queue(rndis_ipa_ctx->net);
1470 RNDIS_IPA_DEBUG("netif_start_queue() was called\n");
1471
1472 RNDIS_IPA_LOG_EXIT();
1473}
1474
1475/**
1476 * rndis_ipa_prepare_header_insertion() - prepare the header insertion request
1477 * for IPA driver
1478 * eth_type: the Ethernet type for this header-insertion header
1479 * hdr_name: string that shall represent this header in IPA data base
1480 * add_hdr: output for caller to be used with ipa_add_hdr() to configure
1481 * the IPA core
1482 * dst_mac: tethered PC MAC (Ethernet) address to be added to packets
1483 * for IPA->USB pipe
1484 * src_mac: device MAC (Ethernet) address to be added to packets
1485 * for IPA->USB pipe
Amir Levy2da9d452017-12-12 10:09:46 +02001486 * is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02001487 *
1488 * This function shall build the header-insertion block request for a
1489 * single Ethernet+RNDIS header)
1490 * this header shall be inserted for packets processed by IPA
1491 * and destined for USB client.
1492 * This header shall be used for HW bridging for packets destined for
1493 * tethered PC.
1494 * For SW data-path, this header won't be used.
1495 */
1496static void rndis_ipa_prepare_header_insertion(
1497 int eth_type,
1498 const char *hdr_name, struct ipa_hdr_add *add_hdr,
Amir Levy2da9d452017-12-12 10:09:46 +02001499 const void *dst_mac, const void *src_mac, bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02001500{
1501 struct ethhdr *eth_hdr;
Amir Levy2da9d452017-12-12 10:09:46 +02001502 struct vlan_ethhdr *eth_vlan_hdr;
Amir Levya7146102016-11-08 14:10:58 +02001503
1504 add_hdr->hdr_len = sizeof(rndis_template_hdr);
1505 add_hdr->is_partial = false;
1506 strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);
1507
1508 memcpy(add_hdr->hdr, &rndis_template_hdr, sizeof(rndis_template_hdr));
Amir Levya7146102016-11-08 14:10:58 +02001509 add_hdr->is_eth2_ofst_valid = true;
1510 add_hdr->eth2_ofst = sizeof(rndis_template_hdr);
Amir Levy2da9d452017-12-12 10:09:46 +02001511
1512 if (is_vlan_mode) {
1513 eth_vlan_hdr = (struct vlan_ethhdr *)(add_hdr->hdr +
1514 sizeof(rndis_template_hdr));
1515 memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
1516 memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
1517 eth_vlan_hdr->h_vlan_encapsulated_proto = htons(eth_type);
1518 eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
1519 add_hdr->hdr_len += VLAN_ETH_HLEN;
1520 add_hdr->type = IPA_HDR_L2_802_1Q;
1521 } else {
1522 eth_hdr = (struct ethhdr *)(add_hdr->hdr +
1523 sizeof(rndis_template_hdr));
1524 memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
1525 memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
1526 eth_hdr->h_proto = htons(eth_type);
1527 add_hdr->hdr_len += ETH_HLEN;
1528 add_hdr->type = IPA_HDR_L2_ETHERNET_II;
1529 }
Amir Levya7146102016-11-08 14:10:58 +02001530}
1531
1532/**
1533 * rndis_ipa_hdrs_cfg() - configure header insertion block in IPA core
1534 * to allow HW bridging
1535 * @rndis_ipa_ctx: main driver context
1536 * @dst_mac: destination MAC address (tethered PC)
1537 * @src_mac: source MAC address (MDM device)
1538 *
1539 * This function shall add 2 headers.
1540 * One header for Ipv4 and one header for Ipv6.
1541 * Both headers shall contain Ethernet header and RNDIS header, the only
1542 * difference shall be in the EtherTye field.
1543 * Headers will be committed to HW
1544 *
1545 * Returns negative errno, or zero on success
1546 */
1547static int rndis_ipa_hdrs_cfg(
1548 struct rndis_ipa_dev *rndis_ipa_ctx,
1549 const void *dst_mac, const void *src_mac)
1550{
1551 struct ipa_ioc_add_hdr *hdrs;
1552 struct ipa_hdr_add *ipv4_hdr;
1553 struct ipa_hdr_add *ipv6_hdr;
1554 int result = 0;
1555
1556 RNDIS_IPA_LOG_ENTRY();
1557
1558 hdrs = kzalloc
1559 (sizeof(*hdrs) + sizeof(*ipv4_hdr) + sizeof(*ipv6_hdr),
1560 GFP_KERNEL);
1561 if (!hdrs) {
1562 RNDIS_IPA_ERROR("mem allocation fail for header-insertion\n");
1563 result = -ENOMEM;
1564 goto fail_mem;
1565 }
1566
1567 ipv4_hdr = &hdrs->hdr[0];
1568 ipv6_hdr = &hdrs->hdr[1];
1569 rndis_ipa_prepare_header_insertion
1570 (ETH_P_IP, IPV4_HDR_NAME,
Amir Levy2da9d452017-12-12 10:09:46 +02001571 ipv4_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +02001572 rndis_ipa_prepare_header_insertion
1573 (ETH_P_IPV6, IPV6_HDR_NAME,
Amir Levy2da9d452017-12-12 10:09:46 +02001574 ipv6_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +02001575
1576 hdrs->commit = 1;
1577 hdrs->num_hdrs = 2;
1578 result = ipa_add_hdr(hdrs);
1579 if (result) {
1580 RNDIS_IPA_ERROR("Fail on Header-Insertion(%d)\n", result);
1581 goto fail_add_hdr;
1582 }
1583 if (ipv4_hdr->status) {
1584 RNDIS_IPA_ERROR("Fail on Header-Insertion ipv4(%d)\n",
1585 ipv4_hdr->status);
1586 result = ipv4_hdr->status;
1587 goto fail_add_hdr;
1588 }
1589 if (ipv6_hdr->status) {
1590 RNDIS_IPA_ERROR("Fail on Header-Insertion ipv6(%d)\n",
1591 ipv6_hdr->status);
1592 result = ipv6_hdr->status;
1593 goto fail_add_hdr;
1594 }
1595 rndis_ipa_ctx->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
1596 rndis_ipa_ctx->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
1597
1598 RNDIS_IPA_LOG_EXIT();
1599
1600fail_add_hdr:
1601 kfree(hdrs);
1602fail_mem:
1603 return result;
1604}
1605
1606/**
1607 * rndis_ipa_hdrs_destroy() - remove the IPA core configuration done for
1608 * the driver data path bridging.
1609 * @rndis_ipa_ctx: the driver context
1610 *
1611 * Revert the work done on rndis_ipa_hdrs_cfg(), which is,
1612 * remove 2 headers for Ethernet+RNDIS.
1613 */
1614static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
1615{
1616 struct ipa_ioc_del_hdr *del_hdr;
1617 struct ipa_hdr_del *ipv4;
1618 struct ipa_hdr_del *ipv6;
1619 int result;
1620
1621 del_hdr = kzalloc(sizeof(*del_hdr) + sizeof(*ipv4) +
1622 sizeof(*ipv6), GFP_KERNEL);
1623 if (!del_hdr) {
1624 RNDIS_IPA_ERROR("memory allocation for del_hdr failed\n");
1625 return -ENOMEM;
1626 }
1627
1628 del_hdr->commit = 1;
1629 del_hdr->num_hdls = 2;
1630
1631 ipv4 = &del_hdr->hdl[0];
1632 ipv4->hdl = rndis_ipa_ctx->eth_ipv4_hdr_hdl;
1633 ipv6 = &del_hdr->hdl[1];
1634 ipv6->hdl = rndis_ipa_ctx->eth_ipv6_hdr_hdl;
1635
1636 result = ipa_del_hdr(del_hdr);
1637 if (result || ipv4->status || ipv6->status)
1638 RNDIS_IPA_ERROR("ipa_del_hdr failed\n");
1639 else
1640 RNDIS_IPA_DEBUG("hdrs deletion done\n");
1641
1642 kfree(del_hdr);
1643 return result;
1644}
1645
1646static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net)
1647{
1648 return &net->stats;
1649}
1650
1651/**
1652 * rndis_ipa_register_properties() - set Tx/Rx properties needed
1653 * by IPA configuration manager
1654 * @netdev_name: a string with the name of the network interface device
Amir Levy2da9d452017-12-12 10:09:46 +02001655 * @is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02001656 *
1657 * Register Tx/Rx properties to allow user space configuration (IPA
1658 * Configuration Manager):
1659 *
1660 * - Two Tx properties (IPA->USB): specify the header names and pipe number
1661 * that shall be used by user space for header-addition configuration
1662 * for ipv4/ipv6 packets flowing from IPA to USB for HW bridging data.
1663 * That header-addition header is added by the Netdev and used by user
1664 * space to close the the HW bridge by adding filtering and routing rules
1665 * that point to this header.
1666 *
1667 * - Two Rx properties (USB->IPA): these properties shall be used by user space
1668 * to configure the IPA core to identify the packets destined
1669 * for Apps-processor by configuring the unicast rules destined for
1670 * the Netdev IP address.
1671 * This rules shall be added based on the attribute mask supplied at
1672 * this function, that is, always hit rule.
1673 */
Amir Levy2da9d452017-12-12 10:09:46 +02001674static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02001675{
1676 struct ipa_tx_intf tx_properties = {0};
1677 struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
1678 struct ipa_ioc_tx_intf_prop *ipv4_property;
1679 struct ipa_ioc_tx_intf_prop *ipv6_property;
1680 struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
1681 struct ipa_rx_intf rx_properties = {0};
1682 struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
1683 struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
Amir Levy2da9d452017-12-12 10:09:46 +02001684 enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
Amir Levya7146102016-11-08 14:10:58 +02001685 int result = 0;
1686
1687 RNDIS_IPA_LOG_ENTRY();
1688
Amir Levy2da9d452017-12-12 10:09:46 +02001689 if (is_vlan_mode)
1690 hdr_l2_type = IPA_HDR_L2_802_1Q;
1691
Amir Levya7146102016-11-08 14:10:58 +02001692 tx_properties.prop = properties;
1693 ipv4_property = &tx_properties.prop[0];
1694 ipv4_property->ip = IPA_IP_v4;
1695 ipv4_property->dst_pipe = IPA_TO_USB_CLIENT;
1696 strlcpy
1697 (ipv4_property->hdr_name, IPV4_HDR_NAME,
1698 IPA_RESOURCE_NAME_MAX);
Amir Levy2da9d452017-12-12 10:09:46 +02001699 ipv4_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001700 ipv6_property = &tx_properties.prop[1];
1701 ipv6_property->ip = IPA_IP_v6;
1702 ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
1703 strlcpy
1704 (ipv6_property->hdr_name, IPV6_HDR_NAME,
1705 IPA_RESOURCE_NAME_MAX);
Amir Levy2da9d452017-12-12 10:09:46 +02001706 ipv6_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001707 tx_properties.num_props = 2;
1708
1709 rx_properties.prop = rx_ioc_properties;
1710 rx_ipv4_property = &rx_properties.prop[0];
1711 rx_ipv4_property->ip = IPA_IP_v4;
1712 rx_ipv4_property->attrib.attrib_mask = 0;
1713 rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
Amir Levy2da9d452017-12-12 10:09:46 +02001714 rx_ipv4_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001715 rx_ipv6_property = &rx_properties.prop[1];
1716 rx_ipv6_property->ip = IPA_IP_v6;
1717 rx_ipv6_property->attrib.attrib_mask = 0;
1718 rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
Amir Levy2da9d452017-12-12 10:09:46 +02001719 rx_ipv6_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001720 rx_properties.num_props = 2;
1721
1722 result = ipa_register_intf("rndis0", &tx_properties, &rx_properties);
1723 if (result)
1724 RNDIS_IPA_ERROR("fail on Tx/Rx properties registration\n");
1725 else
1726 RNDIS_IPA_DEBUG("Tx/Rx properties registration done\n");
1727
1728 RNDIS_IPA_LOG_EXIT();
1729
1730 return result;
1731}
1732
1733/**
1734 * rndis_ipa_deregister_properties() - remove the 2 Tx and 2 Rx properties
1735 * @netdev_name: a string with the name of the network interface device
1736 *
1737 * This function revert the work done on rndis_ipa_register_properties().
1738 */
1739static int rndis_ipa_deregister_properties(char *netdev_name)
1740{
1741 int result;
1742
1743 RNDIS_IPA_LOG_ENTRY();
1744
1745 result = ipa_deregister_intf(netdev_name);
1746 if (result) {
1747 RNDIS_IPA_DEBUG("Fail on Tx prop deregister\n");
1748 return result;
1749 }
1750 RNDIS_IPA_LOG_EXIT();
1751
1752 return 0;
1753}
1754
1755/**
1756 * rndis_ipa_create_rm_resource() -creates the resource representing
1757 * this Netdev and supply notification callback for resource event
1758 * such as Grant/Release
1759 * @rndis_ipa_ctx: this driver context
1760 *
1761 * In order make sure all needed resources are available during packet
1762 * transmit this Netdev shall use Request/Release mechanism of
1763 * the IPA resource manager.
1764 * This mechanism shall iterate over a dependency graph and make sure
1765 * all dependent entities are ready to for packet Tx
1766 * transfer (Apps->IPA->USB).
1767 * In this function the resource representing the Netdev is created
1768 * in addition to the basic dependency between the Netdev and the USB client.
1769 * Hence, USB client, is a dependency for the Netdev and may be notified in
1770 * case of packet transmit from this Netdev to tethered Host.
1771 * As implied from the "may" in the above sentence there is a scenario where
1772 * the USB is not notified. This is done thanks to the IPA resource manager
1773 * inactivity timer.
1774 * The inactivity timer allow the Release requests to be delayed in order
1775 * prevent ping-pong with the USB and other dependencies.
1776 */
1777static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
1778{
1779 struct ipa_rm_create_params create_params = {0};
1780 struct ipa_rm_perf_profile profile;
1781 int result;
1782
1783 RNDIS_IPA_LOG_ENTRY();
1784
1785 create_params.name = DRV_RESOURCE_ID;
1786 create_params.reg_params.user_data = rndis_ipa_ctx;
1787 create_params.reg_params.notify_cb = rndis_ipa_rm_notify;
1788 result = ipa_rm_create_resource(&create_params);
1789 if (result) {
1790 RNDIS_IPA_ERROR("Fail on ipa_rm_create_resource\n");
1791 goto fail_rm_create;
1792 }
1793 RNDIS_IPA_DEBUG("RM client was created\n");
1794
1795 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
1796 ipa_rm_set_perf_profile(DRV_RESOURCE_ID, &profile);
1797
1798 result = ipa_rm_inactivity_timer_init
1799 (DRV_RESOURCE_ID,
1800 INACTIVITY_MSEC_DELAY);
1801 if (result) {
1802 RNDIS_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
1803 goto fail_inactivity_timer;
1804 }
1805
1806 RNDIS_IPA_DEBUG("rm_it client was created\n");
1807
1808 result = ipa_rm_add_dependency_sync
1809 (DRV_RESOURCE_ID,
1810 IPA_RM_RESOURCE_USB_CONS);
1811
1812 if (result && result != -EINPROGRESS)
1813 RNDIS_IPA_ERROR("unable to add RNDIS/USB dependency (%d)\n",
1814 result);
1815 else
1816 RNDIS_IPA_DEBUG("RNDIS/USB dependency was set\n");
1817
1818 result = ipa_rm_add_dependency_sync
1819 (IPA_RM_RESOURCE_USB_PROD,
1820 IPA_RM_RESOURCE_APPS_CONS);
1821 if (result && result != -EINPROGRESS)
1822 RNDIS_IPA_ERROR("unable to add USB/APPS dependency (%d)\n",
1823 result);
1824 else
1825 RNDIS_IPA_DEBUG("USB/APPS dependency was set\n");
1826
1827 RNDIS_IPA_LOG_EXIT();
1828
1829 return 0;
1830
1831fail_inactivity_timer:
1832fail_rm_create:
1833 return result;
1834}
1835
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301836#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001837static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
1838{
1839 struct rndis_ipa_dev *rndis_ipa_ctx = p;
1840
1841 RNDIS_IPA_LOG_ENTRY();
1842
1843 if (event != IPA_PM_CLIENT_ACTIVATED) {
1844 RNDIS_IPA_ERROR("unexpected event %d\n", event);
1845 WARN_ON(1);
1846 return;
1847 }
1848 RNDIS_IPA_DEBUG("Resource Granted\n");
1849
1850 if (netif_queue_stopped(rndis_ipa_ctx->net)) {
1851 RNDIS_IPA_DEBUG("starting queue\n");
1852 netif_start_queue(rndis_ipa_ctx->net);
1853 } else {
1854 RNDIS_IPA_DEBUG("queue already awake\n");
1855 }
1856
1857 RNDIS_IPA_LOG_EXIT();
1858}
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301859#endif
Amir Levya7146102016-11-08 14:10:58 +02001860/**
1861 * rndis_ipa_destroy_rm_resource() - delete the dependency and destroy
1862 * the resource done on rndis_ipa_create_rm_resource()
1863 * @rndis_ipa_ctx: this driver context
1864 *
1865 * This function shall delete the dependency create between
1866 * the Netdev to the USB.
1867 * In addition the inactivity time shall be destroy and the resource shall
1868 * be deleted.
1869 */
1870static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
1871{
1872 int result;
1873
1874 RNDIS_IPA_LOG_ENTRY();
1875
1876 result = ipa_rm_delete_dependency
1877 (DRV_RESOURCE_ID,
1878 IPA_RM_RESOURCE_USB_CONS);
1879 if (result && result != -EINPROGRESS) {
1880 RNDIS_IPA_ERROR("Fail to delete RNDIS/USB dependency\n");
1881 goto bail;
1882 }
1883 RNDIS_IPA_DEBUG("RNDIS/USB dependency was successfully deleted\n");
1884
1885 result = ipa_rm_delete_dependency
1886 (IPA_RM_RESOURCE_USB_PROD,
1887 IPA_RM_RESOURCE_APPS_CONS);
1888 if (result == -EINPROGRESS) {
1889 RNDIS_IPA_DEBUG("RM dependency deletion is in progress");
1890 } else if (result) {
1891 RNDIS_IPA_ERROR("Fail to delete USB/APPS dependency\n");
1892 goto bail;
1893 } else {
1894 RNDIS_IPA_DEBUG("USB/APPS dependency was deleted\n");
1895 }
1896
1897 result = ipa_rm_inactivity_timer_destroy(DRV_RESOURCE_ID);
1898 if (result) {
1899 RNDIS_IPA_ERROR("Fail to destroy inactivity timern");
1900 goto bail;
1901 }
1902 RNDIS_IPA_DEBUG("RM inactivity timer was successfully destroy\n");
1903
1904 result = ipa_rm_delete_resource(DRV_RESOURCE_ID);
1905 if (result) {
1906 RNDIS_IPA_ERROR("resource deletion failed\n");
1907 goto bail;
1908 }
1909 RNDIS_IPA_DEBUG
1910 ("Netdev RM resource was deleted (resid:%d)\n",
1911 DRV_RESOURCE_ID);
1912
1913 RNDIS_IPA_LOG_EXIT();
1914
1915bail:
1916 return result;
1917}
1918
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301919#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001920static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
1921{
1922 int result;
1923 struct ipa_pm_register_params pm_reg;
1924
1925 memset(&pm_reg, 0, sizeof(pm_reg));
1926
1927 pm_reg.name = rndis_ipa_ctx->net->name;
1928 pm_reg.user_data = rndis_ipa_ctx;
1929 pm_reg.callback = rndis_ipa_pm_cb;
1930 pm_reg.group = IPA_PM_GROUP_APPS;
1931 result = ipa_pm_register(&pm_reg, &rndis_ipa_ctx->pm_hdl);
1932 if (result) {
1933 RNDIS_IPA_ERROR("failed to create IPA PM client %d\n", result);
1934 return result;
1935 }
1936 return 0;
1937}
1938
1939static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
1940{
1941 ipa_pm_deactivate_sync(rndis_ipa_ctx->pm_hdl);
1942 ipa_pm_deregister(rndis_ipa_ctx->pm_hdl);
1943 rndis_ipa_ctx->pm_hdl = ~0;
1944 return 0;
1945}
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301946#endif
Amir Levya7146102016-11-08 14:10:58 +02001947/**
1948 * resource_request() - request for the Netdev resource
1949 * @rndis_ipa_ctx: main driver context
1950 *
1951 * This function shall send the IPA resource manager inactivity time a request
1952 * to Grant the Netdev producer.
1953 * In case the resource is already Granted the function shall return immediately
1954 * and "pet" the inactivity timer.
1955 * In case the resource was not already Granted this function shall
1956 * return EINPROGRESS and the Netdev shall stop the send queue until
1957 * the IPA resource manager notify it that the resource is
1958 * granted (done in a differ context)
1959 */
1960static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx)
1961{
1962 int result = 0;
1963
1964 if (!rm_enabled(rndis_ipa_ctx))
Michael Adisumarta3e350812017-09-18 14:54:36 -07001965 return result;
1966
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301967#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001968 if (ipa_pm_is_used())
1969 return ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301970#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001971 return ipa_rm_inactivity_timer_request_resource(
Amir Levya7146102016-11-08 14:10:58 +02001972 DRV_RESOURCE_ID);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001973
Amir Levya7146102016-11-08 14:10:58 +02001974}
1975
1976/**
1977 * resource_release() - release the Netdev resource
1978 * @rndis_ipa_ctx: main driver context
1979 *
1980 * start the inactivity timer count down.by using the IPA resource
1981 * manager inactivity time.
1982 * The actual resource release shall occur only if no request shall be done
1983 * during the INACTIVITY_MSEC_DELAY.
1984 */
1985static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
1986{
1987 if (!rm_enabled(rndis_ipa_ctx))
Michael Adisumarta3e350812017-09-18 14:54:36 -07001988 return;
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301989#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001990 if (ipa_pm_is_used())
1991 ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
1992 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301993#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001994 ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
1995
Amir Levya7146102016-11-08 14:10:58 +02001996 return;
1997}
1998
1999/**
2000 * rndis_encapsulate_skb() - encapsulate the given Ethernet skb with
2001 * an RNDIS header
2002 * @skb: packet to be encapsulated with the RNDIS header
Amir Levy2da9d452017-12-12 10:09:46 +02002003 * @rndis_ipa_ctx: main driver context
Amir Levya7146102016-11-08 14:10:58 +02002004 *
2005 * Shall use a template header for RNDIS and update it with the given
2006 * skb values.
2007 * Ethernet is expected to be already encapsulate the packet.
2008 */
Amir Levy2da9d452017-12-12 10:09:46 +02002009static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
2010 struct rndis_ipa_dev *rndis_ipa_ctx)
Amir Levya7146102016-11-08 14:10:58 +02002011{
2012 struct rndis_pkt_hdr *rndis_hdr;
2013 int payload_byte_len = skb->len;
2014
2015 /* if there is no room in this skb, allocate a new one */
2016 if (unlikely(skb_headroom(skb) < sizeof(rndis_template_hdr))) {
2017 struct sk_buff *new_skb = skb_copy_expand(skb,
2018 sizeof(rndis_template_hdr), 0, GFP_ATOMIC);
2019 if (!new_skb) {
2020 RNDIS_IPA_ERROR("no memory for skb expand\n");
2021 return skb;
2022 }
2023 RNDIS_IPA_DEBUG("skb expanded. old %p new %p\n", skb, new_skb);
2024 dev_kfree_skb_any(skb);
2025 skb = new_skb;
2026 }
2027
Amir Levy2da9d452017-12-12 10:09:46 +02002028 if (rndis_ipa_ctx->is_vlan_mode)
2029 if (unlikely(skb->protocol != ETH_P_8021Q))
2030 RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
2031
Amir Levya7146102016-11-08 14:10:58 +02002032 /* make room at the head of the SKB to put the RNDIS header */
2033 rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
2034 sizeof(rndis_template_hdr));
2035
2036 memcpy(rndis_hdr, &rndis_template_hdr, sizeof(*rndis_hdr));
2037 rndis_hdr->msg_len += payload_byte_len;
2038 rndis_hdr->data_len += payload_byte_len;
2039
2040 return skb;
2041}
2042
2043/**
2044 * rx_filter() - logic that decide if the current skb is to be filtered out
2045 * @skb: skb that may be sent up to the network stack
2046 *
2047 * This function shall do Rx packet filtering on the Netdev level.
2048 */
2049static bool rx_filter(struct sk_buff *skb)
2050{
2051 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
2052
2053 return rndis_ipa_ctx->rx_filter;
2054}
2055
2056/**
2057 * tx_filter() - logic that decide if the current skb is to be filtered out
2058 * @skb: skb that may be sent to the USB core
2059 *
2060 * This function shall do Tx packet filtering on the Netdev level.
2061 * ICMP filter bypass is possible to allow only ICMP packet to be
2062 * sent (pings and etc)
2063 */
2064
2065static bool tx_filter(struct sk_buff *skb)
2066{
2067 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
2068 bool is_icmp;
2069
2070 if (likely(!rndis_ipa_ctx->tx_filter))
2071 return false;
2072
2073 is_icmp = (skb->protocol == htons(ETH_P_IP) &&
2074 ip_hdr(skb)->protocol == IPPROTO_ICMP);
2075
2076 if ((!rndis_ipa_ctx->icmp_filter) && is_icmp)
2077 return false;
2078
2079 return true;
2080}
2081
2082/**
2083 * rm_enabled() - allow the use of resource manager Request/Release to
2084 * be bypassed
2085 * @rndis_ipa_ctx: main driver context
2086 *
2087 * By disabling the resource manager flag the Request for the Netdev resource
2088 * shall be bypassed and the packet shall be sent.
2089 * accordingly, Release request shall be bypass as well.
2090 */
2091static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
2092{
2093 return rndis_ipa_ctx->rm_enable;
2094}
2095
2096/**
2097 * rndis_ipa_ep_registers_cfg() - configure the USB endpoints
2098 * @usb_to_ipa_hdl: handle received from ipa_connect which represents
2099 * the USB to IPA end-point
2100 * @ipa_to_usb_hdl: handle received from ipa_connect which represents
2101 * the IPA to USB end-point
2102 * @max_xfer_size_bytes_to_dev: the maximum size, in bytes, that the device
2103 * expects to receive from the host. supplied on REMOTE_NDIS_INITIALIZE_CMPLT.
2104 * @max_xfer_size_bytes_to_host: the maximum size, in bytes, that the host
2105 * expects to receive from the device. supplied on REMOTE_NDIS_INITIALIZE_MSG.
2106 * @mtu: the netdev MTU size, in bytes
Amir Levy2da9d452017-12-12 10:09:46 +02002107 * @deaggr_enable: should deaggregation be enabled?
2108 * @is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02002109 *
2110 * USB to IPA pipe:
2111 * - de-aggregation
2112 * - Remove Ethernet header
2113 * - Remove RNDIS header
2114 * - SRC NAT
2115 * - Default routing(0)
2116 * IPA to USB Pipe:
2117 * - aggregation
2118 * - Add Ethernet header
2119 * - Add RNDIS header
2120 */
2121static int rndis_ipa_ep_registers_cfg(
2122 u32 usb_to_ipa_hdl,
2123 u32 ipa_to_usb_hdl,
2124 u32 max_xfer_size_bytes_to_dev,
2125 u32 max_xfer_size_bytes_to_host,
2126 u32 mtu,
Amir Levy2da9d452017-12-12 10:09:46 +02002127 bool deaggr_enable,
2128 bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02002129{
2130 int result;
2131 struct ipa_ep_cfg *usb_to_ipa_ep_cfg;
Amir Levy85650962017-12-20 14:24:18 +02002132 int add = 0;
Amir Levya7146102016-11-08 14:10:58 +02002133
2134 if (deaggr_enable) {
2135 usb_to_ipa_ep_cfg = &usb_to_ipa_ep_cfg_deaggr_en;
2136 RNDIS_IPA_DEBUG("deaggregation enabled\n");
2137 } else {
2138 usb_to_ipa_ep_cfg = &usb_to_ipa_ep_cfg_deaggr_dis;
2139 RNDIS_IPA_DEBUG("deaggregation disabled\n");
Amir Levy85650962017-12-20 14:24:18 +02002140 add = sizeof(struct rndis_pkt_hdr);
Amir Levya7146102016-11-08 14:10:58 +02002141 }
2142
Amir Levy2da9d452017-12-12 10:09:46 +02002143 if (is_vlan_mode) {
2144 usb_to_ipa_ep_cfg->hdr.hdr_len =
Amir Levy85650962017-12-20 14:24:18 +02002145 VLAN_ETH_HLEN + add;
Amir Levy2da9d452017-12-12 10:09:46 +02002146 ipa_to_usb_ep_cfg.hdr.hdr_len =
2147 VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
2148 ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = VLAN_ETH_HLEN;
2149 } else {
2150 usb_to_ipa_ep_cfg->hdr.hdr_len =
Amir Levy85650962017-12-20 14:24:18 +02002151 ETH_HLEN + add;
Amir Levy2da9d452017-12-12 10:09:46 +02002152 ipa_to_usb_ep_cfg.hdr.hdr_len =
2153 ETH_HLEN + sizeof(struct rndis_pkt_hdr);
2154 ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = ETH_HLEN;
2155 }
2156
Amir Levya7146102016-11-08 14:10:58 +02002157 usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_xfer_size_bytes_to_dev;
2158 result = ipa_cfg_ep(usb_to_ipa_hdl, usb_to_ipa_ep_cfg);
2159 if (result) {
2160 pr_err("failed to configure USB to IPA point\n");
2161 return result;
2162 }
2163 RNDIS_IPA_DEBUG("IPA<-USB end-point configured\n");
2164
2165 ipa_to_usb_ep_cfg.aggr.aggr_byte_limit =
2166 (max_xfer_size_bytes_to_host - mtu) / 1024;
2167
2168 if (ipa_to_usb_ep_cfg.aggr.aggr_byte_limit == 0) {
2169 ipa_to_usb_ep_cfg.aggr.aggr_time_limit = 0;
2170 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit = 1;
2171 } else {
2172 ipa_to_usb_ep_cfg.aggr.aggr_time_limit =
2173 DEFAULT_AGGR_TIME_LIMIT;
2174 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit =
2175 DEFAULT_AGGR_PKT_LIMIT;
2176 }
2177
2178 RNDIS_IPA_DEBUG(
2179 "RNDIS aggregation param: en=%d byte_limit=%d time_limit=%d pkt_limit=%d\n"
2180 , ipa_to_usb_ep_cfg.aggr.aggr_en,
2181 ipa_to_usb_ep_cfg.aggr.aggr_byte_limit,
2182 ipa_to_usb_ep_cfg.aggr.aggr_time_limit,
2183 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit);
2184
2185 result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
2186 if (result) {
2187 pr_err("failed to configure IPA to USB end-point\n");
2188 return result;
2189 }
2190 RNDIS_IPA_DEBUG("IPA->USB end-point configured\n");
2191
2192 return 0;
2193}
2194
2195/**
2196 * rndis_ipa_set_device_ethernet_addr() - set device Ethernet address
2197 * @dev_ethaddr: device Ethernet address
2198 *
2199 * Returns 0 for success, negative otherwise
2200 */
2201static int rndis_ipa_set_device_ethernet_addr(
2202 u8 *dev_ethaddr,
2203 u8 device_ethaddr[])
2204{
2205 if (!is_valid_ether_addr(device_ethaddr))
2206 return -EINVAL;
2207 memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
2208
2209 return 0;
2210}
2211
2212/** rndis_ipa_next_state - return the next state of the driver
2213 * @current_state: the current state of the driver
2214 * @operation: an enum which represent the operation being made on the driver
2215 * by its API.
2216 *
2217 * This function implements the driver internal state machine.
2218 * Its decisions are based on the driver current state and the operation
2219 * being made.
2220 * In case the operation is invalid this state machine will return
2221 * the value RNDIS_IPA_INVALID to inform the caller for a forbidden sequence.
2222 */
2223static enum rndis_ipa_state rndis_ipa_next_state(
2224 enum rndis_ipa_state current_state,
2225 enum rndis_ipa_operation operation)
2226{
2227 int next_state = RNDIS_IPA_INVALID;
2228
2229 switch (current_state) {
2230 case RNDIS_IPA_UNLOADED:
2231 if (operation == RNDIS_IPA_INITIALIZE)
2232 next_state = RNDIS_IPA_INITIALIZED;
2233 break;
2234 case RNDIS_IPA_INITIALIZED:
2235 if (operation == RNDIS_IPA_CONNECT)
2236 next_state = RNDIS_IPA_CONNECTED;
2237 else if (operation == RNDIS_IPA_OPEN)
2238 next_state = RNDIS_IPA_UP;
2239 else if (operation == RNDIS_IPA_CLEANUP)
2240 next_state = RNDIS_IPA_UNLOADED;
2241 break;
2242 case RNDIS_IPA_CONNECTED:
2243 if (operation == RNDIS_IPA_DISCONNECT)
2244 next_state = RNDIS_IPA_INITIALIZED;
2245 else if (operation == RNDIS_IPA_OPEN)
2246 next_state = RNDIS_IPA_CONNECTED_AND_UP;
2247 break;
2248 case RNDIS_IPA_UP:
2249 if (operation == RNDIS_IPA_STOP)
2250 next_state = RNDIS_IPA_INITIALIZED;
2251 else if (operation == RNDIS_IPA_CONNECT)
2252 next_state = RNDIS_IPA_CONNECTED_AND_UP;
2253 else if (operation == RNDIS_IPA_CLEANUP)
2254 next_state = RNDIS_IPA_UNLOADED;
2255 break;
2256 case RNDIS_IPA_CONNECTED_AND_UP:
2257 if (operation == RNDIS_IPA_STOP)
2258 next_state = RNDIS_IPA_CONNECTED;
2259 else if (operation == RNDIS_IPA_DISCONNECT)
2260 next_state = RNDIS_IPA_UP;
2261 break;
2262 default:
2263 RNDIS_IPA_ERROR("State is not supported\n");
2264 WARN_ON(true);
2265 break;
2266 }
2267
2268 RNDIS_IPA_DEBUG
2269 ("state transition ( %s -> %s )- %s\n",
2270 rndis_ipa_state_string(current_state),
2271 rndis_ipa_state_string(next_state),
2272 next_state == RNDIS_IPA_INVALID ?
2273 "Forbidden" : "Allowed");
2274
2275 return next_state;
2276}
2277
2278/**
2279 * rndis_ipa_state_string - return the state string representation
2280 * @state: enum which describe the state
2281 */
2282static const char *rndis_ipa_state_string(enum rndis_ipa_state state)
2283{
2284 switch (state) {
2285 case RNDIS_IPA_UNLOADED:
2286 return "RNDIS_IPA_UNLOADED";
2287 case RNDIS_IPA_INITIALIZED:
2288 return "RNDIS_IPA_INITIALIZED";
2289 case RNDIS_IPA_CONNECTED:
2290 return "RNDIS_IPA_CONNECTED";
2291 case RNDIS_IPA_UP:
2292 return "RNDIS_IPA_UP";
2293 case RNDIS_IPA_CONNECTED_AND_UP:
2294 return "RNDIS_IPA_CONNECTED_AND_UP";
2295 default:
2296 return "Not supported";
2297 }
2298}
2299
2300static void rndis_ipa_dump_skb(struct sk_buff *skb)
2301{
2302 int i;
2303 u32 *cur = (u32 *)skb->data;
2304 u8 *byte;
2305
2306 RNDIS_IPA_DEBUG
2307 ("packet dump start for skb->len=%d\n",
2308 skb->len);
2309
2310 for (i = 0; i < (skb->len / 4); i++) {
2311 byte = (u8 *)(cur + i);
2312 pr_info
2313 ("%2d %08x %02x %02x %02x %02x\n",
2314 i, *(cur + i),
2315 byte[0], byte[1], byte[2], byte[3]);
2316 }
2317 RNDIS_IPA_DEBUG
2318 ("packet dump ended for skb->len=%d\n", skb->len);
2319}
2320
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302321#ifdef CONFIG_DEBUG_FS
Amir Levya7146102016-11-08 14:10:58 +02002322/**
2323 * Creates the root folder for the driver
2324 */
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302325static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
Amir Levya7146102016-11-08 14:10:58 +02002326{
2327 const mode_t flags_read_write = 0666;
2328 const mode_t flags_read_only = 0444;
2329 const mode_t flags_write_only = 0222;
2330 struct dentry *file;
2331 struct dentry *aggr_directory;
2332
2333 RNDIS_IPA_LOG_ENTRY();
2334
2335 if (!rndis_ipa_ctx)
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302336 return;
Amir Levya7146102016-11-08 14:10:58 +02002337
2338 rndis_ipa_ctx->directory = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
2339 if (!rndis_ipa_ctx->directory) {
2340 RNDIS_IPA_ERROR("could not create debugfs directory entry\n");
2341 goto fail_directory;
2342 }
2343
2344 file = debugfs_create_bool
2345 ("tx_filter", flags_read_write,
2346 rndis_ipa_ctx->directory, &rndis_ipa_ctx->tx_filter);
2347 if (!file) {
2348 RNDIS_IPA_ERROR("could not create debugfs tx_filter file\n");
2349 goto fail_file;
2350 }
2351
2352 file = debugfs_create_bool
2353 ("rx_filter", flags_read_write,
2354 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rx_filter);
2355 if (!file) {
2356 RNDIS_IPA_ERROR("could not create debugfs rx_filter file\n");
2357 goto fail_file;
2358 }
2359
2360 file = debugfs_create_bool
2361 ("icmp_filter", flags_read_write,
2362 rndis_ipa_ctx->directory, &rndis_ipa_ctx->icmp_filter);
2363 if (!file) {
2364 RNDIS_IPA_ERROR("could not create debugfs icmp_filter file\n");
2365 goto fail_file;
2366 }
2367
2368 file = debugfs_create_bool
2369 ("rm_enable", flags_read_write,
2370 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rm_enable);
2371 if (!file) {
2372 RNDIS_IPA_ERROR("could not create debugfs rm file\n");
2373 goto fail_file;
2374 }
2375
2376 file = debugfs_create_u32
2377 ("outstanding_high", flags_read_write,
2378 rndis_ipa_ctx->directory,
2379 &rndis_ipa_ctx->outstanding_high);
2380 if (!file) {
2381 RNDIS_IPA_ERROR("could not create outstanding_high file\n");
2382 goto fail_file;
2383 }
2384
2385 file = debugfs_create_u32
2386 ("outstanding_low", flags_read_write,
2387 rndis_ipa_ctx->directory,
2388 &rndis_ipa_ctx->outstanding_low);
2389 if (!file) {
2390 RNDIS_IPA_ERROR("could not create outstanding_low file\n");
2391 goto fail_file;
2392 }
2393
2394 file = debugfs_create_file
2395 ("outstanding", flags_read_only,
2396 rndis_ipa_ctx->directory,
2397 rndis_ipa_ctx, &rndis_ipa_debugfs_atomic_ops);
2398 if (!file) {
2399 RNDIS_IPA_ERROR("could not create outstanding file\n");
2400 goto fail_file;
2401 }
2402
Amir Levya7146102016-11-08 14:10:58 +02002403 file = debugfs_create_u8
2404 ("state", flags_read_only,
2405 rndis_ipa_ctx->directory, (u8 *)&rndis_ipa_ctx->state);
2406 if (!file) {
2407 RNDIS_IPA_ERROR("could not create state file\n");
2408 goto fail_file;
2409 }
2410
2411 file = debugfs_create_u32
2412 ("tx_dropped", flags_read_only,
2413 rndis_ipa_ctx->directory, &rndis_ipa_ctx->tx_dropped);
2414 if (!file) {
2415 RNDIS_IPA_ERROR("could not create tx_dropped file\n");
2416 goto fail_file;
2417 }
2418
2419 file = debugfs_create_u32
2420 ("rx_dropped", flags_read_only,
2421 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rx_dropped);
2422 if (!file) {
2423 RNDIS_IPA_ERROR("could not create rx_dropped file\n");
2424 goto fail_file;
2425 }
2426
2427 aggr_directory = debugfs_create_dir
2428 (DEBUGFS_AGGR_DIR_NAME,
2429 rndis_ipa_ctx->directory);
2430 if (!aggr_directory) {
2431 RNDIS_IPA_ERROR("could not create debugfs aggr entry\n");
2432 goto fail_directory;
2433 }
2434
2435 file = debugfs_create_file
2436 ("aggr_value_set", flags_write_only,
2437 aggr_directory,
2438 rndis_ipa_ctx, &rndis_ipa_aggr_ops);
2439 if (!file) {
2440 RNDIS_IPA_ERROR("could not create aggr_value_set file\n");
2441 goto fail_file;
2442 }
2443
2444 file = debugfs_create_u8
2445 ("aggr_enable", flags_read_write,
2446 aggr_directory, (u8 *)&ipa_to_usb_ep_cfg.aggr.aggr_en);
2447 if (!file) {
2448 RNDIS_IPA_ERROR("could not create aggr_enable file\n");
2449 goto fail_file;
2450 }
2451
2452 file = debugfs_create_u8
2453 ("aggr_type", flags_read_write,
2454 aggr_directory, (u8 *)&ipa_to_usb_ep_cfg.aggr.aggr);
2455 if (!file) {
2456 RNDIS_IPA_ERROR("could not create aggr_type file\n");
2457 goto fail_file;
2458 }
2459
2460 file = debugfs_create_u32
2461 ("aggr_byte_limit", flags_read_write,
2462 aggr_directory,
2463 &ipa_to_usb_ep_cfg.aggr.aggr_byte_limit);
2464 if (!file) {
2465 RNDIS_IPA_ERROR("could not create aggr_byte_limit file\n");
2466 goto fail_file;
2467 }
2468
2469 file = debugfs_create_u32
2470 ("aggr_time_limit", flags_read_write,
2471 aggr_directory,
2472 &ipa_to_usb_ep_cfg.aggr.aggr_time_limit);
2473 if (!file) {
2474 RNDIS_IPA_ERROR("could not create aggr_time_limit file\n");
2475 goto fail_file;
2476 }
2477
2478 file = debugfs_create_u32
2479 ("aggr_pkt_limit", flags_read_write,
2480 aggr_directory,
2481 &ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit);
2482 if (!file) {
2483 RNDIS_IPA_ERROR("could not create aggr_pkt_limit file\n");
2484 goto fail_file;
2485 }
2486
2487 file = debugfs_create_bool
2488 ("tx_dump_enable", flags_read_write,
2489 rndis_ipa_ctx->directory,
2490 &rndis_ipa_ctx->tx_dump_enable);
2491 if (!file) {
2492 RNDIS_IPA_ERROR("fail to create tx_dump_enable file\n");
2493 goto fail_file;
2494 }
2495
2496 file = debugfs_create_bool
2497 ("rx_dump_enable", flags_read_write,
2498 rndis_ipa_ctx->directory,
2499 &rndis_ipa_ctx->rx_dump_enable);
2500 if (!file) {
2501 RNDIS_IPA_ERROR("fail to create rx_dump_enable file\n");
2502 goto fail_file;
2503 }
2504
2505 file = debugfs_create_bool
2506 ("deaggregation_enable", flags_read_write,
2507 rndis_ipa_ctx->directory,
2508 &rndis_ipa_ctx->deaggregation_enable);
2509 if (!file) {
2510 RNDIS_IPA_ERROR("fail to create deaggregation_enable file\n");
2511 goto fail_file;
2512 }
2513
2514 file = debugfs_create_u32
2515 ("error_msec_sleep_time", flags_read_write,
2516 rndis_ipa_ctx->directory,
2517 &rndis_ipa_ctx->error_msec_sleep_time);
2518 if (!file) {
2519 RNDIS_IPA_ERROR("fail to create error_msec_sleep_time file\n");
2520 goto fail_file;
2521 }
2522
2523 file = debugfs_create_bool
2524 ("during_xmit_error", flags_read_only,
2525 rndis_ipa_ctx->directory,
2526 &rndis_ipa_ctx->during_xmit_error);
2527 if (!file) {
2528 RNDIS_IPA_ERROR("fail to create during_xmit_error file\n");
2529 goto fail_file;
2530 }
2531
Amir Levy2da9d452017-12-12 10:09:46 +02002532 file = debugfs_create_bool("is_vlan_mode", flags_read_only,
2533 rndis_ipa_ctx->directory,
2534 &rndis_ipa_ctx->is_vlan_mode);
2535 if (!file) {
2536 RNDIS_IPA_ERROR("fail to create is_vlan_mode file\n");
2537 goto fail_file;
2538 }
2539
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302540 RNDIS_IPA_DEBUG("debugfs entries were created\n");
Amir Levya7146102016-11-08 14:10:58 +02002541 RNDIS_IPA_LOG_EXIT();
2542
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302543 return;
Amir Levya7146102016-11-08 14:10:58 +02002544fail_file:
2545 debugfs_remove_recursive(rndis_ipa_ctx->directory);
2546fail_directory:
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302547 return;
Amir Levya7146102016-11-08 14:10:58 +02002548}
2549
2550static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
2551{
2552 debugfs_remove_recursive(rndis_ipa_ctx->directory);
2553}
2554
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302555#else /* !CONFIG_DEBUG_FS */
2556
2557static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx) {}
2558
2559static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx) {}
2560
2561#endif /* CONFIG_DEBUG_FS*/
2562
Amir Levya7146102016-11-08 14:10:58 +02002563static int rndis_ipa_debugfs_aggr_open
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302564 (struct inode *inode,
2565 struct file *file)
Amir Levya7146102016-11-08 14:10:58 +02002566{
2567 struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
2568
2569 file->private_data = rndis_ipa_ctx;
2570
2571 return 0;
2572}
2573
2574static ssize_t rndis_ipa_debugfs_aggr_write
2575 (struct file *file,
2576 const char __user *buf, size_t count, loff_t *ppos)
2577{
Mohammed Javidbf4c8022017-08-07 23:15:48 +05302578 struct rndis_ipa_dev *rndis_ipa_ctx = NULL;
Amir Levya7146102016-11-08 14:10:58 +02002579 int result;
2580
Mohammed Javidbf4c8022017-08-07 23:15:48 +05302581 if (file == NULL)
2582 return -EFAULT;
2583 rndis_ipa_ctx = file->private_data;
2584
Amir Levya7146102016-11-08 14:10:58 +02002585 result = ipa_cfg_ep(rndis_ipa_ctx->usb_to_ipa_hdl, &ipa_to_usb_ep_cfg);
2586 if (result) {
2587 pr_err("failed to re-configure USB to IPA point\n");
2588 return result;
2589 }
2590 pr_info("IPA<-USB end-point re-configured\n");
2591
2592 return count;
2593}
2594
Amir Levya7146102016-11-08 14:10:58 +02002595static int rndis_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
2596{
2597 struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
2598
2599 RNDIS_IPA_LOG_ENTRY();
2600
2601 file->private_data = &rndis_ipa_ctx->outstanding_pkts;
2602
2603 RNDIS_IPA_LOG_EXIT();
2604
2605 return 0;
2606}
2607
2608static ssize_t rndis_ipa_debugfs_atomic_read
2609 (struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
2610{
2611 int nbytes;
2612 u8 atomic_str[DEBUGFS_TEMP_BUF_SIZE] = {0};
2613 atomic_t *atomic_var = file->private_data;
2614
2615 RNDIS_IPA_LOG_ENTRY();
2616
2617 nbytes = scnprintf
2618 (atomic_str, sizeof(atomic_str), "%d\n",
2619 atomic_read(atomic_var));
2620
2621 RNDIS_IPA_LOG_EXIT();
2622
2623 return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes);
2624}
2625
Amir Levya7146102016-11-08 14:10:58 +02002626static int rndis_ipa_init_module(void)
2627{
2628 pr_info("RNDIS_IPA module is loaded.");
2629 return 0;
2630}
2631
2632static void rndis_ipa_cleanup_module(void)
2633{
2634 pr_info("RNDIS_IPA module is unloaded.");
2635}
2636
2637MODULE_LICENSE("GPL v2");
2638MODULE_DESCRIPTION("RNDIS_IPA network interface");
2639
2640late_initcall(rndis_ipa_init_module);
2641module_exit(rndis_ipa_cleanup_module);