blob: 0444b67155fdc4d87eb07301122bdc179f74a7ba [file] [log] [blame]
Skylar Changf3a7dac2017-01-25 09:16:55 -08001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
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 */
12
13/*
14 * WWAN Transport Network Driver.
15 */
16
17#include <linux/completion.h>
18#include <linux/errno.h>
19#include <linux/if_arp.h>
20#include <linux/interrupt.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/netdevice.h>
25#include <linux/of_device.h>
26#include <linux/string.h>
27#include <linux/skbuff.h>
28#include <linux/version.h>
29#include <linux/workqueue.h>
30#include <net/pkt_sched.h>
31#include <soc/qcom/subsystem_restart.h>
32#include <soc/qcom/subsystem_notif.h>
33#include "ipa_qmi_service.h"
34#include <linux/rmnet_ipa_fd_ioctl.h>
35#include <linux/ipa.h>
36#include <uapi/linux/net_map.h>
Gidon Studinski3021a6f2016-11-10 12:48:48 +020037#include <uapi/linux/msm_rmnet.h>
38#include <net/rmnet_config.h>
Amir Levy9659e592016-10-27 18:08:27 +030039
40#include "ipa_trace.h"
41
42#define WWAN_METADATA_SHFT 24
43#define WWAN_METADATA_MASK 0xFF000000
44#define WWAN_DATA_LEN 2000
45#define IPA_RM_INACTIVITY_TIMER 100 /* IPA_RM */
46#define HEADROOM_FOR_QMAP 8 /* for mux header */
47#define TAILROOM 0 /* for padding by mux layer */
48#define MAX_NUM_OF_MUX_CHANNEL 10 /* max mux channels */
49#define UL_FILTER_RULE_HANDLE_START 69
Ghanim Fodic6b67492017-03-15 14:19:56 +020050#define DEFAULT_OUTSTANDING_HIGH 128
51#define DEFAULT_OUTSTANDING_HIGH_CTL (DEFAULT_OUTSTANDING_HIGH+32)
52#define DEFAULT_OUTSTANDING_LOW 64
Amir Levy9659e592016-10-27 18:08:27 +030053
54#define IPA_WWAN_DEV_NAME "rmnet_ipa%d"
Skylar Chang6b41f8d2016-11-01 12:50:11 -070055#define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0"
Amir Levy9659e592016-10-27 18:08:27 +030056
57#define IPA_WWAN_RX_SOFTIRQ_THRESH 16
58
59#define INVALID_MUX_ID 0xFF
60#define IPA_QUOTA_REACH_ALERT_MAX_SIZE 64
61#define IPA_QUOTA_REACH_IF_NAME_MAX_SIZE 64
62#define IPA_UEVENT_NUM_EVNP 4 /* number of event pointers */
63#define NAPI_WEIGHT 60
64
65#define IPA_NETDEV() \
66 ((rmnet_ipa3_ctx && rmnet_ipa3_ctx->wwan_priv) ? \
67 rmnet_ipa3_ctx->wwan_priv->net : NULL)
68
Sunil Paidimarri226cf032016-10-14 13:33:08 -070069#define IPA_WWAN_CONS_DESC_FIFO_SZ 256
Amir Levy9659e592016-10-27 18:08:27 +030070
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +053071static void rmnet_ipa_free_msg(void *buff, u32 len, u32 type);
72static void rmnet_ipa_get_stats_and_update(void);
73
Amir Levy9659e592016-10-27 18:08:27 +030074static int ipa3_wwan_add_ul_flt_rule_to_ipa(void);
75static int ipa3_wwan_del_ul_flt_rule_to_ipa(void);
76static void ipa3_wwan_msg_free_cb(void*, u32, u32);
77static void ipa3_rmnet_rx_cb(void *priv);
78static int ipa3_rmnet_poll(struct napi_struct *napi, int budget);
79
80static void ipa3_wake_tx_queue(struct work_struct *work);
81static DECLARE_WORK(ipa3_tx_wakequeue_work, ipa3_wake_tx_queue);
82
83static void tethering_stats_poll_queue(struct work_struct *work);
84static DECLARE_DELAYED_WORK(ipa_tether_stats_poll_wakequeue_work,
85 tethering_stats_poll_queue);
86
87enum ipa3_wwan_device_status {
88 WWAN_DEVICE_INACTIVE = 0,
89 WWAN_DEVICE_ACTIVE = 1
90};
91
92struct ipa3_rmnet_plat_drv_res {
93 bool ipa_rmnet_ssr;
94 bool ipa_loaduC;
95 bool ipa_advertise_sg_support;
96 bool ipa_napi_enable;
Sunil Paidimarri226cf032016-10-14 13:33:08 -070097 u32 wan_rx_desc_size;
Amir Levy9659e592016-10-27 18:08:27 +030098};
99
100/**
101 * struct ipa3_wwan_private - WWAN private data
102 * @net: network interface struct implemented by this driver
103 * @stats: iface statistics
104 * @outstanding_pkts: number of packets sent to IPA without TX complete ACKed
105 * @outstanding_high: number of outstanding packets allowed
106 * @outstanding_low: number of outstanding packets which shall cause
107 * @ch_id: channel id
108 * @lock: spinlock for mutual exclusion
109 * @device_status: holds device status
110 *
111 * WWAN private - holds all relevant info about WWAN driver
112 */
113struct ipa3_wwan_private {
114 struct net_device *net;
115 struct net_device_stats stats;
116 atomic_t outstanding_pkts;
117 int outstanding_high_ctl;
118 int outstanding_high;
119 int outstanding_low;
120 uint32_t ch_id;
121 spinlock_t lock;
122 struct completion resource_granted_completion;
123 enum ipa3_wwan_device_status device_status;
124 struct napi_struct napi;
125};
126
127struct rmnet_ipa3_context {
128 struct ipa3_wwan_private *wwan_priv;
129 struct ipa_sys_connect_params apps_to_ipa_ep_cfg;
130 struct ipa_sys_connect_params ipa_to_apps_ep_cfg;
131 u32 qmap_hdr_hdl;
132 u32 dflt_v4_wan_rt_hdl;
133 u32 dflt_v6_wan_rt_hdl;
134 struct ipa3_rmnet_mux_val mux_channel[MAX_NUM_OF_MUX_CHANNEL];
135 int num_q6_rules;
136 int old_num_q6_rules;
137 int rmnet_index;
138 bool egress_set;
139 bool a7_ul_flt_set;
140 struct workqueue_struct *rm_q6_wq;
141 atomic_t is_initialized;
142 atomic_t is_ssr;
143 void *subsys_notify_handle;
144 u32 apps_to_ipa3_hdl;
145 u32 ipa3_to_apps_hdl;
Ghanim Fodic6b67492017-03-15 14:19:56 +0200146 struct mutex pipe_handle_guard;
Skylar Chang8438ba52017-03-15 21:27:35 -0700147 struct mutex add_mux_channel_lock;
Michael Adisumarta3e350812017-09-18 14:54:36 -0700148 u32 pm_hdl;
149 u32 q6_pm_hdl;
150 u32 q6_teth_pm_hdl;
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +0530151 struct mutex per_client_stats_guard;
152 struct ipa_tether_device_info
153 tether_device
154 [IPACM_MAX_CLIENT_DEVICE_TYPES];
Amir Levy9659e592016-10-27 18:08:27 +0300155};
156
157static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
158static struct ipa3_rmnet_plat_drv_res ipa3_rmnet_res;
159
160/**
161* ipa3_setup_a7_qmap_hdr() - Setup default a7 qmap hdr
162*
163* Return codes:
164* 0: success
165* -ENOMEM: failed to allocate memory
166* -EPERM: failed to add the tables
167*/
168static int ipa3_setup_a7_qmap_hdr(void)
169{
170 struct ipa_ioc_add_hdr *hdr;
171 struct ipa_hdr_add *hdr_entry;
172 u32 pyld_sz;
173 int ret;
174
175 /* install the basic exception header */
176 pyld_sz = sizeof(struct ipa_ioc_add_hdr) + 1 *
177 sizeof(struct ipa_hdr_add);
178 hdr = kzalloc(pyld_sz, GFP_KERNEL);
179 if (!hdr) {
180 IPAWANERR("fail to alloc exception hdr\n");
181 return -ENOMEM;
182 }
183 hdr->num_hdrs = 1;
184 hdr->commit = 1;
185 hdr_entry = &hdr->hdr[0];
186
187 strlcpy(hdr_entry->name, IPA_A7_QMAP_HDR_NAME,
188 IPA_RESOURCE_NAME_MAX);
189 hdr_entry->hdr_len = IPA_QMAP_HEADER_LENGTH; /* 4 bytes */
190
191 if (ipa3_add_hdr(hdr)) {
192 IPAWANERR("fail to add IPA_A7_QMAP hdr\n");
193 ret = -EPERM;
194 goto bail;
195 }
196
197 if (hdr_entry->status) {
198 IPAWANERR("fail to add IPA_A7_QMAP hdr\n");
199 ret = -EPERM;
200 goto bail;
201 }
202 rmnet_ipa3_ctx->qmap_hdr_hdl = hdr_entry->hdr_hdl;
203
204 ret = 0;
205bail:
206 kfree(hdr);
207 return ret;
208}
209
210static void ipa3_del_a7_qmap_hdr(void)
211{
212 struct ipa_ioc_del_hdr *del_hdr;
213 struct ipa_hdr_del *hdl_entry;
214 u32 pyld_sz;
215 int ret;
216
217 pyld_sz = sizeof(struct ipa_ioc_del_hdr) + 1 *
218 sizeof(struct ipa_hdr_del);
219 del_hdr = kzalloc(pyld_sz, GFP_KERNEL);
220 if (!del_hdr) {
221 IPAWANERR("fail to alloc exception hdr_del\n");
222 return;
223 }
224
225 del_hdr->commit = 1;
226 del_hdr->num_hdls = 1;
227 hdl_entry = &del_hdr->hdl[0];
228 hdl_entry->hdl = rmnet_ipa3_ctx->qmap_hdr_hdl;
229
230 ret = ipa3_del_hdr(del_hdr);
231 if (ret || hdl_entry->status)
232 IPAWANERR("ipa3_del_hdr failed\n");
233 else
234 IPAWANDBG("hdrs deletion done\n");
235
236 rmnet_ipa3_ctx->qmap_hdr_hdl = 0;
237 kfree(del_hdr);
238}
239
240static void ipa3_del_qmap_hdr(uint32_t hdr_hdl)
241{
242 struct ipa_ioc_del_hdr *del_hdr;
243 struct ipa_hdr_del *hdl_entry;
244 u32 pyld_sz;
245 int ret;
246
247 if (hdr_hdl == 0) {
248 IPAWANERR("Invalid hdr_hdl provided\n");
249 return;
250 }
251
252 pyld_sz = sizeof(struct ipa_ioc_del_hdr) + 1 *
253 sizeof(struct ipa_hdr_del);
254 del_hdr = kzalloc(pyld_sz, GFP_KERNEL);
255 if (!del_hdr) {
256 IPAWANERR("fail to alloc exception hdr_del\n");
257 return;
258 }
259
260 del_hdr->commit = 1;
261 del_hdr->num_hdls = 1;
262 hdl_entry = &del_hdr->hdl[0];
263 hdl_entry->hdl = hdr_hdl;
264
265 ret = ipa3_del_hdr(del_hdr);
266 if (ret || hdl_entry->status)
267 IPAWANERR("ipa3_del_hdr failed\n");
268 else
269 IPAWANDBG("header deletion done\n");
270
271 rmnet_ipa3_ctx->qmap_hdr_hdl = 0;
272 kfree(del_hdr);
273}
274
275static void ipa3_del_mux_qmap_hdrs(void)
276{
277 int index;
278
279 for (index = 0; index < rmnet_ipa3_ctx->rmnet_index; index++) {
280 ipa3_del_qmap_hdr(rmnet_ipa3_ctx->mux_channel[index].hdr_hdl);
281 rmnet_ipa3_ctx->mux_channel[index].hdr_hdl = 0;
282 }
283}
284
285static int ipa3_add_qmap_hdr(uint32_t mux_id, uint32_t *hdr_hdl)
286{
287 struct ipa_ioc_add_hdr *hdr;
288 struct ipa_hdr_add *hdr_entry;
289 char hdr_name[IPA_RESOURCE_NAME_MAX];
290 u32 pyld_sz;
291 int ret;
292
293 pyld_sz = sizeof(struct ipa_ioc_add_hdr) + 1 *
294 sizeof(struct ipa_hdr_add);
295 hdr = kzalloc(pyld_sz, GFP_KERNEL);
296 if (!hdr) {
297 IPAWANERR("fail to alloc exception hdr\n");
298 return -ENOMEM;
299 }
300 hdr->num_hdrs = 1;
301 hdr->commit = 1;
302 hdr_entry = &hdr->hdr[0];
303
304 snprintf(hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
305 A2_MUX_HDR_NAME_V4_PREF,
306 mux_id);
307 strlcpy(hdr_entry->name, hdr_name,
308 IPA_RESOURCE_NAME_MAX);
309
310 hdr_entry->hdr_len = IPA_QMAP_HEADER_LENGTH; /* 4 bytes */
311 hdr_entry->hdr[1] = (uint8_t) mux_id;
312 IPAWANDBG("header (%s) with mux-id: (%d)\n",
313 hdr_name,
314 hdr_entry->hdr[1]);
315 if (ipa3_add_hdr(hdr)) {
316 IPAWANERR("fail to add IPA_QMAP hdr\n");
317 ret = -EPERM;
318 goto bail;
319 }
320
321 if (hdr_entry->status) {
322 IPAWANERR("fail to add IPA_QMAP hdr\n");
323 ret = -EPERM;
324 goto bail;
325 }
326
327 ret = 0;
328 *hdr_hdl = hdr_entry->hdr_hdl;
329bail:
330 kfree(hdr);
331 return ret;
332}
333
334/**
335* ipa3_setup_dflt_wan_rt_tables() - Setup default wan routing tables
336*
337* Return codes:
338* 0: success
339* -ENOMEM: failed to allocate memory
340* -EPERM: failed to add the tables
341*/
342static int ipa3_setup_dflt_wan_rt_tables(void)
343{
344 struct ipa_ioc_add_rt_rule *rt_rule;
345 struct ipa_rt_rule_add *rt_rule_entry;
346
347 rt_rule =
348 kzalloc(sizeof(struct ipa_ioc_add_rt_rule) + 1 *
349 sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
350 if (!rt_rule) {
351 IPAWANERR("fail to alloc mem\n");
352 return -ENOMEM;
353 }
354 /* setup a default v4 route to point to Apps */
355 rt_rule->num_rules = 1;
356 rt_rule->commit = 1;
357 rt_rule->ip = IPA_IP_v4;
358 strlcpy(rt_rule->rt_tbl_name, IPA_DFLT_WAN_RT_TBL_NAME,
359 IPA_RESOURCE_NAME_MAX);
360
361 rt_rule_entry = &rt_rule->rules[0];
362 rt_rule_entry->at_rear = 1;
363 rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
364 rt_rule_entry->rule.hdr_hdl = rmnet_ipa3_ctx->qmap_hdr_hdl;
365
366 if (ipa3_add_rt_rule(rt_rule)) {
367 IPAWANERR("fail to add dflt_wan v4 rule\n");
368 kfree(rt_rule);
369 return -EPERM;
370 }
371
372 IPAWANDBG("dflt v4 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
373 rmnet_ipa3_ctx->dflt_v4_wan_rt_hdl = rt_rule_entry->rt_rule_hdl;
374
375 /* setup a default v6 route to point to A5 */
376 rt_rule->ip = IPA_IP_v6;
377 if (ipa3_add_rt_rule(rt_rule)) {
378 IPAWANERR("fail to add dflt_wan v6 rule\n");
379 kfree(rt_rule);
380 return -EPERM;
381 }
382 IPAWANDBG("dflt v6 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
383 rmnet_ipa3_ctx->dflt_v6_wan_rt_hdl = rt_rule_entry->rt_rule_hdl;
384
385 kfree(rt_rule);
386 return 0;
387}
388
389static void ipa3_del_dflt_wan_rt_tables(void)
390{
391 struct ipa_ioc_del_rt_rule *rt_rule;
392 struct ipa_rt_rule_del *rt_rule_entry;
393 int len;
394
395 len = sizeof(struct ipa_ioc_del_rt_rule) + 1 *
396 sizeof(struct ipa_rt_rule_del);
397 rt_rule = kzalloc(len, GFP_KERNEL);
398 if (!rt_rule) {
399 IPAWANERR("unable to allocate memory for del route rule\n");
400 return;
401 }
402
403 memset(rt_rule, 0, len);
404 rt_rule->commit = 1;
405 rt_rule->num_hdls = 1;
406 rt_rule->ip = IPA_IP_v4;
407
408 rt_rule_entry = &rt_rule->hdl[0];
409 rt_rule_entry->status = -1;
410 rt_rule_entry->hdl = rmnet_ipa3_ctx->dflt_v4_wan_rt_hdl;
411
412 IPAWANERR("Deleting Route hdl:(0x%x) with ip type: %d\n",
413 rt_rule_entry->hdl, IPA_IP_v4);
414 if (ipa3_del_rt_rule(rt_rule) ||
415 (rt_rule_entry->status)) {
416 IPAWANERR("Routing rule deletion failed!\n");
417 }
418
419 rt_rule->ip = IPA_IP_v6;
420 rt_rule_entry->hdl = rmnet_ipa3_ctx->dflt_v6_wan_rt_hdl;
421 IPAWANERR("Deleting Route hdl:(0x%x) with ip type: %d\n",
422 rt_rule_entry->hdl, IPA_IP_v6);
423 if (ipa3_del_rt_rule(rt_rule) ||
424 (rt_rule_entry->status)) {
425 IPAWANERR("Routing rule deletion failed!\n");
426 }
427
428 kfree(rt_rule);
429}
430
431int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01
432 *rule_req)
433{
434 int i, j;
435
Skylar Chang441cc5e2017-08-11 15:49:21 -0700436 /* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */
437 mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +0300438 if (rule_req->filter_spec_ex_list_valid == true) {
439 rmnet_ipa3_ctx->num_q6_rules =
440 rule_req->filter_spec_ex_list_len;
441 IPAWANDBG("Received (%d) install_flt_req\n",
442 rmnet_ipa3_ctx->num_q6_rules);
443 } else {
444 rmnet_ipa3_ctx->num_q6_rules = 0;
445 IPAWANERR("got no UL rules from modem\n");
Skylar Chang441cc5e2017-08-11 15:49:21 -0700446 mutex_unlock(&rmnet_ipa3_ctx->
447 add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +0300448 return -EINVAL;
449 }
450
451 /* copy UL filter rules from Modem*/
452 for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) {
453 /* check if rules overside the cache*/
454 if (i == MAX_NUM_Q6_RULE) {
455 IPAWANERR("Reaching (%d) max cache ",
456 MAX_NUM_Q6_RULE);
457 IPAWANERR(" however total (%d)\n",
458 rmnet_ipa3_ctx->num_q6_rules);
459 goto failure;
460 }
461 ipa3_qmi_ctx->q6_ul_filter_rule[i].ip =
462 rule_req->filter_spec_ex_list[i].ip_type;
463 ipa3_qmi_ctx->q6_ul_filter_rule[i].action =
464 rule_req->filter_spec_ex_list[i].filter_action;
465 if (rule_req->filter_spec_ex_list[i].
466 is_routing_table_index_valid == true)
467 ipa3_qmi_ctx->q6_ul_filter_rule[i].rt_tbl_idx =
468 rule_req->filter_spec_ex_list[i].route_table_index;
469 if (rule_req->filter_spec_ex_list[i].is_mux_id_valid == true)
470 ipa3_qmi_ctx->q6_ul_filter_rule[i].mux_id =
471 rule_req->filter_spec_ex_list[i].mux_id;
472 ipa3_qmi_ctx->q6_ul_filter_rule[i].rule_id =
473 rule_req->filter_spec_ex_list[i].rule_id;
474 ipa3_qmi_ctx->q6_ul_filter_rule[i].is_rule_hashable =
475 rule_req->filter_spec_ex_list[i].is_rule_hashable;
476 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.rule_eq_bitmap =
477 rule_req->filter_spec_ex_list[i].filter_rule.
478 rule_eq_bitmap;
479 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.tos_eq_present =
480 rule_req->filter_spec_ex_list[i].filter_rule.
481 tos_eq_present;
482 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.tos_eq =
483 rule_req->filter_spec_ex_list[i].filter_rule.tos_eq;
484 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
485 protocol_eq_present = rule_req->filter_spec_ex_list[i].
486 filter_rule.protocol_eq_present;
487 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.protocol_eq =
488 rule_req->filter_spec_ex_list[i].filter_rule.
489 protocol_eq;
490
491 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
492 num_ihl_offset_range_16 =
493 rule_req->filter_spec_ex_list[i].
494 filter_rule.num_ihl_offset_range_16;
495 for (j = 0; j < ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
496 num_ihl_offset_range_16; j++) {
497 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
498 ihl_offset_range_16[j].offset = rule_req->
499 filter_spec_ex_list[i].filter_rule.
500 ihl_offset_range_16[j].offset;
501 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
502 ihl_offset_range_16[j].range_low = rule_req->
503 filter_spec_ex_list[i].filter_rule.
504 ihl_offset_range_16[j].range_low;
505 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
506 ihl_offset_range_16[j].range_high = rule_req->
507 filter_spec_ex_list[i].filter_rule.
508 ihl_offset_range_16[j].range_high;
509 }
510 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.num_offset_meq_32 =
511 rule_req->filter_spec_ex_list[i].filter_rule.
512 num_offset_meq_32;
513 for (j = 0; j < ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
514 num_offset_meq_32; j++) {
515 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
516 offset_meq_32[j].offset =
517 rule_req->filter_spec_ex_list[i].
518 filter_rule.offset_meq_32[j].offset;
519 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
520 offset_meq_32[j].mask =
521 rule_req->filter_spec_ex_list[i].
522 filter_rule.offset_meq_32[j].mask;
523 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
524 offset_meq_32[j].value =
525 rule_req->filter_spec_ex_list[i].
526 filter_rule.offset_meq_32[j].value;
527 }
528
529 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.tc_eq_present =
530 rule_req->filter_spec_ex_list[i].
531 filter_rule.tc_eq_present;
532 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.tc_eq =
533 rule_req->filter_spec_ex_list[i].filter_rule.tc_eq;
534 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.fl_eq_present =
535 rule_req->filter_spec_ex_list[i].filter_rule.
536 flow_eq_present;
537 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.fl_eq =
538 rule_req->filter_spec_ex_list[i].filter_rule.flow_eq;
539 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
540 ihl_offset_eq_16_present = rule_req->filter_spec_ex_list[i].
541 filter_rule.ihl_offset_eq_16_present;
542 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
543 ihl_offset_eq_16.offset = rule_req->filter_spec_ex_list[i].
544 filter_rule.ihl_offset_eq_16.offset;
545 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
546 ihl_offset_eq_16.value = rule_req->filter_spec_ex_list[i].
547 filter_rule.ihl_offset_eq_16.value;
548
549 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
550 ihl_offset_eq_32_present = rule_req->filter_spec_ex_list[i].
551 filter_rule.ihl_offset_eq_32_present;
552 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
553 ihl_offset_eq_32.offset = rule_req->filter_spec_ex_list[i].
554 filter_rule.ihl_offset_eq_32.offset;
555 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
556 ihl_offset_eq_32.value = rule_req->filter_spec_ex_list[i].
557 filter_rule.ihl_offset_eq_32.value;
558
559 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
560 num_ihl_offset_meq_32 = rule_req->filter_spec_ex_list[i].
561 filter_rule.num_ihl_offset_meq_32;
562 for (j = 0; j < ipa3_qmi_ctx->q6_ul_filter_rule[i].
563 eq_attrib.num_ihl_offset_meq_32; j++) {
564 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
565 ihl_offset_meq_32[j].offset = rule_req->
566 filter_spec_ex_list[i].filter_rule.
567 ihl_offset_meq_32[j].offset;
568 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
569 ihl_offset_meq_32[j].mask = rule_req->
570 filter_spec_ex_list[i].filter_rule.
571 ihl_offset_meq_32[j].mask;
572 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
573 ihl_offset_meq_32[j].value = rule_req->
574 filter_spec_ex_list[i].filter_rule.
575 ihl_offset_meq_32[j].value;
576 }
577 ipa3_qmi_ctx->
578 q6_ul_filter_rule[i].eq_attrib.num_offset_meq_128 =
579 rule_req->filter_spec_ex_list[i].filter_rule.
580 num_offset_meq_128;
581 for (j = 0; j < ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
582 num_offset_meq_128; j++) {
583 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
584 offset_meq_128[j].offset = rule_req->
585 filter_spec_ex_list[i].filter_rule.
586 offset_meq_128[j].offset;
587 memcpy(ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
588 offset_meq_128[j].mask,
589 rule_req->filter_spec_ex_list[i].
590 filter_rule.offset_meq_128[j].mask, 16);
591 memcpy(ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
592 offset_meq_128[j].value, rule_req->
593 filter_spec_ex_list[i].filter_rule.
594 offset_meq_128[j].value, 16);
595 }
596
597 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
598 metadata_meq32_present =
599 rule_req->filter_spec_ex_list[i].
600 filter_rule.metadata_meq32_present;
601 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
602 metadata_meq32.offset =
603 rule_req->filter_spec_ex_list[i].
604 filter_rule.metadata_meq32.offset;
605 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
606 metadata_meq32.mask = rule_req->filter_spec_ex_list[i].
607 filter_rule.metadata_meq32.mask;
608 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.metadata_meq32.
609 value = rule_req->filter_spec_ex_list[i].filter_rule.
610 metadata_meq32.value;
611 ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib.
612 ipv4_frag_eq_present = rule_req->filter_spec_ex_list[i].
613 filter_rule.ipv4_frag_eq_present;
614 }
615
616 if (rule_req->xlat_filter_indices_list_valid) {
617 if (rule_req->xlat_filter_indices_list_len >
618 rmnet_ipa3_ctx->num_q6_rules) {
619 IPAWANERR("Number of xlat indices is not valid: %d\n",
620 rule_req->xlat_filter_indices_list_len);
621 goto failure;
622 }
623 IPAWANDBG("Receive %d XLAT indices: ",
624 rule_req->xlat_filter_indices_list_len);
625 for (i = 0; i < rule_req->xlat_filter_indices_list_len; i++)
626 IPAWANDBG("%d ", rule_req->xlat_filter_indices_list[i]);
627 IPAWANDBG("\n");
628
629 for (i = 0; i < rule_req->xlat_filter_indices_list_len; i++) {
630 if (rule_req->xlat_filter_indices_list[i]
631 >= rmnet_ipa3_ctx->num_q6_rules) {
632 IPAWANERR("Xlat rule idx is wrong: %d\n",
633 rule_req->xlat_filter_indices_list[i]);
634 goto failure;
635 } else {
636 ipa3_qmi_ctx->q6_ul_filter_rule
637 [rule_req->xlat_filter_indices_list[i]]
638 .is_xlat_rule = 1;
639 IPAWANDBG("Rule %d is xlat rule\n",
640 rule_req->xlat_filter_indices_list[i]);
641 }
642 }
643 }
644 goto success;
645
646failure:
647 rmnet_ipa3_ctx->num_q6_rules = 0;
648 memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0,
649 sizeof(ipa3_qmi_ctx->q6_ul_filter_rule));
Skylar Chang441cc5e2017-08-11 15:49:21 -0700650 mutex_unlock(&rmnet_ipa3_ctx->
651 add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +0300652 return -EINVAL;
653
654success:
Skylar Chang441cc5e2017-08-11 15:49:21 -0700655 mutex_unlock(&rmnet_ipa3_ctx->
656 add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +0300657 return 0;
658}
659
660static int ipa3_wwan_add_ul_flt_rule_to_ipa(void)
661{
662 u32 pyld_sz;
663 int i, retval = 0;
664 struct ipa_ioc_add_flt_rule *param;
665 struct ipa_flt_rule_add flt_rule_entry;
666 struct ipa_fltr_installed_notif_req_msg_v01 *req;
667
668 pyld_sz = sizeof(struct ipa_ioc_add_flt_rule) +
669 sizeof(struct ipa_flt_rule_add);
670 param = kzalloc(pyld_sz, GFP_KERNEL);
671 if (!param)
672 return -ENOMEM;
673
674 req = (struct ipa_fltr_installed_notif_req_msg_v01 *)
675 kzalloc(sizeof(struct ipa_fltr_installed_notif_req_msg_v01),
676 GFP_KERNEL);
677 if (!req) {
678 kfree(param);
679 return -ENOMEM;
680 }
681
682 param->commit = 1;
Ghanim Fodic6b67492017-03-15 14:19:56 +0200683 param->ep = IPA_CLIENT_APPS_WAN_PROD;
Amir Levy9659e592016-10-27 18:08:27 +0300684 param->global = false;
685 param->num_rules = (uint8_t)1;
686
Mohammed Javidbf4c8022017-08-07 23:15:48 +0530687 memset(req, 0, sizeof(struct ipa_fltr_installed_notif_req_msg_v01));
688
Amir Levy9659e592016-10-27 18:08:27 +0300689 for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) {
690 param->ip = ipa3_qmi_ctx->q6_ul_filter_rule[i].ip;
691 memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
692 flt_rule_entry.at_rear = true;
693 flt_rule_entry.rule.action =
694 ipa3_qmi_ctx->q6_ul_filter_rule[i].action;
695 flt_rule_entry.rule.rt_tbl_idx
696 = ipa3_qmi_ctx->q6_ul_filter_rule[i].rt_tbl_idx;
697 flt_rule_entry.rule.retain_hdr = true;
698 flt_rule_entry.rule.hashable =
699 ipa3_qmi_ctx->q6_ul_filter_rule[i].is_rule_hashable;
700 flt_rule_entry.rule.rule_id =
701 ipa3_qmi_ctx->q6_ul_filter_rule[i].rule_id;
702
703 /* debug rt-hdl*/
704 IPAWANDBG("install-IPA index(%d),rt-tbl:(%d)\n",
705 i, flt_rule_entry.rule.rt_tbl_idx);
706 flt_rule_entry.rule.eq_attrib_type = true;
707 memcpy(&(flt_rule_entry.rule.eq_attrib),
708 &ipa3_qmi_ctx->q6_ul_filter_rule[i].eq_attrib,
709 sizeof(struct ipa_ipfltri_rule_eq));
710 memcpy(&(param->rules[0]), &flt_rule_entry,
711 sizeof(struct ipa_flt_rule_add));
712 if (ipa3_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
713 retval = -EFAULT;
714 IPAWANERR("add A7 UL filter rule(%d) failed\n", i);
715 } else {
716 /* store the rule handler */
717 ipa3_qmi_ctx->q6_ul_filter_rule_hdl[i] =
718 param->rules[0].flt_rule_hdl;
719 }
720 }
721
722 /* send ipa_fltr_installed_notif_req_msg_v01 to Q6*/
723 req->source_pipe_index =
Ghanim Fodic6b67492017-03-15 14:19:56 +0200724 ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
Mohammed Javide53b5462017-07-27 17:23:05 +0530725 if (req->source_pipe_index == IPA_EP_NOT_ALLOCATED) {
726 IPAWANERR("ep mapping failed\n");
727 retval = -EFAULT;
728 }
729
Amir Levy9659e592016-10-27 18:08:27 +0300730 req->install_status = QMI_RESULT_SUCCESS_V01;
731 req->rule_id_valid = 1;
732 req->rule_id_len = rmnet_ipa3_ctx->num_q6_rules;
733 for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) {
734 req->rule_id[i] =
735 ipa3_qmi_ctx->q6_ul_filter_rule[i].rule_id;
736 }
737 if (ipa3_qmi_filter_notify_send(req)) {
738 IPAWANDBG("add filter rule index on A7-RX failed\n");
739 retval = -EFAULT;
740 }
741 rmnet_ipa3_ctx->old_num_q6_rules = rmnet_ipa3_ctx->num_q6_rules;
742 IPAWANDBG("add (%d) filter rule index on A7-RX\n",
743 rmnet_ipa3_ctx->old_num_q6_rules);
744 kfree(param);
745 kfree(req);
746 return retval;
747}
748
749static int ipa3_wwan_del_ul_flt_rule_to_ipa(void)
750{
751 u32 pyld_sz;
752 int i, retval = 0;
753 struct ipa_ioc_del_flt_rule *param;
754 struct ipa_flt_rule_del flt_rule_entry;
755
756 pyld_sz = sizeof(struct ipa_ioc_del_flt_rule) +
757 sizeof(struct ipa_flt_rule_del);
758 param = kzalloc(pyld_sz, GFP_KERNEL);
759 if (!param) {
760 IPAWANERR("kzalloc failed\n");
761 return -ENOMEM;
762 }
763
764 param->commit = 1;
765 param->num_hdls = (uint8_t) 1;
766
767 for (i = 0; i < rmnet_ipa3_ctx->old_num_q6_rules; i++) {
768 param->ip = ipa3_qmi_ctx->q6_ul_filter_rule[i].ip;
769 memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_del));
770 flt_rule_entry.hdl = ipa3_qmi_ctx->q6_ul_filter_rule_hdl[i];
771 /* debug rt-hdl*/
772 IPAWANDBG("delete-IPA rule index(%d)\n", i);
773 memcpy(&(param->hdl[0]), &flt_rule_entry,
774 sizeof(struct ipa_flt_rule_del));
775 if (ipa3_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
776 IPAWANERR("del A7 UL filter rule(%d) failed\n", i);
777 kfree(param);
778 return -EFAULT;
779 }
780 }
781
782 /* set UL filter-rule add-indication */
783 rmnet_ipa3_ctx->a7_ul_flt_set = false;
784 rmnet_ipa3_ctx->old_num_q6_rules = 0;
785
786 kfree(param);
787 return retval;
788}
789
790static int ipa3_find_mux_channel_index(uint32_t mux_id)
791{
792 int i;
793
794 for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++) {
795 if (mux_id == rmnet_ipa3_ctx->mux_channel[i].mux_id)
796 return i;
797 }
798 return MAX_NUM_OF_MUX_CHANNEL;
799}
800
801static int find_vchannel_name_index(const char *vchannel_name)
802{
803 int i;
804
805 for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++) {
806 if (strcmp(rmnet_ipa3_ctx->mux_channel[i].vchannel_name,
807 vchannel_name) == 0)
808 return i;
809 }
810 return MAX_NUM_OF_MUX_CHANNEL;
811}
812
Skylar Chang6b41f8d2016-11-01 12:50:11 -0700813static enum ipa_upstream_type find_upstream_type(const char *upstreamIface)
814{
815 int i;
816
817 for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++) {
818 if (strcmp(rmnet_ipa3_ctx->mux_channel[i].vchannel_name,
819 upstreamIface) == 0)
820 return IPA_UPSTEAM_MODEM;
821 }
822
823 if (strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0)
824 return IPA_UPSTEAM_WLAN;
825 else
826 return MAX_NUM_OF_MUX_CHANNEL;
827}
828
Amir Levy9659e592016-10-27 18:08:27 +0300829static int ipa3_wwan_register_to_ipa(int index)
830{
831 struct ipa_tx_intf tx_properties = {0};
832 struct ipa_ioc_tx_intf_prop tx_ioc_properties[2] = { {0}, {0} };
833 struct ipa_ioc_tx_intf_prop *tx_ipv4_property;
834 struct ipa_ioc_tx_intf_prop *tx_ipv6_property;
835 struct ipa_rx_intf rx_properties = {0};
836 struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
837 struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
838 struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
839 struct ipa_ext_intf ext_properties = {0};
840 struct ipa_ioc_ext_intf_prop *ext_ioc_properties;
841 u32 pyld_sz;
842 int ret = 0, i;
843
844 IPAWANDBG("index(%d) device[%s]:\n", index,
845 rmnet_ipa3_ctx->mux_channel[index].vchannel_name);
846 if (!rmnet_ipa3_ctx->mux_channel[index].mux_hdr_set) {
847 ret = ipa3_add_qmap_hdr(
848 rmnet_ipa3_ctx->mux_channel[index].mux_id,
849 &rmnet_ipa3_ctx->mux_channel[index].hdr_hdl);
850 if (ret) {
851 IPAWANERR("ipa_add_mux_hdr failed (%d)\n", index);
852 return ret;
853 }
854 rmnet_ipa3_ctx->mux_channel[index].mux_hdr_set = true;
855 }
856 tx_properties.prop = tx_ioc_properties;
857 tx_ipv4_property = &tx_properties.prop[0];
858 tx_ipv4_property->ip = IPA_IP_v4;
859 tx_ipv4_property->dst_pipe = IPA_CLIENT_APPS_WAN_CONS;
860 snprintf(tx_ipv4_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
861 A2_MUX_HDR_NAME_V4_PREF,
862 rmnet_ipa3_ctx->mux_channel[index].mux_id);
863 tx_ipv6_property = &tx_properties.prop[1];
864 tx_ipv6_property->ip = IPA_IP_v6;
865 tx_ipv6_property->dst_pipe = IPA_CLIENT_APPS_WAN_CONS;
866 /* no need use A2_MUX_HDR_NAME_V6_PREF, same header */
867 snprintf(tx_ipv6_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
868 A2_MUX_HDR_NAME_V4_PREF,
869 rmnet_ipa3_ctx->mux_channel[index].mux_id);
870 tx_properties.num_props = 2;
871
872 rx_properties.prop = rx_ioc_properties;
873 rx_ipv4_property = &rx_properties.prop[0];
874 rx_ipv4_property->ip = IPA_IP_v4;
875 rx_ipv4_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
876 rx_ipv4_property->attrib.meta_data =
877 rmnet_ipa3_ctx->mux_channel[index].mux_id << WWAN_METADATA_SHFT;
878 rx_ipv4_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
Ghanim Fodic6b67492017-03-15 14:19:56 +0200879 rx_ipv4_property->src_pipe = IPA_CLIENT_APPS_WAN_PROD;
Amir Levy9659e592016-10-27 18:08:27 +0300880 rx_ipv6_property = &rx_properties.prop[1];
881 rx_ipv6_property->ip = IPA_IP_v6;
882 rx_ipv6_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
883 rx_ipv6_property->attrib.meta_data =
884 rmnet_ipa3_ctx->mux_channel[index].mux_id << WWAN_METADATA_SHFT;
885 rx_ipv6_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
Ghanim Fodic6b67492017-03-15 14:19:56 +0200886 rx_ipv6_property->src_pipe = IPA_CLIENT_APPS_WAN_PROD;
Amir Levy9659e592016-10-27 18:08:27 +0300887 rx_properties.num_props = 2;
888
889 pyld_sz = rmnet_ipa3_ctx->num_q6_rules *
890 sizeof(struct ipa_ioc_ext_intf_prop);
891 ext_ioc_properties = kmalloc(pyld_sz, GFP_KERNEL);
892 if (!ext_ioc_properties) {
893 IPAWANERR("Error allocate memory\n");
894 return -ENOMEM;
895 }
896
897 ext_properties.prop = ext_ioc_properties;
898 ext_properties.excp_pipe_valid = true;
899 ext_properties.excp_pipe = IPA_CLIENT_APPS_WAN_CONS;
900 ext_properties.num_props = rmnet_ipa3_ctx->num_q6_rules;
901 for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) {
902 memcpy(&(ext_properties.prop[i]),
903 &(ipa3_qmi_ctx->q6_ul_filter_rule[i]),
904 sizeof(struct ipa_ioc_ext_intf_prop));
905 ext_properties.prop[i].mux_id =
906 rmnet_ipa3_ctx->mux_channel[index].mux_id;
907 IPAWANDBG("index %d ip: %d rt-tbl:%d\n", i,
908 ext_properties.prop[i].ip,
909 ext_properties.prop[i].rt_tbl_idx);
910 IPAWANDBG("action: %d mux:%d\n",
911 ext_properties.prop[i].action,
912 ext_properties.prop[i].mux_id);
913 }
914 ret = ipa3_register_intf_ext(rmnet_ipa3_ctx->mux_channel[index].
915 vchannel_name, &tx_properties,
916 &rx_properties, &ext_properties);
917 if (ret) {
918 IPAWANERR("[%s]:ipa3_register_intf failed %d\n",
919 rmnet_ipa3_ctx->mux_channel[index].vchannel_name, ret);
920 goto fail;
921 }
922 rmnet_ipa3_ctx->mux_channel[index].ul_flt_reg = true;
923fail:
924 kfree(ext_ioc_properties);
925 return ret;
926}
927
928static void ipa3_cleanup_deregister_intf(void)
929{
930 int i;
931 int ret;
932
933 for (i = 0; i < rmnet_ipa3_ctx->rmnet_index; i++) {
934 if (rmnet_ipa3_ctx->mux_channel[i].ul_flt_reg) {
935 ret = ipa3_deregister_intf(
936 rmnet_ipa3_ctx->mux_channel[i].vchannel_name);
937 if (ret < 0) {
938 IPAWANERR("de-register device %s(%d) failed\n",
939 rmnet_ipa3_ctx->mux_channel[i].
940 vchannel_name,
941 i);
942 return;
943 }
944 IPAWANDBG("de-register device %s(%d) success\n",
945 rmnet_ipa3_ctx->mux_channel[i].vchannel_name,
946 i);
947 }
948 rmnet_ipa3_ctx->mux_channel[i].ul_flt_reg = false;
949 }
950}
951
952int ipa3_wwan_update_mux_channel_prop(void)
953{
954 int ret = 0, i;
955 /* install UL filter rules */
956 if (rmnet_ipa3_ctx->egress_set) {
957 if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) {
958 IPAWANDBG("setup UL filter rules\n");
959 if (rmnet_ipa3_ctx->a7_ul_flt_set) {
960 IPAWANDBG("del previous UL filter rules\n");
961 /* delete rule hdlers */
962 ret = ipa3_wwan_del_ul_flt_rule_to_ipa();
963 if (ret) {
964 IPAWANERR("failed to del old rules\n");
965 return -EINVAL;
966 }
967 IPAWANDBG("deleted old UL rules\n");
968 }
969 ret = ipa3_wwan_add_ul_flt_rule_to_ipa();
970 }
971 if (ret)
972 IPAWANERR("failed to install UL rules\n");
973 else
974 rmnet_ipa3_ctx->a7_ul_flt_set = true;
975 }
976 /* update Tx/Rx/Ext property */
977 IPAWANDBG("update Tx/Rx/Ext property in IPA\n");
978 if (rmnet_ipa3_ctx->rmnet_index == 0) {
979 IPAWANDBG("no Tx/Rx/Ext property registered in IPA\n");
980 return ret;
981 }
982
983 ipa3_cleanup_deregister_intf();
984
985 for (i = 0; i < rmnet_ipa3_ctx->rmnet_index; i++) {
986 ret = ipa3_wwan_register_to_ipa(i);
987 if (ret < 0) {
988 IPAWANERR("failed to re-regist %s, mux %d, index %d\n",
989 rmnet_ipa3_ctx->mux_channel[i].vchannel_name,
990 rmnet_ipa3_ctx->mux_channel[i].mux_id,
991 i);
992 return -ENODEV;
993 }
994 IPAWANERR("dev(%s) has registered to IPA\n",
995 rmnet_ipa3_ctx->mux_channel[i].vchannel_name);
996 rmnet_ipa3_ctx->mux_channel[i].ul_flt_reg = true;
997 }
998 return ret;
999}
1000
1001#ifdef INIT_COMPLETION
1002#define reinit_completion(x) INIT_COMPLETION(*(x))
1003#endif /* INIT_COMPLETION */
1004
1005static int __ipa_wwan_open(struct net_device *dev)
1006{
1007 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
1008
1009 IPAWANDBG("[%s] __wwan_open()\n", dev->name);
1010 if (wwan_ptr->device_status != WWAN_DEVICE_ACTIVE)
1011 reinit_completion(&wwan_ptr->resource_granted_completion);
1012 wwan_ptr->device_status = WWAN_DEVICE_ACTIVE;
1013
1014 if (ipa3_rmnet_res.ipa_napi_enable)
1015 napi_enable(&(wwan_ptr->napi));
1016 return 0;
1017}
1018
1019/**
1020 * wwan_open() - Opens the wwan network interface. Opens logical
1021 * channel on A2 MUX driver and starts the network stack queue
1022 *
1023 * @dev: network device
1024 *
1025 * Return codes:
1026 * 0: success
1027 * -ENODEV: Error while opening logical channel on A2 MUX driver
1028 */
1029static int ipa3_wwan_open(struct net_device *dev)
1030{
1031 int rc = 0;
1032
1033 IPAWANDBG("[%s] wwan_open()\n", dev->name);
1034 rc = __ipa_wwan_open(dev);
1035 if (rc == 0)
1036 netif_start_queue(dev);
1037 return rc;
1038}
1039
1040static int __ipa_wwan_close(struct net_device *dev)
1041{
1042 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
1043 int rc = 0;
1044
1045 if (wwan_ptr->device_status == WWAN_DEVICE_ACTIVE) {
1046 wwan_ptr->device_status = WWAN_DEVICE_INACTIVE;
1047 /* do not close wwan port once up, this causes
1048 * remote side to hang if tried to open again
1049 */
1050 reinit_completion(&wwan_ptr->resource_granted_completion);
1051 rc = ipa3_deregister_intf(dev->name);
1052 if (rc) {
1053 IPAWANERR("[%s]: ipa3_deregister_intf failed %d\n",
1054 dev->name, rc);
1055 return rc;
1056 }
1057 return rc;
1058 } else {
1059 return -EBADF;
1060 }
1061}
1062
1063/**
1064 * ipa3_wwan_stop() - Stops the wwan network interface. Closes
1065 * logical channel on A2 MUX driver and stops the network stack
1066 * queue
1067 *
1068 * @dev: network device
1069 *
1070 * Return codes:
1071 * 0: success
1072 * -ENODEV: Error while opening logical channel on A2 MUX driver
1073 */
1074static int ipa3_wwan_stop(struct net_device *dev)
1075{
1076 IPAWANDBG("[%s] ipa3_wwan_stop()\n", dev->name);
1077 __ipa_wwan_close(dev);
1078 netif_stop_queue(dev);
1079 return 0;
1080}
1081
1082static int ipa3_wwan_change_mtu(struct net_device *dev, int new_mtu)
1083{
1084 if (0 > new_mtu || WWAN_DATA_LEN < new_mtu)
1085 return -EINVAL;
1086 IPAWANDBG("[%s] MTU change: old=%d new=%d\n",
1087 dev->name, dev->mtu, new_mtu);
1088 dev->mtu = new_mtu;
1089 return 0;
1090}
1091
1092/**
1093 * ipa3_wwan_xmit() - Transmits an skb.
1094 *
1095 * @skb: skb to be transmitted
1096 * @dev: network device
1097 *
1098 * Return codes:
1099 * 0: success
1100 * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
1101 * later
1102 * -EFAULT: Error while transmitting the skb
1103 */
1104static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
1105{
1106 int ret = 0;
1107 bool qmap_check;
1108 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
Amir Levy9659e592016-10-27 18:08:27 +03001109
1110 if (skb->protocol != htons(ETH_P_MAP)) {
1111 IPAWANDBG_LOW
1112 ("SW filtering out none QMAP packet received from %s",
1113 current->comm);
Sunil Paidimarri6c818e82016-10-17 18:33:13 -07001114 dev_kfree_skb_any(skb);
1115 dev->stats.tx_dropped++;
Amir Levy9659e592016-10-27 18:08:27 +03001116 return NETDEV_TX_OK;
1117 }
1118
1119 qmap_check = RMNET_MAP_GET_CD_BIT(skb);
1120 if (netif_queue_stopped(dev)) {
1121 if (qmap_check &&
1122 atomic_read(&wwan_ptr->outstanding_pkts) <
1123 wwan_ptr->outstanding_high_ctl) {
1124 pr_err("[%s]Queue stop, send ctrl pkts\n", dev->name);
1125 goto send;
1126 } else {
Sunil Paidimarri6c818e82016-10-17 18:33:13 -07001127 pr_err("[%s]fatal: ipa3_wwan_xmit stopped\n",
1128 dev->name);
Amir Levy9659e592016-10-27 18:08:27 +03001129 return NETDEV_TX_BUSY;
1130 }
1131 }
1132
1133 /* checking High WM hit */
1134 if (atomic_read(&wwan_ptr->outstanding_pkts) >=
1135 wwan_ptr->outstanding_high) {
1136 if (!qmap_check) {
1137 IPAWANDBG_LOW("pending(%d)/(%d)- stop(%d)\n",
1138 atomic_read(&wwan_ptr->outstanding_pkts),
1139 wwan_ptr->outstanding_high,
1140 netif_queue_stopped(dev));
1141 IPAWANDBG_LOW("qmap_chk(%d)\n", qmap_check);
1142 netif_stop_queue(dev);
1143 return NETDEV_TX_BUSY;
1144 }
1145 }
1146
1147send:
1148 /* IPA_RM checking start */
Michael Adisumarta3e350812017-09-18 14:54:36 -07001149 if (ipa3_ctx->use_ipa_pm) {
1150 /* activate the modem pm for clock scaling */
1151 ipa_pm_activate(rmnet_ipa3_ctx->q6_pm_hdl);
1152 ret = ipa_pm_activate(rmnet_ipa3_ctx->pm_hdl);
1153 } else {
1154 ret = ipa_rm_inactivity_timer_request_resource(
1155 IPA_RM_RESOURCE_WWAN_0_PROD);
1156 }
Amir Levy9659e592016-10-27 18:08:27 +03001157 if (ret == -EINPROGRESS) {
1158 netif_stop_queue(dev);
1159 return NETDEV_TX_BUSY;
1160 }
1161 if (ret) {
1162 pr_err("[%s] fatal: ipa rm timer request resource failed %d\n",
1163 dev->name, ret);
Sunil Paidimarri6c818e82016-10-17 18:33:13 -07001164 dev_kfree_skb_any(skb);
1165 dev->stats.tx_dropped++;
Amir Levy9659e592016-10-27 18:08:27 +03001166 return -EFAULT;
1167 }
1168 /* IPA_RM checking end */
1169
Skylar Changeaebfca2017-08-16 17:36:21 -07001170 /*
1171 * both data packets and command will be routed to
1172 * IPA_CLIENT_Q6_WAN_CONS based on status configuration
1173 */
1174 ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
Amir Levy9659e592016-10-27 18:08:27 +03001175 if (ret) {
1176 ret = NETDEV_TX_BUSY;
Amir Levy9659e592016-10-27 18:08:27 +03001177 goto out;
1178 }
1179
1180 atomic_inc(&wwan_ptr->outstanding_pkts);
1181 dev->stats.tx_packets++;
1182 dev->stats.tx_bytes += skb->len;
1183 ret = NETDEV_TX_OK;
1184out:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001185 if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
1186 if (ipa3_ctx->use_ipa_pm) {
1187 ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
1188 ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
1189 } else {
1190 ipa_rm_inactivity_timer_release_resource(
1191 IPA_RM_RESOURCE_WWAN_0_PROD);
1192 }
1193 }
Amir Levy9659e592016-10-27 18:08:27 +03001194 return ret;
1195}
1196
1197static void ipa3_wwan_tx_timeout(struct net_device *dev)
1198{
Skylar Chang686267c2017-10-27 15:38:27 -07001199 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
1200
1201 if (atomic_read(&wwan_ptr->outstanding_pkts) != 0)
1202 IPAWANERR("[%s] data stall in UL, %d outstanding\n",
1203 dev->name, atomic_read(&wwan_ptr->outstanding_pkts));
Amir Levy9659e592016-10-27 18:08:27 +03001204}
1205
1206/**
1207 * apps_ipa_tx_complete_notify() - Rx notify
1208 *
1209 * @priv: driver context
1210 * @evt: event type
1211 * @data: data provided with event
1212 *
1213 * Check that the packet is the one we sent and release it
1214 * This function will be called in defered context in IPA wq.
1215 */
1216static void apps_ipa_tx_complete_notify(void *priv,
1217 enum ipa_dp_evt_type evt,
1218 unsigned long data)
1219{
1220 struct sk_buff *skb = (struct sk_buff *)data;
1221 struct net_device *dev = (struct net_device *)priv;
1222 struct ipa3_wwan_private *wwan_ptr;
1223
1224 if (dev != IPA_NETDEV()) {
1225 IPAWANDBG("Received pre-SSR packet completion\n");
1226 dev_kfree_skb_any(skb);
1227 return;
1228 }
1229
1230 if (evt != IPA_WRITE_DONE) {
1231 IPAWANERR("unsupported evt on Tx callback, Drop the packet\n");
1232 dev_kfree_skb_any(skb);
1233 dev->stats.tx_dropped++;
1234 return;
1235 }
1236
1237 wwan_ptr = netdev_priv(dev);
1238 atomic_dec(&wwan_ptr->outstanding_pkts);
1239 __netif_tx_lock_bh(netdev_get_tx_queue(dev, 0));
1240 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
1241 netif_queue_stopped(wwan_ptr->net) &&
1242 atomic_read(&wwan_ptr->outstanding_pkts) <
1243 (wwan_ptr->outstanding_low)) {
1244 IPAWANDBG_LOW("Outstanding low (%d) - waking up queue\n",
1245 wwan_ptr->outstanding_low);
1246 netif_wake_queue(wwan_ptr->net);
1247 }
Skylar Changf3a7dac2017-01-25 09:16:55 -08001248
Michael Adisumarta3e350812017-09-18 14:54:36 -07001249 if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
1250 if (ipa3_ctx->use_ipa_pm) {
1251 ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
1252 ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
1253 } else {
1254 ipa_rm_inactivity_timer_release_resource(
Skylar Changf3a7dac2017-01-25 09:16:55 -08001255 IPA_RM_RESOURCE_WWAN_0_PROD);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001256 }
1257 }
Amir Levy9659e592016-10-27 18:08:27 +03001258 __netif_tx_unlock_bh(netdev_get_tx_queue(dev, 0));
1259 dev_kfree_skb_any(skb);
Amir Levy9659e592016-10-27 18:08:27 +03001260}
1261
1262/**
1263 * apps_ipa_packet_receive_notify() - Rx notify
1264 *
1265 * @priv: driver context
1266 * @evt: event type
1267 * @data: data provided with event
1268 *
1269 * IPA will pass a packet to the Linux network stack with skb->data
1270 */
1271static void apps_ipa_packet_receive_notify(void *priv,
1272 enum ipa_dp_evt_type evt,
1273 unsigned long data)
1274{
1275 struct net_device *dev = (struct net_device *)priv;
1276
1277 if (evt == IPA_RECEIVE) {
1278 struct sk_buff *skb = (struct sk_buff *)data;
1279 int result;
1280 unsigned int packet_len = skb->len;
1281
1282 IPAWANDBG_LOW("Rx packet was received");
1283 skb->dev = IPA_NETDEV();
1284 skb->protocol = htons(ETH_P_MAP);
1285
1286 if (ipa3_rmnet_res.ipa_napi_enable) {
1287 trace_rmnet_ipa_netif_rcv_skb3(dev->stats.rx_packets);
1288 result = netif_receive_skb(skb);
1289 } else {
1290 if (dev->stats.rx_packets % IPA_WWAN_RX_SOFTIRQ_THRESH
1291 == 0) {
1292 trace_rmnet_ipa_netifni3(dev->stats.rx_packets);
1293 result = netif_rx_ni(skb);
1294 } else {
1295 trace_rmnet_ipa_netifrx3(dev->stats.rx_packets);
1296 result = netif_rx(skb);
1297 }
1298 }
1299
1300 if (result) {
1301 pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_receive_skb\n",
1302 __func__, __LINE__);
1303 dev->stats.rx_dropped++;
1304 }
1305 dev->stats.rx_packets++;
1306 dev->stats.rx_bytes += packet_len;
1307 } else if (evt == IPA_CLIENT_START_POLL)
1308 ipa3_rmnet_rx_cb(priv);
1309 else if (evt == IPA_CLIENT_COMP_NAPI) {
1310 if (ipa3_rmnet_res.ipa_napi_enable)
1311 napi_complete(&(rmnet_ipa3_ctx->wwan_priv->napi));
1312 } else
1313 IPAWANERR("Invalid evt %d received in wan_ipa_receive\n", evt);
1314}
1315
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001316static int handle3_ingress_format(struct net_device *dev,
1317 struct rmnet_ioctl_extended_s *in)
1318{
1319 int ret = 0;
1320 struct ipa_sys_connect_params *ipa_wan_ep_cfg;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001321
1322 IPAWANDBG("Get RMNET_IOCTL_SET_INGRESS_DATA_FORMAT\n");
1323 ipa_wan_ep_cfg = &rmnet_ipa3_ctx->ipa_to_apps_ep_cfg;
1324 if ((in->u.data) & RMNET_IOCTL_INGRESS_FORMAT_CHECKSUM)
1325 ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en =
1326 IPA_ENABLE_CS_OFFLOAD_DL;
1327
1328 if ((in->u.data) & RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02001329 IPAWANDBG("get AGG size %d count %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001330 in->u.ingress_format.agg_size,
1331 in->u.ingress_format.agg_count);
1332
1333 ret = ipa_disable_apps_wan_cons_deaggr(
1334 in->u.ingress_format.agg_size,
1335 in->u.ingress_format.agg_count);
1336
1337 if (!ret) {
1338 ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_byte_limit =
1339 in->u.ingress_format.agg_size;
1340 ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_pkt_limit =
1341 in->u.ingress_format.agg_count;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001342 }
1343 }
1344
1345 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4;
1346 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
1347 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata = 1;
1348 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
1349 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2;
1350
1351 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
1352 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = 0;
1353 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = true;
1354 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0;
1355 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_little_endian = 0;
1356 ipa_wan_ep_cfg->ipa_ep_cfg.metadata_mask.metadata_mask = 0xFF000000;
1357
1358 ipa_wan_ep_cfg->client = IPA_CLIENT_APPS_WAN_CONS;
1359 ipa_wan_ep_cfg->notify = apps_ipa_packet_receive_notify;
1360 ipa_wan_ep_cfg->priv = dev;
1361
1362 ipa_wan_ep_cfg->napi_enabled = ipa3_rmnet_res.ipa_napi_enable;
Sunil Paidimarri226cf032016-10-14 13:33:08 -07001363 ipa_wan_ep_cfg->desc_fifo_sz =
1364 ipa3_rmnet_res.wan_rx_desc_size * IPA_FIFO_ELEMENT_SIZE;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001365
Ghanim Fodic6b67492017-03-15 14:19:56 +02001366 mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001367
1368 if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
1369 IPAWANDBG("In SSR sequence/recovery\n");
Ghanim Fodic6b67492017-03-15 14:19:56 +02001370 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001371 return -EFAULT;
1372 }
1373 ret = ipa3_setup_sys_pipe(&rmnet_ipa3_ctx->ipa_to_apps_ep_cfg,
1374 &rmnet_ipa3_ctx->ipa3_to_apps_hdl);
1375
Ghanim Fodic6b67492017-03-15 14:19:56 +02001376 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001377
1378 if (ret)
1379 IPAWANERR("failed to configure ingress\n");
1380
1381 return ret;
1382}
1383
Amir Levy9659e592016-10-27 18:08:27 +03001384/**
Ghanim Fodic6b67492017-03-15 14:19:56 +02001385 * handle3_egress_format() - Egress data format configuration
1386 *
1387 * Setup IPA egress system pipe and Configure:
1388 * header handling, checksum, de-aggregation and fifo size
1389 *
1390 * @dev: network device
1391 * @e: egress configuration
1392 */
1393static int handle3_egress_format(struct net_device *dev,
1394 struct rmnet_ioctl_extended_s *e)
1395{
1396 int rc;
1397 struct ipa_sys_connect_params *ipa_wan_ep_cfg;
1398
1399 IPAWANDBG("get RMNET_IOCTL_SET_EGRESS_DATA_FORMAT\n");
1400 ipa_wan_ep_cfg = &rmnet_ipa3_ctx->apps_to_ipa_ep_cfg;
1401 if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM) {
1402 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 8;
1403 ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en =
1404 IPA_ENABLE_CS_OFFLOAD_UL;
1405 ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_metadata_hdr_offset = 1;
1406 } else {
1407 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4;
1408 }
1409
1410 if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION) {
Skylar Changeaebfca2017-08-16 17:36:21 -07001411 IPAWANDBG("WAN UL Aggregation enabled\n");
Ghanim Fodic6b67492017-03-15 14:19:56 +02001412 ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
1413 ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_QCMAP;
1414
1415 ipa_wan_ep_cfg->ipa_ep_cfg.deaggr.packet_offset_valid = false;
1416
1417 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2;
1418
1419 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid =
1420 true;
1421 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad =
1422 IPA_HDR_PAD;
1423 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment =
1424 2;
1425 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding =
1426 true;
1427 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset =
1428 0;
1429 ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_little_endian =
1430 false;
1431 } else {
1432 IPAWANDBG("WAN UL Aggregation disabled\n");
1433 ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
1434 }
1435
1436 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
1437 /* modem want offset at 0! */
1438 ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata = 0;
1439
1440 ipa_wan_ep_cfg->ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_WAN_PROD;
1441 ipa_wan_ep_cfg->ipa_ep_cfg.mode.mode = IPA_BASIC;
1442
1443 ipa_wan_ep_cfg->client = IPA_CLIENT_APPS_WAN_PROD;
1444 ipa_wan_ep_cfg->notify = apps_ipa_tx_complete_notify;
1445 ipa_wan_ep_cfg->desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
1446 ipa_wan_ep_cfg->priv = dev;
1447
1448 mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
1449 if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
1450 IPAWANDBG("In SSR sequence/recovery\n");
1451 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
1452 return -EFAULT;
1453 }
1454 rc = ipa3_setup_sys_pipe(
1455 ipa_wan_ep_cfg, &rmnet_ipa3_ctx->apps_to_ipa3_hdl);
1456 if (rc) {
1457 IPAWANERR("failed to config egress endpoint\n");
1458 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
1459 return rc;
1460 }
1461 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
1462
1463 if (rmnet_ipa3_ctx->num_q6_rules != 0) {
1464 /* already got Q6 UL filter rules*/
Skylar Chang441cc5e2017-08-11 15:49:21 -07001465 if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) {
1466 /* prevent multi-threads accessing num_q6_rules */
1467 mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
Ghanim Fodic6b67492017-03-15 14:19:56 +02001468 rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
Skylar Chang441cc5e2017-08-11 15:49:21 -07001469 mutex_unlock(&rmnet_ipa3_ctx->
1470 add_mux_channel_lock);
1471 }
Ghanim Fodic6b67492017-03-15 14:19:56 +02001472 if (rc)
1473 IPAWANERR("install UL rules failed\n");
1474 else
1475 rmnet_ipa3_ctx->a7_ul_flt_set = true;
1476 } else {
1477 /* wait Q6 UL filter rules*/
1478 IPAWANDBG("no UL-rules\n");
1479 }
1480 rmnet_ipa3_ctx->egress_set = true;
1481
1482 return rc;
1483}
1484
1485/**
Amir Levy9659e592016-10-27 18:08:27 +03001486 * ipa3_wwan_ioctl() - I/O control for wwan network driver.
1487 *
1488 * @dev: network device
1489 * @ifr: ignored
1490 * @cmd: cmd to be excecuded. can be one of the following:
1491 * IPA_WWAN_IOCTL_OPEN - Open the network interface
1492 * IPA_WWAN_IOCTL_CLOSE - Close the network interface
1493 *
1494 * Return codes:
1495 * 0: success
1496 * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
1497 * later
1498 * -EFAULT: Error while transmitting the skb
1499 */
1500static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1501{
1502 int rc = 0;
1503 int mru = 1000, epid = 1, mux_index, len;
1504 struct ipa_msg_meta msg_meta;
1505 struct ipa_wan_msg *wan_msg = NULL;
1506 struct rmnet_ioctl_extended_s extend_ioctl_data;
1507 struct rmnet_ioctl_data_s ioctl_data;
1508 struct ipa3_rmnet_mux_val *mux_channel;
1509 int rmnet_index;
1510
1511 IPAWANDBG("rmnet_ipa got ioctl number 0x%08x", cmd);
1512 switch (cmd) {
1513 /* Set Ethernet protocol */
1514 case RMNET_IOCTL_SET_LLP_ETHERNET:
1515 break;
1516 /* Set RAWIP protocol */
1517 case RMNET_IOCTL_SET_LLP_IP:
1518 break;
1519 /* Get link protocol */
1520 case RMNET_IOCTL_GET_LLP:
1521 ioctl_data.u.operation_mode = RMNET_MODE_LLP_IP;
1522 if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data,
1523 sizeof(struct rmnet_ioctl_data_s)))
1524 rc = -EFAULT;
1525 break;
1526 /* Set QoS header enabled */
1527 case RMNET_IOCTL_SET_QOS_ENABLE:
1528 return -EINVAL;
1529 /* Set QoS header disabled */
1530 case RMNET_IOCTL_SET_QOS_DISABLE:
1531 break;
1532 /* Get QoS header state */
1533 case RMNET_IOCTL_GET_QOS:
1534 ioctl_data.u.operation_mode = RMNET_MODE_NONE;
1535 if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data,
1536 sizeof(struct rmnet_ioctl_data_s)))
1537 rc = -EFAULT;
1538 break;
1539 /* Get operation mode */
1540 case RMNET_IOCTL_GET_OPMODE:
1541 ioctl_data.u.operation_mode = RMNET_MODE_LLP_IP;
1542 if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data,
1543 sizeof(struct rmnet_ioctl_data_s)))
1544 rc = -EFAULT;
1545 break;
1546 /* Open transport port */
1547 case RMNET_IOCTL_OPEN:
1548 break;
1549 /* Close transport port */
1550 case RMNET_IOCTL_CLOSE:
1551 break;
1552 /* Flow enable */
1553 case RMNET_IOCTL_FLOW_ENABLE:
Skylar Changa699afd2017-06-06 10:06:21 -07001554 IPAWANERR("RMNET_IOCTL_FLOW_ENABLE not supported\n");
1555 rc = -EFAULT;
Amir Levy9659e592016-10-27 18:08:27 +03001556 break;
1557 /* Flow disable */
1558 case RMNET_IOCTL_FLOW_DISABLE:
Skylar Changa699afd2017-06-06 10:06:21 -07001559 IPAWANERR("RMNET_IOCTL_FLOW_DISABLE not supported\n");
1560 rc = -EFAULT;
Amir Levy9659e592016-10-27 18:08:27 +03001561 break;
1562 /* Set flow handle */
1563 case RMNET_IOCTL_FLOW_SET_HNDL:
1564 break;
1565
1566 /* Extended IOCTLs */
1567 case RMNET_IOCTL_EXTENDED:
1568 IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n");
1569 if (copy_from_user(&extend_ioctl_data,
1570 (u8 *)ifr->ifr_ifru.ifru_data,
1571 sizeof(struct rmnet_ioctl_extended_s))) {
1572 IPAWANERR("failed to copy extended ioctl data\n");
1573 rc = -EFAULT;
1574 break;
1575 }
1576 switch (extend_ioctl_data.extended_ioctl) {
1577 /* Get features */
1578 case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
1579 IPAWANDBG("get RMNET_IOCTL_GET_SUPPORTED_FEATURES\n");
1580 extend_ioctl_data.u.data =
1581 (RMNET_IOCTL_FEAT_NOTIFY_MUX_CHANNEL |
1582 RMNET_IOCTL_FEAT_SET_EGRESS_DATA_FORMAT |
1583 RMNET_IOCTL_FEAT_SET_INGRESS_DATA_FORMAT);
1584 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1585 &extend_ioctl_data,
1586 sizeof(struct rmnet_ioctl_extended_s)))
1587 rc = -EFAULT;
1588 break;
1589 /* Set MRU */
1590 case RMNET_IOCTL_SET_MRU:
1591 mru = extend_ioctl_data.u.data;
1592 IPAWANDBG("get MRU size %d\n",
1593 extend_ioctl_data.u.data);
1594 break;
1595 /* Get MRU */
1596 case RMNET_IOCTL_GET_MRU:
1597 extend_ioctl_data.u.data = mru;
1598 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1599 &extend_ioctl_data,
1600 sizeof(struct rmnet_ioctl_extended_s)))
1601 rc = -EFAULT;
1602 break;
1603 /* GET SG support */
1604 case RMNET_IOCTL_GET_SG_SUPPORT:
1605 extend_ioctl_data.u.data =
1606 ipa3_rmnet_res.ipa_advertise_sg_support;
1607 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1608 &extend_ioctl_data,
1609 sizeof(struct rmnet_ioctl_extended_s)))
1610 rc = -EFAULT;
1611 break;
1612 /* Get endpoint ID */
1613 case RMNET_IOCTL_GET_EPID:
1614 IPAWANDBG("get ioctl: RMNET_IOCTL_GET_EPID\n");
1615 extend_ioctl_data.u.data = epid;
1616 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1617 &extend_ioctl_data,
1618 sizeof(struct rmnet_ioctl_extended_s)))
1619 rc = -EFAULT;
1620 if (copy_from_user(&extend_ioctl_data,
1621 (u8 *)ifr->ifr_ifru.ifru_data,
1622 sizeof(struct rmnet_ioctl_extended_s))) {
1623 IPAWANERR("copy extended ioctl data failed\n");
1624 rc = -EFAULT;
1625 break;
1626 }
1627 IPAWANDBG("RMNET_IOCTL_GET_EPID return %d\n",
1628 extend_ioctl_data.u.data);
1629 break;
1630 /* Endpoint pair */
1631 case RMNET_IOCTL_GET_EP_PAIR:
1632 IPAWANDBG("get ioctl: RMNET_IOCTL_GET_EP_PAIR\n");
1633 extend_ioctl_data.u.ipa_ep_pair.consumer_pipe_num =
Ghanim Fodic6b67492017-03-15 14:19:56 +02001634 ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
Amir Levy9659e592016-10-27 18:08:27 +03001635 extend_ioctl_data.u.ipa_ep_pair.producer_pipe_num =
1636 ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
1637 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1638 &extend_ioctl_data,
1639 sizeof(struct rmnet_ioctl_extended_s)))
1640 rc = -EFAULT;
1641 if (copy_from_user(&extend_ioctl_data,
1642 (u8 *)ifr->ifr_ifru.ifru_data,
1643 sizeof(struct rmnet_ioctl_extended_s))) {
1644 IPAWANERR("copy extended ioctl data failed\n");
1645 rc = -EFAULT;
1646 break;
1647 }
1648 IPAWANDBG("RMNET_IOCTL_GET_EP_PAIR c: %d p: %d\n",
1649 extend_ioctl_data.u.ipa_ep_pair.consumer_pipe_num,
1650 extend_ioctl_data.u.ipa_ep_pair.producer_pipe_num);
1651 break;
1652 /* Get driver name */
1653 case RMNET_IOCTL_GET_DRIVER_NAME:
1654 memcpy(&extend_ioctl_data.u.if_name,
Mohammed Javidbf4c8022017-08-07 23:15:48 +05301655 IPA_NETDEV()->name, IFNAMSIZ);
1656 extend_ioctl_data.u.if_name[IFNAMSIZ - 1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001657 if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
1658 &extend_ioctl_data,
1659 sizeof(struct rmnet_ioctl_extended_s)))
1660 rc = -EFAULT;
1661 break;
1662 /* Add MUX ID */
1663 case RMNET_IOCTL_ADD_MUX_CHANNEL:
1664 mux_index = ipa3_find_mux_channel_index(
1665 extend_ioctl_data.u.rmnet_mux_val.mux_id);
1666 if (mux_index < MAX_NUM_OF_MUX_CHANNEL) {
1667 IPAWANDBG("already setup mux(%d)\n",
1668 extend_ioctl_data.u.
1669 rmnet_mux_val.mux_id);
1670 return rc;
1671 }
Skylar Chang8438ba52017-03-15 21:27:35 -07001672 mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +03001673 if (rmnet_ipa3_ctx->rmnet_index
1674 >= MAX_NUM_OF_MUX_CHANNEL) {
1675 IPAWANERR("Exceed mux_channel limit(%d)\n",
1676 rmnet_ipa3_ctx->rmnet_index);
Skylar Chang8438ba52017-03-15 21:27:35 -07001677 mutex_unlock(&rmnet_ipa3_ctx->
1678 add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +03001679 return -EFAULT;
1680 }
Shihuan Liu7b89d4e2017-10-06 20:38:02 -07001681 extend_ioctl_data.u.rmnet_mux_val.vchannel_name
1682 [IFNAMSIZ-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001683 IPAWANDBG("ADD_MUX_CHANNEL(%d, name: %s)\n",
1684 extend_ioctl_data.u.rmnet_mux_val.mux_id,
1685 extend_ioctl_data.u.rmnet_mux_val.vchannel_name);
1686 /* cache the mux name and id */
1687 mux_channel = rmnet_ipa3_ctx->mux_channel;
1688 rmnet_index = rmnet_ipa3_ctx->rmnet_index;
1689
1690 mux_channel[rmnet_index].mux_id =
1691 extend_ioctl_data.u.rmnet_mux_val.mux_id;
1692 memcpy(mux_channel[rmnet_index].vchannel_name,
1693 extend_ioctl_data.u.rmnet_mux_val.vchannel_name,
1694 sizeof(mux_channel[rmnet_index]
1695 .vchannel_name));
Skylar Changba7c5112017-04-14 19:23:05 -07001696 mux_channel[rmnet_index].vchannel_name[
1697 IFNAMSIZ - 1] = '\0';
1698
Amir Levy9659e592016-10-27 18:08:27 +03001699 IPAWANDBG("cashe device[%s:%d] in IPA_wan[%d]\n",
1700 mux_channel[rmnet_index].vchannel_name,
1701 mux_channel[rmnet_index].mux_id,
1702 rmnet_index);
1703 /* check if UL filter rules coming*/
1704 if (rmnet_ipa3_ctx->num_q6_rules != 0) {
1705 IPAWANERR("dev(%s) register to IPA\n",
1706 extend_ioctl_data.u.rmnet_mux_val.
1707 vchannel_name);
1708 rc = ipa3_wwan_register_to_ipa(
1709 rmnet_ipa3_ctx->rmnet_index);
1710 if (rc < 0) {
1711 IPAWANERR("device %s reg IPA failed\n",
1712 extend_ioctl_data.u.
1713 rmnet_mux_val.vchannel_name);
Skylar Chang8438ba52017-03-15 21:27:35 -07001714 mutex_unlock(&rmnet_ipa3_ctx->
1715 add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +03001716 return -ENODEV;
1717 }
1718 mux_channel[rmnet_index].mux_channel_set = true;
1719 mux_channel[rmnet_index].ul_flt_reg = true;
1720 } else {
1721 IPAWANDBG("dev(%s) haven't registered to IPA\n",
1722 extend_ioctl_data.u.
1723 rmnet_mux_val.vchannel_name);
1724 mux_channel[rmnet_index].mux_channel_set = true;
1725 mux_channel[rmnet_index].ul_flt_reg = false;
1726 }
1727 rmnet_ipa3_ctx->rmnet_index++;
Skylar Chang8438ba52017-03-15 21:27:35 -07001728 mutex_unlock(&rmnet_ipa3_ctx->add_mux_channel_lock);
Amir Levy9659e592016-10-27 18:08:27 +03001729 break;
1730 case RMNET_IOCTL_SET_EGRESS_DATA_FORMAT:
Ghanim Fodic6b67492017-03-15 14:19:56 +02001731 rc = handle3_egress_format(dev, &extend_ioctl_data);
Amir Levy9659e592016-10-27 18:08:27 +03001732 break;
1733 case RMNET_IOCTL_SET_INGRESS_DATA_FORMAT:/* Set IDF */
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001734 rc = handle3_ingress_format(dev, &extend_ioctl_data);
Amir Levy9659e592016-10-27 18:08:27 +03001735 break;
1736 case RMNET_IOCTL_SET_XLAT_DEV_INFO:
1737 wan_msg = kzalloc(sizeof(struct ipa_wan_msg),
1738 GFP_KERNEL);
1739 if (!wan_msg) {
1740 IPAWANERR("Failed to allocate memory.\n");
1741 return -ENOMEM;
1742 }
1743 len = sizeof(wan_msg->upstream_ifname) >
1744 sizeof(extend_ioctl_data.u.if_name) ?
1745 sizeof(extend_ioctl_data.u.if_name) :
1746 sizeof(wan_msg->upstream_ifname);
1747 strlcpy(wan_msg->upstream_ifname,
1748 extend_ioctl_data.u.if_name, len);
Mohammed Javidbf4c8022017-08-07 23:15:48 +05301749 wan_msg->upstream_ifname[len-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001750 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
1751 msg_meta.msg_type = WAN_XLAT_CONNECT;
1752 msg_meta.msg_len = sizeof(struct ipa_wan_msg);
1753 rc = ipa3_send_msg(&msg_meta, wan_msg,
1754 ipa3_wwan_msg_free_cb);
1755 if (rc) {
1756 IPAWANERR("Failed to send XLAT_CONNECT msg\n");
1757 kfree(wan_msg);
1758 }
1759 break;
1760 /* Get agg count */
1761 case RMNET_IOCTL_GET_AGGREGATION_COUNT:
1762 break;
1763 /* Set agg count */
1764 case RMNET_IOCTL_SET_AGGREGATION_COUNT:
1765 break;
1766 /* Get agg size */
1767 case RMNET_IOCTL_GET_AGGREGATION_SIZE:
1768 break;
1769 /* Set agg size */
1770 case RMNET_IOCTL_SET_AGGREGATION_SIZE:
1771 break;
1772 /* Do flow control */
1773 case RMNET_IOCTL_FLOW_CONTROL:
1774 break;
1775 /* For legacy use */
1776 case RMNET_IOCTL_GET_DFLT_CONTROL_CHANNEL:
1777 break;
1778 /* Get HW/SW map */
1779 case RMNET_IOCTL_GET_HWSW_MAP:
1780 break;
1781 /* Set RX Headroom */
1782 case RMNET_IOCTL_SET_RX_HEADROOM:
1783 break;
1784 default:
1785 IPAWANERR("[%s] unsupported extended cmd[%d]",
1786 dev->name,
1787 extend_ioctl_data.extended_ioctl);
1788 rc = -EINVAL;
1789 }
1790 break;
1791 default:
1792 IPAWANERR("[%s] unsupported cmd[%d]",
1793 dev->name, cmd);
1794 rc = -EINVAL;
1795 }
1796 return rc;
1797}
1798
1799static const struct net_device_ops ipa3_wwan_ops_ip = {
1800 .ndo_open = ipa3_wwan_open,
1801 .ndo_stop = ipa3_wwan_stop,
1802 .ndo_start_xmit = ipa3_wwan_xmit,
1803 .ndo_tx_timeout = ipa3_wwan_tx_timeout,
1804 .ndo_do_ioctl = ipa3_wwan_ioctl,
1805 .ndo_change_mtu = ipa3_wwan_change_mtu,
1806 .ndo_set_mac_address = 0,
1807 .ndo_validate_addr = 0,
1808};
1809
1810/**
1811 * wwan_setup() - Setups the wwan network driver.
1812 *
1813 * @dev: network device
1814 *
1815 * Return codes:
1816 * None
1817 */
1818
1819static void ipa3_wwan_setup(struct net_device *dev)
1820{
1821 dev->netdev_ops = &ipa3_wwan_ops_ip;
1822 ether_setup(dev);
1823 /* set this after calling ether_setup */
1824 dev->header_ops = 0; /* No header */
1825 dev->type = ARPHRD_RAWIP;
1826 dev->hard_header_len = 0;
1827 dev->mtu = WWAN_DATA_LEN;
1828 dev->addr_len = 0;
1829 dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
1830 dev->needed_headroom = HEADROOM_FOR_QMAP;
1831 dev->needed_tailroom = TAILROOM;
1832 dev->watchdog_timeo = 1000;
1833}
1834
1835/* IPA_RM related functions start*/
1836static void ipa3_q6_prod_rm_request_resource(struct work_struct *work);
1837static DECLARE_DELAYED_WORK(ipa3_q6_con_rm_request,
1838 ipa3_q6_prod_rm_request_resource);
1839static void ipa3_q6_prod_rm_release_resource(struct work_struct *work);
1840static DECLARE_DELAYED_WORK(ipa3_q6_con_rm_release,
1841 ipa3_q6_prod_rm_release_resource);
1842
1843static void ipa3_q6_prod_rm_request_resource(struct work_struct *work)
1844{
1845 int ret = 0;
1846
1847 ret = ipa_rm_request_resource(IPA_RM_RESOURCE_Q6_PROD);
1848 if (ret < 0 && ret != -EINPROGRESS) {
1849 IPAWANERR("%s: ipa_rm_request_resource failed %d\n", __func__,
1850 ret);
1851 return;
1852 }
1853}
1854
1855static int ipa3_q6_rm_request_resource(void)
1856{
1857 queue_delayed_work(rmnet_ipa3_ctx->rm_q6_wq,
1858 &ipa3_q6_con_rm_request, 0);
1859 return 0;
1860}
1861
1862static void ipa3_q6_prod_rm_release_resource(struct work_struct *work)
1863{
1864 int ret = 0;
1865
1866 ret = ipa_rm_release_resource(IPA_RM_RESOURCE_Q6_PROD);
1867 if (ret < 0 && ret != -EINPROGRESS) {
1868 IPAWANERR("%s: ipa_rm_release_resource failed %d\n", __func__,
1869 ret);
1870 return;
1871 }
1872}
1873
1874
1875static int ipa3_q6_rm_release_resource(void)
1876{
1877 queue_delayed_work(rmnet_ipa3_ctx->rm_q6_wq,
1878 &ipa3_q6_con_rm_release, 0);
1879 return 0;
1880}
1881
1882
1883static void ipa3_q6_rm_notify_cb(void *user_data,
1884 enum ipa_rm_event event,
1885 unsigned long data)
1886{
1887 switch (event) {
1888 case IPA_RM_RESOURCE_GRANTED:
1889 IPAWANDBG_LOW("%s: Q6_PROD GRANTED CB\n", __func__);
1890 break;
1891 case IPA_RM_RESOURCE_RELEASED:
1892 IPAWANDBG_LOW("%s: Q6_PROD RELEASED CB\n", __func__);
1893 break;
1894 default:
1895 return;
1896 }
1897}
Michael Adisumarta3e350812017-09-18 14:54:36 -07001898
1899int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state)
1900{
1901 if (!state)
1902 return -EINVAL;
1903
1904 if (!ipa_pm_is_used())
1905 return 0;
1906
1907 if (state->up)
1908 return ipa_pm_activate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
1909 else
1910 return ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
1911}
1912
1913/**
1914 * ipa3_q6_register_pm - Register modem clients for PM
1915 *
1916 * This function will register 2 client with IPA PM to represent modem
1917 * in clock scaling calculation:
1918 * - "EMB MODEM" - this client will be activated with embedded traffic
1919 - "TETH MODEM" - this client we be activated by IPACM on offload to
1920 modem.
1921*/
1922static int ipa3_q6_register_pm(void)
1923{
1924 int result;
1925 struct ipa_pm_register_params pm_reg;
1926
1927 memset(&pm_reg, 0, sizeof(pm_reg));
1928 pm_reg.name = "EMB MODEM";
1929 pm_reg.group = IPA_PM_GROUP_MODEM;
1930 pm_reg.skip_clk_vote = true;
1931 result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_pm_hdl);
1932 if (result) {
1933 IPAERR("failed to create IPA PM client %d\n", result);
1934 return result;
1935 }
1936
1937 pm_reg.name = "TETH MODEM";
1938 pm_reg.group = IPA_PM_GROUP_MODEM;
1939 pm_reg.skip_clk_vote = true;
1940 result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_teth_pm_hdl);
1941 if (result) {
1942 IPAERR("failed to create IPA PM client %d\n", result);
1943 return result;
1944 }
1945
1946 return 0;
1947}
1948
1949static void ipa3_q6_deregister_pm(void)
1950{
1951 ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_pm_hdl);
1952 ipa_pm_deregister(rmnet_ipa3_ctx->q6_pm_hdl);
1953}
1954
1955int ipa3_wwan_set_modem_perf_profile(int throughput)
1956{
1957 struct ipa_rm_perf_profile profile;
1958 int ret;
1959
Michael Adisumarta3e350812017-09-18 14:54:36 -07001960 if (ipa3_ctx->use_ipa_pm) {
1961 ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl,
1962 throughput);
1963 if (ret)
1964 return ret;
1965 ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl,
1966 throughput);
1967 } else {
1968 memset(&profile, 0, sizeof(profile));
1969 profile.max_supported_bandwidth_mbps = throughput;
1970 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
1971 &profile);
1972 }
1973
1974 return ret;
1975}
1976
Amir Levy9659e592016-10-27 18:08:27 +03001977static int ipa3_q6_initialize_rm(void)
1978{
1979 struct ipa_rm_create_params create_params;
1980 struct ipa_rm_perf_profile profile;
1981 int result;
1982
1983 /* Initialize IPA_RM workqueue */
1984 rmnet_ipa3_ctx->rm_q6_wq = create_singlethread_workqueue("clnt_req");
1985 if (!rmnet_ipa3_ctx->rm_q6_wq)
1986 return -ENOMEM;
1987
1988 memset(&create_params, 0, sizeof(create_params));
1989 create_params.name = IPA_RM_RESOURCE_Q6_PROD;
1990 create_params.reg_params.notify_cb = &ipa3_q6_rm_notify_cb;
1991 result = ipa_rm_create_resource(&create_params);
1992 if (result)
1993 goto create_rsrc_err1;
1994 memset(&create_params, 0, sizeof(create_params));
1995 create_params.name = IPA_RM_RESOURCE_Q6_CONS;
1996 create_params.release_resource = &ipa3_q6_rm_release_resource;
1997 create_params.request_resource = &ipa3_q6_rm_request_resource;
1998 result = ipa_rm_create_resource(&create_params);
1999 if (result)
2000 goto create_rsrc_err2;
2001 /* add dependency*/
2002 result = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
2003 IPA_RM_RESOURCE_APPS_CONS);
2004 if (result)
2005 goto add_dpnd_err;
2006 /* setup Performance profile */
2007 memset(&profile, 0, sizeof(profile));
2008 profile.max_supported_bandwidth_mbps = 100;
2009 result = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
2010 &profile);
2011 if (result)
2012 goto set_perf_err;
2013 result = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_CONS,
2014 &profile);
2015 if (result)
2016 goto set_perf_err;
2017 return result;
2018
2019set_perf_err:
2020 ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
2021 IPA_RM_RESOURCE_APPS_CONS);
2022add_dpnd_err:
2023 result = ipa_rm_delete_resource(IPA_RM_RESOURCE_Q6_CONS);
2024 if (result < 0)
2025 IPAWANERR("Error deleting resource %d, ret=%d\n",
2026 IPA_RM_RESOURCE_Q6_CONS, result);
2027create_rsrc_err2:
2028 result = ipa_rm_delete_resource(IPA_RM_RESOURCE_Q6_PROD);
2029 if (result < 0)
2030 IPAWANERR("Error deleting resource %d, ret=%d\n",
2031 IPA_RM_RESOURCE_Q6_PROD, result);
2032create_rsrc_err1:
2033 destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
2034 return result;
2035}
2036
2037void ipa3_q6_deinitialize_rm(void)
2038{
2039 int ret;
2040
2041 ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
2042 IPA_RM_RESOURCE_APPS_CONS);
2043 if (ret < 0)
2044 IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
2045 IPA_RM_RESOURCE_Q6_PROD, IPA_RM_RESOURCE_APPS_CONS,
2046 ret);
2047 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_Q6_CONS);
2048 if (ret < 0)
2049 IPAWANERR("Error deleting resource %d, ret=%d\n",
2050 IPA_RM_RESOURCE_Q6_CONS, ret);
2051 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_Q6_PROD);
2052 if (ret < 0)
2053 IPAWANERR("Error deleting resource %d, ret=%d\n",
2054 IPA_RM_RESOURCE_Q6_PROD, ret);
Mohammed Javid4e3015d2017-07-31 13:27:18 +05302055
2056 if (rmnet_ipa3_ctx->rm_q6_wq)
2057 destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
Amir Levy9659e592016-10-27 18:08:27 +03002058}
2059
2060static void ipa3_wake_tx_queue(struct work_struct *work)
2061{
2062 if (IPA_NETDEV()) {
2063 __netif_tx_lock_bh(netdev_get_tx_queue(IPA_NETDEV(), 0));
2064 netif_wake_queue(IPA_NETDEV());
2065 __netif_tx_unlock_bh(netdev_get_tx_queue(IPA_NETDEV(), 0));
2066 }
2067}
2068
2069/**
2070 * ipa3_rm_resource_granted() - Called upon
2071 * IPA_RM_RESOURCE_GRANTED event. Wakes up queue is was stopped.
2072 *
2073 * @work: work object supplied ny workqueue
2074 *
2075 * Return codes:
2076 * None
2077 */
2078static void ipa3_rm_resource_granted(void *dev)
2079{
2080 IPAWANDBG_LOW("Resource Granted - starting queue\n");
2081 schedule_work(&ipa3_tx_wakequeue_work);
2082}
2083
2084/**
2085 * ipa3_rm_notify() - Callback function for RM events. Handles
2086 * IPA_RM_RESOURCE_GRANTED and IPA_RM_RESOURCE_RELEASED events.
2087 * IPA_RM_RESOURCE_GRANTED is handled in the context of shared
2088 * workqueue.
2089 *
2090 * @dev: network device
2091 * @event: IPA RM event
2092 * @data: Additional data provided by IPA RM
2093 *
2094 * Return codes:
2095 * None
2096 */
2097static void ipa3_rm_notify(void *dev, enum ipa_rm_event event,
2098 unsigned long data)
2099{
2100 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
2101
2102 pr_debug("%s: event %d\n", __func__, event);
2103 switch (event) {
2104 case IPA_RM_RESOURCE_GRANTED:
2105 if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
2106 complete_all(&wwan_ptr->resource_granted_completion);
2107 break;
2108 }
2109 ipa3_rm_resource_granted(dev);
2110 break;
2111 case IPA_RM_RESOURCE_RELEASED:
2112 break;
2113 default:
2114 pr_err("%s: unknown event %d\n", __func__, event);
2115 break;
2116 }
2117}
2118
2119/* IPA_RM related functions end*/
2120
2121static int ipa3_ssr_notifier_cb(struct notifier_block *this,
2122 unsigned long code,
2123 void *data);
2124
2125static struct notifier_block ipa3_ssr_notifier = {
2126 .notifier_call = ipa3_ssr_notifier_cb,
2127};
2128
2129static int get_ipa_rmnet_dts_configuration(struct platform_device *pdev,
2130 struct ipa3_rmnet_plat_drv_res *ipa_rmnet_drv_res)
2131{
Sunil Paidimarri226cf032016-10-14 13:33:08 -07002132 int result;
2133
2134 ipa_rmnet_drv_res->wan_rx_desc_size = IPA_WWAN_CONS_DESC_FIFO_SZ;
Amir Levy9659e592016-10-27 18:08:27 +03002135 ipa_rmnet_drv_res->ipa_rmnet_ssr =
2136 of_property_read_bool(pdev->dev.of_node,
2137 "qcom,rmnet-ipa-ssr");
2138 pr_info("IPA SSR support = %s\n",
2139 ipa_rmnet_drv_res->ipa_rmnet_ssr ? "True" : "False");
2140 ipa_rmnet_drv_res->ipa_loaduC =
2141 of_property_read_bool(pdev->dev.of_node,
2142 "qcom,ipa-loaduC");
2143 pr_info("IPA ipa-loaduC = %s\n",
2144 ipa_rmnet_drv_res->ipa_loaduC ? "True" : "False");
2145
2146 ipa_rmnet_drv_res->ipa_advertise_sg_support =
2147 of_property_read_bool(pdev->dev.of_node,
2148 "qcom,ipa-advertise-sg-support");
2149 pr_info("IPA SG support = %s\n",
2150 ipa_rmnet_drv_res->ipa_advertise_sg_support ? "True" : "False");
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002151
2152 ipa_rmnet_drv_res->ipa_napi_enable =
2153 of_property_read_bool(pdev->dev.of_node,
2154 "qcom,ipa-napi-enable");
2155 pr_info("IPA Napi Enable = %s\n",
2156 ipa_rmnet_drv_res->ipa_napi_enable ? "True" : "False");
Sunil Paidimarri226cf032016-10-14 13:33:08 -07002157
2158 /* Get IPA WAN RX desc fifo size */
2159 result = of_property_read_u32(pdev->dev.of_node,
2160 "qcom,wan-rx-desc-size",
2161 &ipa_rmnet_drv_res->wan_rx_desc_size);
2162 if (result)
2163 pr_info("using default for wan-rx-desc-size = %u\n",
2164 ipa_rmnet_drv_res->wan_rx_desc_size);
2165 else
2166 IPAWANDBG(": found ipa_drv_res->wan-rx-desc-size = %u\n",
2167 ipa_rmnet_drv_res->wan_rx_desc_size);
2168
Amir Levy9659e592016-10-27 18:08:27 +03002169 return 0;
2170}
2171
2172struct ipa3_rmnet_context ipa3_rmnet_ctx;
2173static int ipa3_wwan_probe(struct platform_device *pdev);
2174struct platform_device *m_pdev;
2175
2176static void ipa3_delayed_probe(struct work_struct *work)
2177{
2178 (void)ipa3_wwan_probe(m_pdev);
2179}
2180
2181static DECLARE_WORK(ipa3_scheduled_probe, ipa3_delayed_probe);
2182
2183static void ipa3_ready_cb(void *user_data)
2184{
2185 struct platform_device *pdev = (struct platform_device *)(user_data);
2186
2187 m_pdev = pdev;
2188
2189 IPAWANDBG("IPA ready callback has been triggered!\n");
2190
2191 schedule_work(&ipa3_scheduled_probe);
2192}
2193
Michael Adisumarta3e350812017-09-18 14:54:36 -07002194static void ipa_pm_wwan_pm_cb(void *p, enum ipa_pm_cb_event event)
2195{
2196 struct net_device *dev = (struct net_device *)p;
2197 struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
2198
2199 IPAWANDBG_LOW("event %d\n", event);
2200 switch (event) {
2201 case IPA_PM_CLIENT_ACTIVATED:
2202 if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
2203 complete_all(&wwan_ptr->resource_granted_completion);
2204 break;
2205 }
2206 ipa3_rm_resource_granted(dev);
2207 break;
2208 default:
2209 pr_err("%s: unknown event %d\n", __func__, event);
2210 break;
2211 }
2212}
2213
2214static int ipa3_wwan_register_netdev_pm_client(struct net_device *dev)
2215{
2216 int result;
2217 struct ipa_pm_register_params pm_reg;
2218
2219 memset(&pm_reg, 0, sizeof(pm_reg));
2220 pm_reg.name = IPA_NETDEV()->name;
2221 pm_reg.user_data = dev;
2222 pm_reg.callback = ipa_pm_wwan_pm_cb;
2223 pm_reg.group = IPA_PM_GROUP_APPS;
2224 result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->pm_hdl);
2225 if (result) {
2226 IPAERR("failed to create IPA PM client %d\n", result);
2227 return result;
2228 }
2229 return 0;
2230}
2231
2232static void ipa3_wwan_deregister_netdev_pm_client(void)
2233{
2234 ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
2235 ipa_pm_deregister(rmnet_ipa3_ctx->pm_hdl);
2236}
2237
2238static int ipa3_wwan_create_wwan_rm_resource(struct net_device *dev)
2239{
2240 struct ipa_rm_create_params ipa_rm_params;
2241 struct ipa_rm_perf_profile profile;
2242 int ret;
2243
2244 memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
2245 ipa_rm_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
2246 ipa_rm_params.reg_params.user_data = dev;
2247 ipa_rm_params.reg_params.notify_cb = ipa3_rm_notify;
2248 ret = ipa_rm_create_resource(&ipa_rm_params);
2249 if (ret) {
2250 pr_err("%s: unable to create resourse %d in IPA RM\n",
2251 __func__, IPA_RM_RESOURCE_WWAN_0_PROD);
2252 return ret;
2253 }
2254 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WWAN_0_PROD,
2255 IPA_RM_INACTIVITY_TIMER);
2256 if (ret) {
2257 pr_err("%s: ipa rm timer init failed %d on resourse %d\n",
2258 __func__, ret, IPA_RM_RESOURCE_WWAN_0_PROD);
2259 goto timer_init_err;
2260 }
2261 /* add dependency */
2262 ret = ipa_rm_add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
2263 IPA_RM_RESOURCE_Q6_CONS);
2264 if (ret)
2265 goto add_dpnd_err;
2266 /* setup Performance profile */
2267 memset(&profile, 0, sizeof(profile));
2268 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
2269 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WWAN_0_PROD,
2270 &profile);
2271 if (ret)
2272 goto set_perf_err;
2273
2274 return 0;
2275
2276set_perf_err:
2277 ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
2278 IPA_RM_RESOURCE_Q6_CONS);
2279add_dpnd_err:
2280 ipa_rm_inactivity_timer_destroy(
2281 IPA_RM_RESOURCE_WWAN_0_PROD); /* IPA_RM */
2282timer_init_err:
2283 ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
2284 return ret;
2285}
2286
2287static void ipa3_wwan_delete_wwan_rm_resource(void)
2288{
2289 int ret;
2290
2291 ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
2292 IPA_RM_RESOURCE_Q6_CONS);
2293 if (ret < 0)
2294 IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
2295 IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
2296 ret);
2297 ret = ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WWAN_0_PROD);
2298 if (ret < 0)
2299 IPAWANERR(
2300 "Error ipa_rm_inactivity_timer_destroy resource %d, ret=%d\n",
2301 IPA_RM_RESOURCE_WWAN_0_PROD, ret);
2302 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
2303 if (ret < 0)
2304 IPAWANERR("Error deleting resource %d, ret=%d\n",
2305 IPA_RM_RESOURCE_WWAN_0_PROD, ret);
2306}
2307
Amir Levy9659e592016-10-27 18:08:27 +03002308/**
2309 * ipa3_wwan_probe() - Initialized the module and registers as a
2310 * network interface to the network stack
2311 *
2312 * Note: In case IPA driver hasn't initialized already, the probe function
2313 * will return immediately after registering a callback to be invoked when
2314 * IPA driver initialization is complete.
2315 *
2316 * Return codes:
2317 * 0: success
2318 * -ENOMEM: No memory available
2319 * -EFAULT: Internal error
2320 */
2321static int ipa3_wwan_probe(struct platform_device *pdev)
2322{
2323 int ret, i;
2324 struct net_device *dev;
Amir Levy9659e592016-10-27 18:08:27 +03002325
2326 pr_info("rmnet_ipa3 started initialization\n");
2327
2328 if (!ipa3_is_ready()) {
2329 IPAWANDBG("IPA driver not ready, registering callback\n");
2330 ret = ipa_register_ipa_ready_cb(ipa3_ready_cb, (void *)pdev);
2331
2332 /*
2333 * If we received -EEXIST, IPA has initialized. So we need
2334 * to continue the probing process.
2335 */
2336 if (ret != -EEXIST) {
2337 if (ret)
2338 IPAWANERR("IPA CB reg failed - %d\n", ret);
2339 return ret;
2340 }
2341 }
2342
2343 ret = get_ipa_rmnet_dts_configuration(pdev, &ipa3_rmnet_res);
2344 ipa3_rmnet_ctx.ipa_rmnet_ssr = ipa3_rmnet_res.ipa_rmnet_ssr;
2345
2346 ret = ipa3_init_q6_smem();
2347 if (ret) {
2348 IPAWANERR("ipa3_init_q6_smem failed!\n");
2349 return ret;
2350 }
2351
2352 /* initialize tx/rx endpoint setup */
2353 memset(&rmnet_ipa3_ctx->apps_to_ipa_ep_cfg, 0,
2354 sizeof(struct ipa_sys_connect_params));
2355 memset(&rmnet_ipa3_ctx->ipa_to_apps_ep_cfg, 0,
2356 sizeof(struct ipa_sys_connect_params));
2357
2358 /* initialize ex property setup */
2359 rmnet_ipa3_ctx->num_q6_rules = 0;
2360 rmnet_ipa3_ctx->old_num_q6_rules = 0;
2361 rmnet_ipa3_ctx->rmnet_index = 0;
2362 rmnet_ipa3_ctx->egress_set = false;
2363 rmnet_ipa3_ctx->a7_ul_flt_set = false;
2364 for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++)
2365 memset(&rmnet_ipa3_ctx->mux_channel[i], 0,
2366 sizeof(struct ipa3_rmnet_mux_val));
2367
2368 /* start A7 QMI service/client */
2369 if (ipa3_rmnet_res.ipa_loaduC)
2370 /* Android platform loads uC */
2371 ipa3_qmi_service_init(QMI_IPA_PLATFORM_TYPE_MSM_ANDROID_V01);
2372 else
2373 /* LE platform not loads uC */
2374 ipa3_qmi_service_init(QMI_IPA_PLATFORM_TYPE_LE_V01);
2375
2376 /* construct default WAN RT tbl for IPACM */
2377 ret = ipa3_setup_a7_qmap_hdr();
2378 if (ret)
2379 goto setup_a7_qmap_hdr_err;
2380 ret = ipa3_setup_dflt_wan_rt_tables();
2381 if (ret)
2382 goto setup_dflt_wan_rt_tables_err;
2383
2384 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
2385 /* Start transport-driver fd ioctl for ipacm for first init */
2386 ret = ipa3_wan_ioctl_init();
2387 if (ret)
2388 goto wan_ioctl_init_err;
2389 } else {
2390 /* Enable sending QMI messages after SSR */
2391 ipa3_wan_ioctl_enable_qmi_messages();
2392 }
2393
2394 /* initialize wan-driver netdev */
2395 dev = alloc_netdev(sizeof(struct ipa3_wwan_private),
2396 IPA_WWAN_DEV_NAME,
2397 NET_NAME_UNKNOWN,
2398 ipa3_wwan_setup);
2399 if (!dev) {
2400 IPAWANERR("no memory for netdev\n");
2401 ret = -ENOMEM;
2402 goto alloc_netdev_err;
2403 }
2404 rmnet_ipa3_ctx->wwan_priv = netdev_priv(dev);
2405 memset(rmnet_ipa3_ctx->wwan_priv, 0,
2406 sizeof(*(rmnet_ipa3_ctx->wwan_priv)));
2407 IPAWANDBG("wwan_ptr (private) = %p", rmnet_ipa3_ctx->wwan_priv);
2408 rmnet_ipa3_ctx->wwan_priv->net = dev;
2409 rmnet_ipa3_ctx->wwan_priv->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
2410 rmnet_ipa3_ctx->wwan_priv->outstanding_low = DEFAULT_OUTSTANDING_LOW;
2411 atomic_set(&rmnet_ipa3_ctx->wwan_priv->outstanding_pkts, 0);
2412 spin_lock_init(&rmnet_ipa3_ctx->wwan_priv->lock);
2413 init_completion(
2414 &rmnet_ipa3_ctx->wwan_priv->resource_granted_completion);
2415
2416 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
2417 /* IPA_RM configuration starts */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002418 if (ipa3_ctx->use_ipa_pm)
2419 ret = ipa3_q6_register_pm();
2420 else
2421 ret = ipa3_q6_initialize_rm();
Amir Levy9659e592016-10-27 18:08:27 +03002422 if (ret) {
2423 IPAWANERR("%s: ipa3_q6_initialize_rm failed, ret: %d\n",
2424 __func__, ret);
2425 goto q6_init_err;
2426 }
2427 }
2428
Michael Adisumarta3e350812017-09-18 14:54:36 -07002429 if (ipa3_ctx->use_ipa_pm)
2430 ret = ipa3_wwan_register_netdev_pm_client(dev);
2431 else
2432 ret = ipa3_wwan_create_wwan_rm_resource(dev);
Amir Levy9659e592016-10-27 18:08:27 +03002433 if (ret) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07002434 IPAWANERR("fail to create/register pm resources\n");
2435 goto fail_pm;
Amir Levy9659e592016-10-27 18:08:27 +03002436 }
Amir Levy9659e592016-10-27 18:08:27 +03002437
2438 /* Enable SG support in netdevice. */
2439 if (ipa3_rmnet_res.ipa_advertise_sg_support)
2440 dev->hw_features |= NETIF_F_SG;
2441
2442 if (ipa3_rmnet_res.ipa_napi_enable)
2443 netif_napi_add(dev, &(rmnet_ipa3_ctx->wwan_priv->napi),
2444 ipa3_rmnet_poll, NAPI_WEIGHT);
2445 ret = register_netdev(dev);
2446 if (ret) {
2447 IPAWANERR("unable to register ipa_netdev %d rc=%d\n",
2448 0, ret);
2449 goto set_perf_err;
2450 }
2451
2452 IPAWANDBG("IPA-WWAN devices (%s) initialization ok :>>>>\n", dev->name);
2453 if (ret) {
2454 IPAWANERR("default configuration failed rc=%d\n",
2455 ret);
2456 goto config_err;
2457 }
Michael Adisumarta41fc8342017-12-05 14:37:18 -08002458
2459 /*
2460 * for IPA 4.0 offline charge is not needed and we need to prevent
2461 * power collapse until IPA uC is loaded.
2462 */
Amir Levy9659e592016-10-27 18:08:27 +03002463 atomic_set(&rmnet_ipa3_ctx->is_initialized, 1);
Michael Adisumarta41fc8342017-12-05 14:37:18 -08002464 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type !=
2465 IPA_HW_v4_0) {
Amir Levy9659e592016-10-27 18:08:27 +03002466 /* offline charging mode */
2467 ipa3_proxy_clk_unvote();
2468 }
2469 atomic_set(&rmnet_ipa3_ctx->is_ssr, 0);
2470
2471 pr_info("rmnet_ipa completed initialization\n");
2472 return 0;
2473config_err:
2474 if (ipa3_rmnet_res.ipa_napi_enable)
2475 netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
2476 unregister_netdev(dev);
2477set_perf_err:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002478 if (ipa3_ctx->use_ipa_pm)
2479 ipa3_wwan_deregister_netdev_pm_client();
2480 else
2481 ipa3_wwan_delete_wwan_rm_resource();
2482fail_pm:
2483 if (ipa3_ctx->use_ipa_pm) {
2484 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
2485 ipa3_q6_deregister_pm();
2486 } else {
2487 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
2488 ipa3_q6_deinitialize_rm();
2489 }
Amir Levy9659e592016-10-27 18:08:27 +03002490q6_init_err:
2491 free_netdev(dev);
2492 rmnet_ipa3_ctx->wwan_priv = NULL;
2493alloc_netdev_err:
2494 ipa3_wan_ioctl_deinit();
2495wan_ioctl_init_err:
2496 ipa3_del_dflt_wan_rt_tables();
2497setup_dflt_wan_rt_tables_err:
2498 ipa3_del_a7_qmap_hdr();
2499setup_a7_qmap_hdr_err:
2500 ipa3_qmi_service_exit();
2501 atomic_set(&rmnet_ipa3_ctx->is_ssr, 0);
2502 return ret;
2503}
2504
2505static int ipa3_wwan_remove(struct platform_device *pdev)
2506{
2507 int ret;
2508
2509 pr_info("rmnet_ipa started deinitialization\n");
Ghanim Fodic6b67492017-03-15 14:19:56 +02002510 mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
Amir Levy9659e592016-10-27 18:08:27 +03002511 ret = ipa3_teardown_sys_pipe(rmnet_ipa3_ctx->ipa3_to_apps_hdl);
2512 if (ret < 0)
2513 IPAWANERR("Failed to teardown IPA->APPS pipe\n");
2514 else
2515 rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
Ghanim Fodic6b67492017-03-15 14:19:56 +02002516 ret = ipa3_teardown_sys_pipe(rmnet_ipa3_ctx->apps_to_ipa3_hdl);
2517 if (ret < 0)
2518 IPAWANERR("Failed to teardown APPS->IPA pipe\n");
2519 else
2520 rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
Amir Levy9659e592016-10-27 18:08:27 +03002521 if (ipa3_rmnet_res.ipa_napi_enable)
2522 netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
Ghanim Fodic6b67492017-03-15 14:19:56 +02002523 mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
Amir Levy9659e592016-10-27 18:08:27 +03002524 unregister_netdev(IPA_NETDEV());
Michael Adisumarta3e350812017-09-18 14:54:36 -07002525 if (ipa3_ctx->use_ipa_pm)
2526 ipa3_wwan_deregister_netdev_pm_client();
2527 else
2528 ipa3_wwan_delete_wwan_rm_resource();
Amir Levy9659e592016-10-27 18:08:27 +03002529 cancel_work_sync(&ipa3_tx_wakequeue_work);
2530 cancel_delayed_work(&ipa_tether_stats_poll_wakequeue_work);
2531 if (IPA_NETDEV())
2532 free_netdev(IPA_NETDEV());
2533 rmnet_ipa3_ctx->wwan_priv = NULL;
2534 /* No need to remove wwan_ioctl during SSR */
2535 if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
2536 ipa3_wan_ioctl_deinit();
2537 ipa3_del_dflt_wan_rt_tables();
2538 ipa3_del_a7_qmap_hdr();
2539 ipa3_del_mux_qmap_hdrs();
2540 if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false)
2541 ipa3_wwan_del_ul_flt_rule_to_ipa();
2542 ipa3_cleanup_deregister_intf();
2543 atomic_set(&rmnet_ipa3_ctx->is_initialized, 0);
2544 pr_info("rmnet_ipa completed deinitialization\n");
2545 return 0;
2546}
2547
2548/**
2549* rmnet_ipa_ap_suspend() - suspend callback for runtime_pm
2550* @dev: pointer to device
2551*
2552* This callback will be invoked by the runtime_pm framework when an AP suspend
2553* operation is invoked, usually by pressing a suspend button.
2554*
2555* Returns -EAGAIN to runtime_pm framework in case there are pending packets
2556* in the Tx queue. This will postpone the suspend operation until all the
2557* pending packets will be transmitted.
2558*
2559* In case there are no packets to send, releases the WWAN0_PROD entity.
2560* As an outcome, the number of IPA active clients should be decremented
2561* until IPA clocks can be gated.
2562*/
2563static int rmnet_ipa_ap_suspend(struct device *dev)
2564{
2565 struct net_device *netdev = IPA_NETDEV();
2566 struct ipa3_wwan_private *wwan_ptr;
Skylar Chang24a6cc12017-04-10 14:59:40 -07002567 int ret;
Amir Levy9659e592016-10-27 18:08:27 +03002568
Skylar Chang24a6cc12017-04-10 14:59:40 -07002569 IPAWANDBG("Enter...\n");
2570
Amir Levy9659e592016-10-27 18:08:27 +03002571 if (netdev == NULL) {
2572 IPAWANERR("netdev is NULL.\n");
Skylar Chang24a6cc12017-04-10 14:59:40 -07002573 ret = 0;
2574 goto bail;
Amir Levy9659e592016-10-27 18:08:27 +03002575 }
2576
Skylar Chang24a6cc12017-04-10 14:59:40 -07002577 netif_tx_lock_bh(netdev);
Amir Levy9659e592016-10-27 18:08:27 +03002578 wwan_ptr = netdev_priv(netdev);
2579 if (wwan_ptr == NULL) {
2580 IPAWANERR("wwan_ptr is NULL.\n");
Skylar Chang24a6cc12017-04-10 14:59:40 -07002581 ret = 0;
Michael Adisumarta3e350812017-09-18 14:54:36 -07002582 netif_tx_unlock_bh(netdev);
2583 goto bail;
Amir Levy9659e592016-10-27 18:08:27 +03002584 }
2585
2586 /* Do not allow A7 to suspend in case there are oustanding packets */
2587 if (atomic_read(&wwan_ptr->outstanding_pkts) != 0) {
2588 IPAWANDBG("Outstanding packets, postponing AP suspend.\n");
Skylar Chang24a6cc12017-04-10 14:59:40 -07002589 ret = -EAGAIN;
Michael Adisumarta3e350812017-09-18 14:54:36 -07002590 netif_tx_unlock_bh(netdev);
2591 goto bail;
Amir Levy9659e592016-10-27 18:08:27 +03002592 }
2593
2594 /* Make sure that there is no Tx operation ongoing */
Skylar Chang24a6cc12017-04-10 14:59:40 -07002595 netif_stop_queue(netdev);
Skylar Chang24a6cc12017-04-10 14:59:40 -07002596 netif_tx_unlock_bh(netdev);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002597 if (ipa3_ctx->use_ipa_pm)
2598 ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
2599 else
2600 ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
2601 ret = 0;
Skylar Chang24a6cc12017-04-10 14:59:40 -07002602bail:
2603 IPAWANDBG("Exit with %d\n", ret);
2604 return ret;
Amir Levy9659e592016-10-27 18:08:27 +03002605}
2606
2607/**
2608* rmnet_ipa_ap_resume() - resume callback for runtime_pm
2609* @dev: pointer to device
2610*
2611* This callback will be invoked by the runtime_pm framework when an AP resume
2612* operation is invoked.
2613*
2614* Enables the network interface queue and returns success to the
2615* runtime_pm framework.
2616*/
2617static int rmnet_ipa_ap_resume(struct device *dev)
2618{
2619 struct net_device *netdev = IPA_NETDEV();
2620
Skylar Chang24a6cc12017-04-10 14:59:40 -07002621 IPAWANDBG("Enter...\n");
Amir Levy9659e592016-10-27 18:08:27 +03002622 if (netdev)
2623 netif_wake_queue(netdev);
Skylar Chang24a6cc12017-04-10 14:59:40 -07002624 IPAWANDBG("Exit\n");
Amir Levy9659e592016-10-27 18:08:27 +03002625
2626 return 0;
2627}
2628
2629static void ipa_stop_polling_stats(void)
2630{
2631 cancel_delayed_work(&ipa_tether_stats_poll_wakequeue_work);
2632 ipa3_rmnet_ctx.polling_interval = 0;
2633}
2634
2635static const struct of_device_id rmnet_ipa_dt_match[] = {
2636 {.compatible = "qcom,rmnet-ipa3"},
2637 {},
2638};
2639MODULE_DEVICE_TABLE(of, rmnet_ipa_dt_match);
2640
2641static const struct dev_pm_ops rmnet_ipa_pm_ops = {
2642 .suspend_noirq = rmnet_ipa_ap_suspend,
2643 .resume_noirq = rmnet_ipa_ap_resume,
2644};
2645
2646static struct platform_driver rmnet_ipa_driver = {
2647 .driver = {
2648 .name = "rmnet_ipa3",
2649 .owner = THIS_MODULE,
2650 .pm = &rmnet_ipa_pm_ops,
2651 .of_match_table = rmnet_ipa_dt_match,
2652 },
2653 .probe = ipa3_wwan_probe,
2654 .remove = ipa3_wwan_remove,
2655};
2656
Skylar Chang09e0e252017-03-20 14:51:29 -07002657/**
2658 * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification
2659 *
2660 * This function sends the SSR notification before modem shutdown and
2661 * after_powerup from SSR framework, to user-space module
2662 */
2663static void rmnet_ipa_send_ssr_notification(bool ssr_done)
2664{
2665 struct ipa_msg_meta msg_meta;
2666 int rc;
2667
2668 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
2669 if (ssr_done)
2670 msg_meta.msg_type = IPA_SSR_AFTER_POWERUP;
2671 else
2672 msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN;
2673 rc = ipa_send_msg(&msg_meta, NULL, NULL);
2674 if (rc) {
2675 IPAWANERR("ipa_send_msg failed: %d\n", rc);
2676 return;
2677 }
2678}
2679
Amir Levy9659e592016-10-27 18:08:27 +03002680static int ipa3_ssr_notifier_cb(struct notifier_block *this,
2681 unsigned long code,
2682 void *data)
2683{
2684 if (!ipa3_rmnet_ctx.ipa_rmnet_ssr)
2685 return NOTIFY_DONE;
2686
2687 switch (code) {
2688 case SUBSYS_BEFORE_SHUTDOWN:
2689 IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n");
Skylar Chang09e0e252017-03-20 14:51:29 -07002690 /* send SSR before-shutdown notification to IPACM */
2691 rmnet_ipa_send_ssr_notification(false);
Amir Levy9659e592016-10-27 18:08:27 +03002692 atomic_set(&rmnet_ipa3_ctx->is_ssr, 1);
2693 ipa3_q6_pre_shutdown_cleanup();
2694 if (IPA_NETDEV())
2695 netif_stop_queue(IPA_NETDEV());
2696 ipa3_qmi_stop_workqueues();
2697 ipa3_wan_ioctl_stop_qmi_messages();
2698 ipa_stop_polling_stats();
2699 if (atomic_read(&rmnet_ipa3_ctx->is_initialized))
2700 platform_driver_unregister(&rmnet_ipa_driver);
2701 IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
2702 break;
2703 case SUBSYS_AFTER_SHUTDOWN:
2704 IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n");
2705 if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
2706 ipa3_q6_post_shutdown_cleanup();
2707 IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
2708 break;
2709 case SUBSYS_BEFORE_POWERUP:
2710 IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n");
2711 if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
2712 /* clean up cached QMI msg/handlers */
2713 ipa3_qmi_service_exit();
2714 /*hold a proxy vote for the modem*/
2715 ipa3_proxy_clk_vote();
Skylar Change1209942017-02-02 14:26:38 -08002716 ipa3_reset_freeze_vote();
Amir Levy9659e592016-10-27 18:08:27 +03002717 IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
2718 break;
2719 case SUBSYS_AFTER_POWERUP:
2720 IPAWANINFO("%s:%d IPA received MPSS AFTER_POWERUP\n",
2721 __func__, __LINE__);
2722 if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) &&
2723 atomic_read(&rmnet_ipa3_ctx->is_ssr))
2724 platform_driver_register(&rmnet_ipa_driver);
2725
2726 IPAWANINFO("IPA AFTER_POWERUP handling is complete\n");
2727 break;
2728 default:
2729 IPAWANDBG("Unsupported subsys notification, IPA received: %lu",
2730 code);
2731 break;
2732 }
2733
2734 IPAWANDBG_LOW("Exit\n");
2735 return NOTIFY_DONE;
2736}
2737
2738/**
2739 * rmnet_ipa_free_msg() - Free the msg sent to user space via ipa_send_msg
2740 * @buff: pointer to buffer containing the message
2741 * @len: message len
2742 * @type: message type
2743 *
2744 * This function is invoked when ipa_send_msg is complete (Provided as a
2745 * free function pointer along with the message).
2746 */
2747static void rmnet_ipa_free_msg(void *buff, u32 len, u32 type)
2748{
2749 if (!buff) {
2750 IPAWANERR("Null buffer\n");
2751 return;
2752 }
2753
2754 if (type != IPA_TETHERING_STATS_UPDATE_STATS &&
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05302755 type != IPA_TETHERING_STATS_UPDATE_NETWORK_STATS &&
2756 type != IPA_PER_CLIENT_STATS_CONNECT_EVENT &&
2757 type != IPA_PER_CLIENT_STATS_DISCONNECT_EVENT) {
Amir Levy9659e592016-10-27 18:08:27 +03002758 IPAWANERR("Wrong type given. buff %p type %d\n",
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05302759 buff, type);
Amir Levy9659e592016-10-27 18:08:27 +03002760 }
2761 kfree(buff);
2762}
2763
2764/**
2765 * rmnet_ipa_get_stats_and_update() - Gets pipe stats from Modem
2766 *
2767 * This function queries the IPA Modem driver for the pipe stats
2768 * via QMI, and updates the user space IPA entity.
2769 */
2770static void rmnet_ipa_get_stats_and_update(void)
2771{
2772 struct ipa_get_data_stats_req_msg_v01 req;
2773 struct ipa_get_data_stats_resp_msg_v01 *resp;
2774 struct ipa_msg_meta msg_meta;
2775 int rc;
2776
2777 resp = kzalloc(sizeof(struct ipa_get_data_stats_resp_msg_v01),
2778 GFP_KERNEL);
2779 if (!resp) {
2780 IPAWANERR("Can't allocate memory for stats message\n");
2781 return;
2782 }
2783
2784 memset(&req, 0, sizeof(struct ipa_get_data_stats_req_msg_v01));
2785 memset(resp, 0, sizeof(struct ipa_get_data_stats_resp_msg_v01));
2786
2787 req.ipa_stats_type = QMI_IPA_STATS_TYPE_PIPE_V01;
2788
2789 rc = ipa3_qmi_get_data_stats(&req, resp);
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002790 if (rc) {
2791 IPAWANERR("ipa3_qmi_get_data_stats failed: %d\n", rc);
2792 kfree(resp);
2793 return;
2794 }
Amir Levy9659e592016-10-27 18:08:27 +03002795
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002796 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
2797 msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_STATS;
2798 msg_meta.msg_len = sizeof(struct ipa_get_data_stats_resp_msg_v01);
2799 rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg);
2800 if (rc) {
2801 IPAWANERR("ipa_send_msg failed: %d\n", rc);
2802 kfree(resp);
2803 return;
Amir Levy9659e592016-10-27 18:08:27 +03002804 }
2805}
2806
2807/**
2808 * tethering_stats_poll_queue() - Stats polling function
2809 * @work - Work entry
2810 *
2811 * This function is scheduled periodically (per the interval) in
2812 * order to poll the IPA Modem driver for the pipe stats.
2813 */
2814static void tethering_stats_poll_queue(struct work_struct *work)
2815{
2816 rmnet_ipa_get_stats_and_update();
2817
2818 /* Schedule again only if there's an active polling interval */
2819 if (ipa3_rmnet_ctx.polling_interval != 0)
2820 schedule_delayed_work(&ipa_tether_stats_poll_wakequeue_work,
2821 msecs_to_jiffies(ipa3_rmnet_ctx.polling_interval*1000));
2822}
2823
2824/**
2825 * rmnet_ipa_get_network_stats_and_update() - Get network stats from IPA Modem
2826 *
2827 * This function retrieves the data usage (used quota) from the IPA Modem driver
2828 * via QMI, and updates IPA user space entity.
2829 */
2830static void rmnet_ipa_get_network_stats_and_update(void)
2831{
2832 struct ipa_get_apn_data_stats_req_msg_v01 req;
2833 struct ipa_get_apn_data_stats_resp_msg_v01 *resp;
2834 struct ipa_msg_meta msg_meta;
2835 int rc;
2836
2837 resp = kzalloc(sizeof(struct ipa_get_apn_data_stats_resp_msg_v01),
2838 GFP_KERNEL);
2839 if (!resp) {
2840 IPAWANERR("Can't allocate memory for network stats message\n");
2841 return;
2842 }
2843
2844 memset(&req, 0, sizeof(struct ipa_get_apn_data_stats_req_msg_v01));
2845 memset(resp, 0, sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
2846
2847 req.mux_id_list_valid = true;
2848 req.mux_id_list_len = 1;
2849 req.mux_id_list[0] = ipa3_rmnet_ctx.metered_mux_id;
2850
2851 rc = ipa3_qmi_get_network_stats(&req, resp);
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002852 if (rc) {
2853 IPAWANERR("ipa3_qmi_get_network_stats failed: %d\n", rc);
2854 kfree(resp);
2855 return;
2856 }
Amir Levy9659e592016-10-27 18:08:27 +03002857
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002858 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
2859 msg_meta.msg_type = IPA_TETHERING_STATS_UPDATE_NETWORK_STATS;
2860 msg_meta.msg_len = sizeof(struct ipa_get_apn_data_stats_resp_msg_v01);
2861 rc = ipa_send_msg(&msg_meta, resp, rmnet_ipa_free_msg);
2862 if (rc) {
2863 IPAWANERR("ipa_send_msg failed: %d\n", rc);
2864 kfree(resp);
2865 return;
Amir Levy9659e592016-10-27 18:08:27 +03002866 }
2867}
2868
2869/**
Skylar Chang09e0e252017-03-20 14:51:29 -07002870 * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from
2871 * IPA Modem
2872 * This function sends the quota_reach indication from the IPA Modem driver
2873 * via QMI, to user-space module
2874 */
2875static void rmnet_ipa_send_quota_reach_ind(void)
2876{
2877 struct ipa_msg_meta msg_meta;
2878 int rc;
2879
2880 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
2881 msg_meta.msg_type = IPA_QUOTA_REACH;
2882 rc = ipa_send_msg(&msg_meta, NULL, NULL);
2883 if (rc) {
2884 IPAWANERR("ipa_send_msg failed: %d\n", rc);
2885 return;
2886 }
2887}
2888
2889/**
Amir Levy9659e592016-10-27 18:08:27 +03002890 * rmnet_ipa3_poll_tethering_stats() - Tethering stats polling IOCTL handler
2891 * @data - IOCTL data
2892 *
2893 * This function handles WAN_IOC_POLL_TETHERING_STATS.
2894 * In case polling interval received is 0, polling will stop
2895 * (If there's a polling in progress, it will allow it to finish), and then will
2896 * fetch network stats, and update the IPA user space.
2897 *
2898 * Return codes:
2899 * 0: Success
2900 */
2901int rmnet_ipa3_poll_tethering_stats(struct wan_ioctl_poll_tethering_stats *data)
2902{
2903 ipa3_rmnet_ctx.polling_interval = data->polling_interval_secs;
2904
2905 cancel_delayed_work_sync(&ipa_tether_stats_poll_wakequeue_work);
2906
2907 if (ipa3_rmnet_ctx.polling_interval == 0) {
2908 ipa3_qmi_stop_data_qouta();
2909 rmnet_ipa_get_network_stats_and_update();
2910 rmnet_ipa_get_stats_and_update();
2911 return 0;
2912 }
2913
2914 schedule_delayed_work(&ipa_tether_stats_poll_wakequeue_work, 0);
2915 return 0;
2916}
2917
2918/**
Skylar Chang6b41f8d2016-11-01 12:50:11 -07002919 * rmnet_ipa_set_data_quota_modem() - Data quota setting IOCTL handler
Amir Levy9659e592016-10-27 18:08:27 +03002920 * @data - IOCTL data
2921 *
Skylar Chang6b41f8d2016-11-01 12:50:11 -07002922 * This function handles WAN_IOC_SET_DATA_QUOTA on modem interface.
Amir Levy9659e592016-10-27 18:08:27 +03002923 * It translates the given interface name to the Modem MUX ID and
2924 * sends the request of the quota to the IPA Modem driver via QMI.
2925 *
2926 * Return codes:
2927 * 0: Success
2928 * -EFAULT: Invalid interface name provided
2929 * other: See ipa_qmi_set_data_quota
2930 */
Skylar Chang6b41f8d2016-11-01 12:50:11 -07002931static int rmnet_ipa3_set_data_quota_modem(
2932 struct wan_ioctl_set_data_quota *data)
Amir Levy9659e592016-10-27 18:08:27 +03002933{
2934 u32 mux_id;
2935 int index;
2936 struct ipa_set_data_usage_quota_req_msg_v01 req;
2937
Skylar Chang6b41f8d2016-11-01 12:50:11 -07002938 /* stop quota */
2939 if (!data->set_quota)
2940 ipa3_qmi_stop_data_qouta();
2941
Skylar Changcde17ed2017-06-21 16:51:26 -07002942 /* prevent string buffer overflows */
2943 data->interface_name[IFNAMSIZ-1] = '\0';
2944
Amir Levy9659e592016-10-27 18:08:27 +03002945 index = find_vchannel_name_index(data->interface_name);
2946 IPAWANERR("iface name %s, quota %lu\n",
2947 data->interface_name,
2948 (unsigned long int) data->quota_mbytes);
2949
2950 if (index == MAX_NUM_OF_MUX_CHANNEL) {
2951 IPAWANERR("%s is an invalid iface name\n",
2952 data->interface_name);
2953 return -EFAULT;
2954 }
2955
2956 mux_id = rmnet_ipa3_ctx->mux_channel[index].mux_id;
2957 ipa3_rmnet_ctx.metered_mux_id = mux_id;
2958
2959 memset(&req, 0, sizeof(struct ipa_set_data_usage_quota_req_msg_v01));
2960 req.apn_quota_list_valid = true;
2961 req.apn_quota_list_len = 1;
2962 req.apn_quota_list[0].mux_id = mux_id;
2963 req.apn_quota_list[0].num_Mbytes = data->quota_mbytes;
2964
2965 return ipa3_qmi_set_data_quota(&req);
2966}
2967
Skylar Chang6b41f8d2016-11-01 12:50:11 -07002968static int rmnet_ipa3_set_data_quota_wifi(struct wan_ioctl_set_data_quota *data)
2969{
2970 struct ipa_set_wifi_quota wifi_quota;
2971 int rc = 0;
2972
2973 memset(&wifi_quota, 0, sizeof(struct ipa_set_wifi_quota));
2974 wifi_quota.set_quota = data->set_quota;
2975 wifi_quota.quota_bytes = data->quota_mbytes;
2976 IPAWANERR("iface name %s, quota %lu\n",
2977 data->interface_name,
2978 (unsigned long int) data->quota_mbytes);
2979
2980 rc = ipa3_set_wlan_quota(&wifi_quota);
2981 /* check if wlan-fw takes this quota-set */
2982 if (!wifi_quota.set_valid)
2983 rc = -EFAULT;
2984 return rc;
2985}
2986
2987/**
2988 * rmnet_ipa_set_data_quota() - Data quota setting IOCTL handler
2989 * @data - IOCTL data
2990 *
2991 * This function handles WAN_IOC_SET_DATA_QUOTA.
2992 * It translates the given interface name to the Modem MUX ID and
2993 * sends the request of the quota to the IPA Modem driver via QMI.
2994 *
2995 * Return codes:
2996 * 0: Success
2997 * -EFAULT: Invalid interface name provided
2998 * other: See ipa_qmi_set_data_quota
2999 */
3000int rmnet_ipa3_set_data_quota(struct wan_ioctl_set_data_quota *data)
3001{
3002 enum ipa_upstream_type upstream_type;
3003 int rc = 0;
3004
Mohammed Javidbba17b32017-09-26 12:51:14 +05303005 /* prevent string buffer overflows */
3006 data->interface_name[IFNAMSIZ-1] = '\0';
3007
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003008 /* get IPA backhaul type */
3009 upstream_type = find_upstream_type(data->interface_name);
3010
3011 if (upstream_type == IPA_UPSTEAM_MAX) {
3012 IPAWANERR("Wrong interface_name name %s\n",
3013 data->interface_name);
3014 } else if (upstream_type == IPA_UPSTEAM_WLAN) {
3015 rc = rmnet_ipa3_set_data_quota_wifi(data);
3016 if (rc) {
3017 IPAWANERR("set quota on wifi failed\n");
3018 return rc;
3019 }
3020 } else {
3021 rc = rmnet_ipa3_set_data_quota_modem(data);
3022 if (rc) {
3023 IPAWANERR("set quota on modem failed\n");
3024 return rc;
3025 }
3026 }
3027 return rc;
3028}
Amir Levy9659e592016-10-27 18:08:27 +03003029 /* rmnet_ipa_set_tether_client_pipe() -
3030 * @data - IOCTL data
3031 *
3032 * This function handles WAN_IOC_SET_DATA_QUOTA.
3033 * It translates the given interface name to the Modem MUX ID and
3034 * sends the request of the quota to the IPA Modem driver via QMI.
3035 *
3036 * Return codes:
3037 * 0: Success
3038 * -EFAULT: Invalid interface name provided
3039 * other: See ipa_qmi_set_data_quota
3040 */
3041int rmnet_ipa3_set_tether_client_pipe(
3042 struct wan_ioctl_set_tether_client_pipe *data)
3043{
3044 int number, i;
3045
Skylar Chang345c8142016-11-30 14:41:24 -08003046 /* error checking if ul_src_pipe_len valid or not*/
3047 if (data->ul_src_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
3048 data->ul_src_pipe_len < 0) {
3049 IPAWANERR("UL src pipes %d exceeding max %d\n",
3050 data->ul_src_pipe_len,
3051 QMI_IPA_MAX_PIPES_V01);
3052 return -EFAULT;
3053 }
3054 /* error checking if dl_dst_pipe_len valid or not*/
3055 if (data->dl_dst_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
3056 data->dl_dst_pipe_len < 0) {
3057 IPAWANERR("DL dst pipes %d exceeding max %d\n",
3058 data->dl_dst_pipe_len,
3059 QMI_IPA_MAX_PIPES_V01);
3060 return -EFAULT;
3061 }
3062
Amir Levy9659e592016-10-27 18:08:27 +03003063 IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
3064 data->ipa_client,
3065 data->ul_src_pipe_len,
3066 data->dl_dst_pipe_len,
3067 data->reset_client);
3068 number = data->ul_src_pipe_len;
3069 for (i = 0; i < number; i++) {
3070 IPAWANDBG("UL index-%d pipe %d\n", i,
3071 data->ul_src_pipe_list[i]);
3072 if (data->reset_client)
3073 ipa3_set_client(data->ul_src_pipe_list[i],
3074 0, false);
3075 else
3076 ipa3_set_client(data->ul_src_pipe_list[i],
3077 data->ipa_client, true);
3078 }
3079 number = data->dl_dst_pipe_len;
3080 for (i = 0; i < number; i++) {
3081 IPAWANDBG("DL index-%d pipe %d\n", i,
3082 data->dl_dst_pipe_list[i]);
3083 if (data->reset_client)
3084 ipa3_set_client(data->dl_dst_pipe_list[i],
3085 0, false);
3086 else
3087 ipa3_set_client(data->dl_dst_pipe_list[i],
3088 data->ipa_client, false);
3089 }
3090 return 0;
3091}
3092
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003093static int rmnet_ipa3_query_tethering_stats_wifi(
3094 struct wan_ioctl_query_tether_stats *data, bool reset)
3095{
3096 struct ipa_get_wdi_sap_stats *sap_stats;
3097 int rc;
3098
3099 sap_stats = kzalloc(sizeof(struct ipa_get_wdi_sap_stats),
3100 GFP_KERNEL);
3101 if (!sap_stats) {
3102 IPAWANERR("Can't allocate memory for stats message\n");
3103 return -ENOMEM;
3104 }
3105 memset(sap_stats, 0, sizeof(struct ipa_get_wdi_sap_stats));
3106
3107 sap_stats->reset_stats = reset;
3108 IPAWANDBG("reset the pipe stats %d\n", sap_stats->reset_stats);
3109
3110 rc = ipa3_get_wlan_stats(sap_stats);
3111 if (rc) {
3112 IPAWANERR("can't get ipa3_get_wlan_stats\n");
3113 kfree(sap_stats);
3114 return rc;
3115 } else if (reset) {
3116 kfree(sap_stats);
3117 return 0;
3118 }
3119
3120 if (sap_stats->stats_valid) {
3121 data->ipv4_tx_packets = sap_stats->ipv4_tx_packets;
3122 data->ipv4_tx_bytes = sap_stats->ipv4_tx_bytes;
3123 data->ipv4_rx_packets = sap_stats->ipv4_rx_packets;
3124 data->ipv4_rx_bytes = sap_stats->ipv4_rx_bytes;
3125 data->ipv6_tx_packets = sap_stats->ipv6_tx_packets;
3126 data->ipv6_tx_bytes = sap_stats->ipv6_tx_bytes;
3127 data->ipv6_rx_packets = sap_stats->ipv6_rx_packets;
3128 data->ipv6_rx_bytes = sap_stats->ipv6_rx_bytes;
3129 }
3130
3131 IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n",
3132 (unsigned long int) data->ipv4_rx_packets,
3133 (unsigned long int) data->ipv6_rx_packets,
3134 (unsigned long int) data->ipv4_rx_bytes,
3135 (unsigned long int) data->ipv6_rx_bytes);
3136 IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n",
3137 (unsigned long int) data->ipv4_tx_packets,
3138 (unsigned long int) data->ipv6_tx_packets,
3139 (unsigned long int) data->ipv4_tx_bytes,
3140 (unsigned long int) data->ipv6_tx_bytes);
3141
3142 kfree(sap_stats);
3143 return rc;
3144}
3145
3146static int rmnet_ipa3_query_tethering_stats_modem(
3147 struct wan_ioctl_query_tether_stats *data, bool reset)
Amir Levy9659e592016-10-27 18:08:27 +03003148{
3149 struct ipa_get_data_stats_req_msg_v01 *req;
3150 struct ipa_get_data_stats_resp_msg_v01 *resp;
3151 int pipe_len, rc;
3152
3153 req = kzalloc(sizeof(struct ipa_get_data_stats_req_msg_v01),
3154 GFP_KERNEL);
3155 if (!req) {
3156 IPAWANERR("Can't allocate memory for stats message\n");
3157 return -ENOMEM;
3158 }
3159 resp = kzalloc(sizeof(struct ipa_get_data_stats_resp_msg_v01),
3160 GFP_KERNEL);
3161 if (!resp) {
3162 IPAWANERR("Can't allocate memory for stats message\n");
3163 kfree(req);
3164 return -ENOMEM;
3165 }
3166 memset(req, 0, sizeof(struct ipa_get_data_stats_req_msg_v01));
3167 memset(resp, 0, sizeof(struct ipa_get_data_stats_resp_msg_v01));
3168
3169 req->ipa_stats_type = QMI_IPA_STATS_TYPE_PIPE_V01;
3170 if (reset) {
3171 req->reset_stats_valid = true;
3172 req->reset_stats = true;
3173 IPAWANERR("reset the pipe stats\n");
3174 } else {
3175 /* print tethered-client enum */
Skylar Chang09e0e252017-03-20 14:51:29 -07003176 IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client);
Amir Levy9659e592016-10-27 18:08:27 +03003177 }
3178
3179 rc = ipa3_qmi_get_data_stats(req, resp);
3180 if (rc) {
3181 IPAWANERR("can't get ipa_qmi_get_data_stats\n");
3182 kfree(req);
3183 kfree(resp);
3184 return rc;
Mohammed Javid2cee34a2017-06-14 12:40:34 +05303185 } else if (data == NULL) {
3186 kfree(req);
3187 kfree(resp);
3188 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03003189 }
3190
3191 if (resp->dl_dst_pipe_stats_list_valid) {
3192 for (pipe_len = 0; pipe_len < resp->dl_dst_pipe_stats_list_len;
3193 pipe_len++) {
3194 IPAWANDBG_LOW("Check entry(%d) dl_dst_pipe(%d)\n",
3195 pipe_len, resp->dl_dst_pipe_stats_list
3196 [pipe_len].pipe_index);
3197 IPAWANDBG_LOW("dl_p_v4(%lu)v6(%lu)\n",
3198 (unsigned long int) resp->
3199 dl_dst_pipe_stats_list[pipe_len].
3200 num_ipv4_packets,
3201 (unsigned long int) resp->
3202 dl_dst_pipe_stats_list[pipe_len].
3203 num_ipv6_packets);
3204 IPAWANDBG_LOW("dl_b_v4(%lu)v6(%lu)\n",
3205 (unsigned long int) resp->
3206 dl_dst_pipe_stats_list[pipe_len].
3207 num_ipv4_bytes,
3208 (unsigned long int) resp->
3209 dl_dst_pipe_stats_list[pipe_len].
3210 num_ipv6_bytes);
3211 if (ipa_get_client_uplink(resp->
3212 dl_dst_pipe_stats_list[pipe_len].
3213 pipe_index) == false) {
3214 if (data->ipa_client == ipa_get_client(resp->
3215 dl_dst_pipe_stats_list[pipe_len].
3216 pipe_index)) {
3217 /* update the DL stats */
3218 data->ipv4_rx_packets += resp->
3219 dl_dst_pipe_stats_list[pipe_len].
3220 num_ipv4_packets;
3221 data->ipv6_rx_packets += resp->
3222 dl_dst_pipe_stats_list[pipe_len].
3223 num_ipv6_packets;
3224 data->ipv4_rx_bytes += resp->
3225 dl_dst_pipe_stats_list[pipe_len].
3226 num_ipv4_bytes;
3227 data->ipv6_rx_bytes += resp->
3228 dl_dst_pipe_stats_list[pipe_len].
3229 num_ipv6_bytes;
3230 }
3231 }
3232 }
3233 }
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003234 IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n",
Amir Levy9659e592016-10-27 18:08:27 +03003235 (unsigned long int) data->ipv4_rx_packets,
3236 (unsigned long int) data->ipv6_rx_packets,
3237 (unsigned long int) data->ipv4_rx_bytes,
3238 (unsigned long int) data->ipv6_rx_bytes);
3239
3240 if (resp->ul_src_pipe_stats_list_valid) {
3241 for (pipe_len = 0; pipe_len < resp->ul_src_pipe_stats_list_len;
3242 pipe_len++) {
3243 IPAWANDBG_LOW("Check entry(%d) ul_dst_pipe(%d)\n",
3244 pipe_len,
3245 resp->ul_src_pipe_stats_list[pipe_len].
3246 pipe_index);
3247 IPAWANDBG_LOW("ul_p_v4(%lu)v6(%lu)\n",
3248 (unsigned long int) resp->
3249 ul_src_pipe_stats_list[pipe_len].
3250 num_ipv4_packets,
3251 (unsigned long int) resp->
3252 ul_src_pipe_stats_list[pipe_len].
3253 num_ipv6_packets);
3254 IPAWANDBG_LOW("ul_b_v4(%lu)v6(%lu)\n",
3255 (unsigned long int) resp->
3256 ul_src_pipe_stats_list[pipe_len].
3257 num_ipv4_bytes,
3258 (unsigned long int) resp->
3259 ul_src_pipe_stats_list[pipe_len].
3260 num_ipv6_bytes);
3261 if (ipa_get_client_uplink(resp->
3262 ul_src_pipe_stats_list[pipe_len].
3263 pipe_index) == true) {
3264 if (data->ipa_client == ipa_get_client(resp->
3265 ul_src_pipe_stats_list[pipe_len].
3266 pipe_index)) {
3267 /* update the DL stats */
3268 data->ipv4_tx_packets += resp->
3269 ul_src_pipe_stats_list[pipe_len].
3270 num_ipv4_packets;
3271 data->ipv6_tx_packets += resp->
3272 ul_src_pipe_stats_list[pipe_len].
3273 num_ipv6_packets;
3274 data->ipv4_tx_bytes += resp->
3275 ul_src_pipe_stats_list[pipe_len].
3276 num_ipv4_bytes;
3277 data->ipv6_tx_bytes += resp->
3278 ul_src_pipe_stats_list[pipe_len].
3279 num_ipv6_bytes;
3280 }
3281 }
3282 }
3283 }
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003284 IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n",
Amir Levy9659e592016-10-27 18:08:27 +03003285 (unsigned long int) data->ipv4_tx_packets,
3286 (unsigned long int) data->ipv6_tx_packets,
3287 (unsigned long int) data->ipv4_tx_bytes,
3288 (unsigned long int) data->ipv6_tx_bytes);
3289 kfree(req);
3290 kfree(resp);
3291 return 0;
3292}
3293
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003294int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
3295 bool reset)
3296{
3297 enum ipa_upstream_type upstream_type;
3298 int rc = 0;
3299
Mohammed Javidbba17b32017-09-26 12:51:14 +05303300 /* prevent string buffer overflows */
3301 data->upstreamIface[IFNAMSIZ-1] = '\0';
3302 data->tetherIface[IFNAMSIZ-1] = '\0';
3303
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003304 /* get IPA backhaul type */
3305 upstream_type = find_upstream_type(data->upstreamIface);
3306
3307 if (upstream_type == IPA_UPSTEAM_MAX) {
3308 IPAWANERR(" Wrong upstreamIface name %s\n",
3309 data->upstreamIface);
3310 } else if (upstream_type == IPA_UPSTEAM_WLAN) {
3311 IPAWANDBG_LOW(" query wifi-backhaul stats\n");
3312 rc = rmnet_ipa3_query_tethering_stats_wifi(
3313 data, false);
3314 if (rc) {
3315 IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n");
3316 return rc;
3317 }
3318 } else {
3319 IPAWANDBG_LOW(" query modem-backhaul stats\n");
3320 rc = rmnet_ipa3_query_tethering_stats_modem(
3321 data, false);
3322 if (rc) {
3323 IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n");
3324 return rc;
3325 }
3326 }
3327 return rc;
3328}
3329
Skylar Chang09e0e252017-03-20 14:51:29 -07003330int rmnet_ipa3_query_tethering_stats_all(
3331 struct wan_ioctl_query_tether_stats_all *data)
3332{
3333 struct wan_ioctl_query_tether_stats tether_stats;
3334 enum ipa_upstream_type upstream_type;
3335 int rc = 0;
3336
3337 memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
Mohammed Javidbba17b32017-09-26 12:51:14 +05303338
3339 /* prevent string buffer overflows */
3340 data->upstreamIface[IFNAMSIZ-1] = '\0';
3341
Skylar Chang09e0e252017-03-20 14:51:29 -07003342 /* get IPA backhaul type */
3343 upstream_type = find_upstream_type(data->upstreamIface);
3344
3345 if (upstream_type == IPA_UPSTEAM_MAX) {
3346 IPAWANERR(" Wrong upstreamIface name %s\n",
3347 data->upstreamIface);
3348 } else if (upstream_type == IPA_UPSTEAM_WLAN) {
3349 IPAWANDBG_LOW(" query wifi-backhaul stats\n");
3350 rc = rmnet_ipa3_query_tethering_stats_wifi(
3351 &tether_stats, data->reset_stats);
3352 if (rc) {
3353 IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n");
3354 return rc;
3355 }
3356 data->tx_bytes = tether_stats.ipv4_tx_bytes
3357 + tether_stats.ipv6_tx_bytes;
3358 data->rx_bytes = tether_stats.ipv4_rx_bytes
3359 + tether_stats.ipv6_rx_bytes;
3360 } else {
3361 IPAWANDBG_LOW(" query modem-backhaul stats\n");
3362 tether_stats.ipa_client = data->ipa_client;
3363 rc = rmnet_ipa3_query_tethering_stats_modem(
3364 &tether_stats, data->reset_stats);
3365 if (rc) {
3366 IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n");
3367 return rc;
3368 }
3369 data->tx_bytes = tether_stats.ipv4_tx_bytes
3370 + tether_stats.ipv6_tx_bytes;
3371 data->rx_bytes = tether_stats.ipv4_rx_bytes
3372 + tether_stats.ipv6_rx_bytes;
3373 }
3374 return rc;
3375}
3376
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003377int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
3378{
3379 enum ipa_upstream_type upstream_type;
Mohammed Javid2cee34a2017-06-14 12:40:34 +05303380 struct wan_ioctl_query_tether_stats tether_stats;
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003381 int rc = 0;
3382
Mohammed Javid2cee34a2017-06-14 12:40:34 +05303383 memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
3384
Mohammed Javidbba17b32017-09-26 12:51:14 +05303385 /* prevent string buffer overflows */
3386 data->upstreamIface[IFNAMSIZ-1] = '\0';
3387
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003388 /* get IPA backhaul type */
3389 upstream_type = find_upstream_type(data->upstreamIface);
3390
3391 if (upstream_type == IPA_UPSTEAM_MAX) {
3392 IPAWANERR(" Wrong upstreamIface name %s\n",
3393 data->upstreamIface);
3394 } else if (upstream_type == IPA_UPSTEAM_WLAN) {
3395 IPAWANERR(" reset wifi-backhaul stats\n");
3396 rc = rmnet_ipa3_query_tethering_stats_wifi(
3397 NULL, true);
3398 if (rc) {
3399 IPAWANERR("reset WLAN stats failed\n");
3400 return rc;
3401 }
3402 } else {
3403 IPAWANERR(" reset modem-backhaul stats\n");
3404 rc = rmnet_ipa3_query_tethering_stats_modem(
Mohammed Javid2cee34a2017-06-14 12:40:34 +05303405 &tether_stats, true);
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003406 if (rc) {
3407 IPAWANERR("reset MODEM stats failed\n");
3408 return rc;
3409 }
3410 }
3411 return rc;
3412}
3413
Amir Levy9659e592016-10-27 18:08:27 +03003414/**
3415 * ipa3_broadcast_quota_reach_ind() - Send Netlink broadcast on Quota
3416 * @mux_id - The MUX ID on which the quota has been reached
3417 *
3418 * This function broadcasts a Netlink event using the kobject of the
3419 * rmnet_ipa interface in order to alert the user space that the quota
3420 * on the specific interface which matches the mux_id has been reached.
3421 *
3422 */
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003423void ipa3_broadcast_quota_reach_ind(u32 mux_id,
3424 enum ipa_upstream_type upstream_type)
Amir Levy9659e592016-10-27 18:08:27 +03003425{
3426 char alert_msg[IPA_QUOTA_REACH_ALERT_MAX_SIZE];
3427 char iface_name_m[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
3428 char iface_name_l[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
3429 char *envp[IPA_UEVENT_NUM_EVNP] = {
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003430 alert_msg, iface_name_l, iface_name_m, NULL};
Amir Levy9659e592016-10-27 18:08:27 +03003431 int res;
3432 int index;
3433
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003434 /* check upstream_type*/
3435 if (upstream_type == IPA_UPSTEAM_MAX) {
3436 IPAWANERR(" Wrong upstreamIface type %d\n", upstream_type);
Amir Levy9659e592016-10-27 18:08:27 +03003437 return;
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003438 } else if (upstream_type == IPA_UPSTEAM_MODEM) {
3439 index = ipa3_find_mux_channel_index(mux_id);
3440 if (index == MAX_NUM_OF_MUX_CHANNEL) {
3441 IPAWANERR("%u is an mux ID\n", mux_id);
3442 return;
3443 }
Amir Levy9659e592016-10-27 18:08:27 +03003444 }
Amir Levy9659e592016-10-27 18:08:27 +03003445 res = snprintf(alert_msg, IPA_QUOTA_REACH_ALERT_MAX_SIZE,
3446 "ALERT_NAME=%s", "quotaReachedAlert");
3447 if (res >= IPA_QUOTA_REACH_ALERT_MAX_SIZE) {
3448 IPAWANERR("message too long (%d)", res);
3449 return;
3450 }
3451 /* posting msg for L-release for CNE */
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003452 if (upstream_type == IPA_UPSTEAM_MODEM) {
Amir Levy9659e592016-10-27 18:08:27 +03003453 res = snprintf(iface_name_l, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
3454 "UPSTREAM=%s", rmnet_ipa3_ctx->mux_channel[index].vchannel_name);
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003455 } else {
3456 res = snprintf(iface_name_l, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
3457 "UPSTREAM=%s", IPA_UPSTEAM_WLAN_IFACE_NAME);
3458 }
Amir Levy9659e592016-10-27 18:08:27 +03003459 if (res >= IPA_QUOTA_REACH_IF_NAME_MAX_SIZE) {
3460 IPAWANERR("message too long (%d)", res);
3461 return;
3462 }
3463 /* posting msg for M-release for CNE */
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003464 if (upstream_type == IPA_UPSTEAM_MODEM) {
Amir Levy9659e592016-10-27 18:08:27 +03003465 res = snprintf(iface_name_m, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
3466 "INTERFACE=%s", rmnet_ipa3_ctx->mux_channel[index].vchannel_name);
Skylar Chang6b41f8d2016-11-01 12:50:11 -07003467 } else {
3468 res = snprintf(iface_name_m, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
3469 "INTERFACE=%s", IPA_UPSTEAM_WLAN_IFACE_NAME);
3470 }
Amir Levy9659e592016-10-27 18:08:27 +03003471 if (res >= IPA_QUOTA_REACH_IF_NAME_MAX_SIZE) {
3472 IPAWANERR("message too long (%d)", res);
3473 return;
3474 }
3475
3476 IPAWANERR("putting nlmsg: <%s> <%s> <%s>\n",
3477 alert_msg, iface_name_l, iface_name_m);
3478 kobject_uevent_env(&(IPA_NETDEV()->dev.kobj),
3479 KOBJ_CHANGE, envp);
Skylar Chang09e0e252017-03-20 14:51:29 -07003480
3481 rmnet_ipa_send_quota_reach_ind();
Amir Levy9659e592016-10-27 18:08:27 +03003482}
3483
3484/**
3485 * ipa3_q6_handshake_complete() - Perform operations once Q6 is up
3486 * @ssr_bootup - Indicates whether this is a cold boot-up or post-SSR.
3487 *
3488 * This function is invoked once the handshake between the IPA AP driver
3489 * and IPA Q6 driver is complete. At this point, it is possible to perform
3490 * operations which can't be performed until IPA Q6 driver is up.
3491 *
3492 */
3493void ipa3_q6_handshake_complete(bool ssr_bootup)
3494{
3495 /* It is required to recover the network stats after SSR recovery */
3496 if (ssr_bootup) {
3497 /*
3498 * In case the uC is required to be loaded by the Modem,
3499 * the proxy vote will be removed only when uC loading is
3500 * complete and indication is received by the AP. After SSR,
3501 * uC is already loaded. Therefore, proxy vote can be removed
3502 * once Modem init is complete.
3503 */
3504 ipa3_proxy_clk_unvote();
3505
Skylar Chang09e0e252017-03-20 14:51:29 -07003506 /* send SSR power-up notification to IPACM */
3507 rmnet_ipa_send_ssr_notification(true);
3508
Amir Levy9659e592016-10-27 18:08:27 +03003509 /*
3510 * It is required to recover the network stats after
3511 * SSR recovery
3512 */
3513 rmnet_ipa_get_network_stats_and_update();
3514 }
3515}
3516
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05303517static inline bool rmnet_ipa3_check_any_client_inited
3518(
3519 enum ipacm_per_client_device_type device_type
3520)
3521{
3522 int i = 0;
3523
3524 for (; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
3525 if (rmnet_ipa3_ctx->tether_device[device_type].
3526 lan_client[i].client_idx != -1 &&
3527 rmnet_ipa3_ctx->tether_device[device_type].
3528 lan_client[i].inited) {
3529 IPAWANERR("Found client index: %d which is inited\n",
3530 i);
3531 return true;
3532 }
3533 }
3534
3535 return false;
3536}
3537
3538static inline int rmnet_ipa3_get_lan_client_info
3539(
3540 enum ipacm_per_client_device_type device_type,
3541 uint8_t mac[]
3542)
3543{
3544 int i = 0;
3545
3546 IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
3547 mac[0], mac[1], mac[2],
3548 mac[3], mac[4], mac[5]);
3549
3550 for (; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
3551 if (memcmp(
3552 rmnet_ipa3_ctx->tether_device[device_type].
3553 lan_client[i].mac,
3554 mac,
3555 IPA_MAC_ADDR_SIZE) == 0) {
3556 IPAWANDBG("Matched client index: %d\n", i);
3557 return i;
3558 }
3559 }
3560
3561 return -EINVAL;
3562}
3563
3564static inline int rmnet_ipa3_delete_lan_client_info
3565(
3566 enum ipacm_per_client_device_type device_type,
3567 int lan_clnt_idx
3568)
3569{
3570 struct ipa_lan_client *lan_client = NULL;
3571 int i;
3572
3573 /* Check if the request is to clean up all clients. */
3574 if (lan_clnt_idx == 0xffffffff) {
3575 /* Reset the complete device info. */
3576 memset(&rmnet_ipa3_ctx->tether_device[device_type], 0,
3577 sizeof(struct ipa_tether_device_info));
3578 rmnet_ipa3_ctx->tether_device[device_type].ul_src_pipe = -1;
3579 for (i = 0; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++)
3580 rmnet_ipa3_ctx->tether_device[device_type].
3581 lan_client[i].client_idx = -1;
3582 } else {
3583 lan_client =
3584 &rmnet_ipa3_ctx->tether_device[device_type].
3585 lan_client[lan_clnt_idx];
3586 /* Reset the client info before sending the message. */
3587 memset(lan_client, 0, sizeof(struct ipa_lan_client));
3588 lan_client->client_idx = -1;
3589
3590 }
3591 return 0;
3592}
3593
3594/* rmnet_ipa3_set_lan_client_info() -
3595 * @data - IOCTL data
3596 *
3597 * This function handles WAN_IOC_SET_LAN_CLIENT_INFO.
3598 * It is used to store LAN client information which
3599 * is used to fetch the packet stats for a client.
3600 *
3601 * Return codes:
3602 * 0: Success
3603 * -EINVAL: Invalid args provided
3604 */
3605int rmnet_ipa3_set_lan_client_info(
3606 struct wan_ioctl_lan_client_info *data)
3607{
3608
3609 struct ipa_lan_client *lan_client = NULL;
3610
3611
3612 IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
3613 data->mac[0], data->mac[1], data->mac[2],
3614 data->mac[3], data->mac[4], data->mac[5]);
3615
3616 /* Check if Device type is valid. */
3617 if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
3618 data->device_type < 0) {
3619 IPAWANERR("Invalid Device type: %d\n", data->device_type);
3620 return -EINVAL;
3621 }
3622
3623 /* Check if Client index is valid. */
3624 if (data->client_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS ||
3625 data->client_idx < 0) {
3626 IPAWANERR("Invalid Client Index: %d\n", data->client_idx);
3627 return -EINVAL;
3628 }
3629
3630 mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
3631 if (data->client_init) {
3632 /* check if the client is already inited. */
3633 if (rmnet_ipa3_ctx->tether_device[data->device_type]
3634 .lan_client[data->client_idx].inited) {
3635 IPAWANERR("Client already inited: %d:%d\n",
3636 data->device_type, data->client_idx);
3637 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3638 return -EINVAL;
3639 }
3640 }
3641
3642 lan_client =
3643 &rmnet_ipa3_ctx->tether_device[data->device_type].
3644 lan_client[data->client_idx];
3645
3646 memcpy(lan_client->mac, data->mac, IPA_MAC_ADDR_SIZE);
3647
3648 lan_client->client_idx = data->client_idx;
3649
3650 /* Update the Source pipe. */
3651 rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe =
3652 ipa3_get_ep_mapping(data->ul_src_pipe);
3653
3654 /* Update the header length if not set. */
3655 if (!rmnet_ipa3_ctx->tether_device[data->device_type].hdr_len)
3656 rmnet_ipa3_ctx->tether_device[data->device_type].hdr_len =
3657 data->hdr_len;
3658
3659 lan_client->inited = true;
3660
3661 rmnet_ipa3_ctx->tether_device[data->device_type].num_clients++;
3662
3663 IPAWANDBG("Set the lan client info: %d, %d, %d\n",
3664 lan_client->client_idx,
3665 rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe,
3666 rmnet_ipa3_ctx->tether_device[data->device_type].num_clients);
3667
3668 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3669
3670 return 0;
3671}
3672
3673/* rmnet_ipa3_delete_lan_client_info() -
3674 * @data - IOCTL data
3675 *
3676 * This function handles WAN_IOC_DELETE_LAN_CLIENT_INFO.
3677 * It is used to delete LAN client information which
3678 * is used to fetch the packet stats for a client.
3679 *
3680 * Return codes:
3681 * 0: Success
3682 * -EINVAL: Invalid args provided
3683 */
3684int rmnet_ipa3_clear_lan_client_info(
3685 struct wan_ioctl_lan_client_info *data)
3686{
3687
3688 struct ipa_lan_client *lan_client = NULL;
3689
3690
3691 IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
3692 data->mac[0], data->mac[1], data->mac[2],
3693 data->mac[3], data->mac[4], data->mac[5]);
3694
3695 /* Check if Device type is valid. */
3696 if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
3697 data->device_type < 0) {
3698 IPAWANERR("Invalid Device type: %d\n", data->device_type);
3699 return -EINVAL;
3700 }
3701
3702 /* Check if Client index is valid. */
3703 if (data->client_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS ||
3704 data->client_idx < 0) {
3705 IPAWANERR("Invalid Client Index: %d\n", data->client_idx);
3706 return -EINVAL;
3707 }
3708
3709 mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
3710 lan_client =
3711 &rmnet_ipa3_ctx->tether_device[data->device_type].
3712 lan_client[data->client_idx];
3713
3714 if (!data->client_init) {
3715 /* check if the client is already de-inited. */
3716 if (!lan_client->inited) {
3717 IPAWANERR("Client already de-inited: %d:%d\n",
3718 data->device_type, data->client_idx);
3719 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3720 return -EINVAL;
3721 }
3722 }
3723
3724 lan_client->inited = false;
3725 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3726
3727 return 0;
3728}
3729
3730
3731/* rmnet_ipa3_send_lan_client_msg() -
3732 * @data - IOCTL data
3733 *
3734 * This function handles WAN_IOC_SEND_LAN_CLIENT_MSG.
3735 * It is used to send LAN client information to IPACM.
3736 *
3737 * Return codes:
3738 * 0: Success
3739 * -EINVAL: Invalid args provided
3740 */
3741int rmnet_ipa3_send_lan_client_msg(
3742 struct wan_ioctl_send_lan_client_msg *data)
3743{
3744 struct ipa_msg_meta msg_meta;
3745 int rc;
3746 struct ipa_lan_client_msg *lan_client;
3747
3748 /* Notify IPACM to reset the client index. */
3749 lan_client = kzalloc(sizeof(struct ipa_lan_client_msg),
3750 GFP_KERNEL);
3751 if (!lan_client) {
3752 IPAWANERR("Can't allocate memory for tether_info\n");
3753 return -ENOMEM;
3754 }
3755 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
3756 memcpy(lan_client, &data->lan_client,
3757 sizeof(struct ipa_lan_client_msg));
3758 msg_meta.msg_type = data->client_event;
3759 msg_meta.msg_len = sizeof(struct ipa_lan_client_msg);
3760
3761 rc = ipa_send_msg(&msg_meta, lan_client, rmnet_ipa_free_msg);
3762 if (rc) {
3763 IPAWANERR("ipa_send_msg failed: %d\n", rc);
3764 kfree(lan_client);
3765 return rc;
3766 }
3767 return 0;
3768}
3769
3770/* rmnet_ipa3_enable_per_client_stats() -
3771 * @data - IOCTL data
3772 *
3773 * This function handles WAN_IOC_ENABLE_PER_CLIENT_STATS.
3774 * It is used to indicate Q6 to start capturing per client stats.
3775 *
3776 * Return codes:
3777 * 0: Success
3778 * -EINVAL: Invalid args provided
3779 */
3780int rmnet_ipa3_enable_per_client_stats(
3781 bool *data)
3782{
3783 struct ipa_enable_per_client_stats_req_msg_v01 *req;
3784 struct ipa_enable_per_client_stats_resp_msg_v01 *resp;
3785 int rc;
3786
3787 req =
3788 kzalloc(sizeof(struct ipa_enable_per_client_stats_req_msg_v01),
3789 GFP_KERNEL);
3790 if (!req) {
3791 IPAWANERR("Can't allocate memory for stats message\n");
3792 return -ENOMEM;
3793 }
3794 resp =
3795 kzalloc(sizeof(struct ipa_enable_per_client_stats_resp_msg_v01),
3796 GFP_KERNEL);
3797 if (!resp) {
3798 IPAWANERR("Can't allocate memory for stats message\n");
3799 kfree(req);
3800 return -ENOMEM;
3801 }
3802 memset(req, 0,
3803 sizeof(struct ipa_enable_per_client_stats_req_msg_v01));
3804 memset(resp, 0,
3805 sizeof(struct ipa_enable_per_client_stats_resp_msg_v01));
3806
3807 if (*data)
3808 req->enable_per_client_stats = 1;
3809 else
3810 req->enable_per_client_stats = 0;
3811
3812 rc = ipa3_qmi_enable_per_client_stats(req, resp);
3813 if (rc) {
3814 IPAWANERR("can't enable per client stats\n");
3815 kfree(req);
3816 kfree(resp);
3817 return rc;
3818 }
3819
3820 kfree(req);
3821 kfree(resp);
3822 return 0;
3823}
3824
3825int rmnet_ipa3_query_per_client_stats(
3826 struct wan_ioctl_query_per_client_stats *data)
3827{
3828 struct ipa_get_stats_per_client_req_msg_v01 *req;
3829 struct ipa_get_stats_per_client_resp_msg_v01 *resp;
3830 int rc, lan_clnt_idx, lan_clnt_idx1, i;
3831 struct ipa_lan_client *lan_client = NULL;
3832
3833
3834 IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
3835 data->client_info[0].mac[0],
3836 data->client_info[0].mac[1],
3837 data->client_info[0].mac[2],
3838 data->client_info[0].mac[3],
3839 data->client_info[0].mac[4],
3840 data->client_info[0].mac[5]);
3841
3842 /* Check if Device type is valid. */
3843 if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
3844 data->device_type < 0) {
3845 IPAWANERR("Invalid Device type: %d\n", data->device_type);
3846 return -EINVAL;
3847 }
3848
3849 /* Check if num_clients is valid. */
3850 if (data->num_clients != IPA_MAX_NUM_HW_PATH_CLIENTS &&
3851 data->num_clients != 1) {
3852 IPAWANERR("Invalid number of clients: %d\n", data->num_clients);
3853 return -EINVAL;
3854 }
3855
3856 mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
3857
3858 if (data->num_clients == 1) {
3859 /* Check if the client info is valid.*/
3860 lan_clnt_idx1 = rmnet_ipa3_get_lan_client_info(
3861 data->device_type,
3862 data->client_info[0].mac);
3863 if (lan_clnt_idx1 < 0) {
3864 IPAWANERR("Client info not available return.\n");
3865 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3866 return -EINVAL;
3867 }
3868 lan_client =
3869 &rmnet_ipa3_ctx->tether_device[data->device_type].
3870 lan_client[lan_clnt_idx1];
3871 /*
3872 * Check if disconnect flag is set and
3873 * see if all the clients info are cleared.
3874 */
3875 if (data->disconnect_clnt &&
3876 lan_client->inited) {
3877 IPAWANERR("Client not inited. Try again.\n");
3878 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3879 return -EAGAIN;
3880 }
3881
3882 } else {
3883 /* Max number of clients. */
3884 /* Check if disconnect flag is set and
3885 * see if all the clients info are cleared.
3886 */
3887 if (data->disconnect_clnt &&
3888 rmnet_ipa3_check_any_client_inited(data->device_type)) {
3889 IPAWANERR("CLient not inited. Try again.\n");
3890 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3891 return -EAGAIN;
3892 }
3893 lan_clnt_idx1 = 0xffffffff;
3894 }
3895
3896 req = kzalloc(sizeof(struct ipa_get_stats_per_client_req_msg_v01),
3897 GFP_KERNEL);
3898 if (!req) {
3899 IPAWANERR("Can't allocate memory for stats message\n");
3900 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3901 return -ENOMEM;
3902 }
3903 resp = kzalloc(sizeof(struct ipa_get_stats_per_client_resp_msg_v01),
3904 GFP_KERNEL);
3905 if (!resp) {
3906 IPAWANERR("Can't allocate memory for stats message\n");
3907 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3908 kfree(req);
3909 return -ENOMEM;
3910 }
3911 memset(req, 0, sizeof(struct ipa_get_stats_per_client_req_msg_v01));
3912 memset(resp, 0, sizeof(struct ipa_get_stats_per_client_resp_msg_v01));
3913
3914 if (data->reset_stats) {
3915 req->reset_stats_valid = true;
3916 req->reset_stats = true;
3917 IPAWANDBG("fetch and reset the client stats\n");
3918 }
3919
3920 req->client_id = lan_clnt_idx1;
3921 req->src_pipe_id =
3922 rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe;
3923
3924 IPAWANDBG("fetch the client stats for %d, %d\n", req->client_id,
3925 req->src_pipe_id);
3926
3927 rc = ipa3_qmi_get_per_client_packet_stats(req, resp);
3928 if (rc) {
3929 IPAWANERR("can't get per client stats\n");
3930 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3931 kfree(req);
3932 kfree(resp);
3933 return rc;
3934 }
3935
3936 if (resp->per_client_stats_list_valid) {
3937 for (i = 0; i < resp->per_client_stats_list_len
3938 && i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
3939 /* Subtract the header bytes from the DL bytes. */
3940 data->client_info[i].ipv4_rx_bytes =
3941 (resp->per_client_stats_list[i].num_dl_ipv4_bytes) -
3942 (rmnet_ipa3_ctx->
3943 tether_device[data->device_type].hdr_len *
3944 resp->per_client_stats_list[i].num_dl_ipv4_pkts);
3945 /* UL header bytes are subtracted by Q6. */
3946 data->client_info[i].ipv4_tx_bytes =
3947 resp->per_client_stats_list[i].num_ul_ipv4_bytes;
3948 /* Subtract the header bytes from the DL bytes. */
3949 data->client_info[i].ipv6_rx_bytes =
3950 (resp->per_client_stats_list[i].num_dl_ipv6_bytes) -
3951 (rmnet_ipa3_ctx->
3952 tether_device[data->device_type].hdr_len *
3953 resp->per_client_stats_list[i].num_dl_ipv6_pkts);
3954 /* UL header bytes are subtracted by Q6. */
3955 data->client_info[i].ipv6_tx_bytes =
3956 resp->per_client_stats_list[i].num_ul_ipv6_bytes;
3957
3958 IPAWANDBG("tx_b_v4(%lu)v6(%lu)rx_b_v4(%lu) v6(%lu)\n",
3959 (unsigned long int) data->client_info[i].ipv4_tx_bytes,
3960 (unsigned long int) data->client_info[i].ipv6_tx_bytes,
3961 (unsigned long int) data->client_info[i].ipv4_rx_bytes,
3962 (unsigned long int) data->client_info[i].ipv6_rx_bytes);
3963
3964 /* Get the lan client index. */
3965 lan_clnt_idx = resp->per_client_stats_list[i].client_id;
3966 /* Check if lan_clnt_idx is valid. */
3967 if (lan_clnt_idx < 0 ||
3968 lan_clnt_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS) {
3969 IPAWANERR("Lan client index not valid.\n");
3970 mutex_unlock(
3971 &rmnet_ipa3_ctx->per_client_stats_guard);
3972 kfree(req);
3973 kfree(resp);
3974 ipa_assert();
3975 return -EINVAL;
3976 }
3977 memcpy(data->client_info[i].mac,
3978 rmnet_ipa3_ctx->
3979 tether_device[data->device_type].
3980 lan_client[lan_clnt_idx].mac,
3981 IPA_MAC_ADDR_SIZE);
3982 }
3983 }
3984
3985 if (data->disconnect_clnt) {
3986 rmnet_ipa3_delete_lan_client_info(data->device_type,
3987 lan_clnt_idx1);
3988 }
3989
3990 mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
3991 kfree(req);
3992 kfree(resp);
3993 return 0;
3994}
3995
Amir Levy9659e592016-10-27 18:08:27 +03003996static int __init ipa3_wwan_init(void)
3997{
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05303998 int i, j;
Amir Levy9659e592016-10-27 18:08:27 +03003999 rmnet_ipa3_ctx = kzalloc(sizeof(*rmnet_ipa3_ctx), GFP_KERNEL);
4000 if (!rmnet_ipa3_ctx) {
4001 IPAWANERR("no memory\n");
4002 return -ENOMEM;
4003 }
4004
4005 atomic_set(&rmnet_ipa3_ctx->is_initialized, 0);
4006 atomic_set(&rmnet_ipa3_ctx->is_ssr, 0);
4007
Ghanim Fodic6b67492017-03-15 14:19:56 +02004008 mutex_init(&rmnet_ipa3_ctx->pipe_handle_guard);
Skylar Chang8438ba52017-03-15 21:27:35 -07004009 mutex_init(&rmnet_ipa3_ctx->add_mux_channel_lock);
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05304010 mutex_init(&rmnet_ipa3_ctx->per_client_stats_guard);
4011 /* Reset the Lan Stats. */
4012 for (i = 0; i < IPACM_MAX_CLIENT_DEVICE_TYPES; i++) {
4013 rmnet_ipa3_ctx->tether_device[i].ul_src_pipe = -1;
4014 for (j = 0; j < IPA_MAX_NUM_HW_PATH_CLIENTS; j++)
4015 rmnet_ipa3_ctx->tether_device[i].
4016 lan_client[j].client_idx = -1;
4017 }
Amir Levy9659e592016-10-27 18:08:27 +03004018 rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
Ghanim Fodic6b67492017-03-15 14:19:56 +02004019 rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
Utkarsh Saxenabcb324e2017-04-24 22:56:31 +05304020
4021 ipa3_qmi_init();
4022
Amir Levy9659e592016-10-27 18:08:27 +03004023 /* Register for Modem SSR */
4024 rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
4025 SUBSYS_MODEM,
4026 &ipa3_ssr_notifier);
4027 if (!IS_ERR(rmnet_ipa3_ctx->subsys_notify_handle))
4028 return platform_driver_register(&rmnet_ipa_driver);
4029 else
4030 return (int)PTR_ERR(rmnet_ipa3_ctx->subsys_notify_handle);
4031}
4032
4033static void __exit ipa3_wwan_cleanup(void)
4034{
4035 int ret;
Skylar Chang8438ba52017-03-15 21:27:35 -07004036
Utkarsh Saxenabcb324e2017-04-24 22:56:31 +05304037 ipa3_qmi_cleanup();
Ghanim Fodic6b67492017-03-15 14:19:56 +02004038 mutex_destroy(&rmnet_ipa3_ctx->pipe_handle_guard);
Skylar Chang8438ba52017-03-15 21:27:35 -07004039 mutex_destroy(&rmnet_ipa3_ctx->add_mux_channel_lock);
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05304040 mutex_destroy(&rmnet_ipa3_ctx->per_client_stats_guard);
Amir Levy9659e592016-10-27 18:08:27 +03004041 ret = subsys_notif_unregister_notifier(
4042 rmnet_ipa3_ctx->subsys_notify_handle, &ipa3_ssr_notifier);
4043 if (ret)
4044 IPAWANERR(
4045 "Error subsys_notif_unregister_notifier system %s, ret=%d\n",
4046 SUBSYS_MODEM, ret);
4047 platform_driver_unregister(&rmnet_ipa_driver);
4048 kfree(rmnet_ipa3_ctx);
4049 rmnet_ipa3_ctx = NULL;
4050}
4051
4052static void ipa3_wwan_msg_free_cb(void *buff, u32 len, u32 type)
4053{
4054 if (!buff)
4055 IPAWANERR("Null buffer.\n");
4056 kfree(buff);
4057}
4058
4059static void ipa3_rmnet_rx_cb(void *priv)
4060{
4061 IPAWANDBG_LOW("\n");
4062 napi_schedule(&(rmnet_ipa3_ctx->wwan_priv->napi));
4063}
4064
4065static int ipa3_rmnet_poll(struct napi_struct *napi, int budget)
4066{
4067 int rcvd_pkts = 0;
4068
4069 rcvd_pkts = ipa_rx_poll(rmnet_ipa3_ctx->ipa3_to_apps_hdl,
4070 NAPI_WEIGHT);
4071 IPAWANDBG_LOW("rcvd packets: %d\n", rcvd_pkts);
4072 return rcvd_pkts;
4073}
4074
4075late_initcall(ipa3_wwan_init);
4076module_exit(ipa3_wwan_cleanup);
4077MODULE_DESCRIPTION("WWAN Network Interface");
4078MODULE_LICENSE("GPL v2");