blob: d2744902dd6dfc9be693c553be8809d94d60fe4f [file] [log] [blame]
Skylar Changdf5f2342017-06-05 09:27:48 -07001/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#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;
1335 /* max_outstanding_tre is set in ipa3_request_gsi_channel() */
1336 result = ipa3_request_gsi_channel(&chan_params, out_params);
1337 if (result) {
1338 IPA_USB_ERR("failed to allocate GSI channel\n");
1339 ipa3_usb_smmu_map_xdci_channel(params, false);
1340 return result;
1341 }
1342
1343 IPA_USB_DBG_LOW("exit\n");
1344 return 0;
1345}
1346
1347static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
1348 enum ipa3_usb_transport_type ttype)
1349{
1350 int result = 0;
1351
1352 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001353 if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001354 IPA_USB_ERR("bad parameter.\n");
1355 return -EINVAL;
1356 }
1357
Ghanim Fodi93a61112016-10-05 11:59:18 +03001358 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001359 IPA_USB_ERR("Illegal operation.\n");
1360 return -EPERM;
1361 }
1362
1363 /* Release channel */
1364 result = ipa3_release_gsi_channel(clnt_hdl);
1365 if (result) {
1366 IPA_USB_ERR("failed to deallocate channel.\n");
1367 return result;
1368 }
1369
1370 result = ipa3_usb_smmu_map_xdci_channel(
1371 &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false);
1372
1373 /* Change ipa_usb state to INITIALIZED */
1374 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1375 IPA_USB_ERR("failed to change state to initialized\n");
1376
1377 IPA_USB_DBG_LOW("exit\n");
1378 return 0;
1379}
1380
1381static int ipa3_usb_request_prod(enum ipa3_usb_transport_type ttype)
1382{
1383 int result;
1384 struct ipa3_usb_rm_context *rm_ctx;
1385 const char *rsrc_str;
1386
1387 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1388 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1389
1390 IPA_USB_DBG_LOW("requesting %s\n", rsrc_str);
1391 init_completion(&rm_ctx->prod_comp);
1392 result = ipa_rm_request_resource(rm_ctx->prod_params.name);
1393 if (result) {
1394 if (result != -EINPROGRESS) {
1395 IPA_USB_ERR("failed to request %s: %d\n",
1396 rsrc_str, result);
1397 return result;
1398 }
1399 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1400 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1401 if (result == 0) {
1402 IPA_USB_ERR("timeout request %s\n", rsrc_str);
1403 return -ETIME;
1404 }
1405 }
1406
1407 IPA_USB_DBG_LOW("%s granted\n", rsrc_str);
1408 return 0;
1409}
1410
1411static int ipa3_usb_release_prod(enum ipa3_usb_transport_type ttype)
1412{
1413 int result;
1414 struct ipa3_usb_rm_context *rm_ctx;
1415 const char *rsrc_str;
1416
1417 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1418 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1419
1420 IPA_USB_DBG_LOW("releasing %s\n", rsrc_str);
1421
1422 init_completion(&rm_ctx->prod_comp);
1423 result = ipa_rm_release_resource(rm_ctx->prod_params.name);
1424 if (result) {
1425 if (result != -EINPROGRESS) {
1426 IPA_USB_ERR("failed to release %s: %d\n",
1427 rsrc_str, result);
1428 return result;
1429 }
1430 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1431 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1432 if (result == 0) {
1433 IPA_USB_ERR("timeout release %s\n", rsrc_str);
1434 return -ETIME;
1435 }
1436 }
1437
1438 IPA_USB_DBG_LOW("%s released\n", rsrc_str);
1439 return 0;
1440}
1441
1442static bool ipa3_usb_check_connect_params(
1443 struct ipa_usb_xdci_connect_params_internal *params)
1444{
1445 IPA_USB_DBG_LOW("ul xferrscidx = %d\n", params->usb_to_ipa_xferrscidx);
1446 IPA_USB_DBG_LOW("dl xferrscidx = %d\n", params->ipa_to_usb_xferrscidx);
1447 IPA_USB_DBG_LOW("max_supported_bandwidth_mbps = %d\n",
1448 params->max_supported_bandwidth_mbps);
1449
1450 if (params->max_pkt_size < IPA_USB_HIGH_SPEED_512B ||
1451 params->max_pkt_size > IPA_USB_SUPER_SPEED_1024B ||
1452 params->ipa_to_usb_xferrscidx < 0 ||
1453 params->ipa_to_usb_xferrscidx > 127 ||
1454 (params->teth_prot != IPA_USB_DIAG &&
1455 (params->usb_to_ipa_xferrscidx < 0 ||
1456 params->usb_to_ipa_xferrscidx > 127)) ||
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001457 params->teth_prot < 0 ||
1458 params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03001459 IPA_USB_ERR("Invalid params\n");
1460 return false;
1461 }
1462
1463 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1464 IPA_USB_TETH_PROT_INVALID) {
1465 IPA_USB_ERR("%s is not initialized\n",
1466 ipa3_usb_teth_prot_to_string(
1467 params->teth_prot));
1468 return false;
1469 }
1470
1471 return true;
1472}
1473
1474static int ipa3_usb_connect_teth_bridge(
1475 struct teth_bridge_connect_params *params)
1476{
1477 int result;
1478
1479 result = teth_bridge_connect(params);
1480 if (result) {
1481 IPA_USB_ERR("failed to connect teth_bridge (%s)\n",
1482 params->tethering_mode == TETH_TETHERING_MODE_RMNET ?
1483 "rmnet" : "mbim");
1484 return result;
1485 }
1486
1487 return 0;
1488}
1489
1490static int ipa3_usb_connect_dpl(void)
1491{
1492 int res = 0;
1493
Michael Adisumarta3e350812017-09-18 14:54:36 -07001494 if (ipa_pm_is_used())
1495 return 0;
1496
Amir Levy9659e592016-10-27 18:08:27 +03001497 /*
1498 * Add DPL dependency to RM dependency graph, first add_dependency call
1499 * is sync in order to make sure the IPA clocks are up before we
1500 * continue and notify the USB driver it may continue.
1501 */
1502 res = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1503 IPA_RM_RESOURCE_Q6_CONS);
1504 if (res < 0) {
1505 IPA_USB_ERR("ipa_rm_add_dependency_sync() failed.\n");
1506 return res;
1507 }
1508
1509 /*
1510 * this add_dependency call can't be sync since it will block until DPL
1511 * status is connected (which can happen only later in the flow),
1512 * the clocks are already up so the call doesn't need to block.
1513 */
1514 res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
1515 IPA_RM_RESOURCE_USB_DPL_CONS);
1516 if (res < 0 && res != -EINPROGRESS) {
1517 IPA_USB_ERR("ipa_rm_add_dependency() failed.\n");
1518 ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1519 IPA_RM_RESOURCE_Q6_CONS);
1520 return res;
1521 }
1522
1523 return 0;
1524}
1525
Ghanim Fodi93a61112016-10-05 11:59:18 +03001526static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
Amir Levy9659e592016-10-27 18:08:27 +03001527{
1528 int result;
1529 struct teth_bridge_connect_params teth_bridge_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001530 struct ipa3_usb_teth_prot_conn_params *teth_conn_params;
1531 enum ipa3_usb_transport_type ttype;
Amir Levy9659e592016-10-27 18:08:27 +03001532
Ghanim Fodi93a61112016-10-05 11:59:18 +03001533 IPA_USB_DBG("connecting protocol = %s\n",
1534 ipa3_usb_teth_prot_to_string(teth_prot));
1535
1536 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1537
1538 teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params);
1539
1540 switch (teth_prot) {
Amir Levy9659e592016-10-27 18:08:27 +03001541 case IPA_USB_RNDIS:
1542 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state ==
1543 IPA_USB_TETH_PROT_CONNECTED) {
1544 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001545 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001546 break;
1547 }
1548 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1549 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data;
1550 result = rndis_ipa_pipe_connect_notify(
Ghanim Fodi93a61112016-10-05 11:59:18 +03001551 teth_conn_params->usb_to_ipa_clnt_hdl,
1552 teth_conn_params->ipa_to_usb_clnt_hdl,
1553 teth_conn_params->params.max_xfer_size_bytes_to_dev,
1554 teth_conn_params->params.max_packet_number_to_dev,
1555 teth_conn_params->params.max_xfer_size_bytes_to_host,
Amir Levy9659e592016-10-27 18:08:27 +03001556 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1557 teth_prot_params.rndis.private);
1558 if (result) {
1559 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001560 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001561 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1562 return result;
1563 }
1564 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state =
1565 IPA_USB_TETH_PROT_CONNECTED;
1566 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001567 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001568 break;
1569 case IPA_USB_ECM:
1570 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state ==
1571 IPA_USB_TETH_PROT_CONNECTED) {
1572 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001573 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001574 break;
1575 }
1576 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1577 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001578 result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl,
1579 teth_conn_params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001580 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1581 teth_prot_params.ecm.private);
1582 if (result) {
1583 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001584 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001585 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1586 return result;
1587 }
1588 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state =
1589 IPA_USB_TETH_PROT_CONNECTED;
1590 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001591 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001592 break;
1593 case IPA_USB_RMNET:
1594 case IPA_USB_MBIM:
Ghanim Fodi93a61112016-10-05 11:59:18 +03001595 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
Amir Levy9659e592016-10-27 18:08:27 +03001596 IPA_USB_TETH_PROT_CONNECTED) {
1597 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001598 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001599 break;
1600 }
1601 result = ipa3_usb_init_teth_bridge();
1602 if (result)
1603 return result;
1604
1605 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001606 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
Amir Levy9659e592016-10-27 18:08:27 +03001607 user_data;
1608 teth_bridge_params.ipa_usb_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001609 teth_conn_params->ipa_to_usb_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001610 teth_bridge_params.usb_ipa_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001611 teth_conn_params->usb_to_ipa_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001612 teth_bridge_params.tethering_mode =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001613 (teth_prot == IPA_USB_RMNET) ?
Amir Levy9659e592016-10-27 18:08:27 +03001614 (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
1615 teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
1616 result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
1617 if (result) {
1618 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1619 return result;
1620 }
Ghanim Fodi93a61112016-10-05 11:59:18 +03001621 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
Amir Levy9659e592016-10-27 18:08:27 +03001622 IPA_USB_TETH_PROT_CONNECTED;
1623 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1624 IPA_USB_DBG("%s (%s) is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001625 ipa3_usb_teth_prot_to_string(teth_prot),
1626 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001627 break;
1628 case IPA_USB_DIAG:
1629 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state ==
1630 IPA_USB_TETH_PROT_CONNECTED) {
1631 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001632 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001633 break;
1634 }
1635
1636 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001637 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data;
Amir Levy9659e592016-10-27 18:08:27 +03001638 result = ipa3_usb_connect_dpl();
1639 if (result) {
1640 IPA_USB_ERR("Failed connecting DPL result=%d\n",
1641 result);
1642 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1643 return result;
1644 }
1645 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state =
1646 IPA_USB_TETH_PROT_CONNECTED;
1647 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1648 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001649 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001650 break;
1651 default:
1652 IPA_USB_ERR("Invalid tethering protocol\n");
1653 return -EFAULT;
1654 }
1655
1656 return 0;
1657}
1658
1659static int ipa3_usb_disconnect_teth_bridge(void)
1660{
1661 int result;
1662
1663 result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
1664 if (result) {
1665 IPA_USB_ERR("failed to disconnect teth_bridge.\n");
1666 return result;
1667 }
1668
1669 return 0;
1670}
1671
1672static int ipa3_usb_disconnect_dpl(void)
1673{
1674 int res;
1675
Michael Adisumarta3e350812017-09-18 14:54:36 -07001676 if (ipa_pm_is_used())
1677 return 0;
1678
Amir Levy9659e592016-10-27 18:08:27 +03001679 /* Remove DPL RM dependency */
1680 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1681 IPA_RM_RESOURCE_Q6_CONS);
1682 if (res)
1683 IPA_USB_ERR("deleting DPL_DUMMY_PROD rsrc dependency fail\n");
1684
1685 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
1686 IPA_RM_RESOURCE_USB_DPL_CONS);
1687 if (res)
1688 IPA_USB_ERR("deleting DPL_CONS rsrc dependencty fail\n");
1689
1690 return 0;
1691}
1692
1693static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
1694{
1695 int result = 0;
1696 enum ipa3_usb_transport_type ttype;
1697
1698 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1699
1700 switch (teth_prot) {
1701 case IPA_USB_RNDIS:
1702 case IPA_USB_ECM:
1703 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1704 IPA_USB_TETH_PROT_CONNECTED) {
1705 IPA_USB_DBG("%s is not connected.\n",
1706 ipa3_usb_teth_prot_to_string(teth_prot));
1707 return -EPERM;
1708 }
1709 if (teth_prot == IPA_USB_RNDIS) {
1710 result = rndis_ipa_pipe_disconnect_notify(
1711 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1712 teth_prot_params.rndis.private);
1713 } else {
1714 result = ecm_ipa_disconnect(
1715 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1716 teth_prot_params.ecm.private);
1717 }
1718 if (result) {
1719 IPA_USB_ERR("failed to disconnect %s.\n",
1720 ipa3_usb_teth_prot_to_string(teth_prot));
1721 break;
1722 }
1723 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1724 IPA_USB_TETH_PROT_INITIALIZED;
1725 IPA_USB_DBG("disconnected %s\n",
1726 ipa3_usb_teth_prot_to_string(teth_prot));
1727 break;
1728 case IPA_USB_RMNET:
1729 case IPA_USB_MBIM:
1730 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1731 IPA_USB_TETH_PROT_CONNECTED) {
1732 IPA_USB_DBG("%s (%s) is not connected.\n",
1733 ipa3_usb_teth_prot_to_string(teth_prot),
1734 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1735 return -EPERM;
1736 }
1737 result = ipa3_usb_disconnect_teth_bridge();
1738 if (result)
1739 break;
1740
1741 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1742 IPA_USB_TETH_PROT_INITIALIZED;
1743 IPA_USB_DBG("disconnected %s (%s)\n",
1744 ipa3_usb_teth_prot_to_string(teth_prot),
1745 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1746 break;
1747 case IPA_USB_DIAG:
1748 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1749 IPA_USB_TETH_PROT_CONNECTED) {
1750 IPA_USB_DBG("%s is not connected.\n",
1751 ipa3_usb_teth_prot_to_string(teth_prot));
1752 return -EPERM;
1753 }
1754 result = ipa3_usb_disconnect_dpl();
1755 if (result)
1756 break;
1757 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1758 IPA_USB_TETH_PROT_INITIALIZED;
1759 IPA_USB_DBG("disconnected %s\n",
1760 ipa3_usb_teth_prot_to_string(teth_prot));
1761 break;
1762 default:
1763 break;
1764 }
1765
1766 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1767 return result;
1768}
1769
1770static int ipa3_usb_xdci_connect_internal(
1771 struct ipa_usb_xdci_connect_params_internal *params)
1772{
1773 int result = -EFAULT;
1774 struct ipa_rm_perf_profile profile;
1775 enum ipa3_usb_transport_type ttype;
1776
1777 IPA_USB_DBG_LOW("entry\n");
1778 if (params == NULL || !ipa3_usb_check_connect_params(params)) {
1779 IPA_USB_ERR("bad parameters.\n");
1780 return -EINVAL;
1781 }
1782
1783 ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
1784 IPA_USB_TRANSPORT_TETH;
1785
Ghanim Fodi93a61112016-10-05 11:59:18 +03001786 if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001787 IPA_USB_ERR("Illegal operation.\n");
1788 return -EPERM;
1789 }
1790
Ghanim Fodi93a61112016-10-05 11:59:18 +03001791 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl
1792 = params->ipa_to_usb_clnt_hdl;
1793 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
1794 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.
1795 usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl;
1796 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params
1797 = params->teth_prot_params;
1798
Amir Levy9659e592016-10-27 18:08:27 +03001799 /* Set EE xDCI specific scratch */
1800 result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
1801 if (result) {
1802 IPA_USB_ERR("failed setting xDCI EE scratch field\n");
1803 return result;
1804 }
1805
Michael Adisumarta3e350812017-09-18 14:54:36 -07001806 if (ipa_pm_is_used()) {
1807 result = ipa_pm_set_perf_profile(
1808 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
1809 params->max_supported_bandwidth_mbps);
1810 if (result) {
1811 IPA_USB_ERR("failed to set perf profile\n");
1812 return result;
1813 }
Amir Levy9659e592016-10-27 18:08:27 +03001814
Michael Adisumarta3e350812017-09-18 14:54:36 -07001815 result = ipa_pm_activate_sync(
1816 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1817 if (result) {
1818 IPA_USB_ERR("failed to activate pm\n");
1819 return result;
1820 }
1821 } else {
1822 /* Set RM PROD & CONS perf profile */
1823 profile.max_supported_bandwidth_mbps =
1824 params->max_supported_bandwidth_mbps;
1825 result = ipa_rm_set_perf_profile(
1826 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
1827 &profile);
1828 if (result) {
1829 IPA_USB_ERR("failed to set %s perf profile\n",
1830 ipa_rm_resource_str(ipa3_usb_ctx->
1831 ttype_ctx[ttype].
1832 rm_ctx.prod_params.name));
1833 return result;
1834 }
1835 result = ipa_rm_set_perf_profile(
1836 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
1837 &profile);
1838 if (result) {
1839 IPA_USB_ERR("failed to set %s perf profile\n",
1840 ipa_rm_resource_str(ipa3_usb_ctx->
1841 ttype_ctx[ttype].
1842 rm_ctx.cons_params.name));
1843 return result;
1844 }
1845
1846 /* Request PROD */
1847 result = ipa3_usb_request_prod(ttype);
1848 if (result)
1849 return result;
1850 }
Amir Levy9659e592016-10-27 18:08:27 +03001851
1852 if (params->teth_prot != IPA_USB_DIAG) {
1853 /* Start UL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001854 result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001855 params->usb_to_ipa_xferrscidx,
1856 params->usb_to_ipa_xferrscidx_valid);
1857 if (result) {
1858 IPA_USB_ERR("failed to connect UL channel.\n");
1859 goto connect_ul_fail;
1860 }
1861 }
1862
1863 /* Start DL/DPL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001864 result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001865 params->ipa_to_usb_xferrscidx,
1866 params->ipa_to_usb_xferrscidx_valid);
1867 if (result) {
1868 IPA_USB_ERR("failed to connect DL/DPL channel.\n");
1869 goto connect_dl_fail;
1870 }
1871
1872 /* Connect tethering protocol */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001873 result = ipa3_usb_connect_teth_prot(params->teth_prot);
Amir Levy9659e592016-10-27 18:08:27 +03001874 if (result) {
1875 IPA_USB_ERR("failed to connect teth protocol\n");
1876 goto connect_teth_prot_fail;
1877 }
1878
1879 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
1880 IPA_USB_ERR(
1881 "failed to change state to connected\n");
1882 goto state_change_connected_fail;
1883 }
1884
1885 IPA_USB_DBG_LOW("exit\n");
1886 return 0;
1887
1888state_change_connected_fail:
1889 ipa3_usb_disconnect_teth_prot(params->teth_prot);
1890connect_teth_prot_fail:
1891 ipa3_xdci_disconnect(params->ipa_to_usb_clnt_hdl, false, -1);
1892 ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
1893 ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
1894connect_dl_fail:
1895 if (params->teth_prot != IPA_USB_DIAG) {
1896 ipa3_xdci_disconnect(params->usb_to_ipa_clnt_hdl, false, -1);
1897 ipa3_reset_gsi_channel(params->usb_to_ipa_clnt_hdl);
1898 ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
1899 }
1900connect_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001901 if (ipa_pm_is_used())
1902 ipa_pm_deactivate_sync(
1903 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1904 else
1905 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03001906 return result;
1907}
1908
1909#ifdef CONFIG_DEBUG_FS
1910static char dbg_buff[IPA_USB_MAX_MSG_LEN];
1911
1912static char *ipa3_usb_cons_state_to_string(enum ipa3_usb_cons_state state)
1913{
1914 switch (state) {
1915 case IPA_USB_CONS_GRANTED:
1916 return "CONS_GRANTED";
1917 case IPA_USB_CONS_RELEASED:
1918 return "CONS_RELEASED";
1919 }
1920
1921 return "UNSUPPORTED";
1922}
1923
1924static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status)
1925{
1926 int res;
1927 int i;
1928 unsigned long flags;
1929
1930 IPA_USB_DBG_LOW("entry\n");
1931
1932 if (ipa3_usb_ctx == NULL) {
1933 IPA_USB_ERR("IPA USB was not inited yet\n");
1934 return -EFAULT;
1935 }
1936
1937 mutex_lock(&ipa3_usb_ctx->general_mutex);
1938
1939 if (!status) {
1940 IPA_USB_ERR("Invalid input\n");
1941 res = -EINVAL;
1942 goto bail;
1943 }
1944
1945 memset(status, 0, sizeof(struct ipa3_usb_status_dbg_info));
1946
1947 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
1948 status->teth_state = ipa3_usb_state_to_string(
1949 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].state);
1950 status->dpl_state = ipa3_usb_state_to_string(
1951 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].state);
1952 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].rm_ctx.cons_valid)
1953 status->teth_cons_state = ipa3_usb_cons_state_to_string(
1954 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].
1955 rm_ctx.cons_state);
1956 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].rm_ctx.cons_valid)
1957 status->dpl_cons_state = ipa3_usb_cons_state_to_string(
1958 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].
1959 rm_ctx.cons_state);
1960 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
1961
1962 for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) {
1963 if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1964 IPA_USB_TETH_PROT_INITIALIZED) {
1965 if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM))
1966 status->inited_prots[status->num_init_prot++] =
1967 ipa3_usb_teth_bridge_prot_to_string(i);
1968 else
1969 status->inited_prots[status->num_init_prot++] =
1970 ipa3_usb_teth_prot_to_string(i);
1971 } else if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1972 IPA_USB_TETH_PROT_CONNECTED) {
1973 switch (i) {
1974 case IPA_USB_RMNET:
1975 case IPA_USB_MBIM:
1976 status->teth_connected_prot =
1977 ipa3_usb_teth_bridge_prot_to_string(i);
1978 break;
1979 case IPA_USB_DIAG:
1980 status->dpl_connected_prot =
1981 ipa3_usb_teth_prot_to_string(i);
1982 break;
1983 default:
1984 status->teth_connected_prot =
1985 ipa3_usb_teth_prot_to_string(i);
1986 }
1987 }
1988 }
1989
1990 res = 0;
1991 IPA_USB_DBG_LOW("exit\n");
1992bail:
1993 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1994 return res;
1995}
1996
1997static ssize_t ipa3_read_usb_state_info(struct file *file, char __user *ubuf,
1998 size_t count, loff_t *ppos)
1999{
2000 struct ipa3_usb_status_dbg_info status;
2001 int result;
2002 int nbytes;
2003 int cnt = 0;
2004 int i;
2005
2006 result = ipa3_usb_get_status_dbg_info(&status);
2007 if (result) {
2008 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2009 "Fail to read IPA USB status\n");
2010 cnt += nbytes;
2011 } else {
2012 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2013 "Tethering Data State: %s\n"
2014 "DPL State: %s\n"
2015 "Protocols in Initialized State: ",
2016 status.teth_state,
2017 status.dpl_state);
2018 cnt += nbytes;
2019
2020 for (i = 0 ; i < status.num_init_prot ; i++) {
2021 nbytes = scnprintf(dbg_buff + cnt,
2022 IPA_USB_MAX_MSG_LEN - cnt,
2023 "%s ", status.inited_prots[i]);
2024 cnt += nbytes;
2025 }
2026 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2027 status.num_init_prot ? "\n" : "None\n");
2028 cnt += nbytes;
2029
2030 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2031 "Protocols in Connected State: ");
2032 cnt += nbytes;
2033 if (status.teth_connected_prot) {
2034 nbytes = scnprintf(dbg_buff + cnt,
2035 IPA_USB_MAX_MSG_LEN - cnt,
2036 "%s ", status.teth_connected_prot);
2037 cnt += nbytes;
2038 }
2039 if (status.dpl_connected_prot) {
2040 nbytes = scnprintf(dbg_buff + cnt,
2041 IPA_USB_MAX_MSG_LEN - cnt,
2042 "%s ", status.dpl_connected_prot);
2043 cnt += nbytes;
2044 }
2045 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2046 (status.teth_connected_prot ||
2047 status.dpl_connected_prot) ? "\n" : "None\n");
2048 cnt += nbytes;
2049
2050 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2051 "USB Tethering Consumer State: %s\n",
2052 status.teth_cons_state ?
2053 status.teth_cons_state : "Invalid");
2054 cnt += nbytes;
2055
2056 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2057 "DPL Consumer State: %s\n",
2058 status.dpl_cons_state ? status.dpl_cons_state :
2059 "Invalid");
2060 cnt += nbytes;
2061 }
2062
2063 return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
2064}
2065
2066const struct file_operations ipa3_ipa_usb_ops = {
2067 .read = ipa3_read_usb_state_info,
2068};
2069
2070static void ipa_usb_debugfs_init(void)
2071{
2072 const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
2073
2074 ipa3_usb_ctx->dent = debugfs_create_dir("ipa_usb", 0);
2075 if (IS_ERR(ipa3_usb_ctx->dent)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002076 pr_err("fail to create folder in debug_fs.\n");
Amir Levy9659e592016-10-27 18:08:27 +03002077 return;
2078 }
2079
2080 ipa3_usb_ctx->dfile_state_info = debugfs_create_file("state_info",
2081 read_only_mode, ipa3_usb_ctx->dent, 0,
2082 &ipa3_ipa_usb_ops);
2083 if (!ipa3_usb_ctx->dfile_state_info ||
2084 IS_ERR(ipa3_usb_ctx->dfile_state_info)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002085 pr_err("failed to create file for state_info\n");
Amir Levy9659e592016-10-27 18:08:27 +03002086 goto fail;
2087 }
2088
2089 return;
2090
2091fail:
2092 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2093 ipa3_usb_ctx->dent = NULL;
2094}
2095
2096static void ipa_usb_debugfs_remove(void)
2097{
2098 if (IS_ERR(ipa3_usb_ctx->dent)) {
2099 IPA_USB_ERR("ipa_usb debugfs folder was not created.\n");
2100 return;
2101 }
2102
2103 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2104}
2105#else /* CONFIG_DEBUG_FS */
2106static void ipa_usb_debugfs_init(void){}
2107static void ipa_usb_debugfs_remove(void){}
2108#endif /* CONFIG_DEBUG_FS */
2109
2110
2111
2112int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
2113 struct ipa_usb_xdci_chan_params *dl_chan_params,
2114 struct ipa_req_chan_out_params *ul_out_params,
2115 struct ipa_req_chan_out_params *dl_out_params,
2116 struct ipa_usb_xdci_connect_params *connect_params)
2117{
2118 int result = -EFAULT;
2119 struct ipa_usb_xdci_connect_params_internal conn_params;
2120
2121 mutex_lock(&ipa3_usb_ctx->general_mutex);
2122 IPA_USB_DBG_LOW("entry\n");
2123 if (connect_params == NULL || dl_chan_params == NULL ||
2124 dl_out_params == NULL ||
2125 (connect_params->teth_prot != IPA_USB_DIAG &&
2126 (ul_chan_params == NULL || ul_out_params == NULL))) {
2127 IPA_USB_ERR("bad parameters.\n");
2128 result = -EINVAL;
2129 goto bad_params;
2130 }
2131
2132 if (connect_params->teth_prot != IPA_USB_DIAG) {
2133 result = ipa3_usb_request_xdci_channel(ul_chan_params,
2134 ul_out_params);
2135 if (result) {
2136 IPA_USB_ERR("failed to allocate UL channel.\n");
2137 goto bad_params;
2138 }
2139 }
2140
2141 result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params);
2142 if (result) {
2143 IPA_USB_ERR("failed to allocate DL/DPL channel.\n");
2144 goto alloc_dl_chan_fail;
2145 }
2146
2147 memset(&conn_params, 0,
2148 sizeof(struct ipa_usb_xdci_connect_params_internal));
2149 conn_params.max_pkt_size = connect_params->max_pkt_size;
2150 conn_params.ipa_to_usb_clnt_hdl = dl_out_params->clnt_hdl;
2151 conn_params.ipa_to_usb_xferrscidx =
2152 connect_params->ipa_to_usb_xferrscidx;
2153 conn_params.ipa_to_usb_xferrscidx_valid =
2154 connect_params->ipa_to_usb_xferrscidx_valid;
2155 if (connect_params->teth_prot != IPA_USB_DIAG) {
2156 conn_params.usb_to_ipa_clnt_hdl = ul_out_params->clnt_hdl;
2157 conn_params.usb_to_ipa_xferrscidx =
2158 connect_params->usb_to_ipa_xferrscidx;
2159 conn_params.usb_to_ipa_xferrscidx_valid =
2160 connect_params->usb_to_ipa_xferrscidx_valid;
2161 }
2162 conn_params.teth_prot = connect_params->teth_prot;
2163 conn_params.teth_prot_params = connect_params->teth_prot_params;
2164 conn_params.max_supported_bandwidth_mbps =
2165 connect_params->max_supported_bandwidth_mbps;
2166 result = ipa3_usb_xdci_connect_internal(&conn_params);
2167 if (result) {
2168 IPA_USB_ERR("failed to connect.\n");
2169 goto connect_fail;
2170 }
2171
2172 IPA_USB_DBG_LOW("exit\n");
2173 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2174 return 0;
2175
2176connect_fail:
2177 ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002178 IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002179alloc_dl_chan_fail:
2180 if (connect_params->teth_prot != IPA_USB_DIAG)
2181 ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002182 IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002183bad_params:
2184 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2185 return result;
2186}
2187EXPORT_SYMBOL(ipa_usb_xdci_connect);
2188
2189static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
2190{
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002191 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002192 IPA_USB_ERR("bad parameter.\n");
2193 return -EFAULT;
2194 }
2195
2196 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2197 IPA_USB_TETH_PROT_CONNECTED) {
2198 IPA_USB_ERR("%s is not connected.\n",
2199 ipa3_usb_teth_prot_to_string(teth_prot));
2200 return -EFAULT;
2201 }
2202
2203 return 0;
2204}
2205
Ghanim Fodi93a61112016-10-05 11:59:18 +03002206/* Assumes lock already acquired */
2207static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2208 enum ipa_usb_teth_prot teth_prot)
2209{
2210 int result = 0;
2211 enum ipa3_usb_transport_type ttype;
2212
2213 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2214
2215 IPA_USB_DBG_LOW("entry\n");
2216
2217 /* Reset DL channel */
2218 result = ipa3_reset_gsi_channel(dl_clnt_hdl);
2219 if (result) {
2220 IPA_USB_ERR("failed to reset DL channel.\n");
2221 return result;
2222 }
2223
2224 /* Reset DL event ring */
2225 result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
2226 if (result) {
2227 IPA_USB_ERR("failed to reset DL event ring.\n");
2228 return result;
2229 }
2230
2231 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Mohammed Javida17a6bf2017-11-22 19:40:38 +05302232 ipa3_xdci_ep_delay_rm(ul_clnt_hdl); /* Remove ep_delay if set */
Ghanim Fodi93a61112016-10-05 11:59:18 +03002233 /* Reset UL channel */
2234 result = ipa3_reset_gsi_channel(ul_clnt_hdl);
2235 if (result) {
2236 IPA_USB_ERR("failed to reset UL channel.\n");
2237 return result;
2238 }
2239
2240 /* Reset UL event ring */
2241 result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
2242 if (result) {
2243 IPA_USB_ERR("failed to reset UL event ring.\n");
2244 return result;
2245 }
2246 }
2247
2248 /* Change state to STOPPED */
2249 if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
2250 IPA_USB_ERR("failed to change state to stopped\n");
2251
2252 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2253 result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
2254 if (result) {
2255 IPA_USB_ERR("failed to release UL channel.\n");
2256 return result;
2257 }
2258 }
2259
2260 result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
2261 if (result) {
2262 IPA_USB_ERR("failed to release DL channel.\n");
2263 return result;
2264 }
2265
2266 IPA_USB_DBG_LOW("exit\n");
2267
2268 return 0;
2269}
2270
Amir Levy9659e592016-10-27 18:08:27 +03002271int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2272 enum ipa_usb_teth_prot teth_prot)
2273{
2274 int result = 0;
2275 struct ipa_ep_cfg_holb holb_cfg;
2276 unsigned long flags;
2277 enum ipa3_usb_state orig_state;
2278 enum ipa3_usb_transport_type ttype;
2279
2280 mutex_lock(&ipa3_usb_ctx->general_mutex);
2281 IPA_USB_DBG_LOW("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002282
2283 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2284
Ghanim Fodi93a61112016-10-05 11:59:18 +03002285 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002286 IPA_USB_ERR("Illegal operation.\n");
2287 result = -EPERM;
2288 goto bad_params;
2289 }
2290
2291 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002292 if (ipa3_usb_ctx->ttype_ctx[ttype].state ==
2293 IPA_USB_SUSPENDED_NO_RWAKEUP) {
2294 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2295 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2296 teth_prot);
2297 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2298 return result;
2299 }
2300
2301 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2302 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2303 result = -EINVAL;
2304 goto bad_params;
2305 }
2306
Amir Levy9659e592016-10-27 18:08:27 +03002307 if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
2308 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2309 /* Stop DL/DPL channel */
2310 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2311 if (result) {
2312 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2313 goto bad_params;
2314 }
2315 } else {
2316 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2317 memset(&holb_cfg, 0, sizeof(holb_cfg));
2318 holb_cfg.en = IPA_HOLB_TMR_EN;
2319 holb_cfg.tmr_val = 0;
2320 ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);
2321 }
2322
2323 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2324 orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2325 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Skylar Changdf5f2342017-06-05 09:27:48 -07002326 if (orig_state != IPA_USB_SUSPENDED) {
Amir Levy9659e592016-10-27 18:08:27 +03002327 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2328 flags);
2329 /* Stop UL channel */
2330 result = ipa3_xdci_disconnect(ul_clnt_hdl,
2331 true,
2332 ipa3_usb_ctx->qmi_req_id);
2333 if (result) {
2334 IPA_USB_ERR("failed disconnect UL channel\n");
2335 goto bad_params;
2336 }
2337 ipa3_usb_ctx->qmi_req_id++;
2338 } else
2339 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2340 flags);
2341 } else
2342 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2343
Ghanim Fodi93a61112016-10-05 11:59:18 +03002344 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2345 teth_prot);
2346 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03002347 goto bad_params;
Amir Levy9659e592016-10-27 18:08:27 +03002348
2349 /* Disconnect tethering protocol */
2350 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2351 if (result)
2352 goto bad_params;
2353
Skylar Changdf5f2342017-06-05 09:27:48 -07002354 if (orig_state != IPA_USB_SUSPENDED) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07002355 if (ipa_pm_is_used())
2356 result = ipa_pm_deactivate_sync(
2357 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2358 else
2359 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002360 if (result) {
2361 IPA_USB_ERR("failed to release PROD.\n");
2362 goto bad_params;
2363 }
2364 }
2365
2366 IPA_USB_DBG_LOW("exit\n");
2367 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2368 return 0;
2369
2370bad_params:
2371 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2372 return result;
2373
2374}
2375EXPORT_SYMBOL(ipa_usb_xdci_disconnect);
2376
2377int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
2378{
2379 int result = -EFAULT;
2380 enum ipa3_usb_transport_type ttype;
2381
2382 mutex_lock(&ipa3_usb_ctx->general_mutex);
2383 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002384 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002385 IPA_USB_ERR("bad parameters.\n");
2386 result = -EINVAL;
2387 goto bad_params;
2388 }
2389
2390 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2391
Ghanim Fodi93a61112016-10-05 11:59:18 +03002392 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002393 IPA_USB_ERR("Illegal operation.\n");
2394 result = -EPERM;
2395 goto bad_params;
2396 }
2397
2398 /* Clean-up tethering protocol */
2399 switch (teth_prot) {
2400 case IPA_USB_RNDIS:
2401 case IPA_USB_ECM:
2402 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2403 IPA_USB_TETH_PROT_INITIALIZED) {
2404 IPA_USB_ERR("%s is not initialized\n",
2405 ipa3_usb_teth_prot_to_string(teth_prot));
2406 result = -EINVAL;
2407 goto bad_params;
2408 }
2409 if (teth_prot == IPA_USB_RNDIS)
2410 rndis_ipa_cleanup(
2411 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2412 teth_prot_params.rndis.private);
2413 else
2414 ecm_ipa_cleanup(
2415 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2416 teth_prot_params.ecm.private);
2417 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = NULL;
2418 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2419 IPA_USB_TETH_PROT_INVALID;
2420 ipa3_usb_ctx->num_init_prot--;
2421 IPA_USB_DBG("deinitialized %s\n",
2422 ipa3_usb_teth_prot_to_string(teth_prot));
2423 break;
2424 case IPA_USB_RMNET:
2425 case IPA_USB_MBIM:
2426 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2427 IPA_USB_TETH_PROT_INITIALIZED) {
2428 IPA_USB_ERR("%s (%s) is not initialized\n",
2429 ipa3_usb_teth_prot_to_string(teth_prot),
2430 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2431 result = -EINVAL;
2432 goto bad_params;
2433 }
2434
2435 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2436 NULL;
2437 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2438 IPA_USB_TETH_PROT_INVALID;
2439 ipa3_usb_ctx->num_init_prot--;
2440 IPA_USB_DBG("deinitialized %s (%s)\n",
2441 ipa3_usb_teth_prot_to_string(teth_prot),
2442 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2443 break;
2444 case IPA_USB_DIAG:
2445 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2446 IPA_USB_TETH_PROT_INITIALIZED) {
2447 IPA_USB_ERR("%s is not initialized\n",
2448 ipa3_usb_teth_prot_to_string(teth_prot));
2449 result = -EINVAL;
2450 goto bad_params;
2451 }
2452 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2453 NULL;
2454 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2455 IPA_USB_TETH_PROT_INVALID;
2456 IPA_USB_DBG("deinitialized %s\n",
2457 ipa3_usb_teth_prot_to_string(teth_prot));
2458 break;
2459 default:
2460 IPA_USB_ERR("unexpected tethering protocol\n");
2461 result = -EINVAL;
2462 goto bad_params;
2463 }
2464
2465 if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
2466 (ipa3_usb_ctx->num_init_prot == 0)) {
2467 if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
2468 IPA_USB_ERR("failed to change state to invalid\n");
Michael Adisumarta3e350812017-09-18 14:54:36 -07002469 if (ipa_pm_is_used()) {
2470 ipa3_usb_deregister_pm(ttype);
2471 } else {
2472 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002473 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002474 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
2475 false;
2476 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002477 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002478 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
2479 false;
2480 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
2481 }
Amir Levy9659e592016-10-27 18:08:27 +03002482 }
2483
2484 IPA_USB_DBG_LOW("exit\n");
2485 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2486 return 0;
2487
2488bad_params:
2489 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2490 return result;
2491}
2492EXPORT_SYMBOL(ipa_usb_deinit_teth_prot);
2493
Ghanim Fodi93a61112016-10-05 11:59:18 +03002494/* Assumes lock already acquired */
2495static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03002496 enum ipa_usb_teth_prot teth_prot)
2497{
2498 int result = 0;
Ghanim Fodi93a61112016-10-05 11:59:18 +03002499 enum ipa3_usb_transport_type ttype;
2500
2501 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2502
2503 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) {
2504 IPA_USB_ERR("Illegal operation.\n");
2505 result = -EPERM;
2506 goto fail_exit;
2507 }
2508
2509 IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n",
2510 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2511 "DPL channel":"Data Tethering channels");
2512
2513 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2514 result = -EINVAL;
2515 goto fail_exit;
2516 }
2517
2518 /* Stop DL/DPL channel */
2519 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2520 if (result) {
2521 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2522 goto fail_exit;
2523 }
2524
2525 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2526 /* Stop UL channel */
2527 result = ipa3_xdci_disconnect(ul_clnt_hdl, true,
2528 ipa3_usb_ctx->qmi_req_id);
2529 if (result) {
2530 IPA_USB_ERR("failed disconnect UL channel\n");
2531 goto start_dl;
2532 }
2533 ipa3_usb_ctx->qmi_req_id++;
2534 }
2535
2536 /* Disconnect tethering protocol */
2537 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2538 if (result)
2539 goto start_ul;
2540
Michael Adisumarta3e350812017-09-18 14:54:36 -07002541 if (ipa_pm_is_used())
2542 result = ipa_pm_deactivate_sync(
2543 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2544 else
2545 result = ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002546 if (result) {
2547 IPA_USB_ERR("failed to release PROD.\n");
2548 goto connect_teth;
2549 }
2550
2551 /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */
2552 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype))
2553 IPA_USB_ERR("failed to change state to suspend no rwakeup\n");
2554
2555 IPA_USB_DBG_LOW("exit\n");
2556 return 0;
2557
2558connect_teth:
2559 (void)ipa3_usb_connect_teth_prot(teth_prot);
2560start_ul:
2561 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
2562 (void)ipa3_xdci_connect(ul_clnt_hdl);
2563start_dl:
2564 (void)ipa3_xdci_connect(dl_clnt_hdl);
2565fail_exit:
2566 return result;
2567}
2568
2569int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2570 enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup)
2571{
2572 int result = 0;
Amir Levy9659e592016-10-27 18:08:27 +03002573 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03002574 enum ipa3_usb_transport_type ttype;
2575
2576 mutex_lock(&ipa3_usb_ctx->general_mutex);
2577 IPA_USB_DBG_LOW("entry\n");
Ghanim Fodi93a61112016-10-05 11:59:18 +03002578
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002579 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002580 IPA_USB_ERR("bad parameters.\n");
2581 result = -EINVAL;
2582 goto bad_params;
2583 }
2584
Ghanim Fodi93a61112016-10-05 11:59:18 +03002585 if (!with_remote_wakeup) {
2586 result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl,
2587 dl_clnt_hdl, teth_prot);
2588 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2589 return result;
2590 }
2591
Amir Levy9659e592016-10-27 18:08:27 +03002592 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2593
Ghanim Fodi93a61112016-10-05 11:59:18 +03002594 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002595 IPA_USB_ERR("Illegal operation.\n");
2596 result = -EPERM;
2597 goto bad_params;
2598 }
2599
2600 IPA_USB_DBG("Start suspend sequence: %s\n",
2601 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2602 "DPL channel":"Data Tethering channels");
2603
2604 /* Change state to SUSPEND_REQUESTED */
2605 if (!ipa3_usb_set_state(IPA_USB_SUSPEND_REQUESTED, false, ttype)) {
2606 IPA_USB_ERR(
2607 "fail changing state to suspend_req.\n");
2608 result = -EFAULT;
2609 goto bad_params;
2610 }
2611
2612 /* Stop UL channel & suspend DL/DPL EP */
2613 result = ipa3_xdci_suspend(ul_clnt_hdl, dl_clnt_hdl,
2614 true,
2615 ipa3_usb_ctx->qmi_req_id, IPA3_USB_IS_TTYPE_DPL(ttype));
2616 if (result) {
2617 IPA_USB_ERR("failed to suspend\n");
2618 goto suspend_fail;
2619 }
2620 ipa3_usb_ctx->qmi_req_id++;
2621
Michael Adisumarta3e350812017-09-18 14:54:36 -07002622 if (ipa_pm_is_used())
2623 result = ipa_pm_deactivate_sync(
2624 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2625 else
2626 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002627 if (result) {
2628 IPA_USB_ERR("failed to release PROD\n");
2629 goto release_prod_fail;
2630 }
2631
Skylar Changdf5f2342017-06-05 09:27:48 -07002632 /* Check if DL/DPL data pending */
Amir Levy9659e592016-10-27 18:08:27 +03002633 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Skylar Changdf5f2342017-06-05 09:27:48 -07002634 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
2635 IPA_USB_CONS_GRANTED &&
2636 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2637
2638 IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
2639 queue_work(ipa3_usb_ctx->wq,
2640 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2641 &ipa3_usb_dpl_notify_remote_wakeup_work :
2642 &ipa3_usb_notify_remote_wakeup_work);
2643 }
Amir Levy9659e592016-10-27 18:08:27 +03002644 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +03002645
Amir Levy9659e592016-10-27 18:08:27 +03002646 /* Change state to SUSPENDED */
2647 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
2648 IPA_USB_ERR("failed to change state to suspended\n");
2649
2650 /* Check if DL/DPL data pending */
2651 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2652 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2653 IPA_USB_DBG_LOW(
2654 "DL/DPL data is pending, invoking remote wakeup\n");
2655 queue_work(ipa3_usb_ctx->wq, IPA3_USB_IS_TTYPE_DPL(ttype) ?
2656 &ipa3_usb_dpl_notify_remote_wakeup_work :
2657 &ipa3_usb_notify_remote_wakeup_work);
2658 }
2659 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2660
2661 IPA_USB_DBG_LOW("exit\n");
2662 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2663 return 0;
2664
2665release_prod_fail:
2666 ipa3_xdci_resume(ul_clnt_hdl, dl_clnt_hdl,
2667 IPA3_USB_IS_TTYPE_DPL(ttype));
2668suspend_fail:
2669 /* Change state back to CONNECTED */
2670 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true, ttype))
2671 IPA_USB_ERR("failed to change state back to connected\n");
2672bad_params:
2673 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2674 return result;
2675}
2676EXPORT_SYMBOL(ipa_usb_xdci_suspend);
2677
Ghanim Fodi93a61112016-10-05 11:59:18 +03002678/* Assumes lock already acquired */
2679static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2680 enum ipa_usb_teth_prot teth_prot)
2681{
2682 int result = -EFAULT;
2683 enum ipa3_usb_transport_type ttype;
2684
2685 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2686
2687 IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n",
2688 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2689 "DPL channel":"Data Tethering channels");
2690
2691 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002692 if (ipa_pm_is_used())
2693 result = ipa_pm_activate_sync(
2694 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2695 else
2696 result = ipa3_usb_request_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002697 if (result)
2698 goto fail_exit;
2699
2700 /* Connect tethering protocol */
2701 result = ipa3_usb_connect_teth_prot(teth_prot);
2702 if (result) {
2703 IPA_USB_ERR("failed to connect teth protocol\n");
2704 goto release_prod;
2705 }
2706
2707 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2708 /* Start UL channel */
2709 result = ipa3_xdci_connect(ul_clnt_hdl);
2710 if (result) {
2711 IPA_USB_ERR("failed to start UL channel.\n");
2712 goto disconn_teth;
2713 }
2714 }
2715
2716 /* Start DL/DPL channel */
2717 result = ipa3_xdci_connect(dl_clnt_hdl);
2718 if (result) {
2719 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2720 goto stop_ul;
2721 }
2722
2723 /* Change state to CONNECTED */
2724 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2725 IPA_USB_ERR("failed to change state to connected\n");
2726 result = -EFAULT;
2727 goto stop_dl;
2728 }
2729
2730 return 0;
2731
2732stop_dl:
2733 (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2734stop_ul:
2735 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2736 (void)ipa3_xdci_disconnect(ul_clnt_hdl, true,
2737 ipa3_usb_ctx->qmi_req_id);
2738 ipa3_usb_ctx->qmi_req_id++;
2739 }
2740disconn_teth:
2741 (void)ipa3_usb_disconnect_teth_prot(teth_prot);
2742release_prod:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002743 if (ipa_pm_is_used())
2744 (void)ipa_pm_deactivate_sync(
2745 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2746 else
2747 (void)ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002748fail_exit:
2749 return result;
2750}
2751
Amir Levy9659e592016-10-27 18:08:27 +03002752int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2753 enum ipa_usb_teth_prot teth_prot)
2754{
2755 int result = -EFAULT;
2756 enum ipa3_usb_state prev_state;
2757 unsigned long flags;
2758 enum ipa3_usb_transport_type ttype;
2759
2760 mutex_lock(&ipa3_usb_ctx->general_mutex);
2761 IPA_USB_DBG_LOW("entry\n");
2762
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002763 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002764 IPA_USB_ERR("bad parameters.\n");
2765 result = -EINVAL;
2766 goto bad_params;
2767 }
2768
2769 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2770
Ghanim Fodi93a61112016-10-05 11:59:18 +03002771 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002772 IPA_USB_ERR("Illegal operation.\n");
2773 result = -EPERM;
2774 goto bad_params;
2775 }
2776
Amir Levy9659e592016-10-27 18:08:27 +03002777 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2778 prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2779 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002780 if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) {
2781 result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl,
2782 dl_clnt_hdl, teth_prot);
2783 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2784 return result;
2785 }
2786
2787 IPA_USB_DBG("Start resume sequence: %s\n",
2788 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2789 "DPL channel" : "Data Tethering channels");
Amir Levy9659e592016-10-27 18:08:27 +03002790
2791 /* Change state to RESUME_IN_PROGRESS */
2792 if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) {
2793 IPA_USB_ERR("failed to change state to resume_in_progress\n");
2794 result = -EFAULT;
2795 goto bad_params;
2796 }
2797
2798 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002799 if (ipa_pm_is_used())
2800 result = ipa_pm_activate_sync(
2801 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2802 else
2803 result = ipa3_usb_request_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002804 if (result)
2805 goto prod_req_fail;
2806
2807 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2808 /* Start UL channel */
2809 result = ipa3_start_gsi_channel(ul_clnt_hdl);
2810 if (result) {
2811 IPA_USB_ERR("failed to start UL channel.\n");
2812 goto start_ul_fail;
2813 }
2814 }
2815
Skylar Changdf5f2342017-06-05 09:27:48 -07002816 /* Start DL/DPL channel */
2817 result = ipa3_start_gsi_channel(dl_clnt_hdl);
2818 if (result) {
2819 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2820 goto start_dl_fail;
Amir Levy9659e592016-10-27 18:08:27 +03002821 }
2822
2823 /* Change state to CONNECTED */
2824 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2825 IPA_USB_ERR("failed to change state to connected\n");
2826 result = -EFAULT;
2827 goto state_change_connected_fail;
2828 }
2829
2830 IPA_USB_DBG_LOW("exit\n");
2831 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2832 return 0;
2833
2834state_change_connected_fail:
Skylar Changdf5f2342017-06-05 09:27:48 -07002835 result = ipa3_stop_gsi_channel(dl_clnt_hdl);
2836 if (result)
2837 IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
2838 result);
Amir Levy9659e592016-10-27 18:08:27 +03002839start_dl_fail:
2840 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2841 result = ipa3_stop_gsi_channel(ul_clnt_hdl);
2842 if (result)
2843 IPA_USB_ERR("Error stopping UL channel: %d\n", result);
2844 }
2845start_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002846 if (ipa_pm_is_used())
2847 ipa_pm_deactivate_sync(
2848 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2849 else
2850 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002851prod_req_fail:
2852 /* Change state back to prev_state */
2853 if (!ipa3_usb_set_state(prev_state, true, ttype))
2854 IPA_USB_ERR("failed to change state back to %s\n",
2855 ipa3_usb_state_to_string(prev_state));
2856bad_params:
2857 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2858 return result;
2859}
2860EXPORT_SYMBOL(ipa_usb_xdci_resume);
2861
2862static int __init ipa3_usb_init(void)
2863{
2864 int i;
2865 unsigned long flags;
2866 int res;
2867
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002868 pr_debug("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002869 ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL);
2870 if (ipa3_usb_ctx == NULL) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002871 pr_err("failed to allocate memory\n");
2872 pr_err(":ipa_usb init failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03002873 return -EFAULT;
2874 }
2875 memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context));
2876
2877 for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++)
2878 ipa3_usb_ctx->teth_prot_ctx[i].state =
2879 IPA_USB_TETH_PROT_INVALID;
2880 ipa3_usb_ctx->num_init_prot = 0;
2881 init_completion(&ipa3_usb_ctx->dev_ready_comp);
2882 ipa3_usb_ctx->qmi_req_id = 0;
2883 spin_lock_init(&ipa3_usb_ctx->state_lock);
2884 ipa3_usb_ctx->dl_data_pending = false;
2885 mutex_init(&ipa3_usb_ctx->general_mutex);
2886
Michael Adisumarta3e350812017-09-18 14:54:36 -07002887 if (ipa_pm_is_used()) {
2888 struct ipa3_usb_pm_context *pm_ctx;
2889
2890 pm_ctx =
2891 &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
2892 pm_ctx->hdl = ~0;
2893 pm_ctx->remote_wakeup_work =
2894 &ipa3_usb_notify_remote_wakeup_work;
2895 pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
2896 pm_ctx->hdl = ~0;
2897 pm_ctx->remote_wakeup_work =
2898 &ipa3_usb_dpl_notify_remote_wakeup_work;
2899 }
2900
Amir Levy9659e592016-10-27 18:08:27 +03002901 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2902 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
2903 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
2904 init_completion(&ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_comp);
2905 ipa3_usb_ctx->ttype_ctx[i].user_data = NULL;
2906 }
2907
2908 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2909 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2910 ipa3_usb_ctx->ttype_ctx[i].state = IPA_USB_INVALID;
2911 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_state =
2912 IPA_USB_CONS_RELEASED;
2913 }
2914 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2915
2916 ipa3_usb_ctx->wq = create_singlethread_workqueue("ipa_usb_wq");
2917 if (!ipa3_usb_ctx->wq) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002918 pr_err("failed to create workqueue\n");
Amir Levy9659e592016-10-27 18:08:27 +03002919 res = -EFAULT;
2920 goto ipa_usb_workqueue_fail;
2921 }
2922
2923 ipa_usb_debugfs_init();
2924
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002925 pr_info("exit: IPA_USB init success!\n");
Amir Levy9659e592016-10-27 18:08:27 +03002926
2927 return 0;
2928
2929ipa_usb_workqueue_fail:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002930 pr_err(":init failed (%d)\n", -res);
Amir Levy9659e592016-10-27 18:08:27 +03002931 kfree(ipa3_usb_ctx);
2932 return res;
2933}
2934
2935static void ipa3_usb_exit(void)
2936{
2937 IPA_USB_DBG_LOW("IPA_USB exit\n");
2938 ipa_usb_debugfs_remove();
2939 kfree(ipa3_usb_ctx);
2940}
2941
2942arch_initcall(ipa3_usb_init);
2943module_exit(ipa3_usb_exit);
2944
2945MODULE_LICENSE("GPL v2");
2946MODULE_DESCRIPTION("IPA USB client driver");