blob: 4f608961437c361fc0937047e69dfa1283d042c7 [file] [log] [blame]
Ghanim Fodi76f9dc02016-12-27 13:32:35 +02001/* Copyright (c) 2013-2017, 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);
577
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");
581 goto fail_get_vlan_mode;
582 }
583
584 RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);
585
Amir Levya7146102016-11-08 14:10:58 +0200586 result = rndis_ipa_hdrs_cfg
587 (rndis_ipa_ctx,
588 params->host_ethaddr,
589 params->device_ethaddr);
590 if (result) {
591 RNDIS_IPA_ERROR("fail on ipa hdrs set\n");
592 goto fail_hdrs_cfg;
593 }
594 RNDIS_IPA_DEBUG("IPA header-insertion configed for Ethernet+RNDIS\n");
595
Amir Levy2da9d452017-12-12 10:09:46 +0200596 result = rndis_ipa_register_properties(net->name,
597 rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200598 if (result) {
599 RNDIS_IPA_ERROR("fail on properties set\n");
600 goto fail_register_tx;
601 }
602 RNDIS_IPA_DEBUG("2 TX and 2 RX properties were registered\n");
603
604 netif_carrier_off(net);
605 RNDIS_IPA_DEBUG("set carrier off until pipes are connected\n");
606
607 result = register_netdev(net);
608 if (result) {
609 RNDIS_IPA_ERROR("register_netdev failed: %d\n", result);
610 goto fail_register_netdev;
611 }
612 RNDIS_IPA_DEBUG
613 ("netdev:%s registration succeeded, index=%d\n",
614 net->name, net->ifindex);
615
616 rndis_ipa = rndis_ipa_ctx;
617 params->ipa_rx_notify = rndis_ipa_packet_receive_notify;
618 params->ipa_tx_notify = rndis_ipa_tx_complete_notify;
619 params->private = rndis_ipa_ctx;
620 params->skip_ep_cfg = false;
621 rndis_ipa_ctx->state = RNDIS_IPA_INITIALIZED;
622 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
623 pr_info("RNDIS_IPA NetDev was initialized");
624
625 RNDIS_IPA_LOG_EXIT();
626
627 return 0;
628
629fail_register_netdev:
630 rndis_ipa_deregister_properties(net->name);
631fail_register_tx:
632 rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200633fail_hdrs_cfg:
Amir Levy2da9d452017-12-12 10:09:46 +0200634fail_get_vlan_mode:
635fail_set_device_ethernet:
Amir Levya7146102016-11-08 14:10:58 +0200636 rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200637fail_netdev_priv:
638 free_netdev(net);
639fail_alloc_etherdev:
640 return result;
641}
642EXPORT_SYMBOL(rndis_ipa_init);
643
644/**
645 * rndis_ipa_pipe_connect_notify() - notify rndis_ipa Netdev that the USB pipes
646 * were connected
647 * @usb_to_ipa_hdl: handle from IPA driver client for USB->IPA
648 * @ipa_to_usb_hdl: handle from IPA driver client for IPA->USB
649 * @private: same value that was set by init(), this parameter holds the
650 * network device pointer.
651 * @max_transfer_byte_size: RNDIS protocol specific, the maximum size that
652 * the host expect
653 * @max_packet_number: RNDIS protocol specific, the maximum packet number
654 * that the host expects
655 *
656 * Once USB driver finishes the pipe connection between IPA core
657 * and USB core this method shall be called in order to
658 * allow the driver to complete the data path configurations.
659 * Detailed description:
660 * - configure the IPA end-points register
661 * - notify the Linux kernel for "carrier_on"
662 * - change the driver internal state
663 *
664 * After this function is done the driver state changes to "Connected" or
665 * Connected and Up.
666 * This API is expected to be called after initialization() or
667 * after a call to disconnect().
668 *
669 * Returns negative errno, or zero on success
670 */
671int rndis_ipa_pipe_connect_notify(
672 u32 usb_to_ipa_hdl,
673 u32 ipa_to_usb_hdl,
674 u32 max_xfer_size_bytes_to_dev,
675 u32 max_packet_number_to_dev,
676 u32 max_xfer_size_bytes_to_host,
677 void *private)
678{
679 struct rndis_ipa_dev *rndis_ipa_ctx = private;
680 int next_state;
681 int result;
682 int ret;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530683 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +0200684
685 RNDIS_IPA_LOG_ENTRY();
686
687 ret = 0;
688 NULL_CHECK_RETVAL(private);
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530689
Amir Levya7146102016-11-08 14:10:58 +0200690 if (ret)
691 return ret;
692
693 RNDIS_IPA_DEBUG
694 ("usb_to_ipa_hdl=%d, ipa_to_usb_hdl=%d, private=0x%p\n",
695 usb_to_ipa_hdl, ipa_to_usb_hdl, private);
696 RNDIS_IPA_DEBUG
697 ("max_xfer_sz_to_dev=%d, max_pkt_num_to_dev=%d\n",
698 max_xfer_size_bytes_to_dev,
699 max_packet_number_to_dev);
700 RNDIS_IPA_DEBUG
701 ("max_xfer_sz_to_host=%d\n",
702 max_xfer_size_bytes_to_host);
703
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530704 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200705 next_state = rndis_ipa_next_state
706 (rndis_ipa_ctx->state,
707 RNDIS_IPA_CONNECT);
708 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530709 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200710 RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
711 return -EPERM;
712 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530713 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200714
715 if (usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
716 RNDIS_IPA_ERROR
717 ("usb_to_ipa_hdl(%d) - not valid ipa handle\n",
718 usb_to_ipa_hdl);
719 return -EINVAL;
720 }
721 if (ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
722 RNDIS_IPA_ERROR
723 ("ipa_to_usb_hdl(%d) - not valid ipa handle\n",
724 ipa_to_usb_hdl);
725 return -EINVAL;
726 }
727
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530728#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -0700729 if (ipa_pm_is_used())
730 result = rndis_ipa_register_pm_client(rndis_ipa_ctx);
731 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530732#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -0700733 result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200734 if (result) {
735 RNDIS_IPA_ERROR("fail on RM create\n");
736 goto fail_create_rm;
737 }
738 RNDIS_IPA_DEBUG("RM resource was created\n");
739
740 rndis_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
741 rndis_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
742 if (max_packet_number_to_dev > 1)
743 rndis_ipa_ctx->deaggregation_enable = true;
744 else
745 rndis_ipa_ctx->deaggregation_enable = false;
746 result = rndis_ipa_ep_registers_cfg
747 (usb_to_ipa_hdl,
748 ipa_to_usb_hdl,
749 max_xfer_size_bytes_to_dev,
750 max_xfer_size_bytes_to_host,
751 rndis_ipa_ctx->net->mtu,
Amir Levy2da9d452017-12-12 10:09:46 +0200752 rndis_ipa_ctx->deaggregation_enable,
753 rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +0200754 if (result) {
755 RNDIS_IPA_ERROR("fail on ep cfg\n");
756 goto fail;
757 }
758 RNDIS_IPA_DEBUG("end-points configured\n");
759
760 netif_stop_queue(rndis_ipa_ctx->net);
761 RNDIS_IPA_DEBUG("netif_stop_queue() was called\n");
762
763 netif_carrier_on(rndis_ipa_ctx->net);
764 if (!netif_carrier_ok(rndis_ipa_ctx->net)) {
765 RNDIS_IPA_ERROR("netif_carrier_ok error\n");
766 result = -EBUSY;
767 goto fail;
768 }
769 RNDIS_IPA_DEBUG("netif_carrier_on() was called\n");
770
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530771 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
772 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
773 RNDIS_IPA_CONNECT);
774 if (next_state == RNDIS_IPA_INVALID) {
775 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
776 RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
777 return -EPERM;
778 }
Amir Levya7146102016-11-08 14:10:58 +0200779 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530780 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
781
Amir Levya7146102016-11-08 14:10:58 +0200782 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
783
784 if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
785 rndis_ipa_enable_data_path(rndis_ipa_ctx);
786 else
787 RNDIS_IPA_DEBUG("queue shall be started after open()\n");
788
789 pr_info("RNDIS_IPA NetDev pipes were connected\n");
790
791 RNDIS_IPA_LOG_EXIT();
792
793 return 0;
794
795fail:
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530796#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -0700797 if (ipa_pm_is_used())
798 rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
799 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +0530800#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -0700801 rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200802fail_create_rm:
803 return result;
804}
805EXPORT_SYMBOL(rndis_ipa_pipe_connect_notify);
806
807/**
808 * rndis_ipa_open() - notify Linux network stack to start sending packets
809 * @net: the network interface supplied by the network stack
810 *
811 * Linux uses this API to notify the driver that the network interface
812 * transitions to the up state.
813 * The driver will instruct the Linux network stack to start
814 * delivering data packets.
815 * The driver internal state shall be changed to Up or Connected and Up
816 *
817 * Returns negative errno, or zero on success
818 */
819static int rndis_ipa_open(struct net_device *net)
820{
821 struct rndis_ipa_dev *rndis_ipa_ctx;
822 int next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530823 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +0200824
825 RNDIS_IPA_LOG_ENTRY();
826
827 rndis_ipa_ctx = netdev_priv(net);
828
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530829 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
830
Amir Levya7146102016-11-08 14:10:58 +0200831 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_OPEN);
832 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530833 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +0200834 RNDIS_IPA_ERROR("can't bring driver up before initialize\n");
835 return -EPERM;
836 }
837
838 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +0530839
840 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
841
Amir Levya7146102016-11-08 14:10:58 +0200842 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
843
844 if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
845 rndis_ipa_enable_data_path(rndis_ipa_ctx);
846 else
847 RNDIS_IPA_DEBUG("queue shall be started after connect()\n");
848
849 pr_info("RNDIS_IPA NetDev was opened\n");
850
851 RNDIS_IPA_LOG_EXIT();
852
853 return 0;
854}
855
856/**
857 * rndis_ipa_start_xmit() - send data from APPs to USB core via IPA core
858 * using SW path (Tx data path)
859 * Tx path for this Netdev is Apps-processor->IPA->USB
860 * @skb: packet received from Linux network stack destined for tethered PC
861 * @net: the network device being used to send this packet (rndis0)
862 *
863 * Several conditions needed in order to send the packet to IPA:
864 * - Transmit queue for the network driver is currently
865 * in "started" state
866 * - The driver internal state is in Connected and Up state.
867 * - Filters Tx switch are turned off
868 * - The IPA resource manager state for the driver producer client
869 * is "Granted" which implies that all the resources in the dependency
870 * graph are valid for data flow.
871 * - outstanding high boundary was not reached.
872 *
873 * In case the outstanding packets high boundary is reached, the driver will
874 * stop the send queue until enough packets are processed by
875 * the IPA core (based on calls to rndis_ipa_tx_complete_notify).
876 *
877 * In case all of the conditions are met, the network driver shall:
878 * - encapsulate the Ethernet packet with RNDIS header (REMOTE_NDIS_PACKET_MSG)
879 * - send the packet by using IPA Driver SW path (IP_PACKET_INIT)
880 * - Netdev status fields shall be updated based on the current Tx packet
881 *
882 * Returns NETDEV_TX_BUSY if retry should be made later,
883 * or NETDEV_TX_OK on success.
884 */
885static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
886 struct net_device *net)
887{
888 int ret;
889 netdev_tx_t status = NETDEV_TX_BUSY;
890 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
891
Ghanim Fodi6a3d23f2017-03-07 14:44:58 +0200892 netif_trans_update(net);
Amir Levya7146102016-11-08 14:10:58 +0200893
894 RNDIS_IPA_DEBUG
895 ("Tx, len=%d, skb->protocol=%d, outstanding=%d\n",
896 skb->len, skb->protocol,
897 atomic_read(&rndis_ipa_ctx->outstanding_pkts));
898
899 if (unlikely(netif_queue_stopped(net))) {
900 RNDIS_IPA_ERROR("interface queue is stopped\n");
901 goto out;
902 }
903
904 if (unlikely(rndis_ipa_ctx->tx_dump_enable))
905 rndis_ipa_dump_skb(skb);
906
907 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
908 RNDIS_IPA_ERROR("Missing pipe connected and/or iface up\n");
909 return NETDEV_TX_BUSY;
910 }
911
912 if (unlikely(tx_filter(skb))) {
913 dev_kfree_skb_any(skb);
914 RNDIS_IPA_DEBUG("packet got filtered out on Tx path\n");
915 rndis_ipa_ctx->tx_dropped++;
916 status = NETDEV_TX_OK;
917 goto out;
918 }
919
920 ret = resource_request(rndis_ipa_ctx);
921 if (ret) {
922 RNDIS_IPA_DEBUG("Waiting to resource\n");
923 netif_stop_queue(net);
924 goto resource_busy;
925 }
926
927 if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) >=
928 rndis_ipa_ctx->outstanding_high) {
929 RNDIS_IPA_DEBUG("Outstanding high boundary reached (%d)\n",
930 rndis_ipa_ctx->outstanding_high);
931 netif_stop_queue(net);
932 RNDIS_IPA_DEBUG("send queue was stopped\n");
933 status = NETDEV_TX_BUSY;
934 goto out;
935 }
936
Amir Levy2da9d452017-12-12 10:09:46 +0200937 skb = rndis_encapsulate_skb(skb, rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +0200938 trace_rndis_tx_dp(skb->protocol);
939 ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
940 if (ret) {
941 RNDIS_IPA_ERROR("ipa transmit failed (%d)\n", ret);
942 goto fail_tx_packet;
943 }
944
945 atomic_inc(&rndis_ipa_ctx->outstanding_pkts);
946
947 status = NETDEV_TX_OK;
948 goto out;
949
950fail_tx_packet:
951 rndis_ipa_xmit_error(skb);
952out:
953 resource_release(rndis_ipa_ctx);
954resource_busy:
955 RNDIS_IPA_DEBUG
956 ("packet Tx done - %s\n",
957 (status == NETDEV_TX_OK) ? "OK" : "FAIL");
958
959 return status;
960}
961
962/**
963 * rndis_ipa_tx_complete_notify() - notification for Netdev that the
964 * last packet was successfully sent
965 * @private: driver context stashed by IPA driver upon pipe connect
966 * @evt: event type (expected to be write-done event)
967 * @data: data provided with event (this is actually the skb that
968 * holds the sent packet)
969 *
970 * This function will be called on interrupt bottom halve deferred context.
971 * outstanding packets counter shall be decremented.
972 * Network stack send queue will be re-started in case low outstanding
973 * boundary is reached and queue was stopped before.
974 * At the end the skb shall be freed.
975 */
976static void rndis_ipa_tx_complete_notify(
977 void *private,
978 enum ipa_dp_evt_type evt,
979 unsigned long data)
980{
981 struct sk_buff *skb = (struct sk_buff *)data;
982 struct rndis_ipa_dev *rndis_ipa_ctx = private;
983 int ret;
984
985 ret = 0;
986 NULL_CHECK_RETVAL(private);
987 if (ret)
988 return;
989
990 trace_rndis_status_rcvd(skb->protocol);
991
992 RNDIS_IPA_DEBUG
993 ("Tx-complete, len=%d, skb->prot=%d, outstanding=%d\n",
994 skb->len, skb->protocol,
995 atomic_read(&rndis_ipa_ctx->outstanding_pkts));
996
997 if (unlikely((evt != IPA_WRITE_DONE))) {
998 RNDIS_IPA_ERROR("unsupported event on TX call-back\n");
999 return;
1000 }
1001
1002 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1003 RNDIS_IPA_DEBUG
1004 ("dropping Tx-complete pkt, state=%s\n",
1005 rndis_ipa_state_string(rndis_ipa_ctx->state));
1006 goto out;
1007 }
1008
1009 rndis_ipa_ctx->net->stats.tx_packets++;
1010 rndis_ipa_ctx->net->stats.tx_bytes += skb->len;
1011
1012 atomic_dec(&rndis_ipa_ctx->outstanding_pkts);
1013 if
1014 (netif_queue_stopped(rndis_ipa_ctx->net) &&
1015 netif_carrier_ok(rndis_ipa_ctx->net) &&
1016 atomic_read(&rndis_ipa_ctx->outstanding_pkts) <
1017 (rndis_ipa_ctx->outstanding_low)) {
1018 RNDIS_IPA_DEBUG("outstanding low boundary reached (%d)n",
1019 rndis_ipa_ctx->outstanding_low);
1020 netif_wake_queue(rndis_ipa_ctx->net);
1021 RNDIS_IPA_DEBUG("send queue was awaken\n");
1022 }
1023
1024out:
1025 dev_kfree_skb_any(skb);
1026}
1027
1028static void rndis_ipa_tx_timeout(struct net_device *net)
1029{
1030 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
1031 int outstanding = atomic_read(&rndis_ipa_ctx->outstanding_pkts);
1032
1033 RNDIS_IPA_ERROR
1034 ("possible IPA stall was detected, %d outstanding\n",
1035 outstanding);
1036
1037 net->stats.tx_errors++;
1038}
1039
1040/**
1041 * rndis_ipa_rm_notify() - callback supplied to IPA resource manager
1042 * for grant/release events
1043 * user_data: the driver context supplied to IPA resource manager during call
1044 * to ipa_rm_create_resource().
1045 * event: the event notified to us by IPA resource manager (Release/Grant)
1046 * data: reserved field supplied by IPA resource manager
1047 *
1048 * This callback shall be called based on resource request/release sent
1049 * to the IPA resource manager.
1050 * In case the queue was stopped during EINPROGRESS for Tx path and the
1051 * event received is Grant then the queue shall be restarted.
1052 * In case the event notified is a release notification the netdev discard it.
1053 */
1054static void rndis_ipa_rm_notify(
1055 void *user_data, enum ipa_rm_event event,
1056 unsigned long data)
1057{
1058 struct rndis_ipa_dev *rndis_ipa_ctx = user_data;
1059
1060 RNDIS_IPA_LOG_ENTRY();
1061
1062 if (event == IPA_RM_RESOURCE_RELEASED) {
1063 RNDIS_IPA_DEBUG("Resource Released\n");
1064 return;
1065 }
1066
1067 if (event != IPA_RM_RESOURCE_GRANTED) {
1068 RNDIS_IPA_ERROR
1069 ("Unexceoted event receieved from RM (%d\n)", event);
1070 return;
1071 }
1072 RNDIS_IPA_DEBUG("Resource Granted\n");
1073
1074 if (netif_queue_stopped(rndis_ipa_ctx->net)) {
1075 RNDIS_IPA_DEBUG("starting queue\n");
1076 netif_start_queue(rndis_ipa_ctx->net);
1077 } else {
1078 RNDIS_IPA_DEBUG("queue already awake\n");
1079 }
1080
1081 RNDIS_IPA_LOG_EXIT();
1082}
1083
1084/**
1085 * rndis_ipa_packet_receive_notify() - Rx notify for packet sent from
1086 * tethered PC (USB->IPA).
1087 * is USB->IPA->Apps-processor
1088 * @private: driver context
1089 * @evt: event type
1090 * @data: data provided with event
1091 *
1092 * Once IPA driver receives a packet from USB client this callback will be
1093 * called from bottom-half interrupt handling context (ipa Rx workqueue).
1094 *
1095 * Packets that shall be sent to Apps processor may be of two types:
1096 * 1) Packets that are destined for Apps (e.g: WEBSERVER running on Apps)
1097 * 2) Exception packets that need special handling (based on IPA core
1098 * configuration, e.g: new TCP session or any other packets that IPA core
1099 * can't handle)
1100 * If the next conditions are met, the packet shall be sent up to the
1101 * Linux network stack:
1102 * - Driver internal state is Connected and Up
1103 * - Notification received from IPA driver meets the expected type
1104 * for Rx packet
1105 * -Filters Rx switch are turned off
1106 *
1107 * Prior to the sending to the network stack:
1108 * - Netdev struct shall be stashed to the skb as required by the network stack
1109 * - Ethernet header shall be removed (skb->data shall point to the Ethernet
1110 * payload, Ethernet still stashed under MAC header).
1111 * - The skb->pkt_protocol shall be set based on the ethernet destination
1112 * address, Can be Broadcast, Multicast or Other-Host, The later
1113 * pkt-types packets shall be dropped in case the Netdev is not
1114 * in promisc mode.
1115 * - Set the skb protocol field based on the EtherType field
1116 *
1117 * Netdev status fields shall be updated based on the current Rx packet
1118 */
1119static void rndis_ipa_packet_receive_notify(
1120 void *private,
1121 enum ipa_dp_evt_type evt,
1122 unsigned long data)
1123{
1124 struct sk_buff *skb = (struct sk_buff *)data;
1125 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1126 int result;
1127 unsigned int packet_len = skb->len;
1128
1129 RNDIS_IPA_DEBUG
1130 ("packet Rx, len=%d\n",
1131 skb->len);
1132
1133 if (unlikely(rndis_ipa_ctx->rx_dump_enable))
1134 rndis_ipa_dump_skb(skb);
1135
1136 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1137 RNDIS_IPA_DEBUG("use connect()/up() before receive()\n");
1138 RNDIS_IPA_DEBUG("packet dropped (length=%d)\n",
1139 skb->len);
1140 return;
1141 }
1142
1143 if (evt != IPA_RECEIVE) {
1144 RNDIS_IPA_ERROR("a none IPA_RECEIVE event in driver RX\n");
1145 return;
1146 }
1147
1148 if (!rndis_ipa_ctx->deaggregation_enable)
1149 skb_pull(skb, sizeof(struct rndis_pkt_hdr));
1150
1151 skb->dev = rndis_ipa_ctx->net;
1152 skb->protocol = eth_type_trans(skb, rndis_ipa_ctx->net);
1153
1154 if (rx_filter(skb)) {
1155 RNDIS_IPA_DEBUG("packet got filtered out on RX path\n");
1156 rndis_ipa_ctx->rx_dropped++;
1157 dev_kfree_skb_any(skb);
1158 return;
1159 }
1160
1161 trace_rndis_netif_ni(skb->protocol);
1162 result = netif_rx_ni(skb);
1163 if (result)
1164 RNDIS_IPA_ERROR("fail on netif_rx_ni\n");
1165 rndis_ipa_ctx->net->stats.rx_packets++;
1166 rndis_ipa_ctx->net->stats.rx_bytes += packet_len;
1167}
1168
1169/** rndis_ipa_stop() - notify the network interface to stop
1170 * sending/receiving data
1171 * @net: the network device being stopped.
1172 *
1173 * This API is used by Linux network stack to notify the network driver that
1174 * its state was changed to "down"
1175 * The driver will stop the "send" queue and change its internal
1176 * state to "Connected".
1177 * The Netdev shall be returned to be "Up" after rndis_ipa_open().
1178 */
1179static int rndis_ipa_stop(struct net_device *net)
1180{
1181 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
1182 int next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301183 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001184
1185 RNDIS_IPA_LOG_ENTRY();
1186
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301187 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1188
Amir Levya7146102016-11-08 14:10:58 +02001189 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_STOP);
1190 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301191 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001192 RNDIS_IPA_DEBUG("can't do network interface down without up\n");
1193 return -EPERM;
1194 }
1195
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301196 rndis_ipa_ctx->state = next_state;
1197
1198 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1199
Amir Levya7146102016-11-08 14:10:58 +02001200 netif_stop_queue(net);
1201 pr_info("RNDIS_IPA NetDev queue is stopped\n");
1202
Amir Levya7146102016-11-08 14:10:58 +02001203 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1204
1205 RNDIS_IPA_LOG_EXIT();
1206
1207 return 0;
1208}
1209
1210/** rndis_ipa_disconnect() - notify rndis_ipa Netdev that the USB pipes
1211 * were disconnected
1212 * @private: same value that was set by init(), this parameter holds the
1213 * network device pointer.
1214 *
1215 * USB shall notify the Netdev after disconnecting the pipe.
1216 * - The internal driver state shall returned to its previous
1217 * state (Up or Initialized).
1218 * - Linux network stack shall be informed for carrier off to notify
1219 * user space for pipe disconnect
1220 * - send queue shall be stopped
1221 * During the transition between the pipe disconnection to
1222 * the Netdev notification packets
1223 * are expected to be dropped by IPA driver or IPA core.
1224 */
1225int rndis_ipa_pipe_disconnect_notify(void *private)
1226{
1227 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1228 int next_state;
1229 int outstanding_dropped_pkts;
1230 int retval;
1231 int ret;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301232 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001233
1234 RNDIS_IPA_LOG_ENTRY();
1235
1236 ret = 0;
1237 NULL_CHECK_RETVAL(rndis_ipa_ctx);
1238 if (ret)
1239 return ret;
1240 RNDIS_IPA_DEBUG("private=0x%p\n", private);
1241
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301242 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1243
Amir Levya7146102016-11-08 14:10:58 +02001244 next_state = rndis_ipa_next_state
1245 (rndis_ipa_ctx->state,
1246 RNDIS_IPA_DISCONNECT);
1247 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301248 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001249 RNDIS_IPA_ERROR("can't disconnect before connect\n");
1250 return -EPERM;
1251 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301252 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001253
1254 if (rndis_ipa_ctx->during_xmit_error) {
1255 RNDIS_IPA_DEBUG("canceling xmit-error delayed work\n");
1256 cancel_delayed_work_sync(
1257 &rndis_ipa_ctx->xmit_error_delayed_work);
1258 rndis_ipa_ctx->during_xmit_error = false;
1259 }
1260
1261 netif_carrier_off(rndis_ipa_ctx->net);
1262 RNDIS_IPA_DEBUG("carrier_off notification was sent\n");
1263
1264 netif_stop_queue(rndis_ipa_ctx->net);
1265 RNDIS_IPA_DEBUG("queue stopped\n");
1266
1267 outstanding_dropped_pkts =
1268 atomic_read(&rndis_ipa_ctx->outstanding_pkts);
1269
1270 rndis_ipa_ctx->net->stats.tx_dropped += outstanding_dropped_pkts;
1271 atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);
1272
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301273#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001274 if (ipa_pm_is_used())
1275 retval = rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
1276 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301277#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001278 retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
Amir Levya7146102016-11-08 14:10:58 +02001279 if (retval) {
1280 RNDIS_IPA_ERROR("Fail to clean RM\n");
1281 return retval;
1282 }
1283 RNDIS_IPA_DEBUG("RM was successfully destroyed\n");
1284
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301285 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1286 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
1287 RNDIS_IPA_DISCONNECT);
1288 if (next_state == RNDIS_IPA_INVALID) {
1289 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1290 RNDIS_IPA_ERROR("can't disconnect before connect\n");
1291 return -EPERM;
1292 }
Amir Levya7146102016-11-08 14:10:58 +02001293 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301294 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1295
Amir Levya7146102016-11-08 14:10:58 +02001296 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1297
1298 pr_info("RNDIS_IPA NetDev pipes disconnected (%d outstanding clr)\n",
1299 outstanding_dropped_pkts);
1300
1301 RNDIS_IPA_LOG_EXIT();
1302
1303 return 0;
1304}
1305EXPORT_SYMBOL(rndis_ipa_pipe_disconnect_notify);
1306
1307/**
1308 * rndis_ipa_cleanup() - unregister the network interface driver and free
1309 * internal data structs.
1310 * @private: same value that was set by init(), this
1311 * parameter holds the network device pointer.
1312 *
1313 * This function shall be called once the network interface is not
1314 * needed anymore, e.g: when the USB composition does not support it.
1315 * This function shall be called after the pipes were disconnected.
1316 * Detailed description:
1317 * - remove header-insertion headers from IPA core
1318 * - delete the driver dependency defined for IPA resource manager and
1319 * destroy the producer resource.
1320 * - remove the debugfs entries
1321 * - deregister the network interface from Linux network stack
1322 * - free all internal data structs
1323 *
1324 * It is assumed that no packets shall be sent through HW bridging
1325 * during cleanup to avoid packets trying to add an header that is
1326 * removed during cleanup (IPA configuration manager should have
1327 * removed them at this point)
1328 */
1329void rndis_ipa_cleanup(void *private)
1330{
1331 struct rndis_ipa_dev *rndis_ipa_ctx = private;
1332 int next_state;
1333 int retval;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301334 unsigned long flags;
Amir Levya7146102016-11-08 14:10:58 +02001335
1336 RNDIS_IPA_LOG_ENTRY();
1337
1338 RNDIS_IPA_DEBUG("private=0x%p\n", private);
1339
1340 if (!rndis_ipa_ctx) {
1341 RNDIS_IPA_ERROR("rndis_ipa_ctx NULL pointer\n");
1342 return;
1343 }
1344
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301345 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001346 next_state = rndis_ipa_next_state
1347 (rndis_ipa_ctx->state,
1348 RNDIS_IPA_CLEANUP);
1349 if (next_state == RNDIS_IPA_INVALID) {
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301350 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001351 RNDIS_IPA_ERROR("use disconnect()before clean()\n");
1352 return;
1353 }
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301354 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1355
Amir Levya7146102016-11-08 14:10:58 +02001356 RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
1357
1358 retval = rndis_ipa_deregister_properties(rndis_ipa_ctx->net->name);
1359 if (retval) {
1360 RNDIS_IPA_ERROR("Fail to deregister Tx/Rx properties\n");
1361 return;
1362 }
1363 RNDIS_IPA_DEBUG("deregister Tx/Rx properties was successful\n");
1364
1365 retval = rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
1366 if (retval)
1367 RNDIS_IPA_ERROR(
1368 "Failed removing RNDIS headers from IPA core. Continue anyway\n");
1369 else
1370 RNDIS_IPA_DEBUG("RNDIS headers were removed from IPA core\n");
1371
1372 rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
1373 RNDIS_IPA_DEBUG("debugfs remove was done\n");
1374
1375 unregister_netdev(rndis_ipa_ctx->net);
1376 RNDIS_IPA_DEBUG("netdev unregistered\n");
1377
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301378 spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
1379 next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
1380 RNDIS_IPA_CLEANUP);
1381 if (next_state == RNDIS_IPA_INVALID) {
1382 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
1383 RNDIS_IPA_ERROR("use disconnect()before clean()\n");
1384 return;
1385 }
Amir Levya7146102016-11-08 14:10:58 +02001386 rndis_ipa_ctx->state = next_state;
Utkarsh Saxena93d96bf2016-07-04 17:38:13 +05301387 spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
Amir Levya7146102016-11-08 14:10:58 +02001388 free_netdev(rndis_ipa_ctx->net);
1389 pr_info("RNDIS_IPA NetDev was cleaned\n");
1390
1391 RNDIS_IPA_LOG_EXIT();
1392}
1393EXPORT_SYMBOL(rndis_ipa_cleanup);
1394
1395static void rndis_ipa_enable_data_path(struct rndis_ipa_dev *rndis_ipa_ctx)
1396{
1397 if (rndis_ipa_ctx->device_ready_notify) {
1398 rndis_ipa_ctx->device_ready_notify();
1399 RNDIS_IPA_DEBUG("USB device_ready_notify() was called\n");
1400 } else {
1401 RNDIS_IPA_DEBUG("device_ready_notify() not supplied\n");
1402 }
1403
1404 netif_start_queue(rndis_ipa_ctx->net);
1405 RNDIS_IPA_DEBUG("netif_start_queue() was called\n");
1406}
1407
1408static void rndis_ipa_xmit_error(struct sk_buff *skb)
1409{
1410 bool retval;
1411 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
1412 unsigned long delay_jiffies;
1413 u8 rand_dealy_msec;
1414
1415 RNDIS_IPA_LOG_ENTRY();
1416
1417 RNDIS_IPA_DEBUG("starting Tx-queue backoff\n");
1418
1419 netif_stop_queue(rndis_ipa_ctx->net);
1420 RNDIS_IPA_DEBUG("netif_stop_queue was called\n");
1421
1422 skb_pull(skb, sizeof(rndis_template_hdr));
1423 rndis_ipa_ctx->net->stats.tx_errors++;
1424
1425 get_random_bytes(&rand_dealy_msec, sizeof(rand_dealy_msec));
1426 delay_jiffies = msecs_to_jiffies(
1427 rndis_ipa_ctx->error_msec_sleep_time + rand_dealy_msec);
1428
1429 retval = schedule_delayed_work(
1430 &rndis_ipa_ctx->xmit_error_delayed_work, delay_jiffies);
1431 if (!retval) {
1432 RNDIS_IPA_ERROR("fail to schedule delayed work\n");
1433 netif_start_queue(rndis_ipa_ctx->net);
1434 } else {
1435 RNDIS_IPA_DEBUG
1436 ("work scheduled to start Tx-queue in %d msec\n",
1437 rndis_ipa_ctx->error_msec_sleep_time +
1438 rand_dealy_msec);
1439 rndis_ipa_ctx->during_xmit_error = true;
1440 }
1441
1442 RNDIS_IPA_LOG_EXIT();
1443}
1444
1445static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work)
1446{
1447 struct rndis_ipa_dev *rndis_ipa_ctx;
1448 struct delayed_work *delayed_work;
1449
1450 RNDIS_IPA_LOG_ENTRY();
1451
1452 RNDIS_IPA_DEBUG("Starting queue after xmit error\n");
1453
1454 delayed_work = to_delayed_work(work);
1455 rndis_ipa_ctx = container_of
1456 (delayed_work, struct rndis_ipa_dev,
1457 xmit_error_delayed_work);
1458
1459 if (unlikely(rndis_ipa_ctx->state != RNDIS_IPA_CONNECTED_AND_UP)) {
1460 RNDIS_IPA_ERROR
1461 ("error aftercare handling in bad state (%d)",
1462 rndis_ipa_ctx->state);
1463 return;
1464 }
1465
1466 rndis_ipa_ctx->during_xmit_error = false;
1467
1468 netif_start_queue(rndis_ipa_ctx->net);
1469 RNDIS_IPA_DEBUG("netif_start_queue() was called\n");
1470
1471 RNDIS_IPA_LOG_EXIT();
1472}
1473
1474/**
1475 * rndis_ipa_prepare_header_insertion() - prepare the header insertion request
1476 * for IPA driver
1477 * eth_type: the Ethernet type for this header-insertion header
1478 * hdr_name: string that shall represent this header in IPA data base
1479 * add_hdr: output for caller to be used with ipa_add_hdr() to configure
1480 * the IPA core
1481 * dst_mac: tethered PC MAC (Ethernet) address to be added to packets
1482 * for IPA->USB pipe
1483 * src_mac: device MAC (Ethernet) address to be added to packets
1484 * for IPA->USB pipe
Amir Levy2da9d452017-12-12 10:09:46 +02001485 * is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02001486 *
1487 * This function shall build the header-insertion block request for a
1488 * single Ethernet+RNDIS header)
1489 * this header shall be inserted for packets processed by IPA
1490 * and destined for USB client.
1491 * This header shall be used for HW bridging for packets destined for
1492 * tethered PC.
1493 * For SW data-path, this header won't be used.
1494 */
1495static void rndis_ipa_prepare_header_insertion(
1496 int eth_type,
1497 const char *hdr_name, struct ipa_hdr_add *add_hdr,
Amir Levy2da9d452017-12-12 10:09:46 +02001498 const void *dst_mac, const void *src_mac, bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02001499{
1500 struct ethhdr *eth_hdr;
Amir Levy2da9d452017-12-12 10:09:46 +02001501 struct vlan_ethhdr *eth_vlan_hdr;
Amir Levya7146102016-11-08 14:10:58 +02001502
1503 add_hdr->hdr_len = sizeof(rndis_template_hdr);
1504 add_hdr->is_partial = false;
1505 strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);
1506
1507 memcpy(add_hdr->hdr, &rndis_template_hdr, sizeof(rndis_template_hdr));
Amir Levya7146102016-11-08 14:10:58 +02001508 add_hdr->is_eth2_ofst_valid = true;
1509 add_hdr->eth2_ofst = sizeof(rndis_template_hdr);
Amir Levy2da9d452017-12-12 10:09:46 +02001510
1511 if (is_vlan_mode) {
1512 eth_vlan_hdr = (struct vlan_ethhdr *)(add_hdr->hdr +
1513 sizeof(rndis_template_hdr));
1514 memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
1515 memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
1516 eth_vlan_hdr->h_vlan_encapsulated_proto = htons(eth_type);
1517 eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
1518 add_hdr->hdr_len += VLAN_ETH_HLEN;
1519 add_hdr->type = IPA_HDR_L2_802_1Q;
1520 } else {
1521 eth_hdr = (struct ethhdr *)(add_hdr->hdr +
1522 sizeof(rndis_template_hdr));
1523 memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
1524 memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
1525 eth_hdr->h_proto = htons(eth_type);
1526 add_hdr->hdr_len += ETH_HLEN;
1527 add_hdr->type = IPA_HDR_L2_ETHERNET_II;
1528 }
Amir Levya7146102016-11-08 14:10:58 +02001529}
1530
1531/**
1532 * rndis_ipa_hdrs_cfg() - configure header insertion block in IPA core
1533 * to allow HW bridging
1534 * @rndis_ipa_ctx: main driver context
1535 * @dst_mac: destination MAC address (tethered PC)
1536 * @src_mac: source MAC address (MDM device)
1537 *
1538 * This function shall add 2 headers.
1539 * One header for Ipv4 and one header for Ipv6.
1540 * Both headers shall contain Ethernet header and RNDIS header, the only
1541 * difference shall be in the EtherTye field.
1542 * Headers will be committed to HW
1543 *
1544 * Returns negative errno, or zero on success
1545 */
1546static int rndis_ipa_hdrs_cfg(
1547 struct rndis_ipa_dev *rndis_ipa_ctx,
1548 const void *dst_mac, const void *src_mac)
1549{
1550 struct ipa_ioc_add_hdr *hdrs;
1551 struct ipa_hdr_add *ipv4_hdr;
1552 struct ipa_hdr_add *ipv6_hdr;
1553 int result = 0;
1554
1555 RNDIS_IPA_LOG_ENTRY();
1556
1557 hdrs = kzalloc
1558 (sizeof(*hdrs) + sizeof(*ipv4_hdr) + sizeof(*ipv6_hdr),
1559 GFP_KERNEL);
1560 if (!hdrs) {
1561 RNDIS_IPA_ERROR("mem allocation fail for header-insertion\n");
1562 result = -ENOMEM;
1563 goto fail_mem;
1564 }
1565
1566 ipv4_hdr = &hdrs->hdr[0];
1567 ipv6_hdr = &hdrs->hdr[1];
1568 rndis_ipa_prepare_header_insertion
1569 (ETH_P_IP, IPV4_HDR_NAME,
Amir Levy2da9d452017-12-12 10:09:46 +02001570 ipv4_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +02001571 rndis_ipa_prepare_header_insertion
1572 (ETH_P_IPV6, IPV6_HDR_NAME,
Amir Levy2da9d452017-12-12 10:09:46 +02001573 ipv6_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
Amir Levya7146102016-11-08 14:10:58 +02001574
1575 hdrs->commit = 1;
1576 hdrs->num_hdrs = 2;
1577 result = ipa_add_hdr(hdrs);
1578 if (result) {
1579 RNDIS_IPA_ERROR("Fail on Header-Insertion(%d)\n", result);
1580 goto fail_add_hdr;
1581 }
1582 if (ipv4_hdr->status) {
1583 RNDIS_IPA_ERROR("Fail on Header-Insertion ipv4(%d)\n",
1584 ipv4_hdr->status);
1585 result = ipv4_hdr->status;
1586 goto fail_add_hdr;
1587 }
1588 if (ipv6_hdr->status) {
1589 RNDIS_IPA_ERROR("Fail on Header-Insertion ipv6(%d)\n",
1590 ipv6_hdr->status);
1591 result = ipv6_hdr->status;
1592 goto fail_add_hdr;
1593 }
1594 rndis_ipa_ctx->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
1595 rndis_ipa_ctx->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
1596
1597 RNDIS_IPA_LOG_EXIT();
1598
1599fail_add_hdr:
1600 kfree(hdrs);
1601fail_mem:
1602 return result;
1603}
1604
1605/**
1606 * rndis_ipa_hdrs_destroy() - remove the IPA core configuration done for
1607 * the driver data path bridging.
1608 * @rndis_ipa_ctx: the driver context
1609 *
1610 * Revert the work done on rndis_ipa_hdrs_cfg(), which is,
1611 * remove 2 headers for Ethernet+RNDIS.
1612 */
1613static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
1614{
1615 struct ipa_ioc_del_hdr *del_hdr;
1616 struct ipa_hdr_del *ipv4;
1617 struct ipa_hdr_del *ipv6;
1618 int result;
1619
1620 del_hdr = kzalloc(sizeof(*del_hdr) + sizeof(*ipv4) +
1621 sizeof(*ipv6), GFP_KERNEL);
1622 if (!del_hdr) {
1623 RNDIS_IPA_ERROR("memory allocation for del_hdr failed\n");
1624 return -ENOMEM;
1625 }
1626
1627 del_hdr->commit = 1;
1628 del_hdr->num_hdls = 2;
1629
1630 ipv4 = &del_hdr->hdl[0];
1631 ipv4->hdl = rndis_ipa_ctx->eth_ipv4_hdr_hdl;
1632 ipv6 = &del_hdr->hdl[1];
1633 ipv6->hdl = rndis_ipa_ctx->eth_ipv6_hdr_hdl;
1634
1635 result = ipa_del_hdr(del_hdr);
1636 if (result || ipv4->status || ipv6->status)
1637 RNDIS_IPA_ERROR("ipa_del_hdr failed\n");
1638 else
1639 RNDIS_IPA_DEBUG("hdrs deletion done\n");
1640
1641 kfree(del_hdr);
1642 return result;
1643}
1644
1645static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net)
1646{
1647 return &net->stats;
1648}
1649
1650/**
1651 * rndis_ipa_register_properties() - set Tx/Rx properties needed
1652 * by IPA configuration manager
1653 * @netdev_name: a string with the name of the network interface device
Amir Levy2da9d452017-12-12 10:09:46 +02001654 * @is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02001655 *
1656 * Register Tx/Rx properties to allow user space configuration (IPA
1657 * Configuration Manager):
1658 *
1659 * - Two Tx properties (IPA->USB): specify the header names and pipe number
1660 * that shall be used by user space for header-addition configuration
1661 * for ipv4/ipv6 packets flowing from IPA to USB for HW bridging data.
1662 * That header-addition header is added by the Netdev and used by user
1663 * space to close the the HW bridge by adding filtering and routing rules
1664 * that point to this header.
1665 *
1666 * - Two Rx properties (USB->IPA): these properties shall be used by user space
1667 * to configure the IPA core to identify the packets destined
1668 * for Apps-processor by configuring the unicast rules destined for
1669 * the Netdev IP address.
1670 * This rules shall be added based on the attribute mask supplied at
1671 * this function, that is, always hit rule.
1672 */
Amir Levy2da9d452017-12-12 10:09:46 +02001673static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02001674{
1675 struct ipa_tx_intf tx_properties = {0};
1676 struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
1677 struct ipa_ioc_tx_intf_prop *ipv4_property;
1678 struct ipa_ioc_tx_intf_prop *ipv6_property;
1679 struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
1680 struct ipa_rx_intf rx_properties = {0};
1681 struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
1682 struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
Amir Levy2da9d452017-12-12 10:09:46 +02001683 enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
Amir Levya7146102016-11-08 14:10:58 +02001684 int result = 0;
1685
1686 RNDIS_IPA_LOG_ENTRY();
1687
Amir Levy2da9d452017-12-12 10:09:46 +02001688 if (is_vlan_mode)
1689 hdr_l2_type = IPA_HDR_L2_802_1Q;
1690
Amir Levya7146102016-11-08 14:10:58 +02001691 tx_properties.prop = properties;
1692 ipv4_property = &tx_properties.prop[0];
1693 ipv4_property->ip = IPA_IP_v4;
1694 ipv4_property->dst_pipe = IPA_TO_USB_CLIENT;
1695 strlcpy
1696 (ipv4_property->hdr_name, IPV4_HDR_NAME,
1697 IPA_RESOURCE_NAME_MAX);
Amir Levy2da9d452017-12-12 10:09:46 +02001698 ipv4_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001699 ipv6_property = &tx_properties.prop[1];
1700 ipv6_property->ip = IPA_IP_v6;
1701 ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
1702 strlcpy
1703 (ipv6_property->hdr_name, IPV6_HDR_NAME,
1704 IPA_RESOURCE_NAME_MAX);
Amir Levy2da9d452017-12-12 10:09:46 +02001705 ipv6_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001706 tx_properties.num_props = 2;
1707
1708 rx_properties.prop = rx_ioc_properties;
1709 rx_ipv4_property = &rx_properties.prop[0];
1710 rx_ipv4_property->ip = IPA_IP_v4;
1711 rx_ipv4_property->attrib.attrib_mask = 0;
1712 rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
Amir Levy2da9d452017-12-12 10:09:46 +02001713 rx_ipv4_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001714 rx_ipv6_property = &rx_properties.prop[1];
1715 rx_ipv6_property->ip = IPA_IP_v6;
1716 rx_ipv6_property->attrib.attrib_mask = 0;
1717 rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
Amir Levy2da9d452017-12-12 10:09:46 +02001718 rx_ipv6_property->hdr_l2_type = hdr_l2_type;
Amir Levya7146102016-11-08 14:10:58 +02001719 rx_properties.num_props = 2;
1720
1721 result = ipa_register_intf("rndis0", &tx_properties, &rx_properties);
1722 if (result)
1723 RNDIS_IPA_ERROR("fail on Tx/Rx properties registration\n");
1724 else
1725 RNDIS_IPA_DEBUG("Tx/Rx properties registration done\n");
1726
1727 RNDIS_IPA_LOG_EXIT();
1728
1729 return result;
1730}
1731
1732/**
1733 * rndis_ipa_deregister_properties() - remove the 2 Tx and 2 Rx properties
1734 * @netdev_name: a string with the name of the network interface device
1735 *
1736 * This function revert the work done on rndis_ipa_register_properties().
1737 */
1738static int rndis_ipa_deregister_properties(char *netdev_name)
1739{
1740 int result;
1741
1742 RNDIS_IPA_LOG_ENTRY();
1743
1744 result = ipa_deregister_intf(netdev_name);
1745 if (result) {
1746 RNDIS_IPA_DEBUG("Fail on Tx prop deregister\n");
1747 return result;
1748 }
1749 RNDIS_IPA_LOG_EXIT();
1750
1751 return 0;
1752}
1753
1754/**
1755 * rndis_ipa_create_rm_resource() -creates the resource representing
1756 * this Netdev and supply notification callback for resource event
1757 * such as Grant/Release
1758 * @rndis_ipa_ctx: this driver context
1759 *
1760 * In order make sure all needed resources are available during packet
1761 * transmit this Netdev shall use Request/Release mechanism of
1762 * the IPA resource manager.
1763 * This mechanism shall iterate over a dependency graph and make sure
1764 * all dependent entities are ready to for packet Tx
1765 * transfer (Apps->IPA->USB).
1766 * In this function the resource representing the Netdev is created
1767 * in addition to the basic dependency between the Netdev and the USB client.
1768 * Hence, USB client, is a dependency for the Netdev and may be notified in
1769 * case of packet transmit from this Netdev to tethered Host.
1770 * As implied from the "may" in the above sentence there is a scenario where
1771 * the USB is not notified. This is done thanks to the IPA resource manager
1772 * inactivity timer.
1773 * The inactivity timer allow the Release requests to be delayed in order
1774 * prevent ping-pong with the USB and other dependencies.
1775 */
1776static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
1777{
1778 struct ipa_rm_create_params create_params = {0};
1779 struct ipa_rm_perf_profile profile;
1780 int result;
1781
1782 RNDIS_IPA_LOG_ENTRY();
1783
1784 create_params.name = DRV_RESOURCE_ID;
1785 create_params.reg_params.user_data = rndis_ipa_ctx;
1786 create_params.reg_params.notify_cb = rndis_ipa_rm_notify;
1787 result = ipa_rm_create_resource(&create_params);
1788 if (result) {
1789 RNDIS_IPA_ERROR("Fail on ipa_rm_create_resource\n");
1790 goto fail_rm_create;
1791 }
1792 RNDIS_IPA_DEBUG("RM client was created\n");
1793
1794 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
1795 ipa_rm_set_perf_profile(DRV_RESOURCE_ID, &profile);
1796
1797 result = ipa_rm_inactivity_timer_init
1798 (DRV_RESOURCE_ID,
1799 INACTIVITY_MSEC_DELAY);
1800 if (result) {
1801 RNDIS_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
1802 goto fail_inactivity_timer;
1803 }
1804
1805 RNDIS_IPA_DEBUG("rm_it client was created\n");
1806
1807 result = ipa_rm_add_dependency_sync
1808 (DRV_RESOURCE_ID,
1809 IPA_RM_RESOURCE_USB_CONS);
1810
1811 if (result && result != -EINPROGRESS)
1812 RNDIS_IPA_ERROR("unable to add RNDIS/USB dependency (%d)\n",
1813 result);
1814 else
1815 RNDIS_IPA_DEBUG("RNDIS/USB dependency was set\n");
1816
1817 result = ipa_rm_add_dependency_sync
1818 (IPA_RM_RESOURCE_USB_PROD,
1819 IPA_RM_RESOURCE_APPS_CONS);
1820 if (result && result != -EINPROGRESS)
1821 RNDIS_IPA_ERROR("unable to add USB/APPS dependency (%d)\n",
1822 result);
1823 else
1824 RNDIS_IPA_DEBUG("USB/APPS dependency was set\n");
1825
1826 RNDIS_IPA_LOG_EXIT();
1827
1828 return 0;
1829
1830fail_inactivity_timer:
1831fail_rm_create:
1832 return result;
1833}
1834
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301835#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001836static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
1837{
1838 struct rndis_ipa_dev *rndis_ipa_ctx = p;
1839
1840 RNDIS_IPA_LOG_ENTRY();
1841
1842 if (event != IPA_PM_CLIENT_ACTIVATED) {
1843 RNDIS_IPA_ERROR("unexpected event %d\n", event);
1844 WARN_ON(1);
1845 return;
1846 }
1847 RNDIS_IPA_DEBUG("Resource Granted\n");
1848
1849 if (netif_queue_stopped(rndis_ipa_ctx->net)) {
1850 RNDIS_IPA_DEBUG("starting queue\n");
1851 netif_start_queue(rndis_ipa_ctx->net);
1852 } else {
1853 RNDIS_IPA_DEBUG("queue already awake\n");
1854 }
1855
1856 RNDIS_IPA_LOG_EXIT();
1857}
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301858#endif
Amir Levya7146102016-11-08 14:10:58 +02001859/**
1860 * rndis_ipa_destroy_rm_resource() - delete the dependency and destroy
1861 * the resource done on rndis_ipa_create_rm_resource()
1862 * @rndis_ipa_ctx: this driver context
1863 *
1864 * This function shall delete the dependency create between
1865 * the Netdev to the USB.
1866 * In addition the inactivity time shall be destroy and the resource shall
1867 * be deleted.
1868 */
1869static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
1870{
1871 int result;
1872
1873 RNDIS_IPA_LOG_ENTRY();
1874
1875 result = ipa_rm_delete_dependency
1876 (DRV_RESOURCE_ID,
1877 IPA_RM_RESOURCE_USB_CONS);
1878 if (result && result != -EINPROGRESS) {
1879 RNDIS_IPA_ERROR("Fail to delete RNDIS/USB dependency\n");
1880 goto bail;
1881 }
1882 RNDIS_IPA_DEBUG("RNDIS/USB dependency was successfully deleted\n");
1883
1884 result = ipa_rm_delete_dependency
1885 (IPA_RM_RESOURCE_USB_PROD,
1886 IPA_RM_RESOURCE_APPS_CONS);
1887 if (result == -EINPROGRESS) {
1888 RNDIS_IPA_DEBUG("RM dependency deletion is in progress");
1889 } else if (result) {
1890 RNDIS_IPA_ERROR("Fail to delete USB/APPS dependency\n");
1891 goto bail;
1892 } else {
1893 RNDIS_IPA_DEBUG("USB/APPS dependency was deleted\n");
1894 }
1895
1896 result = ipa_rm_inactivity_timer_destroy(DRV_RESOURCE_ID);
1897 if (result) {
1898 RNDIS_IPA_ERROR("Fail to destroy inactivity timern");
1899 goto bail;
1900 }
1901 RNDIS_IPA_DEBUG("RM inactivity timer was successfully destroy\n");
1902
1903 result = ipa_rm_delete_resource(DRV_RESOURCE_ID);
1904 if (result) {
1905 RNDIS_IPA_ERROR("resource deletion failed\n");
1906 goto bail;
1907 }
1908 RNDIS_IPA_DEBUG
1909 ("Netdev RM resource was deleted (resid:%d)\n",
1910 DRV_RESOURCE_ID);
1911
1912 RNDIS_IPA_LOG_EXIT();
1913
1914bail:
1915 return result;
1916}
1917
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301918#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001919static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
1920{
1921 int result;
1922 struct ipa_pm_register_params pm_reg;
1923
1924 memset(&pm_reg, 0, sizeof(pm_reg));
1925
1926 pm_reg.name = rndis_ipa_ctx->net->name;
1927 pm_reg.user_data = rndis_ipa_ctx;
1928 pm_reg.callback = rndis_ipa_pm_cb;
1929 pm_reg.group = IPA_PM_GROUP_APPS;
1930 result = ipa_pm_register(&pm_reg, &rndis_ipa_ctx->pm_hdl);
1931 if (result) {
1932 RNDIS_IPA_ERROR("failed to create IPA PM client %d\n", result);
1933 return result;
1934 }
1935 return 0;
1936}
1937
1938static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
1939{
1940 ipa_pm_deactivate_sync(rndis_ipa_ctx->pm_hdl);
1941 ipa_pm_deregister(rndis_ipa_ctx->pm_hdl);
1942 rndis_ipa_ctx->pm_hdl = ~0;
1943 return 0;
1944}
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301945#endif
Amir Levya7146102016-11-08 14:10:58 +02001946/**
1947 * resource_request() - request for the Netdev resource
1948 * @rndis_ipa_ctx: main driver context
1949 *
1950 * This function shall send the IPA resource manager inactivity time a request
1951 * to Grant the Netdev producer.
1952 * In case the resource is already Granted the function shall return immediately
1953 * and "pet" the inactivity timer.
1954 * In case the resource was not already Granted this function shall
1955 * return EINPROGRESS and the Netdev shall stop the send queue until
1956 * the IPA resource manager notify it that the resource is
1957 * granted (done in a differ context)
1958 */
1959static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx)
1960{
1961 int result = 0;
1962
1963 if (!rm_enabled(rndis_ipa_ctx))
Michael Adisumarta3e350812017-09-18 14:54:36 -07001964 return result;
1965
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301966#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001967 if (ipa_pm_is_used())
1968 return ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301969#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001970 return ipa_rm_inactivity_timer_request_resource(
Amir Levya7146102016-11-08 14:10:58 +02001971 DRV_RESOURCE_ID);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001972
Amir Levya7146102016-11-08 14:10:58 +02001973}
1974
1975/**
1976 * resource_release() - release the Netdev resource
1977 * @rndis_ipa_ctx: main driver context
1978 *
1979 * start the inactivity timer count down.by using the IPA resource
1980 * manager inactivity time.
1981 * The actual resource release shall occur only if no request shall be done
1982 * during the INACTIVITY_MSEC_DELAY.
1983 */
1984static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
1985{
1986 if (!rm_enabled(rndis_ipa_ctx))
Michael Adisumarta3e350812017-09-18 14:54:36 -07001987 return;
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301988#ifdef CONFIG_IPA3
Michael Adisumarta3e350812017-09-18 14:54:36 -07001989 if (ipa_pm_is_used())
1990 ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
1991 else
Mohammed Javid4c4037e2017-11-27 16:23:35 +05301992#endif
Michael Adisumarta3e350812017-09-18 14:54:36 -07001993 ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
1994
Amir Levya7146102016-11-08 14:10:58 +02001995 return;
1996}
1997
1998/**
1999 * rndis_encapsulate_skb() - encapsulate the given Ethernet skb with
2000 * an RNDIS header
2001 * @skb: packet to be encapsulated with the RNDIS header
Amir Levy2da9d452017-12-12 10:09:46 +02002002 * @rndis_ipa_ctx: main driver context
Amir Levya7146102016-11-08 14:10:58 +02002003 *
2004 * Shall use a template header for RNDIS and update it with the given
2005 * skb values.
2006 * Ethernet is expected to be already encapsulate the packet.
2007 */
Amir Levy2da9d452017-12-12 10:09:46 +02002008static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
2009 struct rndis_ipa_dev *rndis_ipa_ctx)
Amir Levya7146102016-11-08 14:10:58 +02002010{
2011 struct rndis_pkt_hdr *rndis_hdr;
2012 int payload_byte_len = skb->len;
2013
2014 /* if there is no room in this skb, allocate a new one */
2015 if (unlikely(skb_headroom(skb) < sizeof(rndis_template_hdr))) {
2016 struct sk_buff *new_skb = skb_copy_expand(skb,
2017 sizeof(rndis_template_hdr), 0, GFP_ATOMIC);
2018 if (!new_skb) {
2019 RNDIS_IPA_ERROR("no memory for skb expand\n");
2020 return skb;
2021 }
2022 RNDIS_IPA_DEBUG("skb expanded. old %p new %p\n", skb, new_skb);
2023 dev_kfree_skb_any(skb);
2024 skb = new_skb;
2025 }
2026
Amir Levy2da9d452017-12-12 10:09:46 +02002027 if (rndis_ipa_ctx->is_vlan_mode)
2028 if (unlikely(skb->protocol != ETH_P_8021Q))
2029 RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
2030
Amir Levya7146102016-11-08 14:10:58 +02002031 /* make room at the head of the SKB to put the RNDIS header */
2032 rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
2033 sizeof(rndis_template_hdr));
2034
2035 memcpy(rndis_hdr, &rndis_template_hdr, sizeof(*rndis_hdr));
2036 rndis_hdr->msg_len += payload_byte_len;
2037 rndis_hdr->data_len += payload_byte_len;
2038
2039 return skb;
2040}
2041
2042/**
2043 * rx_filter() - logic that decide if the current skb is to be filtered out
2044 * @skb: skb that may be sent up to the network stack
2045 *
2046 * This function shall do Rx packet filtering on the Netdev level.
2047 */
2048static bool rx_filter(struct sk_buff *skb)
2049{
2050 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
2051
2052 return rndis_ipa_ctx->rx_filter;
2053}
2054
2055/**
2056 * tx_filter() - logic that decide if the current skb is to be filtered out
2057 * @skb: skb that may be sent to the USB core
2058 *
2059 * This function shall do Tx packet filtering on the Netdev level.
2060 * ICMP filter bypass is possible to allow only ICMP packet to be
2061 * sent (pings and etc)
2062 */
2063
2064static bool tx_filter(struct sk_buff *skb)
2065{
2066 struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(skb->dev);
2067 bool is_icmp;
2068
2069 if (likely(!rndis_ipa_ctx->tx_filter))
2070 return false;
2071
2072 is_icmp = (skb->protocol == htons(ETH_P_IP) &&
2073 ip_hdr(skb)->protocol == IPPROTO_ICMP);
2074
2075 if ((!rndis_ipa_ctx->icmp_filter) && is_icmp)
2076 return false;
2077
2078 return true;
2079}
2080
2081/**
2082 * rm_enabled() - allow the use of resource manager Request/Release to
2083 * be bypassed
2084 * @rndis_ipa_ctx: main driver context
2085 *
2086 * By disabling the resource manager flag the Request for the Netdev resource
2087 * shall be bypassed and the packet shall be sent.
2088 * accordingly, Release request shall be bypass as well.
2089 */
2090static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
2091{
2092 return rndis_ipa_ctx->rm_enable;
2093}
2094
2095/**
2096 * rndis_ipa_ep_registers_cfg() - configure the USB endpoints
2097 * @usb_to_ipa_hdl: handle received from ipa_connect which represents
2098 * the USB to IPA end-point
2099 * @ipa_to_usb_hdl: handle received from ipa_connect which represents
2100 * the IPA to USB end-point
2101 * @max_xfer_size_bytes_to_dev: the maximum size, in bytes, that the device
2102 * expects to receive from the host. supplied on REMOTE_NDIS_INITIALIZE_CMPLT.
2103 * @max_xfer_size_bytes_to_host: the maximum size, in bytes, that the host
2104 * expects to receive from the device. supplied on REMOTE_NDIS_INITIALIZE_MSG.
2105 * @mtu: the netdev MTU size, in bytes
Amir Levy2da9d452017-12-12 10:09:46 +02002106 * @deaggr_enable: should deaggregation be enabled?
2107 * @is_vlan_mode: should driver work in vlan mode?
Amir Levya7146102016-11-08 14:10:58 +02002108 *
2109 * USB to IPA pipe:
2110 * - de-aggregation
2111 * - Remove Ethernet header
2112 * - Remove RNDIS header
2113 * - SRC NAT
2114 * - Default routing(0)
2115 * IPA to USB Pipe:
2116 * - aggregation
2117 * - Add Ethernet header
2118 * - Add RNDIS header
2119 */
2120static int rndis_ipa_ep_registers_cfg(
2121 u32 usb_to_ipa_hdl,
2122 u32 ipa_to_usb_hdl,
2123 u32 max_xfer_size_bytes_to_dev,
2124 u32 max_xfer_size_bytes_to_host,
2125 u32 mtu,
Amir Levy2da9d452017-12-12 10:09:46 +02002126 bool deaggr_enable,
2127 bool is_vlan_mode)
Amir Levya7146102016-11-08 14:10:58 +02002128{
2129 int result;
2130 struct ipa_ep_cfg *usb_to_ipa_ep_cfg;
Amir Levy85650962017-12-20 14:24:18 +02002131 int add = 0;
Amir Levya7146102016-11-08 14:10:58 +02002132
2133 if (deaggr_enable) {
2134 usb_to_ipa_ep_cfg = &usb_to_ipa_ep_cfg_deaggr_en;
2135 RNDIS_IPA_DEBUG("deaggregation enabled\n");
2136 } else {
2137 usb_to_ipa_ep_cfg = &usb_to_ipa_ep_cfg_deaggr_dis;
2138 RNDIS_IPA_DEBUG("deaggregation disabled\n");
Amir Levy85650962017-12-20 14:24:18 +02002139 add = sizeof(struct rndis_pkt_hdr);
Amir Levya7146102016-11-08 14:10:58 +02002140 }
2141
Amir Levy2da9d452017-12-12 10:09:46 +02002142 if (is_vlan_mode) {
2143 usb_to_ipa_ep_cfg->hdr.hdr_len =
Amir Levy85650962017-12-20 14:24:18 +02002144 VLAN_ETH_HLEN + add;
Amir Levy2da9d452017-12-12 10:09:46 +02002145 ipa_to_usb_ep_cfg.hdr.hdr_len =
2146 VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
2147 ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = VLAN_ETH_HLEN;
2148 } else {
2149 usb_to_ipa_ep_cfg->hdr.hdr_len =
Amir Levy85650962017-12-20 14:24:18 +02002150 ETH_HLEN + add;
Amir Levy2da9d452017-12-12 10:09:46 +02002151 ipa_to_usb_ep_cfg.hdr.hdr_len =
2152 ETH_HLEN + sizeof(struct rndis_pkt_hdr);
2153 ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = ETH_HLEN;
2154 }
2155
Amir Levya7146102016-11-08 14:10:58 +02002156 usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_xfer_size_bytes_to_dev;
2157 result = ipa_cfg_ep(usb_to_ipa_hdl, usb_to_ipa_ep_cfg);
2158 if (result) {
2159 pr_err("failed to configure USB to IPA point\n");
2160 return result;
2161 }
2162 RNDIS_IPA_DEBUG("IPA<-USB end-point configured\n");
2163
2164 ipa_to_usb_ep_cfg.aggr.aggr_byte_limit =
2165 (max_xfer_size_bytes_to_host - mtu) / 1024;
2166
2167 if (ipa_to_usb_ep_cfg.aggr.aggr_byte_limit == 0) {
2168 ipa_to_usb_ep_cfg.aggr.aggr_time_limit = 0;
2169 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit = 1;
2170 } else {
2171 ipa_to_usb_ep_cfg.aggr.aggr_time_limit =
2172 DEFAULT_AGGR_TIME_LIMIT;
2173 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit =
2174 DEFAULT_AGGR_PKT_LIMIT;
2175 }
2176
2177 RNDIS_IPA_DEBUG(
2178 "RNDIS aggregation param: en=%d byte_limit=%d time_limit=%d pkt_limit=%d\n"
2179 , ipa_to_usb_ep_cfg.aggr.aggr_en,
2180 ipa_to_usb_ep_cfg.aggr.aggr_byte_limit,
2181 ipa_to_usb_ep_cfg.aggr.aggr_time_limit,
2182 ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit);
2183
2184 result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
2185 if (result) {
2186 pr_err("failed to configure IPA to USB end-point\n");
2187 return result;
2188 }
2189 RNDIS_IPA_DEBUG("IPA->USB end-point configured\n");
2190
2191 return 0;
2192}
2193
2194/**
2195 * rndis_ipa_set_device_ethernet_addr() - set device Ethernet address
2196 * @dev_ethaddr: device Ethernet address
2197 *
2198 * Returns 0 for success, negative otherwise
2199 */
2200static int rndis_ipa_set_device_ethernet_addr(
2201 u8 *dev_ethaddr,
2202 u8 device_ethaddr[])
2203{
2204 if (!is_valid_ether_addr(device_ethaddr))
2205 return -EINVAL;
2206 memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
2207
2208 return 0;
2209}
2210
2211/** rndis_ipa_next_state - return the next state of the driver
2212 * @current_state: the current state of the driver
2213 * @operation: an enum which represent the operation being made on the driver
2214 * by its API.
2215 *
2216 * This function implements the driver internal state machine.
2217 * Its decisions are based on the driver current state and the operation
2218 * being made.
2219 * In case the operation is invalid this state machine will return
2220 * the value RNDIS_IPA_INVALID to inform the caller for a forbidden sequence.
2221 */
2222static enum rndis_ipa_state rndis_ipa_next_state(
2223 enum rndis_ipa_state current_state,
2224 enum rndis_ipa_operation operation)
2225{
2226 int next_state = RNDIS_IPA_INVALID;
2227
2228 switch (current_state) {
2229 case RNDIS_IPA_UNLOADED:
2230 if (operation == RNDIS_IPA_INITIALIZE)
2231 next_state = RNDIS_IPA_INITIALIZED;
2232 break;
2233 case RNDIS_IPA_INITIALIZED:
2234 if (operation == RNDIS_IPA_CONNECT)
2235 next_state = RNDIS_IPA_CONNECTED;
2236 else if (operation == RNDIS_IPA_OPEN)
2237 next_state = RNDIS_IPA_UP;
2238 else if (operation == RNDIS_IPA_CLEANUP)
2239 next_state = RNDIS_IPA_UNLOADED;
2240 break;
2241 case RNDIS_IPA_CONNECTED:
2242 if (operation == RNDIS_IPA_DISCONNECT)
2243 next_state = RNDIS_IPA_INITIALIZED;
2244 else if (operation == RNDIS_IPA_OPEN)
2245 next_state = RNDIS_IPA_CONNECTED_AND_UP;
2246 break;
2247 case RNDIS_IPA_UP:
2248 if (operation == RNDIS_IPA_STOP)
2249 next_state = RNDIS_IPA_INITIALIZED;
2250 else if (operation == RNDIS_IPA_CONNECT)
2251 next_state = RNDIS_IPA_CONNECTED_AND_UP;
2252 else if (operation == RNDIS_IPA_CLEANUP)
2253 next_state = RNDIS_IPA_UNLOADED;
2254 break;
2255 case RNDIS_IPA_CONNECTED_AND_UP:
2256 if (operation == RNDIS_IPA_STOP)
2257 next_state = RNDIS_IPA_CONNECTED;
2258 else if (operation == RNDIS_IPA_DISCONNECT)
2259 next_state = RNDIS_IPA_UP;
2260 break;
2261 default:
2262 RNDIS_IPA_ERROR("State is not supported\n");
2263 WARN_ON(true);
2264 break;
2265 }
2266
2267 RNDIS_IPA_DEBUG
2268 ("state transition ( %s -> %s )- %s\n",
2269 rndis_ipa_state_string(current_state),
2270 rndis_ipa_state_string(next_state),
2271 next_state == RNDIS_IPA_INVALID ?
2272 "Forbidden" : "Allowed");
2273
2274 return next_state;
2275}
2276
2277/**
2278 * rndis_ipa_state_string - return the state string representation
2279 * @state: enum which describe the state
2280 */
2281static const char *rndis_ipa_state_string(enum rndis_ipa_state state)
2282{
2283 switch (state) {
2284 case RNDIS_IPA_UNLOADED:
2285 return "RNDIS_IPA_UNLOADED";
2286 case RNDIS_IPA_INITIALIZED:
2287 return "RNDIS_IPA_INITIALIZED";
2288 case RNDIS_IPA_CONNECTED:
2289 return "RNDIS_IPA_CONNECTED";
2290 case RNDIS_IPA_UP:
2291 return "RNDIS_IPA_UP";
2292 case RNDIS_IPA_CONNECTED_AND_UP:
2293 return "RNDIS_IPA_CONNECTED_AND_UP";
2294 default:
2295 return "Not supported";
2296 }
2297}
2298
2299static void rndis_ipa_dump_skb(struct sk_buff *skb)
2300{
2301 int i;
2302 u32 *cur = (u32 *)skb->data;
2303 u8 *byte;
2304
2305 RNDIS_IPA_DEBUG
2306 ("packet dump start for skb->len=%d\n",
2307 skb->len);
2308
2309 for (i = 0; i < (skb->len / 4); i++) {
2310 byte = (u8 *)(cur + i);
2311 pr_info
2312 ("%2d %08x %02x %02x %02x %02x\n",
2313 i, *(cur + i),
2314 byte[0], byte[1], byte[2], byte[3]);
2315 }
2316 RNDIS_IPA_DEBUG
2317 ("packet dump ended for skb->len=%d\n", skb->len);
2318}
2319
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302320#ifdef CONFIG_DEBUG_FS
Amir Levya7146102016-11-08 14:10:58 +02002321/**
2322 * Creates the root folder for the driver
2323 */
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302324static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
Amir Levya7146102016-11-08 14:10:58 +02002325{
2326 const mode_t flags_read_write = 0666;
2327 const mode_t flags_read_only = 0444;
2328 const mode_t flags_write_only = 0222;
2329 struct dentry *file;
2330 struct dentry *aggr_directory;
2331
2332 RNDIS_IPA_LOG_ENTRY();
2333
2334 if (!rndis_ipa_ctx)
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302335 return;
Amir Levya7146102016-11-08 14:10:58 +02002336
2337 rndis_ipa_ctx->directory = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
2338 if (!rndis_ipa_ctx->directory) {
2339 RNDIS_IPA_ERROR("could not create debugfs directory entry\n");
2340 goto fail_directory;
2341 }
2342
2343 file = debugfs_create_bool
2344 ("tx_filter", flags_read_write,
2345 rndis_ipa_ctx->directory, &rndis_ipa_ctx->tx_filter);
2346 if (!file) {
2347 RNDIS_IPA_ERROR("could not create debugfs tx_filter file\n");
2348 goto fail_file;
2349 }
2350
2351 file = debugfs_create_bool
2352 ("rx_filter", flags_read_write,
2353 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rx_filter);
2354 if (!file) {
2355 RNDIS_IPA_ERROR("could not create debugfs rx_filter file\n");
2356 goto fail_file;
2357 }
2358
2359 file = debugfs_create_bool
2360 ("icmp_filter", flags_read_write,
2361 rndis_ipa_ctx->directory, &rndis_ipa_ctx->icmp_filter);
2362 if (!file) {
2363 RNDIS_IPA_ERROR("could not create debugfs icmp_filter file\n");
2364 goto fail_file;
2365 }
2366
2367 file = debugfs_create_bool
2368 ("rm_enable", flags_read_write,
2369 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rm_enable);
2370 if (!file) {
2371 RNDIS_IPA_ERROR("could not create debugfs rm file\n");
2372 goto fail_file;
2373 }
2374
2375 file = debugfs_create_u32
2376 ("outstanding_high", flags_read_write,
2377 rndis_ipa_ctx->directory,
2378 &rndis_ipa_ctx->outstanding_high);
2379 if (!file) {
2380 RNDIS_IPA_ERROR("could not create outstanding_high file\n");
2381 goto fail_file;
2382 }
2383
2384 file = debugfs_create_u32
2385 ("outstanding_low", flags_read_write,
2386 rndis_ipa_ctx->directory,
2387 &rndis_ipa_ctx->outstanding_low);
2388 if (!file) {
2389 RNDIS_IPA_ERROR("could not create outstanding_low file\n");
2390 goto fail_file;
2391 }
2392
2393 file = debugfs_create_file
2394 ("outstanding", flags_read_only,
2395 rndis_ipa_ctx->directory,
2396 rndis_ipa_ctx, &rndis_ipa_debugfs_atomic_ops);
2397 if (!file) {
2398 RNDIS_IPA_ERROR("could not create outstanding file\n");
2399 goto fail_file;
2400 }
2401
Amir Levya7146102016-11-08 14:10:58 +02002402 file = debugfs_create_u8
2403 ("state", flags_read_only,
2404 rndis_ipa_ctx->directory, (u8 *)&rndis_ipa_ctx->state);
2405 if (!file) {
2406 RNDIS_IPA_ERROR("could not create state file\n");
2407 goto fail_file;
2408 }
2409
2410 file = debugfs_create_u32
2411 ("tx_dropped", flags_read_only,
2412 rndis_ipa_ctx->directory, &rndis_ipa_ctx->tx_dropped);
2413 if (!file) {
2414 RNDIS_IPA_ERROR("could not create tx_dropped file\n");
2415 goto fail_file;
2416 }
2417
2418 file = debugfs_create_u32
2419 ("rx_dropped", flags_read_only,
2420 rndis_ipa_ctx->directory, &rndis_ipa_ctx->rx_dropped);
2421 if (!file) {
2422 RNDIS_IPA_ERROR("could not create rx_dropped file\n");
2423 goto fail_file;
2424 }
2425
2426 aggr_directory = debugfs_create_dir
2427 (DEBUGFS_AGGR_DIR_NAME,
2428 rndis_ipa_ctx->directory);
2429 if (!aggr_directory) {
2430 RNDIS_IPA_ERROR("could not create debugfs aggr entry\n");
2431 goto fail_directory;
2432 }
2433
2434 file = debugfs_create_file
2435 ("aggr_value_set", flags_write_only,
2436 aggr_directory,
2437 rndis_ipa_ctx, &rndis_ipa_aggr_ops);
2438 if (!file) {
2439 RNDIS_IPA_ERROR("could not create aggr_value_set file\n");
2440 goto fail_file;
2441 }
2442
2443 file = debugfs_create_u8
2444 ("aggr_enable", flags_read_write,
2445 aggr_directory, (u8 *)&ipa_to_usb_ep_cfg.aggr.aggr_en);
2446 if (!file) {
2447 RNDIS_IPA_ERROR("could not create aggr_enable file\n");
2448 goto fail_file;
2449 }
2450
2451 file = debugfs_create_u8
2452 ("aggr_type", flags_read_write,
2453 aggr_directory, (u8 *)&ipa_to_usb_ep_cfg.aggr.aggr);
2454 if (!file) {
2455 RNDIS_IPA_ERROR("could not create aggr_type file\n");
2456 goto fail_file;
2457 }
2458
2459 file = debugfs_create_u32
2460 ("aggr_byte_limit", flags_read_write,
2461 aggr_directory,
2462 &ipa_to_usb_ep_cfg.aggr.aggr_byte_limit);
2463 if (!file) {
2464 RNDIS_IPA_ERROR("could not create aggr_byte_limit file\n");
2465 goto fail_file;
2466 }
2467
2468 file = debugfs_create_u32
2469 ("aggr_time_limit", flags_read_write,
2470 aggr_directory,
2471 &ipa_to_usb_ep_cfg.aggr.aggr_time_limit);
2472 if (!file) {
2473 RNDIS_IPA_ERROR("could not create aggr_time_limit file\n");
2474 goto fail_file;
2475 }
2476
2477 file = debugfs_create_u32
2478 ("aggr_pkt_limit", flags_read_write,
2479 aggr_directory,
2480 &ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit);
2481 if (!file) {
2482 RNDIS_IPA_ERROR("could not create aggr_pkt_limit file\n");
2483 goto fail_file;
2484 }
2485
2486 file = debugfs_create_bool
2487 ("tx_dump_enable", flags_read_write,
2488 rndis_ipa_ctx->directory,
2489 &rndis_ipa_ctx->tx_dump_enable);
2490 if (!file) {
2491 RNDIS_IPA_ERROR("fail to create tx_dump_enable file\n");
2492 goto fail_file;
2493 }
2494
2495 file = debugfs_create_bool
2496 ("rx_dump_enable", flags_read_write,
2497 rndis_ipa_ctx->directory,
2498 &rndis_ipa_ctx->rx_dump_enable);
2499 if (!file) {
2500 RNDIS_IPA_ERROR("fail to create rx_dump_enable file\n");
2501 goto fail_file;
2502 }
2503
2504 file = debugfs_create_bool
2505 ("deaggregation_enable", flags_read_write,
2506 rndis_ipa_ctx->directory,
2507 &rndis_ipa_ctx->deaggregation_enable);
2508 if (!file) {
2509 RNDIS_IPA_ERROR("fail to create deaggregation_enable file\n");
2510 goto fail_file;
2511 }
2512
2513 file = debugfs_create_u32
2514 ("error_msec_sleep_time", flags_read_write,
2515 rndis_ipa_ctx->directory,
2516 &rndis_ipa_ctx->error_msec_sleep_time);
2517 if (!file) {
2518 RNDIS_IPA_ERROR("fail to create error_msec_sleep_time file\n");
2519 goto fail_file;
2520 }
2521
2522 file = debugfs_create_bool
2523 ("during_xmit_error", flags_read_only,
2524 rndis_ipa_ctx->directory,
2525 &rndis_ipa_ctx->during_xmit_error);
2526 if (!file) {
2527 RNDIS_IPA_ERROR("fail to create during_xmit_error file\n");
2528 goto fail_file;
2529 }
2530
Amir Levy2da9d452017-12-12 10:09:46 +02002531 file = debugfs_create_bool("is_vlan_mode", flags_read_only,
2532 rndis_ipa_ctx->directory,
2533 &rndis_ipa_ctx->is_vlan_mode);
2534 if (!file) {
2535 RNDIS_IPA_ERROR("fail to create is_vlan_mode file\n");
2536 goto fail_file;
2537 }
2538
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302539 RNDIS_IPA_DEBUG("debugfs entries were created\n");
Amir Levya7146102016-11-08 14:10:58 +02002540 RNDIS_IPA_LOG_EXIT();
2541
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302542 return;
Amir Levya7146102016-11-08 14:10:58 +02002543fail_file:
2544 debugfs_remove_recursive(rndis_ipa_ctx->directory);
2545fail_directory:
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302546 return;
Amir Levya7146102016-11-08 14:10:58 +02002547}
2548
2549static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
2550{
2551 debugfs_remove_recursive(rndis_ipa_ctx->directory);
2552}
2553
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302554#else /* !CONFIG_DEBUG_FS */
2555
2556static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx) {}
2557
2558static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx) {}
2559
2560#endif /* CONFIG_DEBUG_FS*/
2561
Amir Levya7146102016-11-08 14:10:58 +02002562static int rndis_ipa_debugfs_aggr_open
Utkarsh Saxenadb9087e2016-10-17 16:10:11 +05302563 (struct inode *inode,
2564 struct file *file)
Amir Levya7146102016-11-08 14:10:58 +02002565{
2566 struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
2567
2568 file->private_data = rndis_ipa_ctx;
2569
2570 return 0;
2571}
2572
2573static ssize_t rndis_ipa_debugfs_aggr_write
2574 (struct file *file,
2575 const char __user *buf, size_t count, loff_t *ppos)
2576{
Mohammed Javidbf4c8022017-08-07 23:15:48 +05302577 struct rndis_ipa_dev *rndis_ipa_ctx = NULL;
Amir Levya7146102016-11-08 14:10:58 +02002578 int result;
2579
Mohammed Javidbf4c8022017-08-07 23:15:48 +05302580 if (file == NULL)
2581 return -EFAULT;
2582 rndis_ipa_ctx = file->private_data;
2583
Amir Levya7146102016-11-08 14:10:58 +02002584 result = ipa_cfg_ep(rndis_ipa_ctx->usb_to_ipa_hdl, &ipa_to_usb_ep_cfg);
2585 if (result) {
2586 pr_err("failed to re-configure USB to IPA point\n");
2587 return result;
2588 }
2589 pr_info("IPA<-USB end-point re-configured\n");
2590
2591 return count;
2592}
2593
Amir Levya7146102016-11-08 14:10:58 +02002594static int rndis_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
2595{
2596 struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
2597
2598 RNDIS_IPA_LOG_ENTRY();
2599
2600 file->private_data = &rndis_ipa_ctx->outstanding_pkts;
2601
2602 RNDIS_IPA_LOG_EXIT();
2603
2604 return 0;
2605}
2606
2607static ssize_t rndis_ipa_debugfs_atomic_read
2608 (struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
2609{
2610 int nbytes;
2611 u8 atomic_str[DEBUGFS_TEMP_BUF_SIZE] = {0};
2612 atomic_t *atomic_var = file->private_data;
2613
2614 RNDIS_IPA_LOG_ENTRY();
2615
2616 nbytes = scnprintf
2617 (atomic_str, sizeof(atomic_str), "%d\n",
2618 atomic_read(atomic_var));
2619
2620 RNDIS_IPA_LOG_EXIT();
2621
2622 return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes);
2623}
2624
Amir Levya7146102016-11-08 14:10:58 +02002625static int rndis_ipa_init_module(void)
2626{
2627 pr_info("RNDIS_IPA module is loaded.");
2628 return 0;
2629}
2630
2631static void rndis_ipa_cleanup_module(void)
2632{
2633 pr_info("RNDIS_IPA module is unloaded.");
2634}
2635
2636MODULE_LICENSE("GPL v2");
2637MODULE_DESCRIPTION("RNDIS_IPA network interface");
2638
2639late_initcall(rndis_ipa_init_module);
2640module_exit(rndis_ipa_cleanup_module);