blob: 612a439f4780ead3a66d808bfd40b30ded5935ae [file] [log] [blame]
Michael Adisumartabb530002018-01-16 19:09:38 -08001/* Copyright (c) 2015-2018 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#include <linux/mutex.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/debugfs.h>
17#include <linux/ipa.h>
18#include <linux/ipa_usb.h>
19#include <linux/rndis_ipa.h>
20#include <linux/ecm_ipa.h>
21#include "../ipa_v3/ipa_i.h"
22#include "../ipa_rm_i.h"
23
24#define IPA_USB_RM_TIMEOUT_MSEC 10000
25#define IPA_USB_DEV_READY_TIMEOUT_MSEC 10000
26
27#define IPA_HOLB_TMR_EN 0x1
28
29/* GSI channels weights */
30#define IPA_USB_DL_CHAN_LOW_WEIGHT 0x5
31#define IPA_USB_UL_CHAN_LOW_WEIGHT 0x4
32
33#define IPA_USB_MAX_MSG_LEN 4096
34
35#define IPA_USB_DRV_NAME "ipa_usb"
36
37#define IPA_USB_DBG(fmt, args...) \
38 do { \
39 pr_debug(IPA_USB_DRV_NAME " %s:%d " fmt, \
40 __func__, __LINE__, ## args); \
41 IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
42 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
43 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
44 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
45 } while (0)
46
47#define IPA_USB_DBG_LOW(fmt, args...) \
48 do { \
49 pr_debug(IPA_USB_DRV_NAME " %s:%d " fmt, \
50 __func__, __LINE__, ## args); \
51 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
52 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
53 } while (0)
54
55#define IPA_USB_ERR(fmt, args...) \
56 do { \
57 pr_err(IPA_USB_DRV_NAME " %s:%d " fmt, \
58 __func__, __LINE__, ## args); \
59 IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
60 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
61 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
62 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
63 } while (0)
64
65#define IPA_USB_INFO(fmt, args...) \
66 do { \
67 pr_info(IPA_USB_DRV_NAME " %s:%d " fmt, \
68 __func__, __LINE__, ## args); \
69 IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
70 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
71 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
72 IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \
73 } while (0)
74
75struct ipa_usb_xdci_connect_params_internal {
76 enum ipa_usb_max_usb_packet_size max_pkt_size;
77 u32 ipa_to_usb_clnt_hdl;
78 u8 ipa_to_usb_xferrscidx;
79 bool ipa_to_usb_xferrscidx_valid;
80 u32 usb_to_ipa_clnt_hdl;
81 u8 usb_to_ipa_xferrscidx;
82 bool usb_to_ipa_xferrscidx_valid;
83 enum ipa_usb_teth_prot teth_prot;
84 struct ipa_usb_teth_prot_params teth_prot_params;
85 u32 max_supported_bandwidth_mbps;
86};
87
88enum ipa3_usb_teth_prot_state {
89 IPA_USB_TETH_PROT_INITIALIZED,
90 IPA_USB_TETH_PROT_CONNECTED,
91 IPA_USB_TETH_PROT_INVALID
92};
93
94struct ipa3_usb_teth_prot_context {
95 union {
96 struct ipa_usb_init_params rndis;
97 struct ecm_ipa_params ecm;
98 struct teth_bridge_init_params teth_bridge;
99 } teth_prot_params;
100 enum ipa3_usb_teth_prot_state state;
101 void *user_data;
102};
103
104enum ipa3_usb_cons_state {
105 IPA_USB_CONS_GRANTED,
106 IPA_USB_CONS_RELEASED
107};
108
109struct ipa3_usb_rm_context {
110 struct ipa_rm_create_params prod_params;
111 struct ipa_rm_create_params cons_params;
112 bool prod_valid;
113 bool cons_valid;
114 struct completion prod_comp;
115 enum ipa3_usb_cons_state cons_state;
116 /* consumer was requested*/
117 bool cons_requested;
118 /* consumer was requested and released before it was granted*/
119 bool cons_requested_released;
120};
121
Michael Adisumarta3e350812017-09-18 14:54:36 -0700122struct ipa3_usb_pm_context {
123 struct ipa_pm_register_params reg_params;
124 struct work_struct *remote_wakeup_work;
125 u32 hdl;
126};
127
Amir Levy9659e592016-10-27 18:08:27 +0300128enum ipa3_usb_state {
129 IPA_USB_INVALID,
130 IPA_USB_INITIALIZED,
131 IPA_USB_CONNECTED,
132 IPA_USB_STOPPED,
133 IPA_USB_SUSPEND_REQUESTED,
Amir Levy9659e592016-10-27 18:08:27 +0300134 IPA_USB_SUSPENDED,
Ghanim Fodi93a61112016-10-05 11:59:18 +0300135 IPA_USB_SUSPENDED_NO_RWAKEUP,
Amir Levy9659e592016-10-27 18:08:27 +0300136 IPA_USB_RESUME_IN_PROGRESS
137};
138
139enum ipa3_usb_transport_type {
140 IPA_USB_TRANSPORT_TETH,
141 IPA_USB_TRANSPORT_DPL,
142 IPA_USB_TRANSPORT_MAX
143};
144
145/* Get transport type from tethering protocol */
146#define IPA3_USB_GET_TTYPE(__teth_prot) \
147 (((__teth_prot) == IPA_USB_DIAG) ? \
148 IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH)
149
150/* Does the given transport type is DPL? */
151#define IPA3_USB_IS_TTYPE_DPL(__ttype) \
152 ((__ttype) == IPA_USB_TRANSPORT_DPL)
153
Ghanim Fodi93a61112016-10-05 11:59:18 +0300154struct ipa3_usb_teth_prot_conn_params {
155 u32 usb_to_ipa_clnt_hdl;
156 u32 ipa_to_usb_clnt_hdl;
157 struct ipa_usb_teth_prot_params params;
158};
159
Amir Levy9659e592016-10-27 18:08:27 +0300160/**
161 * Transport type - could be either data tethering or DPL
162 * Each transport has it's own RM resources and statuses
163 */
164struct ipa3_usb_transport_type_ctx {
165 struct ipa3_usb_rm_context rm_ctx;
Michael Adisumarta3e350812017-09-18 14:54:36 -0700166 struct ipa3_usb_pm_context pm_ctx;
Amir Levy9659e592016-10-27 18:08:27 +0300167 int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
168 void *user_data;
169 enum ipa3_usb_state state;
Amir Levy9659e592016-10-27 18:08:27 +0300170 struct ipa_usb_xdci_chan_params ch_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300171 struct ipa3_usb_teth_prot_conn_params teth_conn_params;
Amir Levy9659e592016-10-27 18:08:27 +0300172};
173
174struct ipa3_usb_smmu_reg_map {
175 int cnt;
176 phys_addr_t addr;
177};
178
179struct ipa3_usb_context {
180 struct ipa3_usb_teth_prot_context
181 teth_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE];
182 int num_init_prot; /* without dpl */
183 struct teth_bridge_init_params teth_bridge_params;
184 struct completion dev_ready_comp;
185 u32 qmi_req_id;
186 spinlock_t state_lock;
187 bool dl_data_pending;
188 struct workqueue_struct *wq;
189 struct mutex general_mutex;
190 struct ipa3_usb_transport_type_ctx
191 ttype_ctx[IPA_USB_TRANSPORT_MAX];
192 struct dentry *dfile_state_info;
193 struct dentry *dent;
194 struct ipa3_usb_smmu_reg_map smmu_reg_map;
195};
196
197enum ipa3_usb_op {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300198 IPA_USB_OP_INIT_TETH_PROT,
199 IPA_USB_OP_REQUEST_CHANNEL,
200 IPA_USB_OP_CONNECT,
201 IPA_USB_OP_DISCONNECT,
202 IPA_USB_OP_RELEASE_CHANNEL,
203 IPA_USB_OP_DEINIT_TETH_PROT,
204 IPA_USB_OP_SUSPEND,
205 IPA_USB_OP_SUSPEND_NO_RWAKEUP,
206 IPA_USB_OP_RESUME
Amir Levy9659e592016-10-27 18:08:27 +0300207};
208
209struct ipa3_usb_status_dbg_info {
210 const char *teth_state;
211 const char *dpl_state;
212 int num_init_prot;
213 const char *inited_prots[IPA_USB_MAX_TETH_PROT_SIZE];
214 const char *teth_connected_prot;
215 const char *dpl_connected_prot;
216 const char *teth_cons_state;
217 const char *dpl_cons_state;
218};
219
220static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work);
221static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work);
Amir Levy9659e592016-10-27 18:08:27 +0300222static DECLARE_WORK(ipa3_usb_notify_remote_wakeup_work,
223 ipa3_usb_wq_notify_remote_wakeup);
224static DECLARE_WORK(ipa3_usb_dpl_notify_remote_wakeup_work,
225 ipa3_usb_wq_dpl_notify_remote_wakeup);
Amir Levy9659e592016-10-27 18:08:27 +0300226
227struct ipa3_usb_context *ipa3_usb_ctx;
228
229static char *ipa3_usb_op_to_string(enum ipa3_usb_op op)
230{
231 switch (op) {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300232 case IPA_USB_OP_INIT_TETH_PROT:
233 return "IPA_USB_OP_INIT_TETH_PROT";
234 case IPA_USB_OP_REQUEST_CHANNEL:
235 return "IPA_USB_OP_REQUEST_CHANNEL";
236 case IPA_USB_OP_CONNECT:
237 return "IPA_USB_OP_CONNECT";
238 case IPA_USB_OP_DISCONNECT:
239 return "IPA_USB_OP_DISCONNECT";
240 case IPA_USB_OP_RELEASE_CHANNEL:
241 return "IPA_USB_OP_RELEASE_CHANNEL";
242 case IPA_USB_OP_DEINIT_TETH_PROT:
243 return "IPA_USB_OP_DEINIT_TETH_PROT";
244 case IPA_USB_OP_SUSPEND:
245 return "IPA_USB_OP_SUSPEND";
246 case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
247 return "IPA_USB_OP_SUSPEND_NO_RWAKEUP";
248 case IPA_USB_OP_RESUME:
249 return "IPA_USB_OP_RESUME";
Amir Levy9659e592016-10-27 18:08:27 +0300250 }
251
252 return "UNSUPPORTED";
253}
254
255static char *ipa3_usb_state_to_string(enum ipa3_usb_state state)
256{
257 switch (state) {
258 case IPA_USB_INVALID:
259 return "IPA_USB_INVALID";
260 case IPA_USB_INITIALIZED:
261 return "IPA_USB_INITIALIZED";
262 case IPA_USB_CONNECTED:
263 return "IPA_USB_CONNECTED";
264 case IPA_USB_STOPPED:
265 return "IPA_USB_STOPPED";
266 case IPA_USB_SUSPEND_REQUESTED:
267 return "IPA_USB_SUSPEND_REQUESTED";
Amir Levy9659e592016-10-27 18:08:27 +0300268 case IPA_USB_SUSPENDED:
269 return "IPA_USB_SUSPENDED";
Ghanim Fodi93a61112016-10-05 11:59:18 +0300270 case IPA_USB_SUSPENDED_NO_RWAKEUP:
271 return "IPA_USB_SUSPENDED_NO_RWAKEUP";
Amir Levy9659e592016-10-27 18:08:27 +0300272 case IPA_USB_RESUME_IN_PROGRESS:
273 return "IPA_USB_RESUME_IN_PROGRESS";
274 }
275
276 return "UNSUPPORTED";
277}
278
279static char *ipa3_usb_notify_event_to_string(enum ipa_usb_notify_event event)
280{
281 switch (event) {
282 case IPA_USB_DEVICE_READY:
283 return "IPA_USB_DEVICE_READY";
284 case IPA_USB_REMOTE_WAKEUP:
285 return "IPA_USB_REMOTE_WAKEUP";
286 case IPA_USB_SUSPEND_COMPLETED:
287 return "IPA_USB_SUSPEND_COMPLETED";
288 }
289
290 return "UNSUPPORTED";
291}
292
293static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit,
294 enum ipa3_usb_transport_type ttype)
295{
296 unsigned long flags;
297 int state_legal = false;
298 enum ipa3_usb_state state;
299 struct ipa3_usb_rm_context *rm_ctx;
300
301 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
302 state = ipa3_usb_ctx->ttype_ctx[ttype].state;
303 switch (new_state) {
304 case IPA_USB_INVALID:
305 if (state == IPA_USB_INITIALIZED)
306 state_legal = true;
307 break;
308 case IPA_USB_INITIALIZED:
309 if (state == IPA_USB_STOPPED || state == IPA_USB_INVALID ||
310 ((!IPA3_USB_IS_TTYPE_DPL(ttype)) &&
311 (state == IPA_USB_INITIALIZED)))
312 state_legal = true;
313 break;
314 case IPA_USB_CONNECTED:
315 if (state == IPA_USB_INITIALIZED ||
316 state == IPA_USB_STOPPED ||
317 state == IPA_USB_RESUME_IN_PROGRESS ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300318 state == IPA_USB_SUSPENDED_NO_RWAKEUP ||
Amir Levy9659e592016-10-27 18:08:27 +0300319 /*
320 * In case of failure during suspend request
321 * handling, state is reverted to connected.
322 */
Skylar Changdf5f2342017-06-05 09:27:48 -0700323 (err_permit && state == IPA_USB_SUSPEND_REQUESTED))
Amir Levy9659e592016-10-27 18:08:27 +0300324 state_legal = true;
325 break;
326 case IPA_USB_STOPPED:
Skylar Changdf5f2342017-06-05 09:27:48 -0700327 if (state == IPA_USB_CONNECTED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300328 state == IPA_USB_SUSPENDED ||
329 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300330 state_legal = true;
331 break;
332 case IPA_USB_SUSPEND_REQUESTED:
333 if (state == IPA_USB_CONNECTED)
334 state_legal = true;
335 break;
Amir Levy9659e592016-10-27 18:08:27 +0300336 case IPA_USB_SUSPENDED:
337 if (state == IPA_USB_SUSPEND_REQUESTED ||
Amir Levy9659e592016-10-27 18:08:27 +0300338 /*
339 * In case of failure during resume, state is reverted
340 * to original, which could be suspended. Allow it
341 */
342 (err_permit && state == IPA_USB_RESUME_IN_PROGRESS))
343 state_legal = true;
344 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300345 case IPA_USB_SUSPENDED_NO_RWAKEUP:
346 if (state == IPA_USB_CONNECTED)
347 state_legal = true;
348 break;
Amir Levy9659e592016-10-27 18:08:27 +0300349 case IPA_USB_RESUME_IN_PROGRESS:
Skylar Changdf5f2342017-06-05 09:27:48 -0700350 if (state == IPA_USB_SUSPENDED)
Amir Levy9659e592016-10-27 18:08:27 +0300351 state_legal = true;
352 break;
353 default:
354 state_legal = false;
355 break;
356
357 }
358 if (state_legal) {
359 if (state != new_state) {
360 IPA_USB_DBG("ipa_usb %s state changed %s -> %s\n",
361 IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL" : "",
362 ipa3_usb_state_to_string(state),
363 ipa3_usb_state_to_string(new_state));
364 ipa3_usb_ctx->ttype_ctx[ttype].state = new_state;
365 }
366 } else {
367 IPA_USB_ERR("invalid state change %s -> %s\n",
368 ipa3_usb_state_to_string(state),
369 ipa3_usb_state_to_string(new_state));
370 }
371
Michael Adisumarta3e350812017-09-18 14:54:36 -0700372 if (!ipa_pm_is_used() &&
373 state_legal && (new_state == IPA_USB_CONNECTED)) {
Amir Levy9659e592016-10-27 18:08:27 +0300374 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
375 if ((rm_ctx->cons_state == IPA_USB_CONS_GRANTED) ||
376 rm_ctx->cons_requested_released) {
377 rm_ctx->cons_requested = false;
378 rm_ctx->cons_requested_released =
379 false;
380 }
381 /* Notify RM that consumer is granted */
382 if (rm_ctx->cons_requested) {
383 ipa_rm_notify_completion(
384 IPA_RM_RESOURCE_GRANTED,
385 rm_ctx->cons_params.name);
386 rm_ctx->cons_state = IPA_USB_CONS_GRANTED;
387 rm_ctx->cons_requested = false;
388 }
389 }
390
391 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
392 return state_legal;
393}
394
395static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op,
396 enum ipa3_usb_transport_type ttype)
397{
398 unsigned long flags;
399 bool is_legal = false;
400 enum ipa3_usb_state state;
401 bool is_dpl;
402
403 if (ipa3_usb_ctx == NULL) {
404 IPA_USB_ERR("ipa_usb_ctx is not initialized!\n");
405 return false;
406 }
407
408 is_dpl = IPA3_USB_IS_TTYPE_DPL(ttype);
409
410 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
411 state = ipa3_usb_ctx->ttype_ctx[ttype].state;
412 switch (op) {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300413 case IPA_USB_OP_INIT_TETH_PROT:
Amir Levy9659e592016-10-27 18:08:27 +0300414 if (state == IPA_USB_INVALID ||
415 (!is_dpl && state == IPA_USB_INITIALIZED))
416 is_legal = true;
417 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300418 case IPA_USB_OP_REQUEST_CHANNEL:
Amir Levy9659e592016-10-27 18:08:27 +0300419 if (state == IPA_USB_INITIALIZED)
420 is_legal = true;
421 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300422 case IPA_USB_OP_CONNECT:
Amir Levy9659e592016-10-27 18:08:27 +0300423 if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED)
424 is_legal = true;
425 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300426 case IPA_USB_OP_DISCONNECT:
Amir Levy9659e592016-10-27 18:08:27 +0300427 if (state == IPA_USB_CONNECTED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300428 state == IPA_USB_SUSPENDED ||
429 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300430 is_legal = true;
431 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300432 case IPA_USB_OP_RELEASE_CHANNEL:
Amir Levy9659e592016-10-27 18:08:27 +0300433 /* when releasing 1st channel state will be changed already */
434 if (state == IPA_USB_STOPPED ||
435 (!is_dpl && state == IPA_USB_INITIALIZED))
436 is_legal = true;
437 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300438 case IPA_USB_OP_DEINIT_TETH_PROT:
Amir Levy9659e592016-10-27 18:08:27 +0300439 /*
440 * For data tethering we should allow deinit an inited protocol
441 * always. E.g. rmnet is inited and rndis is connected.
442 * USB can deinit rmnet first and then disconnect rndis
443 * on cable disconnect.
444 */
445 if (!is_dpl || state == IPA_USB_INITIALIZED)
446 is_legal = true;
447 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300448 case IPA_USB_OP_SUSPEND:
Amir Levy9659e592016-10-27 18:08:27 +0300449 if (state == IPA_USB_CONNECTED)
450 is_legal = true;
451 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300452 case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
453 if (state == IPA_USB_CONNECTED)
454 is_legal = true;
455 break;
456 case IPA_USB_OP_RESUME:
Amir Levy9659e592016-10-27 18:08:27 +0300457 if (state == IPA_USB_SUSPENDED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300458 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300459 is_legal = true;
460 break;
461 default:
462 is_legal = false;
463 break;
464 }
465
466 if (!is_legal) {
467 IPA_USB_ERR("Illegal %s operation: state=%s operation=%s\n",
468 is_dpl ? "DPL" : "",
469 ipa3_usb_state_to_string(state),
470 ipa3_usb_op_to_string(op));
471 }
472
473 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
474 return is_legal;
475}
476
477static void ipa3_usb_notify_do(enum ipa3_usb_transport_type ttype,
478 enum ipa_usb_notify_event event)
479{
480 int (*cb)(enum ipa_usb_notify_event, void *user_data);
481 void *user_data;
482 int res;
483
484 IPA_USB_DBG("Trying to notify USB with %s\n",
485 ipa3_usb_notify_event_to_string(event));
486
487 cb = ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb;
488 user_data = ipa3_usb_ctx->ttype_ctx[ttype].user_data;
489
490 if (cb) {
491 res = cb(event, user_data);
492 IPA_USB_DBG("Notified USB with %s. is_dpl=%d result=%d\n",
493 ipa3_usb_notify_event_to_string(event),
494 IPA3_USB_IS_TTYPE_DPL(ttype), res);
495 }
496}
497
498/*
499 * This call-back is called from ECM or RNDIS drivers.
500 * Both drivers are data tethering drivers and not DPL
501 */
502void ipa3_usb_device_ready_notify_cb(void)
503{
504 IPA_USB_DBG_LOW("entry\n");
505 ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH,
506 IPA_USB_DEVICE_READY);
507 IPA_USB_DBG_LOW("exit\n");
508}
509
510static void ipa3_usb_prod_notify_cb_do(enum ipa_rm_event event,
511 enum ipa3_usb_transport_type ttype)
512{
513 struct ipa3_usb_rm_context *rm_ctx;
514
515 IPA_USB_DBG_LOW("entry\n");
516
517 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
518
519 switch (event) {
520 case IPA_RM_RESOURCE_GRANTED:
521 IPA_USB_DBG(":%s granted\n",
522 ipa_rm_resource_str(rm_ctx->prod_params.name));
523 complete_all(&rm_ctx->prod_comp);
524 break;
525 case IPA_RM_RESOURCE_RELEASED:
526 IPA_USB_DBG(":%s released\n",
527 ipa_rm_resource_str(rm_ctx->prod_params.name));
528 complete_all(&rm_ctx->prod_comp);
529 break;
530 }
531 IPA_USB_DBG_LOW("exit\n");
532}
533
534static void ipa3_usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
535 unsigned long data)
536{
537 ipa3_usb_prod_notify_cb_do(event, IPA_USB_TRANSPORT_TETH);
538}
539
540static void ipa3_usb_dpl_dummy_prod_notify_cb(void *user_data,
541 enum ipa_rm_event event, unsigned long data)
542{
543 ipa3_usb_prod_notify_cb_do(event, IPA_USB_TRANSPORT_TETH);
544}
545
546static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work)
547{
548 ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH, IPA_USB_REMOTE_WAKEUP);
549}
550
551static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work)
552{
553 ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_REMOTE_WAKEUP);
554}
555
Amir Levy9659e592016-10-27 18:08:27 +0300556static int ipa3_usb_cons_request_resource_cb_do(
557 enum ipa3_usb_transport_type ttype,
558 struct work_struct *remote_wakeup_work)
559{
560 struct ipa3_usb_rm_context *rm_ctx;
561 unsigned long flags;
562 int result;
563
564 IPA_USB_DBG_LOW("entry\n");
565 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
566 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
567 IPA_USB_DBG("state is %s\n",
568 ipa3_usb_state_to_string(
569 ipa3_usb_ctx->ttype_ctx[ttype].state));
570 switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
571 case IPA_USB_CONNECTED:
Ghanim Fodi93a61112016-10-05 11:59:18 +0300572 case IPA_USB_SUSPENDED_NO_RWAKEUP:
Amir Levy9659e592016-10-27 18:08:27 +0300573 rm_ctx->cons_state = IPA_USB_CONS_GRANTED;
574 result = 0;
575 break;
576 case IPA_USB_SUSPEND_REQUESTED:
577 rm_ctx->cons_requested = true;
578 if (rm_ctx->cons_state == IPA_USB_CONS_GRANTED)
579 result = 0;
580 else
581 result = -EINPROGRESS;
582 break;
Amir Levy9659e592016-10-27 18:08:27 +0300583 case IPA_USB_SUSPENDED:
584 if (!rm_ctx->cons_requested) {
585 rm_ctx->cons_requested = true;
586 queue_work(ipa3_usb_ctx->wq, remote_wakeup_work);
587 }
588 result = -EINPROGRESS;
589 break;
590 default:
591 rm_ctx->cons_requested = true;
592 result = -EINPROGRESS;
593 break;
594 }
595 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
596 IPA_USB_DBG_LOW("exit with %d\n", result);
597 return result;
598}
599
600static int ipa3_usb_cons_request_resource_cb(void)
601{
602 return ipa3_usb_cons_request_resource_cb_do(IPA_USB_TRANSPORT_TETH,
603 &ipa3_usb_notify_remote_wakeup_work);
604}
605
606static int ipa3_usb_dpl_cons_request_resource_cb(void)
607{
608 return ipa3_usb_cons_request_resource_cb_do(IPA_USB_TRANSPORT_DPL,
609 &ipa3_usb_dpl_notify_remote_wakeup_work);
610}
611
612static int ipa3_usb_cons_release_resource_cb_do(
613 enum ipa3_usb_transport_type ttype)
614{
615 unsigned long flags;
616 struct ipa3_usb_rm_context *rm_ctx;
617
618 IPA_USB_DBG_LOW("entry\n");
619 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
620 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
621 IPA_USB_DBG("state is %s\n",
622 ipa3_usb_state_to_string(
623 ipa3_usb_ctx->ttype_ctx[ttype].state));
624 switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
Skylar Changdf5f2342017-06-05 09:27:48 -0700625 case IPA_USB_SUSPENDED:
Amir Levy9659e592016-10-27 18:08:27 +0300626 /* Proceed with the suspend if no DL/DPL data */
627 if (rm_ctx->cons_requested)
628 rm_ctx->cons_requested_released = true;
Amir Levy9659e592016-10-27 18:08:27 +0300629 break;
630 case IPA_USB_SUSPEND_REQUESTED:
631 if (rm_ctx->cons_requested)
632 rm_ctx->cons_requested_released = true;
633 break;
634 case IPA_USB_STOPPED:
635 case IPA_USB_RESUME_IN_PROGRESS:
Ghanim Fodi93a61112016-10-05 11:59:18 +0300636 case IPA_USB_SUSPENDED_NO_RWAKEUP:
Amir Levy9659e592016-10-27 18:08:27 +0300637 if (rm_ctx->cons_requested)
638 rm_ctx->cons_requested = false;
639 break;
640 case IPA_USB_CONNECTED:
641 case IPA_USB_INITIALIZED:
642 break;
643 default:
644 IPA_USB_ERR("received cons_release_cb in bad state: %s!\n",
645 ipa3_usb_state_to_string(
646 ipa3_usb_ctx->ttype_ctx[ttype].state));
647 WARN_ON(1);
648 break;
649 }
650
651 rm_ctx->cons_state = IPA_USB_CONS_RELEASED;
652 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
653 IPA_USB_DBG_LOW("exit\n");
654 return 0;
655}
656
657static int ipa3_usb_cons_release_resource_cb(void)
658{
659 return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_TETH);
660}
661
662static int ipa3_usb_dpl_cons_release_resource_cb(void)
663{
664 return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_DPL);
665}
666
Michael Adisumarta3e350812017-09-18 14:54:36 -0700667static void ipa3_usb_pm_cb(void *p, enum ipa_pm_cb_event event)
668{
669 struct ipa3_usb_transport_type_ctx *ttype_ctx =
670 (struct ipa3_usb_transport_type_ctx *)p;
671 unsigned long flags;
672
673 IPA_USB_DBG_LOW("entry\n");
674
675 if (event != IPA_PM_REQUEST_WAKEUP) {
676 IPA_USB_ERR("Unexpected event %d\n", event);
677 WARN_ON(1);
678 return;
679 }
680
681 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
682 IPA_USB_DBG("state is %s\n",
683 ipa3_usb_state_to_string(ttype_ctx->state));
684 if (ttype_ctx->state == IPA_USB_SUSPENDED)
685 queue_work(ipa3_usb_ctx->wq,
686 ttype_ctx->pm_ctx.remote_wakeup_work);
687 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
688 IPA_USB_DBG_LOW("exit\n");
689}
690
Amir Levy9659e592016-10-27 18:08:27 +0300691static char *ipa3_usb_teth_prot_to_string(enum ipa_usb_teth_prot teth_prot)
692{
693 switch (teth_prot) {
694 case IPA_USB_RNDIS:
695 return "rndis_ipa";
696 case IPA_USB_ECM:
697 return "ecm_ipa";
698 case IPA_USB_RMNET:
699 case IPA_USB_MBIM:
700 return "teth_bridge";
701 case IPA_USB_DIAG:
702 return "dpl";
703 default:
704 break;
705 }
706
707 return "unsupported";
708}
709
710static char *ipa3_usb_teth_bridge_prot_to_string(
711 enum ipa_usb_teth_prot teth_prot)
712{
713 switch (teth_prot) {
714 case IPA_USB_RMNET:
715 return "rmnet";
716 case IPA_USB_MBIM:
717 return "mbim";
718 default:
719 break;
720 }
721
722 return "unsupported";
723}
724
725static int ipa3_usb_init_teth_bridge(void)
726{
727 int result;
728
729 result = teth_bridge_init(&ipa3_usb_ctx->teth_bridge_params);
730 if (result) {
731 IPA_USB_ERR("Failed to initialize teth_bridge.\n");
732 return result;
733 }
734
735 return 0;
736}
737
Michael Adisumarta3e350812017-09-18 14:54:36 -0700738static int ipa3_usb_register_pm(enum ipa3_usb_transport_type ttype)
739{
740 struct ipa3_usb_transport_type_ctx *ttype_ctx =
741 &ipa3_usb_ctx->ttype_ctx[ttype];
742 int result;
743
Skylar Changb42196b2017-12-13 15:33:51 -0800744 /* create PM resources for the first tethering protocol only */
745 if (ipa3_usb_ctx->num_init_prot > 0)
746 return 0;
747
Michael Adisumarta3e350812017-09-18 14:54:36 -0700748 memset(&ttype_ctx->pm_ctx.reg_params, 0,
749 sizeof(ttype_ctx->pm_ctx.reg_params));
750 ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
751 "USB DPL" : "USB";
752 ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb;
753 ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx;
754 ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT;
755
756 result = ipa_pm_register(&ttype_ctx->pm_ctx.reg_params,
757 &ttype_ctx->pm_ctx.hdl);
758 if (result) {
759 IPA_USB_ERR("fail to register with PM %d\n", result);
760 goto fail_pm_reg;
761 }
762
763 result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl,
764 (ttype == IPA_USB_TRANSPORT_DPL) ?
765 IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS);
766 if (result) {
767 IPA_USB_ERR("fail to associate cons with PM %d\n", result);
768 goto fail_pm_cons;
769 }
770
771 return 0;
772
773fail_pm_cons:
774 ipa_pm_deregister(ttype_ctx->pm_ctx.hdl);
775fail_pm_reg:
776 memset(&ttype_ctx->pm_ctx.reg_params, 0,
777 sizeof(ttype_ctx->pm_ctx.reg_params));
778 return result;
779}
780
781static int ipa3_usb_deregister_pm(enum ipa3_usb_transport_type ttype)
782{
783 struct ipa3_usb_pm_context *pm_ctx =
784 &ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx;
785 int result;
786
787 result = ipa_pm_deregister(pm_ctx->hdl);
788 if (result)
789 return result;
790
791 memset(&pm_ctx->reg_params, 0, sizeof(pm_ctx->reg_params));
792 return 0;
793}
794
Amir Levy9659e592016-10-27 18:08:27 +0300795static int ipa3_usb_create_rm_resources(enum ipa3_usb_transport_type ttype)
796{
797 struct ipa3_usb_rm_context *rm_ctx;
798 int result = -EFAULT;
799 bool created = false;
800
801 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
802
803 /* create PROD */
804 if (!rm_ctx->prod_valid) {
805 rm_ctx->prod_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
806 IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD :
807 IPA_RM_RESOURCE_USB_PROD;
Skylar Chang448d8b82017-08-08 17:30:32 -0700808 rm_ctx->prod_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300809 rm_ctx->prod_params.reg_params.user_data = NULL;
810 rm_ctx->prod_params.reg_params.notify_cb =
811 IPA3_USB_IS_TTYPE_DPL(ttype) ?
812 ipa3_usb_dpl_dummy_prod_notify_cb :
813 ipa3_usb_prod_notify_cb;
814 rm_ctx->prod_params.request_resource = NULL;
815 rm_ctx->prod_params.release_resource = NULL;
816 result = ipa_rm_create_resource(&rm_ctx->prod_params);
817 if (result) {
818 IPA_USB_ERR("Failed to create %s RM resource\n",
819 ipa_rm_resource_str(rm_ctx->prod_params.name));
820 return result;
821 }
822 rm_ctx->prod_valid = true;
823 created = true;
824 IPA_USB_DBG("Created %s RM resource\n",
825 ipa_rm_resource_str(rm_ctx->prod_params.name));
826 }
827
828 /* Create CONS */
829 if (!rm_ctx->cons_valid) {
830 rm_ctx->cons_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
831 IPA_RM_RESOURCE_USB_DPL_CONS :
832 IPA_RM_RESOURCE_USB_CONS;
Skylar Chang448d8b82017-08-08 17:30:32 -0700833 rm_ctx->cons_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300834 rm_ctx->cons_params.reg_params.user_data = NULL;
835 rm_ctx->cons_params.reg_params.notify_cb = NULL;
836 rm_ctx->cons_params.request_resource =
837 IPA3_USB_IS_TTYPE_DPL(ttype) ?
838 ipa3_usb_dpl_cons_request_resource_cb :
839 ipa3_usb_cons_request_resource_cb;
840 rm_ctx->cons_params.release_resource =
841 IPA3_USB_IS_TTYPE_DPL(ttype) ?
842 ipa3_usb_dpl_cons_release_resource_cb :
843 ipa3_usb_cons_release_resource_cb;
844 result = ipa_rm_create_resource(&rm_ctx->cons_params);
845 if (result) {
846 IPA_USB_ERR("Failed to create %s RM resource\n",
847 ipa_rm_resource_str(rm_ctx->cons_params.name));
848 goto create_cons_rsc_fail;
849 }
850 rm_ctx->cons_valid = true;
851 IPA_USB_DBG("Created %s RM resource\n",
852 ipa_rm_resource_str(rm_ctx->cons_params.name));
853 }
854
855 return 0;
856
857create_cons_rsc_fail:
858 if (created) {
859 rm_ctx->prod_valid = false;
860 ipa_rm_delete_resource(rm_ctx->prod_params.name);
861 }
862 return result;
863}
864
865int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
866 struct ipa_usb_teth_params *teth_params,
867 int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event,
868 void *),
869 void *user_data)
870{
871 int result = -EFAULT;
872 enum ipa3_usb_transport_type ttype;
873
874 mutex_lock(&ipa3_usb_ctx->general_mutex);
875 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -0700876 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
Amir Levy9659e592016-10-27 18:08:27 +0300877 ((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) &&
878 teth_params == NULL) || ipa_usb_notify_cb == NULL ||
879 user_data == NULL) {
880 IPA_USB_ERR("bad parameters.\n");
881 result = -EINVAL;
882 goto bad_params;
883 }
884
885 ttype = IPA3_USB_GET_TTYPE(teth_prot);
886
Ghanim Fodi93a61112016-10-05 11:59:18 +0300887 if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +0300888 IPA_USB_ERR("Illegal operation.\n");
889 result = -EPERM;
890 goto bad_params;
891 }
892
893 /* Create IPA RM USB resources */
Michael Adisumarta3e350812017-09-18 14:54:36 -0700894 if (ipa_pm_is_used())
895 result = ipa3_usb_register_pm(ttype);
896 else
897 result = ipa3_usb_create_rm_resources(ttype);
Amir Levy9659e592016-10-27 18:08:27 +0300898 if (result) {
899 IPA_USB_ERR("Failed creating IPA RM USB resources\n");
900 goto bad_params;
901 }
902
903 if (!ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb) {
904 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb =
905 ipa_usb_notify_cb;
906 } else if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
907 if (ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb !=
908 ipa_usb_notify_cb) {
909 IPA_USB_ERR("Got different notify_cb\n");
910 result = -EINVAL;
911 goto bad_params;
912 }
913 } else {
914 IPA_USB_ERR("Already has dpl_notify_cb\n");
915 result = -EINVAL;
916 goto bad_params;
917 }
918
919 /* Initialize tethering protocol */
920 switch (teth_prot) {
921 case IPA_USB_RNDIS:
922 case IPA_USB_ECM:
923 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
924 IPA_USB_TETH_PROT_INVALID) {
925 IPA_USB_DBG("%s already initialized\n",
926 ipa3_usb_teth_prot_to_string(teth_prot));
927 result = -EPERM;
928 goto bad_params;
929 }
930 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
931 if (teth_prot == IPA_USB_RNDIS) {
932 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
933 teth_prot_params.rndis.device_ready_notify =
934 ipa3_usb_device_ready_notify_cb;
935 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
936 teth_prot_params.rndis.host_ethaddr,
937 teth_params->host_ethaddr,
938 sizeof(teth_params->host_ethaddr));
939 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
940 teth_prot_params.rndis.device_ethaddr,
941 teth_params->device_ethaddr,
942 sizeof(teth_params->device_ethaddr));
943
944 result = rndis_ipa_init(&ipa3_usb_ctx->
945 teth_prot_ctx[teth_prot].
946 teth_prot_params.rndis);
947 if (result) {
948 IPA_USB_ERR("Failed to initialize %s\n",
949 ipa3_usb_teth_prot_to_string(
950 teth_prot));
951 goto teth_prot_init_fail;
952 }
953 } else {
954 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
955 teth_prot_params.ecm.device_ready_notify =
956 ipa3_usb_device_ready_notify_cb;
957 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
958 teth_prot_params.ecm.host_ethaddr,
959 teth_params->host_ethaddr,
960 sizeof(teth_params->host_ethaddr));
961 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
962 teth_prot_params.ecm.device_ethaddr,
963 teth_params->device_ethaddr,
964 sizeof(teth_params->device_ethaddr));
965
966 result = ecm_ipa_init(&ipa3_usb_ctx->
967 teth_prot_ctx[teth_prot].teth_prot_params.ecm);
968 if (result) {
969 IPA_USB_ERR("Failed to initialize %s\n",
970 ipa3_usb_teth_prot_to_string(
971 teth_prot));
972 goto teth_prot_init_fail;
973 }
974 }
975 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
976 IPA_USB_TETH_PROT_INITIALIZED;
977 ipa3_usb_ctx->num_init_prot++;
978 IPA_USB_DBG("initialized %s\n",
979 ipa3_usb_teth_prot_to_string(teth_prot));
980 break;
981 case IPA_USB_RMNET:
982 case IPA_USB_MBIM:
983 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
984 IPA_USB_TETH_PROT_INVALID) {
985 IPA_USB_DBG("%s already initialized\n",
986 ipa3_usb_teth_prot_to_string(teth_prot));
987 result = -EPERM;
988 goto bad_params;
989 }
990 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
991 result = ipa3_usb_init_teth_bridge();
992 if (result)
993 goto teth_prot_init_fail;
994 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
995 IPA_USB_TETH_PROT_INITIALIZED;
996 ipa3_usb_ctx->num_init_prot++;
997 IPA_USB_DBG("initialized %s %s\n",
998 ipa3_usb_teth_prot_to_string(teth_prot),
999 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1000 break;
1001 case IPA_USB_DIAG:
1002 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1003 IPA_USB_TETH_PROT_INVALID) {
1004 IPA_USB_DBG("DPL already initialized\n");
1005 result = -EPERM;
1006 goto bad_params;
1007 }
1008 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
1009 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1010 IPA_USB_TETH_PROT_INITIALIZED;
1011 IPA_USB_DBG("initialized DPL\n");
1012 break;
1013 default:
1014 IPA_USB_ERR("unexpected tethering protocol\n");
1015 result = -EINVAL;
1016 goto bad_params;
1017 }
1018
1019 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1020 IPA_USB_ERR("failed to change state to initialized\n");
1021
1022 IPA_USB_DBG_LOW("exit\n");
1023 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1024 return 0;
1025
1026teth_prot_init_fail:
1027 if ((IPA3_USB_IS_TTYPE_DPL(ttype))
1028 || (ipa3_usb_ctx->num_init_prot == 0)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07001029 if (ipa_pm_is_used()) {
1030 ipa3_usb_deregister_pm(ttype);
1031 } else {
1032 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
1033 false;
1034 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
1035 false;
1036 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03001037 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001038 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03001039 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001040 }
Amir Levy9659e592016-10-27 18:08:27 +03001041 }
1042bad_params:
1043 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1044 return result;
1045}
1046EXPORT_SYMBOL(ipa_usb_init_teth_prot);
1047
1048void ipa3_usb_gsi_evt_err_cb(struct gsi_evt_err_notify *notify)
1049{
1050 IPA_USB_DBG_LOW("entry\n");
1051 if (!notify)
1052 return;
1053 IPA_USB_ERR("Received event error %d, description: %d\n",
1054 notify->evt_id, notify->err_desc);
1055 IPA_USB_DBG_LOW("exit\n");
1056}
1057
1058void ipa3_usb_gsi_chan_err_cb(struct gsi_chan_err_notify *notify)
1059{
1060 IPA_USB_DBG_LOW("entry\n");
1061 if (!notify)
1062 return;
1063 IPA_USB_ERR("Received channel error %d, description: %d\n",
1064 notify->evt_id, notify->err_desc);
1065 IPA_USB_DBG_LOW("exit\n");
1066}
1067
1068static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
1069{
1070 IPA_USB_DBG_LOW("gevntcount_low_addr = %x\n",
1071 params->gevntcount_low_addr);
1072 IPA_USB_DBG_LOW("gevntcount_hi_addr = %x\n",
1073 params->gevntcount_hi_addr);
1074 IPA_USB_DBG_LOW("dir = %d\n", params->dir);
1075 IPA_USB_DBG_LOW("xfer_ring_len = %d\n", params->xfer_ring_len);
1076 IPA_USB_DBG_LOW("xfer_ring_base_addr = %llx\n",
1077 params->xfer_ring_base_addr);
1078 IPA_USB_DBG_LOW("last_trb_addr_iova = %x\n",
1079 params->xfer_scratch.last_trb_addr_iova);
1080 IPA_USB_DBG_LOW("const_buffer_size = %d\n",
1081 params->xfer_scratch.const_buffer_size);
1082 IPA_USB_DBG_LOW("depcmd_low_addr = %x\n",
1083 params->xfer_scratch.depcmd_low_addr);
1084 IPA_USB_DBG_LOW("depcmd_hi_addr = %x\n",
1085 params->xfer_scratch.depcmd_hi_addr);
1086
1087 if (params->client >= IPA_CLIENT_MAX ||
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001088 params->teth_prot < 0 ||
1089 params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
Amir Levy9659e592016-10-27 18:08:27 +03001090 params->xfer_ring_len % GSI_CHAN_RE_SIZE_16B ||
1091 params->xfer_scratch.const_buffer_size < 1 ||
1092 params->xfer_scratch.const_buffer_size > 31) {
1093 IPA_USB_ERR("Invalid params\n");
1094 return false;
1095 }
1096 switch (params->teth_prot) {
1097 case IPA_USB_DIAG:
1098 if (!IPA_CLIENT_IS_CONS(params->client)) {
1099 IPA_USB_ERR("DPL supports only DL channel\n");
1100 return false;
1101 }
1102 case IPA_USB_RNDIS:
1103 case IPA_USB_ECM:
1104 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1105 IPA_USB_TETH_PROT_INVALID) {
1106 IPA_USB_ERR("%s is not initialized\n",
1107 ipa3_usb_teth_prot_to_string(
1108 params->teth_prot));
1109 return false;
1110 }
1111 break;
1112 case IPA_USB_RMNET:
1113 case IPA_USB_MBIM:
1114 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1115 IPA_USB_TETH_PROT_INVALID) {
1116 IPA_USB_ERR("%s is not initialized\n",
1117 ipa3_usb_teth_bridge_prot_to_string(
1118 params->teth_prot));
1119 return false;
1120 }
1121 break;
1122 default:
1123 IPA_USB_ERR("Unknown tethering protocol (%d)\n",
1124 params->teth_prot);
1125 return false;
1126 }
1127 return true;
1128}
1129
1130static int ipa3_usb_smmu_map_xdci_channel(
1131 struct ipa_usb_xdci_chan_params *params, bool map)
1132{
1133 int result;
1134 u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE);
1135 u32 xfer_scratch_r =
1136 rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
1137
1138 if (gevntcount_r != xfer_scratch_r) {
1139 IPA_USB_ERR("No support more than 1 page map for USB regs\n");
1140 WARN_ON(1);
1141 return -EINVAL;
1142 }
1143
1144 if (map) {
1145 if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
1146 ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r;
1147 result = ipa3_smmu_map_peer_reg(
1148 ipa3_usb_ctx->smmu_reg_map.addr, true);
1149 if (result) {
1150 IPA_USB_ERR("failed to map USB regs %d\n",
1151 result);
1152 return result;
1153 }
1154 } else {
1155 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1156 IPA_USB_ERR(
1157 "No support for map different reg\n");
1158 return -EINVAL;
1159 }
1160 }
1161 ipa3_usb_ctx->smmu_reg_map.cnt++;
1162 } else {
1163 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1164 IPA_USB_ERR(
1165 "No support for map different reg\n");
1166 return -EINVAL;
1167 }
1168
1169 if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
1170 result = ipa3_smmu_map_peer_reg(
1171 ipa3_usb_ctx->smmu_reg_map.addr, false);
1172 if (result) {
1173 IPA_USB_ERR("failed to unmap USB regs %d\n",
1174 result);
1175 return result;
1176 }
1177 }
1178 ipa3_usb_ctx->smmu_reg_map.cnt--;
1179 }
1180
1181 result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
1182 params->xfer_ring_base_addr, params->xfer_ring_len, map);
1183 if (result) {
1184 IPA_USB_ERR("failed to map Xfer ring %d\n", result);
1185 return result;
1186 }
1187
1188 result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova,
1189 params->data_buff_base_addr, params->data_buff_base_len, map);
1190 if (result) {
1191 IPA_USB_ERR("failed to map TRBs buff %d\n", result);
1192 return result;
1193 }
1194
1195 return 0;
1196}
1197
1198static int ipa3_usb_request_xdci_channel(
1199 struct ipa_usb_xdci_chan_params *params,
1200 struct ipa_req_chan_out_params *out_params)
1201{
1202 int result = -EFAULT;
1203 struct ipa_request_gsi_channel_params chan_params;
1204 enum ipa3_usb_transport_type ttype;
1205
1206 IPA_USB_DBG_LOW("entry\n");
1207 if (params == NULL || out_params == NULL ||
1208 !ipa3_usb_check_chan_params(params)) {
1209 IPA_USB_ERR("bad parameters\n");
1210 return -EINVAL;
1211 }
1212
1213 ttype = IPA3_USB_GET_TTYPE(params->teth_prot);
1214
Ghanim Fodi93a61112016-10-05 11:59:18 +03001215 if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001216 IPA_USB_ERR("Illegal operation\n");
1217 return -EPERM;
1218 }
1219
1220 memset(&chan_params, 0, sizeof(struct ipa_request_gsi_channel_params));
1221 memcpy(&chan_params.ipa_ep_cfg, &params->ipa_ep_cfg,
1222 sizeof(struct ipa_ep_cfg));
1223 chan_params.client = params->client;
1224 switch (params->teth_prot) {
1225 case IPA_USB_RNDIS:
1226 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1227 teth_prot_params.rndis.private;
1228 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1229 chan_params.notify =
1230 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1231 teth_prot_params.rndis.ipa_tx_notify;
1232 else
1233 chan_params.notify =
1234 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1235 teth_prot_params.rndis.ipa_rx_notify;
1236 chan_params.skip_ep_cfg =
1237 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1238 teth_prot_params.rndis.skip_ep_cfg;
1239 break;
1240 case IPA_USB_ECM:
1241 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1242 teth_prot_params.ecm.private;
1243 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1244 chan_params.notify =
1245 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1246 teth_prot_params.ecm.ecm_ipa_tx_dp_notify;
1247 else
1248 chan_params.notify =
1249 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1250 teth_prot_params.ecm.ecm_ipa_rx_dp_notify;
1251 chan_params.skip_ep_cfg =
1252 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1253 teth_prot_params.ecm.skip_ep_cfg;
1254 break;
1255 case IPA_USB_RMNET:
1256 case IPA_USB_MBIM:
1257 chan_params.priv =
1258 ipa3_usb_ctx->teth_bridge_params.private_data;
1259 chan_params.notify =
1260 ipa3_usb_ctx->teth_bridge_params.usb_notify_cb;
1261 chan_params.skip_ep_cfg =
1262 ipa3_usb_ctx->teth_bridge_params.skip_ep_cfg;
1263 break;
1264 case IPA_USB_DIAG:
1265 chan_params.priv = NULL;
1266 chan_params.notify = NULL;
1267 chan_params.skip_ep_cfg = true;
1268 break;
1269 default:
1270 break;
1271 }
1272
1273 result = ipa3_usb_smmu_map_xdci_channel(params, true);
1274 if (result) {
1275 IPA_USB_ERR("failed to smmu map %d\n", result);
1276 return result;
1277 }
1278
1279 /* store channel params for SMMU unmap */
1280 ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params;
1281
1282 chan_params.keep_ipa_awake = params->keep_ipa_awake;
1283 chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV;
1284 chan_params.evt_ring_params.intr = GSI_INTR_IRQ;
1285 chan_params.evt_ring_params.re_size = GSI_EVT_RING_RE_SIZE_16B;
1286 chan_params.evt_ring_params.ring_len = params->xfer_ring_len -
1287 chan_params.evt_ring_params.re_size;
1288 chan_params.evt_ring_params.ring_base_addr =
1289 params->xfer_ring_base_addr;
1290 chan_params.evt_ring_params.ring_base_vaddr = NULL;
1291 chan_params.evt_ring_params.int_modt = 0;
1292 chan_params.evt_ring_params.int_modt = 0;
1293 chan_params.evt_ring_params.intvec = 0;
1294 chan_params.evt_ring_params.msi_addr = 0;
1295 chan_params.evt_ring_params.rp_update_addr = 0;
1296 chan_params.evt_ring_params.exclusive = true;
1297 chan_params.evt_ring_params.err_cb = ipa3_usb_gsi_evt_err_cb;
1298 chan_params.evt_ring_params.user_data = NULL;
1299 chan_params.evt_scratch.xdci.gevntcount_low_addr =
1300 params->gevntcount_low_addr;
1301 chan_params.evt_scratch.xdci.gevntcount_hi_addr =
1302 params->gevntcount_hi_addr;
1303 chan_params.chan_params.prot = GSI_CHAN_PROT_XDCI;
1304 chan_params.chan_params.dir = params->dir;
1305 /* chan_id is set in ipa3_request_gsi_channel() */
1306 chan_params.chan_params.re_size = GSI_CHAN_RE_SIZE_16B;
1307 chan_params.chan_params.ring_len = params->xfer_ring_len;
1308 chan_params.chan_params.ring_base_addr =
1309 params->xfer_ring_base_addr;
1310 chan_params.chan_params.ring_base_vaddr = NULL;
1311 chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE;
1312 chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG;
1313 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1314 chan_params.chan_params.low_weight =
1315 IPA_USB_DL_CHAN_LOW_WEIGHT;
1316 else
1317 chan_params.chan_params.low_weight =
1318 IPA_USB_UL_CHAN_LOW_WEIGHT;
1319 chan_params.chan_params.xfer_cb = NULL;
1320 chan_params.chan_params.err_cb = ipa3_usb_gsi_chan_err_cb;
1321 chan_params.chan_params.chan_user_data = NULL;
1322 chan_params.chan_scratch.xdci.last_trb_addr =
1323 params->xfer_scratch.last_trb_addr_iova;
1324 /* xferrscidx will be updated later */
1325 chan_params.chan_scratch.xdci.xferrscidx = 0;
1326 chan_params.chan_scratch.xdci.const_buffer_size =
1327 params->xfer_scratch.const_buffer_size;
1328 chan_params.chan_scratch.xdci.depcmd_low_addr =
1329 params->xfer_scratch.depcmd_low_addr;
1330 chan_params.chan_scratch.xdci.depcmd_hi_addr =
1331 params->xfer_scratch.depcmd_hi_addr;
1332 chan_params.chan_scratch.xdci.outstanding_threshold =
1333 ((params->teth_prot == IPA_USB_MBIM) ? 1 : 2) *
1334 chan_params.chan_params.re_size;
Michael Adisumartabb530002018-01-16 19:09:38 -08001335
1336 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
1337 chan_params.chan_scratch.xdci.outstanding_threshold = 0;
1338
Amir Levy9659e592016-10-27 18:08:27 +03001339 /* max_outstanding_tre is set in ipa3_request_gsi_channel() */
1340 result = ipa3_request_gsi_channel(&chan_params, out_params);
1341 if (result) {
1342 IPA_USB_ERR("failed to allocate GSI channel\n");
1343 ipa3_usb_smmu_map_xdci_channel(params, false);
1344 return result;
1345 }
1346
1347 IPA_USB_DBG_LOW("exit\n");
1348 return 0;
1349}
1350
1351static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
1352 enum ipa3_usb_transport_type ttype)
1353{
1354 int result = 0;
1355
1356 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001357 if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001358 IPA_USB_ERR("bad parameter.\n");
1359 return -EINVAL;
1360 }
1361
Ghanim Fodi93a61112016-10-05 11:59:18 +03001362 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001363 IPA_USB_ERR("Illegal operation.\n");
1364 return -EPERM;
1365 }
1366
1367 /* Release channel */
1368 result = ipa3_release_gsi_channel(clnt_hdl);
1369 if (result) {
1370 IPA_USB_ERR("failed to deallocate channel.\n");
1371 return result;
1372 }
1373
1374 result = ipa3_usb_smmu_map_xdci_channel(
1375 &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false);
1376
1377 /* Change ipa_usb state to INITIALIZED */
1378 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1379 IPA_USB_ERR("failed to change state to initialized\n");
1380
1381 IPA_USB_DBG_LOW("exit\n");
1382 return 0;
1383}
1384
1385static int ipa3_usb_request_prod(enum ipa3_usb_transport_type ttype)
1386{
1387 int result;
1388 struct ipa3_usb_rm_context *rm_ctx;
1389 const char *rsrc_str;
1390
1391 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1392 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1393
1394 IPA_USB_DBG_LOW("requesting %s\n", rsrc_str);
1395 init_completion(&rm_ctx->prod_comp);
1396 result = ipa_rm_request_resource(rm_ctx->prod_params.name);
1397 if (result) {
1398 if (result != -EINPROGRESS) {
1399 IPA_USB_ERR("failed to request %s: %d\n",
1400 rsrc_str, result);
1401 return result;
1402 }
1403 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1404 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1405 if (result == 0) {
1406 IPA_USB_ERR("timeout request %s\n", rsrc_str);
1407 return -ETIME;
1408 }
1409 }
1410
1411 IPA_USB_DBG_LOW("%s granted\n", rsrc_str);
1412 return 0;
1413}
1414
1415static int ipa3_usb_release_prod(enum ipa3_usb_transport_type ttype)
1416{
1417 int result;
1418 struct ipa3_usb_rm_context *rm_ctx;
1419 const char *rsrc_str;
1420
1421 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1422 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1423
1424 IPA_USB_DBG_LOW("releasing %s\n", rsrc_str);
1425
1426 init_completion(&rm_ctx->prod_comp);
1427 result = ipa_rm_release_resource(rm_ctx->prod_params.name);
1428 if (result) {
1429 if (result != -EINPROGRESS) {
1430 IPA_USB_ERR("failed to release %s: %d\n",
1431 rsrc_str, result);
1432 return result;
1433 }
1434 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1435 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1436 if (result == 0) {
1437 IPA_USB_ERR("timeout release %s\n", rsrc_str);
1438 return -ETIME;
1439 }
1440 }
1441
1442 IPA_USB_DBG_LOW("%s released\n", rsrc_str);
1443 return 0;
1444}
1445
1446static bool ipa3_usb_check_connect_params(
1447 struct ipa_usb_xdci_connect_params_internal *params)
1448{
1449 IPA_USB_DBG_LOW("ul xferrscidx = %d\n", params->usb_to_ipa_xferrscidx);
1450 IPA_USB_DBG_LOW("dl xferrscidx = %d\n", params->ipa_to_usb_xferrscidx);
1451 IPA_USB_DBG_LOW("max_supported_bandwidth_mbps = %d\n",
1452 params->max_supported_bandwidth_mbps);
1453
1454 if (params->max_pkt_size < IPA_USB_HIGH_SPEED_512B ||
1455 params->max_pkt_size > IPA_USB_SUPER_SPEED_1024B ||
1456 params->ipa_to_usb_xferrscidx < 0 ||
1457 params->ipa_to_usb_xferrscidx > 127 ||
1458 (params->teth_prot != IPA_USB_DIAG &&
1459 (params->usb_to_ipa_xferrscidx < 0 ||
1460 params->usb_to_ipa_xferrscidx > 127)) ||
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001461 params->teth_prot < 0 ||
1462 params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03001463 IPA_USB_ERR("Invalid params\n");
1464 return false;
1465 }
1466
1467 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1468 IPA_USB_TETH_PROT_INVALID) {
1469 IPA_USB_ERR("%s is not initialized\n",
1470 ipa3_usb_teth_prot_to_string(
1471 params->teth_prot));
1472 return false;
1473 }
1474
1475 return true;
1476}
1477
1478static int ipa3_usb_connect_teth_bridge(
1479 struct teth_bridge_connect_params *params)
1480{
1481 int result;
1482
1483 result = teth_bridge_connect(params);
1484 if (result) {
1485 IPA_USB_ERR("failed to connect teth_bridge (%s)\n",
1486 params->tethering_mode == TETH_TETHERING_MODE_RMNET ?
1487 "rmnet" : "mbim");
1488 return result;
1489 }
1490
1491 return 0;
1492}
1493
1494static int ipa3_usb_connect_dpl(void)
1495{
1496 int res = 0;
1497
Michael Adisumarta3e350812017-09-18 14:54:36 -07001498 if (ipa_pm_is_used())
1499 return 0;
1500
Amir Levy9659e592016-10-27 18:08:27 +03001501 /*
1502 * Add DPL dependency to RM dependency graph, first add_dependency call
1503 * is sync in order to make sure the IPA clocks are up before we
1504 * continue and notify the USB driver it may continue.
1505 */
1506 res = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1507 IPA_RM_RESOURCE_Q6_CONS);
1508 if (res < 0) {
1509 IPA_USB_ERR("ipa_rm_add_dependency_sync() failed.\n");
1510 return res;
1511 }
1512
1513 /*
1514 * this add_dependency call can't be sync since it will block until DPL
1515 * status is connected (which can happen only later in the flow),
1516 * the clocks are already up so the call doesn't need to block.
1517 */
1518 res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
1519 IPA_RM_RESOURCE_USB_DPL_CONS);
1520 if (res < 0 && res != -EINPROGRESS) {
1521 IPA_USB_ERR("ipa_rm_add_dependency() failed.\n");
1522 ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1523 IPA_RM_RESOURCE_Q6_CONS);
1524 return res;
1525 }
1526
1527 return 0;
1528}
1529
Ghanim Fodi93a61112016-10-05 11:59:18 +03001530static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
Amir Levy9659e592016-10-27 18:08:27 +03001531{
1532 int result;
1533 struct teth_bridge_connect_params teth_bridge_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001534 struct ipa3_usb_teth_prot_conn_params *teth_conn_params;
1535 enum ipa3_usb_transport_type ttype;
Amir Levy9659e592016-10-27 18:08:27 +03001536
Ghanim Fodi93a61112016-10-05 11:59:18 +03001537 IPA_USB_DBG("connecting protocol = %s\n",
1538 ipa3_usb_teth_prot_to_string(teth_prot));
1539
1540 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1541
1542 teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params);
1543
1544 switch (teth_prot) {
Amir Levy9659e592016-10-27 18:08:27 +03001545 case IPA_USB_RNDIS:
1546 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state ==
1547 IPA_USB_TETH_PROT_CONNECTED) {
1548 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001549 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001550 break;
1551 }
1552 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1553 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data;
1554 result = rndis_ipa_pipe_connect_notify(
Ghanim Fodi93a61112016-10-05 11:59:18 +03001555 teth_conn_params->usb_to_ipa_clnt_hdl,
1556 teth_conn_params->ipa_to_usb_clnt_hdl,
1557 teth_conn_params->params.max_xfer_size_bytes_to_dev,
1558 teth_conn_params->params.max_packet_number_to_dev,
1559 teth_conn_params->params.max_xfer_size_bytes_to_host,
Amir Levy9659e592016-10-27 18:08:27 +03001560 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1561 teth_prot_params.rndis.private);
1562 if (result) {
1563 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001564 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001565 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1566 return result;
1567 }
1568 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state =
1569 IPA_USB_TETH_PROT_CONNECTED;
1570 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001571 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001572 break;
1573 case IPA_USB_ECM:
1574 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state ==
1575 IPA_USB_TETH_PROT_CONNECTED) {
1576 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001577 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001578 break;
1579 }
1580 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1581 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001582 result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl,
1583 teth_conn_params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001584 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1585 teth_prot_params.ecm.private);
1586 if (result) {
1587 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001588 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001589 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1590 return result;
1591 }
1592 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state =
1593 IPA_USB_TETH_PROT_CONNECTED;
1594 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001595 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001596 break;
1597 case IPA_USB_RMNET:
1598 case IPA_USB_MBIM:
Ghanim Fodi93a61112016-10-05 11:59:18 +03001599 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
Amir Levy9659e592016-10-27 18:08:27 +03001600 IPA_USB_TETH_PROT_CONNECTED) {
1601 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001602 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001603 break;
1604 }
1605 result = ipa3_usb_init_teth_bridge();
1606 if (result)
1607 return result;
1608
1609 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001610 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
Amir Levy9659e592016-10-27 18:08:27 +03001611 user_data;
1612 teth_bridge_params.ipa_usb_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001613 teth_conn_params->ipa_to_usb_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001614 teth_bridge_params.usb_ipa_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001615 teth_conn_params->usb_to_ipa_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001616 teth_bridge_params.tethering_mode =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001617 (teth_prot == IPA_USB_RMNET) ?
Amir Levy9659e592016-10-27 18:08:27 +03001618 (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
1619 teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
1620 result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
1621 if (result) {
1622 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1623 return result;
1624 }
Ghanim Fodi93a61112016-10-05 11:59:18 +03001625 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
Amir Levy9659e592016-10-27 18:08:27 +03001626 IPA_USB_TETH_PROT_CONNECTED;
1627 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1628 IPA_USB_DBG("%s (%s) is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001629 ipa3_usb_teth_prot_to_string(teth_prot),
1630 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001631 break;
1632 case IPA_USB_DIAG:
1633 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state ==
1634 IPA_USB_TETH_PROT_CONNECTED) {
1635 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001636 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001637 break;
1638 }
1639
1640 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001641 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data;
Amir Levy9659e592016-10-27 18:08:27 +03001642 result = ipa3_usb_connect_dpl();
1643 if (result) {
1644 IPA_USB_ERR("Failed connecting DPL result=%d\n",
1645 result);
1646 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1647 return result;
1648 }
1649 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state =
1650 IPA_USB_TETH_PROT_CONNECTED;
1651 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1652 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001653 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001654 break;
1655 default:
1656 IPA_USB_ERR("Invalid tethering protocol\n");
1657 return -EFAULT;
1658 }
1659
1660 return 0;
1661}
1662
1663static int ipa3_usb_disconnect_teth_bridge(void)
1664{
1665 int result;
1666
1667 result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
1668 if (result) {
1669 IPA_USB_ERR("failed to disconnect teth_bridge.\n");
1670 return result;
1671 }
1672
1673 return 0;
1674}
1675
1676static int ipa3_usb_disconnect_dpl(void)
1677{
1678 int res;
1679
Michael Adisumarta3e350812017-09-18 14:54:36 -07001680 if (ipa_pm_is_used())
1681 return 0;
1682
Amir Levy9659e592016-10-27 18:08:27 +03001683 /* Remove DPL RM dependency */
1684 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1685 IPA_RM_RESOURCE_Q6_CONS);
1686 if (res)
1687 IPA_USB_ERR("deleting DPL_DUMMY_PROD rsrc dependency fail\n");
1688
1689 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
1690 IPA_RM_RESOURCE_USB_DPL_CONS);
1691 if (res)
1692 IPA_USB_ERR("deleting DPL_CONS rsrc dependencty fail\n");
1693
1694 return 0;
1695}
1696
1697static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
1698{
1699 int result = 0;
1700 enum ipa3_usb_transport_type ttype;
1701
1702 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1703
1704 switch (teth_prot) {
1705 case IPA_USB_RNDIS:
1706 case IPA_USB_ECM:
1707 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1708 IPA_USB_TETH_PROT_CONNECTED) {
1709 IPA_USB_DBG("%s is not connected.\n",
1710 ipa3_usb_teth_prot_to_string(teth_prot));
1711 return -EPERM;
1712 }
1713 if (teth_prot == IPA_USB_RNDIS) {
1714 result = rndis_ipa_pipe_disconnect_notify(
1715 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1716 teth_prot_params.rndis.private);
1717 } else {
1718 result = ecm_ipa_disconnect(
1719 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1720 teth_prot_params.ecm.private);
1721 }
1722 if (result) {
1723 IPA_USB_ERR("failed to disconnect %s.\n",
1724 ipa3_usb_teth_prot_to_string(teth_prot));
1725 break;
1726 }
1727 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1728 IPA_USB_TETH_PROT_INITIALIZED;
1729 IPA_USB_DBG("disconnected %s\n",
1730 ipa3_usb_teth_prot_to_string(teth_prot));
1731 break;
1732 case IPA_USB_RMNET:
1733 case IPA_USB_MBIM:
1734 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1735 IPA_USB_TETH_PROT_CONNECTED) {
1736 IPA_USB_DBG("%s (%s) is not connected.\n",
1737 ipa3_usb_teth_prot_to_string(teth_prot),
1738 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1739 return -EPERM;
1740 }
1741 result = ipa3_usb_disconnect_teth_bridge();
1742 if (result)
1743 break;
1744
1745 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1746 IPA_USB_TETH_PROT_INITIALIZED;
1747 IPA_USB_DBG("disconnected %s (%s)\n",
1748 ipa3_usb_teth_prot_to_string(teth_prot),
1749 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1750 break;
1751 case IPA_USB_DIAG:
1752 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1753 IPA_USB_TETH_PROT_CONNECTED) {
1754 IPA_USB_DBG("%s is not connected.\n",
1755 ipa3_usb_teth_prot_to_string(teth_prot));
1756 return -EPERM;
1757 }
1758 result = ipa3_usb_disconnect_dpl();
1759 if (result)
1760 break;
1761 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1762 IPA_USB_TETH_PROT_INITIALIZED;
1763 IPA_USB_DBG("disconnected %s\n",
1764 ipa3_usb_teth_prot_to_string(teth_prot));
1765 break;
1766 default:
1767 break;
1768 }
1769
1770 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1771 return result;
1772}
1773
1774static int ipa3_usb_xdci_connect_internal(
1775 struct ipa_usb_xdci_connect_params_internal *params)
1776{
1777 int result = -EFAULT;
1778 struct ipa_rm_perf_profile profile;
1779 enum ipa3_usb_transport_type ttype;
1780
1781 IPA_USB_DBG_LOW("entry\n");
1782 if (params == NULL || !ipa3_usb_check_connect_params(params)) {
1783 IPA_USB_ERR("bad parameters.\n");
1784 return -EINVAL;
1785 }
1786
1787 ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
1788 IPA_USB_TRANSPORT_TETH;
1789
Ghanim Fodi93a61112016-10-05 11:59:18 +03001790 if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001791 IPA_USB_ERR("Illegal operation.\n");
1792 return -EPERM;
1793 }
1794
Ghanim Fodi93a61112016-10-05 11:59:18 +03001795 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl
1796 = params->ipa_to_usb_clnt_hdl;
1797 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
1798 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.
1799 usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl;
1800 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params
1801 = params->teth_prot_params;
1802
Amir Levy9659e592016-10-27 18:08:27 +03001803 /* Set EE xDCI specific scratch */
1804 result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
1805 if (result) {
1806 IPA_USB_ERR("failed setting xDCI EE scratch field\n");
1807 return result;
1808 }
1809
Michael Adisumarta3e350812017-09-18 14:54:36 -07001810 if (ipa_pm_is_used()) {
1811 result = ipa_pm_set_perf_profile(
1812 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
1813 params->max_supported_bandwidth_mbps);
1814 if (result) {
1815 IPA_USB_ERR("failed to set perf profile\n");
1816 return result;
1817 }
Amir Levy9659e592016-10-27 18:08:27 +03001818
Michael Adisumarta3e350812017-09-18 14:54:36 -07001819 result = ipa_pm_activate_sync(
1820 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1821 if (result) {
1822 IPA_USB_ERR("failed to activate pm\n");
1823 return result;
1824 }
1825 } else {
1826 /* Set RM PROD & CONS perf profile */
1827 profile.max_supported_bandwidth_mbps =
1828 params->max_supported_bandwidth_mbps;
1829 result = ipa_rm_set_perf_profile(
1830 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
1831 &profile);
1832 if (result) {
1833 IPA_USB_ERR("failed to set %s perf profile\n",
1834 ipa_rm_resource_str(ipa3_usb_ctx->
1835 ttype_ctx[ttype].
1836 rm_ctx.prod_params.name));
1837 return result;
1838 }
1839 result = ipa_rm_set_perf_profile(
1840 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
1841 &profile);
1842 if (result) {
1843 IPA_USB_ERR("failed to set %s perf profile\n",
1844 ipa_rm_resource_str(ipa3_usb_ctx->
1845 ttype_ctx[ttype].
1846 rm_ctx.cons_params.name));
1847 return result;
1848 }
1849
1850 /* Request PROD */
1851 result = ipa3_usb_request_prod(ttype);
1852 if (result)
1853 return result;
1854 }
Amir Levy9659e592016-10-27 18:08:27 +03001855
1856 if (params->teth_prot != IPA_USB_DIAG) {
1857 /* Start UL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001858 result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001859 params->usb_to_ipa_xferrscidx,
1860 params->usb_to_ipa_xferrscidx_valid);
1861 if (result) {
1862 IPA_USB_ERR("failed to connect UL channel.\n");
1863 goto connect_ul_fail;
1864 }
1865 }
1866
1867 /* Start DL/DPL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001868 result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001869 params->ipa_to_usb_xferrscidx,
1870 params->ipa_to_usb_xferrscidx_valid);
1871 if (result) {
1872 IPA_USB_ERR("failed to connect DL/DPL channel.\n");
1873 goto connect_dl_fail;
1874 }
1875
1876 /* Connect tethering protocol */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001877 result = ipa3_usb_connect_teth_prot(params->teth_prot);
Amir Levy9659e592016-10-27 18:08:27 +03001878 if (result) {
1879 IPA_USB_ERR("failed to connect teth protocol\n");
1880 goto connect_teth_prot_fail;
1881 }
1882
1883 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
1884 IPA_USB_ERR(
1885 "failed to change state to connected\n");
1886 goto state_change_connected_fail;
1887 }
1888
1889 IPA_USB_DBG_LOW("exit\n");
1890 return 0;
1891
1892state_change_connected_fail:
1893 ipa3_usb_disconnect_teth_prot(params->teth_prot);
1894connect_teth_prot_fail:
1895 ipa3_xdci_disconnect(params->ipa_to_usb_clnt_hdl, false, -1);
1896 ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
1897 ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
1898connect_dl_fail:
1899 if (params->teth_prot != IPA_USB_DIAG) {
1900 ipa3_xdci_disconnect(params->usb_to_ipa_clnt_hdl, false, -1);
1901 ipa3_reset_gsi_channel(params->usb_to_ipa_clnt_hdl);
1902 ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
1903 }
1904connect_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001905 if (ipa_pm_is_used())
1906 ipa_pm_deactivate_sync(
1907 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1908 else
1909 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03001910 return result;
1911}
1912
1913#ifdef CONFIG_DEBUG_FS
1914static char dbg_buff[IPA_USB_MAX_MSG_LEN];
1915
1916static char *ipa3_usb_cons_state_to_string(enum ipa3_usb_cons_state state)
1917{
1918 switch (state) {
1919 case IPA_USB_CONS_GRANTED:
1920 return "CONS_GRANTED";
1921 case IPA_USB_CONS_RELEASED:
1922 return "CONS_RELEASED";
1923 }
1924
1925 return "UNSUPPORTED";
1926}
1927
1928static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status)
1929{
1930 int res;
1931 int i;
1932 unsigned long flags;
1933
1934 IPA_USB_DBG_LOW("entry\n");
1935
1936 if (ipa3_usb_ctx == NULL) {
1937 IPA_USB_ERR("IPA USB was not inited yet\n");
1938 return -EFAULT;
1939 }
1940
1941 mutex_lock(&ipa3_usb_ctx->general_mutex);
1942
1943 if (!status) {
1944 IPA_USB_ERR("Invalid input\n");
1945 res = -EINVAL;
1946 goto bail;
1947 }
1948
1949 memset(status, 0, sizeof(struct ipa3_usb_status_dbg_info));
1950
1951 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
1952 status->teth_state = ipa3_usb_state_to_string(
1953 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].state);
1954 status->dpl_state = ipa3_usb_state_to_string(
1955 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].state);
1956 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].rm_ctx.cons_valid)
1957 status->teth_cons_state = ipa3_usb_cons_state_to_string(
1958 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].
1959 rm_ctx.cons_state);
1960 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].rm_ctx.cons_valid)
1961 status->dpl_cons_state = ipa3_usb_cons_state_to_string(
1962 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].
1963 rm_ctx.cons_state);
1964 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
1965
1966 for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) {
1967 if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1968 IPA_USB_TETH_PROT_INITIALIZED) {
1969 if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM))
1970 status->inited_prots[status->num_init_prot++] =
1971 ipa3_usb_teth_bridge_prot_to_string(i);
1972 else
1973 status->inited_prots[status->num_init_prot++] =
1974 ipa3_usb_teth_prot_to_string(i);
1975 } else if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1976 IPA_USB_TETH_PROT_CONNECTED) {
1977 switch (i) {
1978 case IPA_USB_RMNET:
1979 case IPA_USB_MBIM:
1980 status->teth_connected_prot =
1981 ipa3_usb_teth_bridge_prot_to_string(i);
1982 break;
1983 case IPA_USB_DIAG:
1984 status->dpl_connected_prot =
1985 ipa3_usb_teth_prot_to_string(i);
1986 break;
1987 default:
1988 status->teth_connected_prot =
1989 ipa3_usb_teth_prot_to_string(i);
1990 }
1991 }
1992 }
1993
1994 res = 0;
1995 IPA_USB_DBG_LOW("exit\n");
1996bail:
1997 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1998 return res;
1999}
2000
2001static ssize_t ipa3_read_usb_state_info(struct file *file, char __user *ubuf,
2002 size_t count, loff_t *ppos)
2003{
2004 struct ipa3_usb_status_dbg_info status;
2005 int result;
2006 int nbytes;
2007 int cnt = 0;
2008 int i;
2009
2010 result = ipa3_usb_get_status_dbg_info(&status);
2011 if (result) {
2012 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2013 "Fail to read IPA USB status\n");
2014 cnt += nbytes;
2015 } else {
2016 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2017 "Tethering Data State: %s\n"
2018 "DPL State: %s\n"
2019 "Protocols in Initialized State: ",
2020 status.teth_state,
2021 status.dpl_state);
2022 cnt += nbytes;
2023
2024 for (i = 0 ; i < status.num_init_prot ; i++) {
2025 nbytes = scnprintf(dbg_buff + cnt,
2026 IPA_USB_MAX_MSG_LEN - cnt,
2027 "%s ", status.inited_prots[i]);
2028 cnt += nbytes;
2029 }
2030 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2031 status.num_init_prot ? "\n" : "None\n");
2032 cnt += nbytes;
2033
2034 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2035 "Protocols in Connected State: ");
2036 cnt += nbytes;
2037 if (status.teth_connected_prot) {
2038 nbytes = scnprintf(dbg_buff + cnt,
2039 IPA_USB_MAX_MSG_LEN - cnt,
2040 "%s ", status.teth_connected_prot);
2041 cnt += nbytes;
2042 }
2043 if (status.dpl_connected_prot) {
2044 nbytes = scnprintf(dbg_buff + cnt,
2045 IPA_USB_MAX_MSG_LEN - cnt,
2046 "%s ", status.dpl_connected_prot);
2047 cnt += nbytes;
2048 }
2049 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2050 (status.teth_connected_prot ||
2051 status.dpl_connected_prot) ? "\n" : "None\n");
2052 cnt += nbytes;
2053
2054 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2055 "USB Tethering Consumer State: %s\n",
2056 status.teth_cons_state ?
2057 status.teth_cons_state : "Invalid");
2058 cnt += nbytes;
2059
2060 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2061 "DPL Consumer State: %s\n",
2062 status.dpl_cons_state ? status.dpl_cons_state :
2063 "Invalid");
2064 cnt += nbytes;
2065 }
2066
2067 return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
2068}
2069
2070const struct file_operations ipa3_ipa_usb_ops = {
2071 .read = ipa3_read_usb_state_info,
2072};
2073
2074static void ipa_usb_debugfs_init(void)
2075{
2076 const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
2077
2078 ipa3_usb_ctx->dent = debugfs_create_dir("ipa_usb", 0);
2079 if (IS_ERR(ipa3_usb_ctx->dent)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002080 pr_err("fail to create folder in debug_fs.\n");
Amir Levy9659e592016-10-27 18:08:27 +03002081 return;
2082 }
2083
2084 ipa3_usb_ctx->dfile_state_info = debugfs_create_file("state_info",
2085 read_only_mode, ipa3_usb_ctx->dent, 0,
2086 &ipa3_ipa_usb_ops);
2087 if (!ipa3_usb_ctx->dfile_state_info ||
2088 IS_ERR(ipa3_usb_ctx->dfile_state_info)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002089 pr_err("failed to create file for state_info\n");
Amir Levy9659e592016-10-27 18:08:27 +03002090 goto fail;
2091 }
2092
2093 return;
2094
2095fail:
2096 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2097 ipa3_usb_ctx->dent = NULL;
2098}
2099
2100static void ipa_usb_debugfs_remove(void)
2101{
2102 if (IS_ERR(ipa3_usb_ctx->dent)) {
2103 IPA_USB_ERR("ipa_usb debugfs folder was not created.\n");
2104 return;
2105 }
2106
2107 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2108}
2109#else /* CONFIG_DEBUG_FS */
2110static void ipa_usb_debugfs_init(void){}
2111static void ipa_usb_debugfs_remove(void){}
2112#endif /* CONFIG_DEBUG_FS */
2113
2114
2115
2116int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
2117 struct ipa_usb_xdci_chan_params *dl_chan_params,
2118 struct ipa_req_chan_out_params *ul_out_params,
2119 struct ipa_req_chan_out_params *dl_out_params,
2120 struct ipa_usb_xdci_connect_params *connect_params)
2121{
2122 int result = -EFAULT;
2123 struct ipa_usb_xdci_connect_params_internal conn_params;
2124
2125 mutex_lock(&ipa3_usb_ctx->general_mutex);
2126 IPA_USB_DBG_LOW("entry\n");
2127 if (connect_params == NULL || dl_chan_params == NULL ||
2128 dl_out_params == NULL ||
2129 (connect_params->teth_prot != IPA_USB_DIAG &&
2130 (ul_chan_params == NULL || ul_out_params == NULL))) {
2131 IPA_USB_ERR("bad parameters.\n");
2132 result = -EINVAL;
2133 goto bad_params;
2134 }
2135
2136 if (connect_params->teth_prot != IPA_USB_DIAG) {
2137 result = ipa3_usb_request_xdci_channel(ul_chan_params,
2138 ul_out_params);
2139 if (result) {
2140 IPA_USB_ERR("failed to allocate UL channel.\n");
2141 goto bad_params;
2142 }
2143 }
2144
2145 result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params);
2146 if (result) {
2147 IPA_USB_ERR("failed to allocate DL/DPL channel.\n");
2148 goto alloc_dl_chan_fail;
2149 }
2150
2151 memset(&conn_params, 0,
2152 sizeof(struct ipa_usb_xdci_connect_params_internal));
2153 conn_params.max_pkt_size = connect_params->max_pkt_size;
2154 conn_params.ipa_to_usb_clnt_hdl = dl_out_params->clnt_hdl;
2155 conn_params.ipa_to_usb_xferrscidx =
2156 connect_params->ipa_to_usb_xferrscidx;
2157 conn_params.ipa_to_usb_xferrscidx_valid =
2158 connect_params->ipa_to_usb_xferrscidx_valid;
2159 if (connect_params->teth_prot != IPA_USB_DIAG) {
2160 conn_params.usb_to_ipa_clnt_hdl = ul_out_params->clnt_hdl;
2161 conn_params.usb_to_ipa_xferrscidx =
2162 connect_params->usb_to_ipa_xferrscidx;
2163 conn_params.usb_to_ipa_xferrscidx_valid =
2164 connect_params->usb_to_ipa_xferrscidx_valid;
2165 }
2166 conn_params.teth_prot = connect_params->teth_prot;
2167 conn_params.teth_prot_params = connect_params->teth_prot_params;
2168 conn_params.max_supported_bandwidth_mbps =
2169 connect_params->max_supported_bandwidth_mbps;
2170 result = ipa3_usb_xdci_connect_internal(&conn_params);
2171 if (result) {
2172 IPA_USB_ERR("failed to connect.\n");
2173 goto connect_fail;
2174 }
2175
2176 IPA_USB_DBG_LOW("exit\n");
2177 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2178 return 0;
2179
2180connect_fail:
2181 ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002182 IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002183alloc_dl_chan_fail:
2184 if (connect_params->teth_prot != IPA_USB_DIAG)
2185 ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002186 IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002187bad_params:
2188 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2189 return result;
2190}
2191EXPORT_SYMBOL(ipa_usb_xdci_connect);
2192
2193static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
2194{
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002195 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002196 IPA_USB_ERR("bad parameter.\n");
2197 return -EFAULT;
2198 }
2199
2200 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2201 IPA_USB_TETH_PROT_CONNECTED) {
2202 IPA_USB_ERR("%s is not connected.\n",
2203 ipa3_usb_teth_prot_to_string(teth_prot));
2204 return -EFAULT;
2205 }
2206
2207 return 0;
2208}
2209
Ghanim Fodi93a61112016-10-05 11:59:18 +03002210/* Assumes lock already acquired */
2211static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2212 enum ipa_usb_teth_prot teth_prot)
2213{
2214 int result = 0;
2215 enum ipa3_usb_transport_type ttype;
2216
2217 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2218
2219 IPA_USB_DBG_LOW("entry\n");
2220
2221 /* Reset DL channel */
2222 result = ipa3_reset_gsi_channel(dl_clnt_hdl);
2223 if (result) {
2224 IPA_USB_ERR("failed to reset DL channel.\n");
2225 return result;
2226 }
2227
2228 /* Reset DL event ring */
2229 result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
2230 if (result) {
2231 IPA_USB_ERR("failed to reset DL event ring.\n");
2232 return result;
2233 }
2234
2235 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Mohammed Javida17a6bf2017-11-22 19:40:38 +05302236 ipa3_xdci_ep_delay_rm(ul_clnt_hdl); /* Remove ep_delay if set */
Ghanim Fodi93a61112016-10-05 11:59:18 +03002237 /* Reset UL channel */
2238 result = ipa3_reset_gsi_channel(ul_clnt_hdl);
2239 if (result) {
2240 IPA_USB_ERR("failed to reset UL channel.\n");
2241 return result;
2242 }
2243
2244 /* Reset UL event ring */
2245 result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
2246 if (result) {
2247 IPA_USB_ERR("failed to reset UL event ring.\n");
2248 return result;
2249 }
2250 }
2251
2252 /* Change state to STOPPED */
2253 if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
2254 IPA_USB_ERR("failed to change state to stopped\n");
2255
2256 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2257 result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
2258 if (result) {
2259 IPA_USB_ERR("failed to release UL channel.\n");
2260 return result;
2261 }
2262 }
2263
2264 result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
2265 if (result) {
2266 IPA_USB_ERR("failed to release DL channel.\n");
2267 return result;
2268 }
2269
2270 IPA_USB_DBG_LOW("exit\n");
2271
2272 return 0;
2273}
2274
Amir Levy9659e592016-10-27 18:08:27 +03002275int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2276 enum ipa_usb_teth_prot teth_prot)
2277{
2278 int result = 0;
2279 struct ipa_ep_cfg_holb holb_cfg;
2280 unsigned long flags;
2281 enum ipa3_usb_state orig_state;
2282 enum ipa3_usb_transport_type ttype;
2283
2284 mutex_lock(&ipa3_usb_ctx->general_mutex);
2285 IPA_USB_DBG_LOW("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002286
2287 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2288
Ghanim Fodi93a61112016-10-05 11:59:18 +03002289 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002290 IPA_USB_ERR("Illegal operation.\n");
2291 result = -EPERM;
2292 goto bad_params;
2293 }
2294
2295 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002296 if (ipa3_usb_ctx->ttype_ctx[ttype].state ==
2297 IPA_USB_SUSPENDED_NO_RWAKEUP) {
2298 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2299 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2300 teth_prot);
2301 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2302 return result;
2303 }
2304
2305 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2306 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2307 result = -EINVAL;
2308 goto bad_params;
2309 }
2310
Amir Levy9659e592016-10-27 18:08:27 +03002311 if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
2312 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2313 /* Stop DL/DPL channel */
2314 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2315 if (result) {
2316 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2317 goto bad_params;
2318 }
2319 } else {
2320 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2321 memset(&holb_cfg, 0, sizeof(holb_cfg));
2322 holb_cfg.en = IPA_HOLB_TMR_EN;
2323 holb_cfg.tmr_val = 0;
2324 ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);
2325 }
2326
2327 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2328 orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2329 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Skylar Changdf5f2342017-06-05 09:27:48 -07002330 if (orig_state != IPA_USB_SUSPENDED) {
Amir Levy9659e592016-10-27 18:08:27 +03002331 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2332 flags);
2333 /* Stop UL channel */
2334 result = ipa3_xdci_disconnect(ul_clnt_hdl,
2335 true,
2336 ipa3_usb_ctx->qmi_req_id);
2337 if (result) {
2338 IPA_USB_ERR("failed disconnect UL channel\n");
2339 goto bad_params;
2340 }
2341 ipa3_usb_ctx->qmi_req_id++;
2342 } else
2343 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2344 flags);
2345 } else
2346 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2347
Ghanim Fodi93a61112016-10-05 11:59:18 +03002348 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2349 teth_prot);
2350 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03002351 goto bad_params;
Amir Levy9659e592016-10-27 18:08:27 +03002352
2353 /* Disconnect tethering protocol */
2354 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2355 if (result)
2356 goto bad_params;
2357
Skylar Changdf5f2342017-06-05 09:27:48 -07002358 if (orig_state != IPA_USB_SUSPENDED) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07002359 if (ipa_pm_is_used())
2360 result = ipa_pm_deactivate_sync(
2361 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2362 else
2363 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002364 if (result) {
2365 IPA_USB_ERR("failed to release PROD.\n");
2366 goto bad_params;
2367 }
2368 }
2369
2370 IPA_USB_DBG_LOW("exit\n");
2371 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2372 return 0;
2373
2374bad_params:
2375 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2376 return result;
2377
2378}
2379EXPORT_SYMBOL(ipa_usb_xdci_disconnect);
2380
2381int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
2382{
2383 int result = -EFAULT;
2384 enum ipa3_usb_transport_type ttype;
2385
2386 mutex_lock(&ipa3_usb_ctx->general_mutex);
2387 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002388 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002389 IPA_USB_ERR("bad parameters.\n");
2390 result = -EINVAL;
2391 goto bad_params;
2392 }
2393
2394 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2395
Ghanim Fodi93a61112016-10-05 11:59:18 +03002396 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002397 IPA_USB_ERR("Illegal operation.\n");
2398 result = -EPERM;
2399 goto bad_params;
2400 }
2401
2402 /* Clean-up tethering protocol */
2403 switch (teth_prot) {
2404 case IPA_USB_RNDIS:
2405 case IPA_USB_ECM:
2406 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2407 IPA_USB_TETH_PROT_INITIALIZED) {
2408 IPA_USB_ERR("%s is not initialized\n",
2409 ipa3_usb_teth_prot_to_string(teth_prot));
2410 result = -EINVAL;
2411 goto bad_params;
2412 }
2413 if (teth_prot == IPA_USB_RNDIS)
2414 rndis_ipa_cleanup(
2415 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2416 teth_prot_params.rndis.private);
2417 else
2418 ecm_ipa_cleanup(
2419 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2420 teth_prot_params.ecm.private);
2421 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = NULL;
2422 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2423 IPA_USB_TETH_PROT_INVALID;
2424 ipa3_usb_ctx->num_init_prot--;
2425 IPA_USB_DBG("deinitialized %s\n",
2426 ipa3_usb_teth_prot_to_string(teth_prot));
2427 break;
2428 case IPA_USB_RMNET:
2429 case IPA_USB_MBIM:
2430 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2431 IPA_USB_TETH_PROT_INITIALIZED) {
2432 IPA_USB_ERR("%s (%s) is not initialized\n",
2433 ipa3_usb_teth_prot_to_string(teth_prot),
2434 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2435 result = -EINVAL;
2436 goto bad_params;
2437 }
2438
2439 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2440 NULL;
2441 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2442 IPA_USB_TETH_PROT_INVALID;
2443 ipa3_usb_ctx->num_init_prot--;
2444 IPA_USB_DBG("deinitialized %s (%s)\n",
2445 ipa3_usb_teth_prot_to_string(teth_prot),
2446 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2447 break;
2448 case IPA_USB_DIAG:
2449 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2450 IPA_USB_TETH_PROT_INITIALIZED) {
2451 IPA_USB_ERR("%s is not initialized\n",
2452 ipa3_usb_teth_prot_to_string(teth_prot));
2453 result = -EINVAL;
2454 goto bad_params;
2455 }
2456 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2457 NULL;
2458 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2459 IPA_USB_TETH_PROT_INVALID;
2460 IPA_USB_DBG("deinitialized %s\n",
2461 ipa3_usb_teth_prot_to_string(teth_prot));
2462 break;
2463 default:
2464 IPA_USB_ERR("unexpected tethering protocol\n");
2465 result = -EINVAL;
2466 goto bad_params;
2467 }
2468
2469 if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
2470 (ipa3_usb_ctx->num_init_prot == 0)) {
2471 if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
2472 IPA_USB_ERR("failed to change state to invalid\n");
Michael Adisumarta3e350812017-09-18 14:54:36 -07002473 if (ipa_pm_is_used()) {
2474 ipa3_usb_deregister_pm(ttype);
2475 } else {
2476 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002477 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002478 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
2479 false;
2480 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002481 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002482 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
2483 false;
2484 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
2485 }
Amir Levy9659e592016-10-27 18:08:27 +03002486 }
2487
2488 IPA_USB_DBG_LOW("exit\n");
2489 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2490 return 0;
2491
2492bad_params:
2493 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2494 return result;
2495}
2496EXPORT_SYMBOL(ipa_usb_deinit_teth_prot);
2497
Ghanim Fodi93a61112016-10-05 11:59:18 +03002498/* Assumes lock already acquired */
2499static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03002500 enum ipa_usb_teth_prot teth_prot)
2501{
2502 int result = 0;
Ghanim Fodi93a61112016-10-05 11:59:18 +03002503 enum ipa3_usb_transport_type ttype;
2504
2505 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2506
2507 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) {
2508 IPA_USB_ERR("Illegal operation.\n");
2509 result = -EPERM;
2510 goto fail_exit;
2511 }
2512
2513 IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n",
2514 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2515 "DPL channel":"Data Tethering channels");
2516
2517 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2518 result = -EINVAL;
2519 goto fail_exit;
2520 }
2521
2522 /* Stop DL/DPL channel */
2523 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2524 if (result) {
2525 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2526 goto fail_exit;
2527 }
2528
2529 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2530 /* Stop UL channel */
2531 result = ipa3_xdci_disconnect(ul_clnt_hdl, true,
2532 ipa3_usb_ctx->qmi_req_id);
2533 if (result) {
2534 IPA_USB_ERR("failed disconnect UL channel\n");
2535 goto start_dl;
2536 }
2537 ipa3_usb_ctx->qmi_req_id++;
2538 }
2539
2540 /* Disconnect tethering protocol */
2541 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2542 if (result)
2543 goto start_ul;
2544
Michael Adisumarta3e350812017-09-18 14:54:36 -07002545 if (ipa_pm_is_used())
2546 result = ipa_pm_deactivate_sync(
2547 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2548 else
2549 result = ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002550 if (result) {
2551 IPA_USB_ERR("failed to release PROD.\n");
2552 goto connect_teth;
2553 }
2554
2555 /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */
2556 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype))
2557 IPA_USB_ERR("failed to change state to suspend no rwakeup\n");
2558
2559 IPA_USB_DBG_LOW("exit\n");
2560 return 0;
2561
2562connect_teth:
2563 (void)ipa3_usb_connect_teth_prot(teth_prot);
2564start_ul:
2565 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
2566 (void)ipa3_xdci_connect(ul_clnt_hdl);
2567start_dl:
2568 (void)ipa3_xdci_connect(dl_clnt_hdl);
2569fail_exit:
2570 return result;
2571}
2572
2573int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2574 enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup)
2575{
2576 int result = 0;
Amir Levy9659e592016-10-27 18:08:27 +03002577 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03002578 enum ipa3_usb_transport_type ttype;
2579
2580 mutex_lock(&ipa3_usb_ctx->general_mutex);
2581 IPA_USB_DBG_LOW("entry\n");
Ghanim Fodi93a61112016-10-05 11:59:18 +03002582
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002583 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002584 IPA_USB_ERR("bad parameters.\n");
2585 result = -EINVAL;
2586 goto bad_params;
2587 }
2588
Ghanim Fodi93a61112016-10-05 11:59:18 +03002589 if (!with_remote_wakeup) {
2590 result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl,
2591 dl_clnt_hdl, teth_prot);
2592 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2593 return result;
2594 }
2595
Amir Levy9659e592016-10-27 18:08:27 +03002596 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2597
Ghanim Fodi93a61112016-10-05 11:59:18 +03002598 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002599 IPA_USB_ERR("Illegal operation.\n");
2600 result = -EPERM;
2601 goto bad_params;
2602 }
2603
2604 IPA_USB_DBG("Start suspend sequence: %s\n",
2605 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2606 "DPL channel":"Data Tethering channels");
2607
2608 /* Change state to SUSPEND_REQUESTED */
2609 if (!ipa3_usb_set_state(IPA_USB_SUSPEND_REQUESTED, false, ttype)) {
2610 IPA_USB_ERR(
2611 "fail changing state to suspend_req.\n");
2612 result = -EFAULT;
2613 goto bad_params;
2614 }
2615
2616 /* Stop UL channel & suspend DL/DPL EP */
2617 result = ipa3_xdci_suspend(ul_clnt_hdl, dl_clnt_hdl,
2618 true,
2619 ipa3_usb_ctx->qmi_req_id, IPA3_USB_IS_TTYPE_DPL(ttype));
2620 if (result) {
2621 IPA_USB_ERR("failed to suspend\n");
2622 goto suspend_fail;
2623 }
2624 ipa3_usb_ctx->qmi_req_id++;
2625
Michael Adisumarta3e350812017-09-18 14:54:36 -07002626 if (ipa_pm_is_used())
2627 result = ipa_pm_deactivate_sync(
2628 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2629 else
2630 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002631 if (result) {
2632 IPA_USB_ERR("failed to release PROD\n");
2633 goto release_prod_fail;
2634 }
2635
Skylar Changdf5f2342017-06-05 09:27:48 -07002636 /* Check if DL/DPL data pending */
Amir Levy9659e592016-10-27 18:08:27 +03002637 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Skylar Changdf5f2342017-06-05 09:27:48 -07002638 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
2639 IPA_USB_CONS_GRANTED &&
2640 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2641
2642 IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
2643 queue_work(ipa3_usb_ctx->wq,
2644 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2645 &ipa3_usb_dpl_notify_remote_wakeup_work :
2646 &ipa3_usb_notify_remote_wakeup_work);
2647 }
Amir Levy9659e592016-10-27 18:08:27 +03002648 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +03002649
Amir Levy9659e592016-10-27 18:08:27 +03002650 /* Change state to SUSPENDED */
2651 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
2652 IPA_USB_ERR("failed to change state to suspended\n");
2653
2654 /* Check if DL/DPL data pending */
2655 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2656 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2657 IPA_USB_DBG_LOW(
2658 "DL/DPL data is pending, invoking remote wakeup\n");
2659 queue_work(ipa3_usb_ctx->wq, IPA3_USB_IS_TTYPE_DPL(ttype) ?
2660 &ipa3_usb_dpl_notify_remote_wakeup_work :
2661 &ipa3_usb_notify_remote_wakeup_work);
2662 }
2663 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2664
2665 IPA_USB_DBG_LOW("exit\n");
2666 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2667 return 0;
2668
2669release_prod_fail:
2670 ipa3_xdci_resume(ul_clnt_hdl, dl_clnt_hdl,
2671 IPA3_USB_IS_TTYPE_DPL(ttype));
2672suspend_fail:
2673 /* Change state back to CONNECTED */
2674 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true, ttype))
2675 IPA_USB_ERR("failed to change state back to connected\n");
2676bad_params:
2677 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2678 return result;
2679}
2680EXPORT_SYMBOL(ipa_usb_xdci_suspend);
2681
Ghanim Fodi93a61112016-10-05 11:59:18 +03002682/* Assumes lock already acquired */
2683static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2684 enum ipa_usb_teth_prot teth_prot)
2685{
2686 int result = -EFAULT;
2687 enum ipa3_usb_transport_type ttype;
2688
2689 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2690
2691 IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n",
2692 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2693 "DPL channel":"Data Tethering channels");
2694
2695 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002696 if (ipa_pm_is_used())
2697 result = ipa_pm_activate_sync(
2698 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2699 else
2700 result = ipa3_usb_request_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002701 if (result)
2702 goto fail_exit;
2703
2704 /* Connect tethering protocol */
2705 result = ipa3_usb_connect_teth_prot(teth_prot);
2706 if (result) {
2707 IPA_USB_ERR("failed to connect teth protocol\n");
2708 goto release_prod;
2709 }
2710
2711 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2712 /* Start UL channel */
2713 result = ipa3_xdci_connect(ul_clnt_hdl);
2714 if (result) {
2715 IPA_USB_ERR("failed to start UL channel.\n");
2716 goto disconn_teth;
2717 }
2718 }
2719
2720 /* Start DL/DPL channel */
2721 result = ipa3_xdci_connect(dl_clnt_hdl);
2722 if (result) {
2723 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2724 goto stop_ul;
2725 }
2726
2727 /* Change state to CONNECTED */
2728 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2729 IPA_USB_ERR("failed to change state to connected\n");
2730 result = -EFAULT;
2731 goto stop_dl;
2732 }
2733
2734 return 0;
2735
2736stop_dl:
2737 (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2738stop_ul:
2739 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2740 (void)ipa3_xdci_disconnect(ul_clnt_hdl, true,
2741 ipa3_usb_ctx->qmi_req_id);
2742 ipa3_usb_ctx->qmi_req_id++;
2743 }
2744disconn_teth:
2745 (void)ipa3_usb_disconnect_teth_prot(teth_prot);
2746release_prod:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002747 if (ipa_pm_is_used())
2748 (void)ipa_pm_deactivate_sync(
2749 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2750 else
2751 (void)ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002752fail_exit:
2753 return result;
2754}
2755
Amir Levy9659e592016-10-27 18:08:27 +03002756int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2757 enum ipa_usb_teth_prot teth_prot)
2758{
2759 int result = -EFAULT;
2760 enum ipa3_usb_state prev_state;
2761 unsigned long flags;
2762 enum ipa3_usb_transport_type ttype;
2763
2764 mutex_lock(&ipa3_usb_ctx->general_mutex);
2765 IPA_USB_DBG_LOW("entry\n");
2766
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002767 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002768 IPA_USB_ERR("bad parameters.\n");
2769 result = -EINVAL;
2770 goto bad_params;
2771 }
2772
2773 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2774
Ghanim Fodi93a61112016-10-05 11:59:18 +03002775 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002776 IPA_USB_ERR("Illegal operation.\n");
2777 result = -EPERM;
2778 goto bad_params;
2779 }
2780
Amir Levy9659e592016-10-27 18:08:27 +03002781 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2782 prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2783 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002784 if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) {
2785 result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl,
2786 dl_clnt_hdl, teth_prot);
2787 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2788 return result;
2789 }
2790
2791 IPA_USB_DBG("Start resume sequence: %s\n",
2792 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2793 "DPL channel" : "Data Tethering channels");
Amir Levy9659e592016-10-27 18:08:27 +03002794
2795 /* Change state to RESUME_IN_PROGRESS */
2796 if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) {
2797 IPA_USB_ERR("failed to change state to resume_in_progress\n");
2798 result = -EFAULT;
2799 goto bad_params;
2800 }
2801
2802 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002803 if (ipa_pm_is_used())
2804 result = ipa_pm_activate_sync(
2805 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2806 else
2807 result = ipa3_usb_request_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002808 if (result)
2809 goto prod_req_fail;
2810
2811 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2812 /* Start UL channel */
2813 result = ipa3_start_gsi_channel(ul_clnt_hdl);
2814 if (result) {
2815 IPA_USB_ERR("failed to start UL channel.\n");
2816 goto start_ul_fail;
2817 }
2818 }
2819
Skylar Changdf5f2342017-06-05 09:27:48 -07002820 /* Start DL/DPL channel */
2821 result = ipa3_start_gsi_channel(dl_clnt_hdl);
2822 if (result) {
2823 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2824 goto start_dl_fail;
Amir Levy9659e592016-10-27 18:08:27 +03002825 }
2826
2827 /* Change state to CONNECTED */
2828 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2829 IPA_USB_ERR("failed to change state to connected\n");
2830 result = -EFAULT;
2831 goto state_change_connected_fail;
2832 }
2833
2834 IPA_USB_DBG_LOW("exit\n");
2835 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2836 return 0;
2837
2838state_change_connected_fail:
Skylar Changdf5f2342017-06-05 09:27:48 -07002839 result = ipa3_stop_gsi_channel(dl_clnt_hdl);
2840 if (result)
2841 IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
2842 result);
Amir Levy9659e592016-10-27 18:08:27 +03002843start_dl_fail:
2844 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2845 result = ipa3_stop_gsi_channel(ul_clnt_hdl);
2846 if (result)
2847 IPA_USB_ERR("Error stopping UL channel: %d\n", result);
2848 }
2849start_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002850 if (ipa_pm_is_used())
2851 ipa_pm_deactivate_sync(
2852 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2853 else
2854 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002855prod_req_fail:
2856 /* Change state back to prev_state */
2857 if (!ipa3_usb_set_state(prev_state, true, ttype))
2858 IPA_USB_ERR("failed to change state back to %s\n",
2859 ipa3_usb_state_to_string(prev_state));
2860bad_params:
2861 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2862 return result;
2863}
2864EXPORT_SYMBOL(ipa_usb_xdci_resume);
2865
2866static int __init ipa3_usb_init(void)
2867{
2868 int i;
2869 unsigned long flags;
2870 int res;
2871
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002872 pr_debug("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002873 ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL);
2874 if (ipa3_usb_ctx == NULL) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002875 pr_err("failed to allocate memory\n");
2876 pr_err(":ipa_usb init failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03002877 return -EFAULT;
2878 }
2879 memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context));
2880
2881 for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++)
2882 ipa3_usb_ctx->teth_prot_ctx[i].state =
2883 IPA_USB_TETH_PROT_INVALID;
2884 ipa3_usb_ctx->num_init_prot = 0;
2885 init_completion(&ipa3_usb_ctx->dev_ready_comp);
2886 ipa3_usb_ctx->qmi_req_id = 0;
2887 spin_lock_init(&ipa3_usb_ctx->state_lock);
2888 ipa3_usb_ctx->dl_data_pending = false;
2889 mutex_init(&ipa3_usb_ctx->general_mutex);
2890
Michael Adisumarta3e350812017-09-18 14:54:36 -07002891 if (ipa_pm_is_used()) {
2892 struct ipa3_usb_pm_context *pm_ctx;
2893
2894 pm_ctx =
2895 &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
2896 pm_ctx->hdl = ~0;
2897 pm_ctx->remote_wakeup_work =
2898 &ipa3_usb_notify_remote_wakeup_work;
2899 pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
2900 pm_ctx->hdl = ~0;
2901 pm_ctx->remote_wakeup_work =
2902 &ipa3_usb_dpl_notify_remote_wakeup_work;
2903 }
2904
Amir Levy9659e592016-10-27 18:08:27 +03002905 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2906 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
2907 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
2908 init_completion(&ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_comp);
2909 ipa3_usb_ctx->ttype_ctx[i].user_data = NULL;
2910 }
2911
2912 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2913 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2914 ipa3_usb_ctx->ttype_ctx[i].state = IPA_USB_INVALID;
2915 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_state =
2916 IPA_USB_CONS_RELEASED;
2917 }
2918 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2919
2920 ipa3_usb_ctx->wq = create_singlethread_workqueue("ipa_usb_wq");
2921 if (!ipa3_usb_ctx->wq) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002922 pr_err("failed to create workqueue\n");
Amir Levy9659e592016-10-27 18:08:27 +03002923 res = -EFAULT;
2924 goto ipa_usb_workqueue_fail;
2925 }
2926
2927 ipa_usb_debugfs_init();
2928
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002929 pr_info("exit: IPA_USB init success!\n");
Amir Levy9659e592016-10-27 18:08:27 +03002930
2931 return 0;
2932
2933ipa_usb_workqueue_fail:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002934 pr_err(":init failed (%d)\n", -res);
Amir Levy9659e592016-10-27 18:08:27 +03002935 kfree(ipa3_usb_ctx);
2936 return res;
2937}
2938
2939static void ipa3_usb_exit(void)
2940{
2941 IPA_USB_DBG_LOW("IPA_USB exit\n");
2942 ipa_usb_debugfs_remove();
2943 kfree(ipa3_usb_ctx);
2944}
2945
2946arch_initcall(ipa3_usb_init);
2947module_exit(ipa3_usb_exit);
2948
2949MODULE_LICENSE("GPL v2");
2950MODULE_DESCRIPTION("IPA USB client driver");