blob: 90920d9a68e90cb6a04c0cc42653c9de789c4023 [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
744 memset(&ttype_ctx->pm_ctx.reg_params, 0,
745 sizeof(ttype_ctx->pm_ctx.reg_params));
746 ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
747 "USB DPL" : "USB";
748 ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb;
749 ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx;
750 ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT;
751
752 result = ipa_pm_register(&ttype_ctx->pm_ctx.reg_params,
753 &ttype_ctx->pm_ctx.hdl);
754 if (result) {
755 IPA_USB_ERR("fail to register with PM %d\n", result);
756 goto fail_pm_reg;
757 }
758
759 result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl,
760 (ttype == IPA_USB_TRANSPORT_DPL) ?
761 IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS);
762 if (result) {
763 IPA_USB_ERR("fail to associate cons with PM %d\n", result);
764 goto fail_pm_cons;
765 }
766
767 return 0;
768
769fail_pm_cons:
770 ipa_pm_deregister(ttype_ctx->pm_ctx.hdl);
771fail_pm_reg:
772 memset(&ttype_ctx->pm_ctx.reg_params, 0,
773 sizeof(ttype_ctx->pm_ctx.reg_params));
774 return result;
775}
776
777static int ipa3_usb_deregister_pm(enum ipa3_usb_transport_type ttype)
778{
779 struct ipa3_usb_pm_context *pm_ctx =
780 &ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx;
781 int result;
782
783 result = ipa_pm_deregister(pm_ctx->hdl);
784 if (result)
785 return result;
786
787 memset(&pm_ctx->reg_params, 0, sizeof(pm_ctx->reg_params));
788 return 0;
789}
790
Amir Levy9659e592016-10-27 18:08:27 +0300791static int ipa3_usb_create_rm_resources(enum ipa3_usb_transport_type ttype)
792{
793 struct ipa3_usb_rm_context *rm_ctx;
794 int result = -EFAULT;
795 bool created = false;
796
797 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
798
799 /* create PROD */
800 if (!rm_ctx->prod_valid) {
801 rm_ctx->prod_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
802 IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD :
803 IPA_RM_RESOURCE_USB_PROD;
Skylar Chang448d8b82017-08-08 17:30:32 -0700804 rm_ctx->prod_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300805 rm_ctx->prod_params.reg_params.user_data = NULL;
806 rm_ctx->prod_params.reg_params.notify_cb =
807 IPA3_USB_IS_TTYPE_DPL(ttype) ?
808 ipa3_usb_dpl_dummy_prod_notify_cb :
809 ipa3_usb_prod_notify_cb;
810 rm_ctx->prod_params.request_resource = NULL;
811 rm_ctx->prod_params.release_resource = NULL;
812 result = ipa_rm_create_resource(&rm_ctx->prod_params);
813 if (result) {
814 IPA_USB_ERR("Failed to create %s RM resource\n",
815 ipa_rm_resource_str(rm_ctx->prod_params.name));
816 return result;
817 }
818 rm_ctx->prod_valid = true;
819 created = true;
820 IPA_USB_DBG("Created %s RM resource\n",
821 ipa_rm_resource_str(rm_ctx->prod_params.name));
822 }
823
824 /* Create CONS */
825 if (!rm_ctx->cons_valid) {
826 rm_ctx->cons_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
827 IPA_RM_RESOURCE_USB_DPL_CONS :
828 IPA_RM_RESOURCE_USB_CONS;
Skylar Chang448d8b82017-08-08 17:30:32 -0700829 rm_ctx->cons_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300830 rm_ctx->cons_params.reg_params.user_data = NULL;
831 rm_ctx->cons_params.reg_params.notify_cb = NULL;
832 rm_ctx->cons_params.request_resource =
833 IPA3_USB_IS_TTYPE_DPL(ttype) ?
834 ipa3_usb_dpl_cons_request_resource_cb :
835 ipa3_usb_cons_request_resource_cb;
836 rm_ctx->cons_params.release_resource =
837 IPA3_USB_IS_TTYPE_DPL(ttype) ?
838 ipa3_usb_dpl_cons_release_resource_cb :
839 ipa3_usb_cons_release_resource_cb;
840 result = ipa_rm_create_resource(&rm_ctx->cons_params);
841 if (result) {
842 IPA_USB_ERR("Failed to create %s RM resource\n",
843 ipa_rm_resource_str(rm_ctx->cons_params.name));
844 goto create_cons_rsc_fail;
845 }
846 rm_ctx->cons_valid = true;
847 IPA_USB_DBG("Created %s RM resource\n",
848 ipa_rm_resource_str(rm_ctx->cons_params.name));
849 }
850
851 return 0;
852
853create_cons_rsc_fail:
854 if (created) {
855 rm_ctx->prod_valid = false;
856 ipa_rm_delete_resource(rm_ctx->prod_params.name);
857 }
858 return result;
859}
860
861int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
862 struct ipa_usb_teth_params *teth_params,
863 int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event,
864 void *),
865 void *user_data)
866{
867 int result = -EFAULT;
868 enum ipa3_usb_transport_type ttype;
869
870 mutex_lock(&ipa3_usb_ctx->general_mutex);
871 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -0700872 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
Amir Levy9659e592016-10-27 18:08:27 +0300873 ((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) &&
874 teth_params == NULL) || ipa_usb_notify_cb == NULL ||
875 user_data == NULL) {
876 IPA_USB_ERR("bad parameters.\n");
877 result = -EINVAL;
878 goto bad_params;
879 }
880
881 ttype = IPA3_USB_GET_TTYPE(teth_prot);
882
Ghanim Fodi93a61112016-10-05 11:59:18 +0300883 if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +0300884 IPA_USB_ERR("Illegal operation.\n");
885 result = -EPERM;
886 goto bad_params;
887 }
888
889 /* Create IPA RM USB resources */
Michael Adisumarta3e350812017-09-18 14:54:36 -0700890 if (ipa_pm_is_used())
891 result = ipa3_usb_register_pm(ttype);
892 else
893 result = ipa3_usb_create_rm_resources(ttype);
Amir Levy9659e592016-10-27 18:08:27 +0300894 if (result) {
895 IPA_USB_ERR("Failed creating IPA RM USB resources\n");
896 goto bad_params;
897 }
898
899 if (!ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb) {
900 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb =
901 ipa_usb_notify_cb;
902 } else if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
903 if (ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb !=
904 ipa_usb_notify_cb) {
905 IPA_USB_ERR("Got different notify_cb\n");
906 result = -EINVAL;
907 goto bad_params;
908 }
909 } else {
910 IPA_USB_ERR("Already has dpl_notify_cb\n");
911 result = -EINVAL;
912 goto bad_params;
913 }
914
915 /* Initialize tethering protocol */
916 switch (teth_prot) {
917 case IPA_USB_RNDIS:
918 case IPA_USB_ECM:
919 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
920 IPA_USB_TETH_PROT_INVALID) {
921 IPA_USB_DBG("%s already initialized\n",
922 ipa3_usb_teth_prot_to_string(teth_prot));
923 result = -EPERM;
924 goto bad_params;
925 }
926 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
927 if (teth_prot == IPA_USB_RNDIS) {
928 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
929 teth_prot_params.rndis.device_ready_notify =
930 ipa3_usb_device_ready_notify_cb;
931 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
932 teth_prot_params.rndis.host_ethaddr,
933 teth_params->host_ethaddr,
934 sizeof(teth_params->host_ethaddr));
935 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
936 teth_prot_params.rndis.device_ethaddr,
937 teth_params->device_ethaddr,
938 sizeof(teth_params->device_ethaddr));
939
940 result = rndis_ipa_init(&ipa3_usb_ctx->
941 teth_prot_ctx[teth_prot].
942 teth_prot_params.rndis);
943 if (result) {
944 IPA_USB_ERR("Failed to initialize %s\n",
945 ipa3_usb_teth_prot_to_string(
946 teth_prot));
947 goto teth_prot_init_fail;
948 }
949 } else {
950 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
951 teth_prot_params.ecm.device_ready_notify =
952 ipa3_usb_device_ready_notify_cb;
953 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
954 teth_prot_params.ecm.host_ethaddr,
955 teth_params->host_ethaddr,
956 sizeof(teth_params->host_ethaddr));
957 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
958 teth_prot_params.ecm.device_ethaddr,
959 teth_params->device_ethaddr,
960 sizeof(teth_params->device_ethaddr));
961
962 result = ecm_ipa_init(&ipa3_usb_ctx->
963 teth_prot_ctx[teth_prot].teth_prot_params.ecm);
964 if (result) {
965 IPA_USB_ERR("Failed to initialize %s\n",
966 ipa3_usb_teth_prot_to_string(
967 teth_prot));
968 goto teth_prot_init_fail;
969 }
970 }
971 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
972 IPA_USB_TETH_PROT_INITIALIZED;
973 ipa3_usb_ctx->num_init_prot++;
974 IPA_USB_DBG("initialized %s\n",
975 ipa3_usb_teth_prot_to_string(teth_prot));
976 break;
977 case IPA_USB_RMNET:
978 case IPA_USB_MBIM:
979 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
980 IPA_USB_TETH_PROT_INVALID) {
981 IPA_USB_DBG("%s already initialized\n",
982 ipa3_usb_teth_prot_to_string(teth_prot));
983 result = -EPERM;
984 goto bad_params;
985 }
986 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
987 result = ipa3_usb_init_teth_bridge();
988 if (result)
989 goto teth_prot_init_fail;
990 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
991 IPA_USB_TETH_PROT_INITIALIZED;
992 ipa3_usb_ctx->num_init_prot++;
993 IPA_USB_DBG("initialized %s %s\n",
994 ipa3_usb_teth_prot_to_string(teth_prot),
995 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
996 break;
997 case IPA_USB_DIAG:
998 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
999 IPA_USB_TETH_PROT_INVALID) {
1000 IPA_USB_DBG("DPL already initialized\n");
1001 result = -EPERM;
1002 goto bad_params;
1003 }
1004 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
1005 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1006 IPA_USB_TETH_PROT_INITIALIZED;
1007 IPA_USB_DBG("initialized DPL\n");
1008 break;
1009 default:
1010 IPA_USB_ERR("unexpected tethering protocol\n");
1011 result = -EINVAL;
1012 goto bad_params;
1013 }
1014
1015 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1016 IPA_USB_ERR("failed to change state to initialized\n");
1017
1018 IPA_USB_DBG_LOW("exit\n");
1019 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1020 return 0;
1021
1022teth_prot_init_fail:
1023 if ((IPA3_USB_IS_TTYPE_DPL(ttype))
1024 || (ipa3_usb_ctx->num_init_prot == 0)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07001025 if (ipa_pm_is_used()) {
1026 ipa3_usb_deregister_pm(ttype);
1027 } else {
1028 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
1029 false;
1030 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
1031 false;
1032 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03001033 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001034 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03001035 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07001036 }
Amir Levy9659e592016-10-27 18:08:27 +03001037 }
1038bad_params:
1039 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1040 return result;
1041}
1042EXPORT_SYMBOL(ipa_usb_init_teth_prot);
1043
1044void ipa3_usb_gsi_evt_err_cb(struct gsi_evt_err_notify *notify)
1045{
1046 IPA_USB_DBG_LOW("entry\n");
1047 if (!notify)
1048 return;
1049 IPA_USB_ERR("Received event error %d, description: %d\n",
1050 notify->evt_id, notify->err_desc);
1051 IPA_USB_DBG_LOW("exit\n");
1052}
1053
1054void ipa3_usb_gsi_chan_err_cb(struct gsi_chan_err_notify *notify)
1055{
1056 IPA_USB_DBG_LOW("entry\n");
1057 if (!notify)
1058 return;
1059 IPA_USB_ERR("Received channel error %d, description: %d\n",
1060 notify->evt_id, notify->err_desc);
1061 IPA_USB_DBG_LOW("exit\n");
1062}
1063
1064static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
1065{
1066 IPA_USB_DBG_LOW("gevntcount_low_addr = %x\n",
1067 params->gevntcount_low_addr);
1068 IPA_USB_DBG_LOW("gevntcount_hi_addr = %x\n",
1069 params->gevntcount_hi_addr);
1070 IPA_USB_DBG_LOW("dir = %d\n", params->dir);
1071 IPA_USB_DBG_LOW("xfer_ring_len = %d\n", params->xfer_ring_len);
1072 IPA_USB_DBG_LOW("xfer_ring_base_addr = %llx\n",
1073 params->xfer_ring_base_addr);
1074 IPA_USB_DBG_LOW("last_trb_addr_iova = %x\n",
1075 params->xfer_scratch.last_trb_addr_iova);
1076 IPA_USB_DBG_LOW("const_buffer_size = %d\n",
1077 params->xfer_scratch.const_buffer_size);
1078 IPA_USB_DBG_LOW("depcmd_low_addr = %x\n",
1079 params->xfer_scratch.depcmd_low_addr);
1080 IPA_USB_DBG_LOW("depcmd_hi_addr = %x\n",
1081 params->xfer_scratch.depcmd_hi_addr);
1082
1083 if (params->client >= IPA_CLIENT_MAX ||
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001084 params->teth_prot < 0 ||
1085 params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
Amir Levy9659e592016-10-27 18:08:27 +03001086 params->xfer_ring_len % GSI_CHAN_RE_SIZE_16B ||
1087 params->xfer_scratch.const_buffer_size < 1 ||
1088 params->xfer_scratch.const_buffer_size > 31) {
1089 IPA_USB_ERR("Invalid params\n");
1090 return false;
1091 }
1092 switch (params->teth_prot) {
1093 case IPA_USB_DIAG:
1094 if (!IPA_CLIENT_IS_CONS(params->client)) {
1095 IPA_USB_ERR("DPL supports only DL channel\n");
1096 return false;
1097 }
1098 case IPA_USB_RNDIS:
1099 case IPA_USB_ECM:
1100 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1101 IPA_USB_TETH_PROT_INVALID) {
1102 IPA_USB_ERR("%s is not initialized\n",
1103 ipa3_usb_teth_prot_to_string(
1104 params->teth_prot));
1105 return false;
1106 }
1107 break;
1108 case IPA_USB_RMNET:
1109 case IPA_USB_MBIM:
1110 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1111 IPA_USB_TETH_PROT_INVALID) {
1112 IPA_USB_ERR("%s is not initialized\n",
1113 ipa3_usb_teth_bridge_prot_to_string(
1114 params->teth_prot));
1115 return false;
1116 }
1117 break;
1118 default:
1119 IPA_USB_ERR("Unknown tethering protocol (%d)\n",
1120 params->teth_prot);
1121 return false;
1122 }
1123 return true;
1124}
1125
1126static int ipa3_usb_smmu_map_xdci_channel(
1127 struct ipa_usb_xdci_chan_params *params, bool map)
1128{
1129 int result;
1130 u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE);
1131 u32 xfer_scratch_r =
1132 rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
1133
1134 if (gevntcount_r != xfer_scratch_r) {
1135 IPA_USB_ERR("No support more than 1 page map for USB regs\n");
1136 WARN_ON(1);
1137 return -EINVAL;
1138 }
1139
1140 if (map) {
1141 if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
1142 ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r;
1143 result = ipa3_smmu_map_peer_reg(
1144 ipa3_usb_ctx->smmu_reg_map.addr, true);
1145 if (result) {
1146 IPA_USB_ERR("failed to map USB regs %d\n",
1147 result);
1148 return result;
1149 }
1150 } else {
1151 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1152 IPA_USB_ERR(
1153 "No support for map different reg\n");
1154 return -EINVAL;
1155 }
1156 }
1157 ipa3_usb_ctx->smmu_reg_map.cnt++;
1158 } else {
1159 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1160 IPA_USB_ERR(
1161 "No support for map different reg\n");
1162 return -EINVAL;
1163 }
1164
1165 if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
1166 result = ipa3_smmu_map_peer_reg(
1167 ipa3_usb_ctx->smmu_reg_map.addr, false);
1168 if (result) {
1169 IPA_USB_ERR("failed to unmap USB regs %d\n",
1170 result);
1171 return result;
1172 }
1173 }
1174 ipa3_usb_ctx->smmu_reg_map.cnt--;
1175 }
1176
1177 result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
1178 params->xfer_ring_base_addr, params->xfer_ring_len, map);
1179 if (result) {
1180 IPA_USB_ERR("failed to map Xfer ring %d\n", result);
1181 return result;
1182 }
1183
1184 result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova,
1185 params->data_buff_base_addr, params->data_buff_base_len, map);
1186 if (result) {
1187 IPA_USB_ERR("failed to map TRBs buff %d\n", result);
1188 return result;
1189 }
1190
1191 return 0;
1192}
1193
1194static int ipa3_usb_request_xdci_channel(
1195 struct ipa_usb_xdci_chan_params *params,
1196 struct ipa_req_chan_out_params *out_params)
1197{
1198 int result = -EFAULT;
1199 struct ipa_request_gsi_channel_params chan_params;
1200 enum ipa3_usb_transport_type ttype;
1201
1202 IPA_USB_DBG_LOW("entry\n");
1203 if (params == NULL || out_params == NULL ||
1204 !ipa3_usb_check_chan_params(params)) {
1205 IPA_USB_ERR("bad parameters\n");
1206 return -EINVAL;
1207 }
1208
1209 ttype = IPA3_USB_GET_TTYPE(params->teth_prot);
1210
Ghanim Fodi93a61112016-10-05 11:59:18 +03001211 if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001212 IPA_USB_ERR("Illegal operation\n");
1213 return -EPERM;
1214 }
1215
1216 memset(&chan_params, 0, sizeof(struct ipa_request_gsi_channel_params));
1217 memcpy(&chan_params.ipa_ep_cfg, &params->ipa_ep_cfg,
1218 sizeof(struct ipa_ep_cfg));
1219 chan_params.client = params->client;
1220 switch (params->teth_prot) {
1221 case IPA_USB_RNDIS:
1222 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1223 teth_prot_params.rndis.private;
1224 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1225 chan_params.notify =
1226 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1227 teth_prot_params.rndis.ipa_tx_notify;
1228 else
1229 chan_params.notify =
1230 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1231 teth_prot_params.rndis.ipa_rx_notify;
1232 chan_params.skip_ep_cfg =
1233 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1234 teth_prot_params.rndis.skip_ep_cfg;
1235 break;
1236 case IPA_USB_ECM:
1237 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1238 teth_prot_params.ecm.private;
1239 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1240 chan_params.notify =
1241 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1242 teth_prot_params.ecm.ecm_ipa_tx_dp_notify;
1243 else
1244 chan_params.notify =
1245 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1246 teth_prot_params.ecm.ecm_ipa_rx_dp_notify;
1247 chan_params.skip_ep_cfg =
1248 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1249 teth_prot_params.ecm.skip_ep_cfg;
1250 break;
1251 case IPA_USB_RMNET:
1252 case IPA_USB_MBIM:
1253 chan_params.priv =
1254 ipa3_usb_ctx->teth_bridge_params.private_data;
1255 chan_params.notify =
1256 ipa3_usb_ctx->teth_bridge_params.usb_notify_cb;
1257 chan_params.skip_ep_cfg =
1258 ipa3_usb_ctx->teth_bridge_params.skip_ep_cfg;
1259 break;
1260 case IPA_USB_DIAG:
1261 chan_params.priv = NULL;
1262 chan_params.notify = NULL;
1263 chan_params.skip_ep_cfg = true;
1264 break;
1265 default:
1266 break;
1267 }
1268
1269 result = ipa3_usb_smmu_map_xdci_channel(params, true);
1270 if (result) {
1271 IPA_USB_ERR("failed to smmu map %d\n", result);
1272 return result;
1273 }
1274
1275 /* store channel params for SMMU unmap */
1276 ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params;
1277
1278 chan_params.keep_ipa_awake = params->keep_ipa_awake;
1279 chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV;
1280 chan_params.evt_ring_params.intr = GSI_INTR_IRQ;
1281 chan_params.evt_ring_params.re_size = GSI_EVT_RING_RE_SIZE_16B;
1282 chan_params.evt_ring_params.ring_len = params->xfer_ring_len -
1283 chan_params.evt_ring_params.re_size;
1284 chan_params.evt_ring_params.ring_base_addr =
1285 params->xfer_ring_base_addr;
1286 chan_params.evt_ring_params.ring_base_vaddr = NULL;
1287 chan_params.evt_ring_params.int_modt = 0;
1288 chan_params.evt_ring_params.int_modt = 0;
1289 chan_params.evt_ring_params.intvec = 0;
1290 chan_params.evt_ring_params.msi_addr = 0;
1291 chan_params.evt_ring_params.rp_update_addr = 0;
1292 chan_params.evt_ring_params.exclusive = true;
1293 chan_params.evt_ring_params.err_cb = ipa3_usb_gsi_evt_err_cb;
1294 chan_params.evt_ring_params.user_data = NULL;
1295 chan_params.evt_scratch.xdci.gevntcount_low_addr =
1296 params->gevntcount_low_addr;
1297 chan_params.evt_scratch.xdci.gevntcount_hi_addr =
1298 params->gevntcount_hi_addr;
1299 chan_params.chan_params.prot = GSI_CHAN_PROT_XDCI;
1300 chan_params.chan_params.dir = params->dir;
1301 /* chan_id is set in ipa3_request_gsi_channel() */
1302 chan_params.chan_params.re_size = GSI_CHAN_RE_SIZE_16B;
1303 chan_params.chan_params.ring_len = params->xfer_ring_len;
1304 chan_params.chan_params.ring_base_addr =
1305 params->xfer_ring_base_addr;
1306 chan_params.chan_params.ring_base_vaddr = NULL;
1307 chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE;
1308 chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG;
1309 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1310 chan_params.chan_params.low_weight =
1311 IPA_USB_DL_CHAN_LOW_WEIGHT;
1312 else
1313 chan_params.chan_params.low_weight =
1314 IPA_USB_UL_CHAN_LOW_WEIGHT;
1315 chan_params.chan_params.xfer_cb = NULL;
1316 chan_params.chan_params.err_cb = ipa3_usb_gsi_chan_err_cb;
1317 chan_params.chan_params.chan_user_data = NULL;
1318 chan_params.chan_scratch.xdci.last_trb_addr =
1319 params->xfer_scratch.last_trb_addr_iova;
1320 /* xferrscidx will be updated later */
1321 chan_params.chan_scratch.xdci.xferrscidx = 0;
1322 chan_params.chan_scratch.xdci.const_buffer_size =
1323 params->xfer_scratch.const_buffer_size;
1324 chan_params.chan_scratch.xdci.depcmd_low_addr =
1325 params->xfer_scratch.depcmd_low_addr;
1326 chan_params.chan_scratch.xdci.depcmd_hi_addr =
1327 params->xfer_scratch.depcmd_hi_addr;
1328 chan_params.chan_scratch.xdci.outstanding_threshold =
1329 ((params->teth_prot == IPA_USB_MBIM) ? 1 : 2) *
1330 chan_params.chan_params.re_size;
1331 /* max_outstanding_tre is set in ipa3_request_gsi_channel() */
1332 result = ipa3_request_gsi_channel(&chan_params, out_params);
1333 if (result) {
1334 IPA_USB_ERR("failed to allocate GSI channel\n");
1335 ipa3_usb_smmu_map_xdci_channel(params, false);
1336 return result;
1337 }
1338
1339 IPA_USB_DBG_LOW("exit\n");
1340 return 0;
1341}
1342
1343static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
1344 enum ipa3_usb_transport_type ttype)
1345{
1346 int result = 0;
1347
1348 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001349 if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001350 IPA_USB_ERR("bad parameter.\n");
1351 return -EINVAL;
1352 }
1353
Ghanim Fodi93a61112016-10-05 11:59:18 +03001354 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001355 IPA_USB_ERR("Illegal operation.\n");
1356 return -EPERM;
1357 }
1358
1359 /* Release channel */
1360 result = ipa3_release_gsi_channel(clnt_hdl);
1361 if (result) {
1362 IPA_USB_ERR("failed to deallocate channel.\n");
1363 return result;
1364 }
1365
1366 result = ipa3_usb_smmu_map_xdci_channel(
1367 &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false);
1368
1369 /* Change ipa_usb state to INITIALIZED */
1370 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1371 IPA_USB_ERR("failed to change state to initialized\n");
1372
1373 IPA_USB_DBG_LOW("exit\n");
1374 return 0;
1375}
1376
1377static int ipa3_usb_request_prod(enum ipa3_usb_transport_type ttype)
1378{
1379 int result;
1380 struct ipa3_usb_rm_context *rm_ctx;
1381 const char *rsrc_str;
1382
1383 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1384 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1385
1386 IPA_USB_DBG_LOW("requesting %s\n", rsrc_str);
1387 init_completion(&rm_ctx->prod_comp);
1388 result = ipa_rm_request_resource(rm_ctx->prod_params.name);
1389 if (result) {
1390 if (result != -EINPROGRESS) {
1391 IPA_USB_ERR("failed to request %s: %d\n",
1392 rsrc_str, result);
1393 return result;
1394 }
1395 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1396 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1397 if (result == 0) {
1398 IPA_USB_ERR("timeout request %s\n", rsrc_str);
1399 return -ETIME;
1400 }
1401 }
1402
1403 IPA_USB_DBG_LOW("%s granted\n", rsrc_str);
1404 return 0;
1405}
1406
1407static int ipa3_usb_release_prod(enum ipa3_usb_transport_type ttype)
1408{
1409 int result;
1410 struct ipa3_usb_rm_context *rm_ctx;
1411 const char *rsrc_str;
1412
1413 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1414 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1415
1416 IPA_USB_DBG_LOW("releasing %s\n", rsrc_str);
1417
1418 init_completion(&rm_ctx->prod_comp);
1419 result = ipa_rm_release_resource(rm_ctx->prod_params.name);
1420 if (result) {
1421 if (result != -EINPROGRESS) {
1422 IPA_USB_ERR("failed to release %s: %d\n",
1423 rsrc_str, result);
1424 return result;
1425 }
1426 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1427 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1428 if (result == 0) {
1429 IPA_USB_ERR("timeout release %s\n", rsrc_str);
1430 return -ETIME;
1431 }
1432 }
1433
1434 IPA_USB_DBG_LOW("%s released\n", rsrc_str);
1435 return 0;
1436}
1437
1438static bool ipa3_usb_check_connect_params(
1439 struct ipa_usb_xdci_connect_params_internal *params)
1440{
1441 IPA_USB_DBG_LOW("ul xferrscidx = %d\n", params->usb_to_ipa_xferrscidx);
1442 IPA_USB_DBG_LOW("dl xferrscidx = %d\n", params->ipa_to_usb_xferrscidx);
1443 IPA_USB_DBG_LOW("max_supported_bandwidth_mbps = %d\n",
1444 params->max_supported_bandwidth_mbps);
1445
1446 if (params->max_pkt_size < IPA_USB_HIGH_SPEED_512B ||
1447 params->max_pkt_size > IPA_USB_SUPER_SPEED_1024B ||
1448 params->ipa_to_usb_xferrscidx < 0 ||
1449 params->ipa_to_usb_xferrscidx > 127 ||
1450 (params->teth_prot != IPA_USB_DIAG &&
1451 (params->usb_to_ipa_xferrscidx < 0 ||
1452 params->usb_to_ipa_xferrscidx > 127)) ||
Skylar Changc5e2b7e2017-08-29 10:54:04 -07001453 params->teth_prot < 0 ||
1454 params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03001455 IPA_USB_ERR("Invalid params\n");
1456 return false;
1457 }
1458
1459 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1460 IPA_USB_TETH_PROT_INVALID) {
1461 IPA_USB_ERR("%s is not initialized\n",
1462 ipa3_usb_teth_prot_to_string(
1463 params->teth_prot));
1464 return false;
1465 }
1466
1467 return true;
1468}
1469
1470static int ipa3_usb_connect_teth_bridge(
1471 struct teth_bridge_connect_params *params)
1472{
1473 int result;
1474
1475 result = teth_bridge_connect(params);
1476 if (result) {
1477 IPA_USB_ERR("failed to connect teth_bridge (%s)\n",
1478 params->tethering_mode == TETH_TETHERING_MODE_RMNET ?
1479 "rmnet" : "mbim");
1480 return result;
1481 }
1482
1483 return 0;
1484}
1485
1486static int ipa3_usb_connect_dpl(void)
1487{
1488 int res = 0;
1489
Michael Adisumarta3e350812017-09-18 14:54:36 -07001490 if (ipa_pm_is_used())
1491 return 0;
1492
Amir Levy9659e592016-10-27 18:08:27 +03001493 /*
1494 * Add DPL dependency to RM dependency graph, first add_dependency call
1495 * is sync in order to make sure the IPA clocks are up before we
1496 * continue and notify the USB driver it may continue.
1497 */
1498 res = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1499 IPA_RM_RESOURCE_Q6_CONS);
1500 if (res < 0) {
1501 IPA_USB_ERR("ipa_rm_add_dependency_sync() failed.\n");
1502 return res;
1503 }
1504
1505 /*
1506 * this add_dependency call can't be sync since it will block until DPL
1507 * status is connected (which can happen only later in the flow),
1508 * the clocks are already up so the call doesn't need to block.
1509 */
1510 res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
1511 IPA_RM_RESOURCE_USB_DPL_CONS);
1512 if (res < 0 && res != -EINPROGRESS) {
1513 IPA_USB_ERR("ipa_rm_add_dependency() failed.\n");
1514 ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1515 IPA_RM_RESOURCE_Q6_CONS);
1516 return res;
1517 }
1518
1519 return 0;
1520}
1521
Ghanim Fodi93a61112016-10-05 11:59:18 +03001522static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
Amir Levy9659e592016-10-27 18:08:27 +03001523{
1524 int result;
1525 struct teth_bridge_connect_params teth_bridge_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001526 struct ipa3_usb_teth_prot_conn_params *teth_conn_params;
1527 enum ipa3_usb_transport_type ttype;
Amir Levy9659e592016-10-27 18:08:27 +03001528
Ghanim Fodi93a61112016-10-05 11:59:18 +03001529 IPA_USB_DBG("connecting protocol = %s\n",
1530 ipa3_usb_teth_prot_to_string(teth_prot));
1531
1532 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1533
1534 teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params);
1535
1536 switch (teth_prot) {
Amir Levy9659e592016-10-27 18:08:27 +03001537 case IPA_USB_RNDIS:
1538 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state ==
1539 IPA_USB_TETH_PROT_CONNECTED) {
1540 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001541 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001542 break;
1543 }
1544 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1545 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data;
1546 result = rndis_ipa_pipe_connect_notify(
Ghanim Fodi93a61112016-10-05 11:59:18 +03001547 teth_conn_params->usb_to_ipa_clnt_hdl,
1548 teth_conn_params->ipa_to_usb_clnt_hdl,
1549 teth_conn_params->params.max_xfer_size_bytes_to_dev,
1550 teth_conn_params->params.max_packet_number_to_dev,
1551 teth_conn_params->params.max_xfer_size_bytes_to_host,
Amir Levy9659e592016-10-27 18:08:27 +03001552 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1553 teth_prot_params.rndis.private);
1554 if (result) {
1555 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001556 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001557 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1558 return result;
1559 }
1560 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state =
1561 IPA_USB_TETH_PROT_CONNECTED;
1562 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001563 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001564 break;
1565 case IPA_USB_ECM:
1566 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state ==
1567 IPA_USB_TETH_PROT_CONNECTED) {
1568 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001569 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001570 break;
1571 }
1572 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1573 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001574 result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl,
1575 teth_conn_params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001576 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1577 teth_prot_params.ecm.private);
1578 if (result) {
1579 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001580 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001581 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1582 return result;
1583 }
1584 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state =
1585 IPA_USB_TETH_PROT_CONNECTED;
1586 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001587 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001588 break;
1589 case IPA_USB_RMNET:
1590 case IPA_USB_MBIM:
Ghanim Fodi93a61112016-10-05 11:59:18 +03001591 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
Amir Levy9659e592016-10-27 18:08:27 +03001592 IPA_USB_TETH_PROT_CONNECTED) {
1593 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001594 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001595 break;
1596 }
1597 result = ipa3_usb_init_teth_bridge();
1598 if (result)
1599 return result;
1600
1601 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001602 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
Amir Levy9659e592016-10-27 18:08:27 +03001603 user_data;
1604 teth_bridge_params.ipa_usb_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001605 teth_conn_params->ipa_to_usb_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001606 teth_bridge_params.usb_ipa_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001607 teth_conn_params->usb_to_ipa_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001608 teth_bridge_params.tethering_mode =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001609 (teth_prot == IPA_USB_RMNET) ?
Amir Levy9659e592016-10-27 18:08:27 +03001610 (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
1611 teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
1612 result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
1613 if (result) {
1614 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1615 return result;
1616 }
Ghanim Fodi93a61112016-10-05 11:59:18 +03001617 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
Amir Levy9659e592016-10-27 18:08:27 +03001618 IPA_USB_TETH_PROT_CONNECTED;
1619 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1620 IPA_USB_DBG("%s (%s) is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001621 ipa3_usb_teth_prot_to_string(teth_prot),
1622 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001623 break;
1624 case IPA_USB_DIAG:
1625 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state ==
1626 IPA_USB_TETH_PROT_CONNECTED) {
1627 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001628 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001629 break;
1630 }
1631
1632 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001633 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data;
Amir Levy9659e592016-10-27 18:08:27 +03001634 result = ipa3_usb_connect_dpl();
1635 if (result) {
1636 IPA_USB_ERR("Failed connecting DPL result=%d\n",
1637 result);
1638 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1639 return result;
1640 }
1641 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state =
1642 IPA_USB_TETH_PROT_CONNECTED;
1643 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1644 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001645 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001646 break;
1647 default:
1648 IPA_USB_ERR("Invalid tethering protocol\n");
1649 return -EFAULT;
1650 }
1651
1652 return 0;
1653}
1654
1655static int ipa3_usb_disconnect_teth_bridge(void)
1656{
1657 int result;
1658
1659 result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
1660 if (result) {
1661 IPA_USB_ERR("failed to disconnect teth_bridge.\n");
1662 return result;
1663 }
1664
1665 return 0;
1666}
1667
1668static int ipa3_usb_disconnect_dpl(void)
1669{
1670 int res;
1671
Michael Adisumarta3e350812017-09-18 14:54:36 -07001672 if (ipa_pm_is_used())
1673 return 0;
1674
Amir Levy9659e592016-10-27 18:08:27 +03001675 /* Remove DPL RM dependency */
1676 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1677 IPA_RM_RESOURCE_Q6_CONS);
1678 if (res)
1679 IPA_USB_ERR("deleting DPL_DUMMY_PROD rsrc dependency fail\n");
1680
1681 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
1682 IPA_RM_RESOURCE_USB_DPL_CONS);
1683 if (res)
1684 IPA_USB_ERR("deleting DPL_CONS rsrc dependencty fail\n");
1685
1686 return 0;
1687}
1688
1689static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
1690{
1691 int result = 0;
1692 enum ipa3_usb_transport_type ttype;
1693
1694 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1695
1696 switch (teth_prot) {
1697 case IPA_USB_RNDIS:
1698 case IPA_USB_ECM:
1699 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1700 IPA_USB_TETH_PROT_CONNECTED) {
1701 IPA_USB_DBG("%s is not connected.\n",
1702 ipa3_usb_teth_prot_to_string(teth_prot));
1703 return -EPERM;
1704 }
1705 if (teth_prot == IPA_USB_RNDIS) {
1706 result = rndis_ipa_pipe_disconnect_notify(
1707 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1708 teth_prot_params.rndis.private);
1709 } else {
1710 result = ecm_ipa_disconnect(
1711 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1712 teth_prot_params.ecm.private);
1713 }
1714 if (result) {
1715 IPA_USB_ERR("failed to disconnect %s.\n",
1716 ipa3_usb_teth_prot_to_string(teth_prot));
1717 break;
1718 }
1719 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1720 IPA_USB_TETH_PROT_INITIALIZED;
1721 IPA_USB_DBG("disconnected %s\n",
1722 ipa3_usb_teth_prot_to_string(teth_prot));
1723 break;
1724 case IPA_USB_RMNET:
1725 case IPA_USB_MBIM:
1726 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1727 IPA_USB_TETH_PROT_CONNECTED) {
1728 IPA_USB_DBG("%s (%s) is not connected.\n",
1729 ipa3_usb_teth_prot_to_string(teth_prot),
1730 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1731 return -EPERM;
1732 }
1733 result = ipa3_usb_disconnect_teth_bridge();
1734 if (result)
1735 break;
1736
1737 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1738 IPA_USB_TETH_PROT_INITIALIZED;
1739 IPA_USB_DBG("disconnected %s (%s)\n",
1740 ipa3_usb_teth_prot_to_string(teth_prot),
1741 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1742 break;
1743 case IPA_USB_DIAG:
1744 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1745 IPA_USB_TETH_PROT_CONNECTED) {
1746 IPA_USB_DBG("%s is not connected.\n",
1747 ipa3_usb_teth_prot_to_string(teth_prot));
1748 return -EPERM;
1749 }
1750 result = ipa3_usb_disconnect_dpl();
1751 if (result)
1752 break;
1753 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1754 IPA_USB_TETH_PROT_INITIALIZED;
1755 IPA_USB_DBG("disconnected %s\n",
1756 ipa3_usb_teth_prot_to_string(teth_prot));
1757 break;
1758 default:
1759 break;
1760 }
1761
1762 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1763 return result;
1764}
1765
1766static int ipa3_usb_xdci_connect_internal(
1767 struct ipa_usb_xdci_connect_params_internal *params)
1768{
1769 int result = -EFAULT;
1770 struct ipa_rm_perf_profile profile;
1771 enum ipa3_usb_transport_type ttype;
1772
1773 IPA_USB_DBG_LOW("entry\n");
1774 if (params == NULL || !ipa3_usb_check_connect_params(params)) {
1775 IPA_USB_ERR("bad parameters.\n");
1776 return -EINVAL;
1777 }
1778
1779 ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
1780 IPA_USB_TRANSPORT_TETH;
1781
Ghanim Fodi93a61112016-10-05 11:59:18 +03001782 if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001783 IPA_USB_ERR("Illegal operation.\n");
1784 return -EPERM;
1785 }
1786
Ghanim Fodi93a61112016-10-05 11:59:18 +03001787 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl
1788 = params->ipa_to_usb_clnt_hdl;
1789 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
1790 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.
1791 usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl;
1792 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params
1793 = params->teth_prot_params;
1794
Amir Levy9659e592016-10-27 18:08:27 +03001795 /* Set EE xDCI specific scratch */
1796 result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
1797 if (result) {
1798 IPA_USB_ERR("failed setting xDCI EE scratch field\n");
1799 return result;
1800 }
1801
Michael Adisumarta3e350812017-09-18 14:54:36 -07001802 if (ipa_pm_is_used()) {
1803 result = ipa_pm_set_perf_profile(
1804 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
1805 params->max_supported_bandwidth_mbps);
1806 if (result) {
1807 IPA_USB_ERR("failed to set perf profile\n");
1808 return result;
1809 }
Amir Levy9659e592016-10-27 18:08:27 +03001810
Michael Adisumarta3e350812017-09-18 14:54:36 -07001811 result = ipa_pm_activate_sync(
1812 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1813 if (result) {
1814 IPA_USB_ERR("failed to activate pm\n");
1815 return result;
1816 }
1817 } else {
1818 /* Set RM PROD & CONS perf profile */
1819 profile.max_supported_bandwidth_mbps =
1820 params->max_supported_bandwidth_mbps;
1821 result = ipa_rm_set_perf_profile(
1822 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
1823 &profile);
1824 if (result) {
1825 IPA_USB_ERR("failed to set %s perf profile\n",
1826 ipa_rm_resource_str(ipa3_usb_ctx->
1827 ttype_ctx[ttype].
1828 rm_ctx.prod_params.name));
1829 return result;
1830 }
1831 result = ipa_rm_set_perf_profile(
1832 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
1833 &profile);
1834 if (result) {
1835 IPA_USB_ERR("failed to set %s perf profile\n",
1836 ipa_rm_resource_str(ipa3_usb_ctx->
1837 ttype_ctx[ttype].
1838 rm_ctx.cons_params.name));
1839 return result;
1840 }
1841
1842 /* Request PROD */
1843 result = ipa3_usb_request_prod(ttype);
1844 if (result)
1845 return result;
1846 }
Amir Levy9659e592016-10-27 18:08:27 +03001847
1848 if (params->teth_prot != IPA_USB_DIAG) {
1849 /* Start UL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001850 result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001851 params->usb_to_ipa_xferrscidx,
1852 params->usb_to_ipa_xferrscidx_valid);
1853 if (result) {
1854 IPA_USB_ERR("failed to connect UL channel.\n");
1855 goto connect_ul_fail;
1856 }
1857 }
1858
1859 /* Start DL/DPL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001860 result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001861 params->ipa_to_usb_xferrscidx,
1862 params->ipa_to_usb_xferrscidx_valid);
1863 if (result) {
1864 IPA_USB_ERR("failed to connect DL/DPL channel.\n");
1865 goto connect_dl_fail;
1866 }
1867
1868 /* Connect tethering protocol */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001869 result = ipa3_usb_connect_teth_prot(params->teth_prot);
Amir Levy9659e592016-10-27 18:08:27 +03001870 if (result) {
1871 IPA_USB_ERR("failed to connect teth protocol\n");
1872 goto connect_teth_prot_fail;
1873 }
1874
1875 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
1876 IPA_USB_ERR(
1877 "failed to change state to connected\n");
1878 goto state_change_connected_fail;
1879 }
1880
1881 IPA_USB_DBG_LOW("exit\n");
1882 return 0;
1883
1884state_change_connected_fail:
1885 ipa3_usb_disconnect_teth_prot(params->teth_prot);
1886connect_teth_prot_fail:
1887 ipa3_xdci_disconnect(params->ipa_to_usb_clnt_hdl, false, -1);
1888 ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
1889 ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
1890connect_dl_fail:
1891 if (params->teth_prot != IPA_USB_DIAG) {
1892 ipa3_xdci_disconnect(params->usb_to_ipa_clnt_hdl, false, -1);
1893 ipa3_reset_gsi_channel(params->usb_to_ipa_clnt_hdl);
1894 ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
1895 }
1896connect_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001897 if (ipa_pm_is_used())
1898 ipa_pm_deactivate_sync(
1899 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
1900 else
1901 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03001902 return result;
1903}
1904
1905#ifdef CONFIG_DEBUG_FS
1906static char dbg_buff[IPA_USB_MAX_MSG_LEN];
1907
1908static char *ipa3_usb_cons_state_to_string(enum ipa3_usb_cons_state state)
1909{
1910 switch (state) {
1911 case IPA_USB_CONS_GRANTED:
1912 return "CONS_GRANTED";
1913 case IPA_USB_CONS_RELEASED:
1914 return "CONS_RELEASED";
1915 }
1916
1917 return "UNSUPPORTED";
1918}
1919
1920static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status)
1921{
1922 int res;
1923 int i;
1924 unsigned long flags;
1925
1926 IPA_USB_DBG_LOW("entry\n");
1927
1928 if (ipa3_usb_ctx == NULL) {
1929 IPA_USB_ERR("IPA USB was not inited yet\n");
1930 return -EFAULT;
1931 }
1932
1933 mutex_lock(&ipa3_usb_ctx->general_mutex);
1934
1935 if (!status) {
1936 IPA_USB_ERR("Invalid input\n");
1937 res = -EINVAL;
1938 goto bail;
1939 }
1940
1941 memset(status, 0, sizeof(struct ipa3_usb_status_dbg_info));
1942
1943 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
1944 status->teth_state = ipa3_usb_state_to_string(
1945 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].state);
1946 status->dpl_state = ipa3_usb_state_to_string(
1947 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].state);
1948 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].rm_ctx.cons_valid)
1949 status->teth_cons_state = ipa3_usb_cons_state_to_string(
1950 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].
1951 rm_ctx.cons_state);
1952 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].rm_ctx.cons_valid)
1953 status->dpl_cons_state = ipa3_usb_cons_state_to_string(
1954 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].
1955 rm_ctx.cons_state);
1956 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
1957
1958 for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) {
1959 if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1960 IPA_USB_TETH_PROT_INITIALIZED) {
1961 if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM))
1962 status->inited_prots[status->num_init_prot++] =
1963 ipa3_usb_teth_bridge_prot_to_string(i);
1964 else
1965 status->inited_prots[status->num_init_prot++] =
1966 ipa3_usb_teth_prot_to_string(i);
1967 } else if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1968 IPA_USB_TETH_PROT_CONNECTED) {
1969 switch (i) {
1970 case IPA_USB_RMNET:
1971 case IPA_USB_MBIM:
1972 status->teth_connected_prot =
1973 ipa3_usb_teth_bridge_prot_to_string(i);
1974 break;
1975 case IPA_USB_DIAG:
1976 status->dpl_connected_prot =
1977 ipa3_usb_teth_prot_to_string(i);
1978 break;
1979 default:
1980 status->teth_connected_prot =
1981 ipa3_usb_teth_prot_to_string(i);
1982 }
1983 }
1984 }
1985
1986 res = 0;
1987 IPA_USB_DBG_LOW("exit\n");
1988bail:
1989 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1990 return res;
1991}
1992
1993static ssize_t ipa3_read_usb_state_info(struct file *file, char __user *ubuf,
1994 size_t count, loff_t *ppos)
1995{
1996 struct ipa3_usb_status_dbg_info status;
1997 int result;
1998 int nbytes;
1999 int cnt = 0;
2000 int i;
2001
2002 result = ipa3_usb_get_status_dbg_info(&status);
2003 if (result) {
2004 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2005 "Fail to read IPA USB status\n");
2006 cnt += nbytes;
2007 } else {
2008 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
2009 "Tethering Data State: %s\n"
2010 "DPL State: %s\n"
2011 "Protocols in Initialized State: ",
2012 status.teth_state,
2013 status.dpl_state);
2014 cnt += nbytes;
2015
2016 for (i = 0 ; i < status.num_init_prot ; i++) {
2017 nbytes = scnprintf(dbg_buff + cnt,
2018 IPA_USB_MAX_MSG_LEN - cnt,
2019 "%s ", status.inited_prots[i]);
2020 cnt += nbytes;
2021 }
2022 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2023 status.num_init_prot ? "\n" : "None\n");
2024 cnt += nbytes;
2025
2026 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2027 "Protocols in Connected State: ");
2028 cnt += nbytes;
2029 if (status.teth_connected_prot) {
2030 nbytes = scnprintf(dbg_buff + cnt,
2031 IPA_USB_MAX_MSG_LEN - cnt,
2032 "%s ", status.teth_connected_prot);
2033 cnt += nbytes;
2034 }
2035 if (status.dpl_connected_prot) {
2036 nbytes = scnprintf(dbg_buff + cnt,
2037 IPA_USB_MAX_MSG_LEN - cnt,
2038 "%s ", status.dpl_connected_prot);
2039 cnt += nbytes;
2040 }
2041 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2042 (status.teth_connected_prot ||
2043 status.dpl_connected_prot) ? "\n" : "None\n");
2044 cnt += nbytes;
2045
2046 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2047 "USB Tethering Consumer State: %s\n",
2048 status.teth_cons_state ?
2049 status.teth_cons_state : "Invalid");
2050 cnt += nbytes;
2051
2052 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
2053 "DPL Consumer State: %s\n",
2054 status.dpl_cons_state ? status.dpl_cons_state :
2055 "Invalid");
2056 cnt += nbytes;
2057 }
2058
2059 return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
2060}
2061
2062const struct file_operations ipa3_ipa_usb_ops = {
2063 .read = ipa3_read_usb_state_info,
2064};
2065
2066static void ipa_usb_debugfs_init(void)
2067{
2068 const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
2069
2070 ipa3_usb_ctx->dent = debugfs_create_dir("ipa_usb", 0);
2071 if (IS_ERR(ipa3_usb_ctx->dent)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002072 pr_err("fail to create folder in debug_fs.\n");
Amir Levy9659e592016-10-27 18:08:27 +03002073 return;
2074 }
2075
2076 ipa3_usb_ctx->dfile_state_info = debugfs_create_file("state_info",
2077 read_only_mode, ipa3_usb_ctx->dent, 0,
2078 &ipa3_ipa_usb_ops);
2079 if (!ipa3_usb_ctx->dfile_state_info ||
2080 IS_ERR(ipa3_usb_ctx->dfile_state_info)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002081 pr_err("failed to create file for state_info\n");
Amir Levy9659e592016-10-27 18:08:27 +03002082 goto fail;
2083 }
2084
2085 return;
2086
2087fail:
2088 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2089 ipa3_usb_ctx->dent = NULL;
2090}
2091
2092static void ipa_usb_debugfs_remove(void)
2093{
2094 if (IS_ERR(ipa3_usb_ctx->dent)) {
2095 IPA_USB_ERR("ipa_usb debugfs folder was not created.\n");
2096 return;
2097 }
2098
2099 debugfs_remove_recursive(ipa3_usb_ctx->dent);
2100}
2101#else /* CONFIG_DEBUG_FS */
2102static void ipa_usb_debugfs_init(void){}
2103static void ipa_usb_debugfs_remove(void){}
2104#endif /* CONFIG_DEBUG_FS */
2105
2106
2107
2108int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
2109 struct ipa_usb_xdci_chan_params *dl_chan_params,
2110 struct ipa_req_chan_out_params *ul_out_params,
2111 struct ipa_req_chan_out_params *dl_out_params,
2112 struct ipa_usb_xdci_connect_params *connect_params)
2113{
2114 int result = -EFAULT;
2115 struct ipa_usb_xdci_connect_params_internal conn_params;
2116
2117 mutex_lock(&ipa3_usb_ctx->general_mutex);
2118 IPA_USB_DBG_LOW("entry\n");
2119 if (connect_params == NULL || dl_chan_params == NULL ||
2120 dl_out_params == NULL ||
2121 (connect_params->teth_prot != IPA_USB_DIAG &&
2122 (ul_chan_params == NULL || ul_out_params == NULL))) {
2123 IPA_USB_ERR("bad parameters.\n");
2124 result = -EINVAL;
2125 goto bad_params;
2126 }
2127
2128 if (connect_params->teth_prot != IPA_USB_DIAG) {
2129 result = ipa3_usb_request_xdci_channel(ul_chan_params,
2130 ul_out_params);
2131 if (result) {
2132 IPA_USB_ERR("failed to allocate UL channel.\n");
2133 goto bad_params;
2134 }
2135 }
2136
2137 result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params);
2138 if (result) {
2139 IPA_USB_ERR("failed to allocate DL/DPL channel.\n");
2140 goto alloc_dl_chan_fail;
2141 }
2142
2143 memset(&conn_params, 0,
2144 sizeof(struct ipa_usb_xdci_connect_params_internal));
2145 conn_params.max_pkt_size = connect_params->max_pkt_size;
2146 conn_params.ipa_to_usb_clnt_hdl = dl_out_params->clnt_hdl;
2147 conn_params.ipa_to_usb_xferrscidx =
2148 connect_params->ipa_to_usb_xferrscidx;
2149 conn_params.ipa_to_usb_xferrscidx_valid =
2150 connect_params->ipa_to_usb_xferrscidx_valid;
2151 if (connect_params->teth_prot != IPA_USB_DIAG) {
2152 conn_params.usb_to_ipa_clnt_hdl = ul_out_params->clnt_hdl;
2153 conn_params.usb_to_ipa_xferrscidx =
2154 connect_params->usb_to_ipa_xferrscidx;
2155 conn_params.usb_to_ipa_xferrscidx_valid =
2156 connect_params->usb_to_ipa_xferrscidx_valid;
2157 }
2158 conn_params.teth_prot = connect_params->teth_prot;
2159 conn_params.teth_prot_params = connect_params->teth_prot_params;
2160 conn_params.max_supported_bandwidth_mbps =
2161 connect_params->max_supported_bandwidth_mbps;
2162 result = ipa3_usb_xdci_connect_internal(&conn_params);
2163 if (result) {
2164 IPA_USB_ERR("failed to connect.\n");
2165 goto connect_fail;
2166 }
2167
2168 IPA_USB_DBG_LOW("exit\n");
2169 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2170 return 0;
2171
2172connect_fail:
2173 ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002174 IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002175alloc_dl_chan_fail:
2176 if (connect_params->teth_prot != IPA_USB_DIAG)
2177 ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002178 IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002179bad_params:
2180 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2181 return result;
2182}
2183EXPORT_SYMBOL(ipa_usb_xdci_connect);
2184
2185static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
2186{
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002187 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002188 IPA_USB_ERR("bad parameter.\n");
2189 return -EFAULT;
2190 }
2191
2192 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2193 IPA_USB_TETH_PROT_CONNECTED) {
2194 IPA_USB_ERR("%s is not connected.\n",
2195 ipa3_usb_teth_prot_to_string(teth_prot));
2196 return -EFAULT;
2197 }
2198
2199 return 0;
2200}
2201
Ghanim Fodi93a61112016-10-05 11:59:18 +03002202/* Assumes lock already acquired */
2203static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2204 enum ipa_usb_teth_prot teth_prot)
2205{
2206 int result = 0;
2207 enum ipa3_usb_transport_type ttype;
2208
2209 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2210
2211 IPA_USB_DBG_LOW("entry\n");
2212
2213 /* Reset DL channel */
2214 result = ipa3_reset_gsi_channel(dl_clnt_hdl);
2215 if (result) {
2216 IPA_USB_ERR("failed to reset DL channel.\n");
2217 return result;
2218 }
2219
2220 /* Reset DL event ring */
2221 result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
2222 if (result) {
2223 IPA_USB_ERR("failed to reset DL event ring.\n");
2224 return result;
2225 }
2226
2227 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Mohammed Javida17a6bf2017-11-22 19:40:38 +05302228 ipa3_xdci_ep_delay_rm(ul_clnt_hdl); /* Remove ep_delay if set */
Ghanim Fodi93a61112016-10-05 11:59:18 +03002229 /* Reset UL channel */
2230 result = ipa3_reset_gsi_channel(ul_clnt_hdl);
2231 if (result) {
2232 IPA_USB_ERR("failed to reset UL channel.\n");
2233 return result;
2234 }
2235
2236 /* Reset UL event ring */
2237 result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
2238 if (result) {
2239 IPA_USB_ERR("failed to reset UL event ring.\n");
2240 return result;
2241 }
2242 }
2243
2244 /* Change state to STOPPED */
2245 if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
2246 IPA_USB_ERR("failed to change state to stopped\n");
2247
2248 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2249 result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
2250 if (result) {
2251 IPA_USB_ERR("failed to release UL channel.\n");
2252 return result;
2253 }
2254 }
2255
2256 result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
2257 if (result) {
2258 IPA_USB_ERR("failed to release DL channel.\n");
2259 return result;
2260 }
2261
2262 IPA_USB_DBG_LOW("exit\n");
2263
2264 return 0;
2265}
2266
Amir Levy9659e592016-10-27 18:08:27 +03002267int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2268 enum ipa_usb_teth_prot teth_prot)
2269{
2270 int result = 0;
2271 struct ipa_ep_cfg_holb holb_cfg;
2272 unsigned long flags;
2273 enum ipa3_usb_state orig_state;
2274 enum ipa3_usb_transport_type ttype;
2275
2276 mutex_lock(&ipa3_usb_ctx->general_mutex);
2277 IPA_USB_DBG_LOW("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002278
2279 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2280
Ghanim Fodi93a61112016-10-05 11:59:18 +03002281 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002282 IPA_USB_ERR("Illegal operation.\n");
2283 result = -EPERM;
2284 goto bad_params;
2285 }
2286
2287 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002288 if (ipa3_usb_ctx->ttype_ctx[ttype].state ==
2289 IPA_USB_SUSPENDED_NO_RWAKEUP) {
2290 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2291 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2292 teth_prot);
2293 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2294 return result;
2295 }
2296
2297 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2298 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2299 result = -EINVAL;
2300 goto bad_params;
2301 }
2302
Amir Levy9659e592016-10-27 18:08:27 +03002303 if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
2304 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2305 /* Stop DL/DPL channel */
2306 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2307 if (result) {
2308 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2309 goto bad_params;
2310 }
2311 } else {
2312 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2313 memset(&holb_cfg, 0, sizeof(holb_cfg));
2314 holb_cfg.en = IPA_HOLB_TMR_EN;
2315 holb_cfg.tmr_val = 0;
2316 ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);
2317 }
2318
2319 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2320 orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2321 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Skylar Changdf5f2342017-06-05 09:27:48 -07002322 if (orig_state != IPA_USB_SUSPENDED) {
Amir Levy9659e592016-10-27 18:08:27 +03002323 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2324 flags);
2325 /* Stop UL channel */
2326 result = ipa3_xdci_disconnect(ul_clnt_hdl,
2327 true,
2328 ipa3_usb_ctx->qmi_req_id);
2329 if (result) {
2330 IPA_USB_ERR("failed disconnect UL channel\n");
2331 goto bad_params;
2332 }
2333 ipa3_usb_ctx->qmi_req_id++;
2334 } else
2335 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2336 flags);
2337 } else
2338 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2339
Ghanim Fodi93a61112016-10-05 11:59:18 +03002340 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2341 teth_prot);
2342 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03002343 goto bad_params;
Amir Levy9659e592016-10-27 18:08:27 +03002344
2345 /* Disconnect tethering protocol */
2346 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2347 if (result)
2348 goto bad_params;
2349
Skylar Changdf5f2342017-06-05 09:27:48 -07002350 if (orig_state != IPA_USB_SUSPENDED) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07002351 if (ipa_pm_is_used())
2352 result = ipa_pm_deactivate_sync(
2353 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2354 else
2355 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002356 if (result) {
2357 IPA_USB_ERR("failed to release PROD.\n");
2358 goto bad_params;
2359 }
2360 }
2361
2362 IPA_USB_DBG_LOW("exit\n");
2363 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2364 return 0;
2365
2366bad_params:
2367 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2368 return result;
2369
2370}
2371EXPORT_SYMBOL(ipa_usb_xdci_disconnect);
2372
2373int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
2374{
2375 int result = -EFAULT;
2376 enum ipa3_usb_transport_type ttype;
2377
2378 mutex_lock(&ipa3_usb_ctx->general_mutex);
2379 IPA_USB_DBG_LOW("entry\n");
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002380 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002381 IPA_USB_ERR("bad parameters.\n");
2382 result = -EINVAL;
2383 goto bad_params;
2384 }
2385
2386 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2387
Ghanim Fodi93a61112016-10-05 11:59:18 +03002388 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002389 IPA_USB_ERR("Illegal operation.\n");
2390 result = -EPERM;
2391 goto bad_params;
2392 }
2393
2394 /* Clean-up tethering protocol */
2395 switch (teth_prot) {
2396 case IPA_USB_RNDIS:
2397 case IPA_USB_ECM:
2398 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2399 IPA_USB_TETH_PROT_INITIALIZED) {
2400 IPA_USB_ERR("%s is not initialized\n",
2401 ipa3_usb_teth_prot_to_string(teth_prot));
2402 result = -EINVAL;
2403 goto bad_params;
2404 }
2405 if (teth_prot == IPA_USB_RNDIS)
2406 rndis_ipa_cleanup(
2407 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2408 teth_prot_params.rndis.private);
2409 else
2410 ecm_ipa_cleanup(
2411 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2412 teth_prot_params.ecm.private);
2413 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = NULL;
2414 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2415 IPA_USB_TETH_PROT_INVALID;
2416 ipa3_usb_ctx->num_init_prot--;
2417 IPA_USB_DBG("deinitialized %s\n",
2418 ipa3_usb_teth_prot_to_string(teth_prot));
2419 break;
2420 case IPA_USB_RMNET:
2421 case IPA_USB_MBIM:
2422 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2423 IPA_USB_TETH_PROT_INITIALIZED) {
2424 IPA_USB_ERR("%s (%s) is not initialized\n",
2425 ipa3_usb_teth_prot_to_string(teth_prot),
2426 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2427 result = -EINVAL;
2428 goto bad_params;
2429 }
2430
2431 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2432 NULL;
2433 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2434 IPA_USB_TETH_PROT_INVALID;
2435 ipa3_usb_ctx->num_init_prot--;
2436 IPA_USB_DBG("deinitialized %s (%s)\n",
2437 ipa3_usb_teth_prot_to_string(teth_prot),
2438 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2439 break;
2440 case IPA_USB_DIAG:
2441 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2442 IPA_USB_TETH_PROT_INITIALIZED) {
2443 IPA_USB_ERR("%s is not initialized\n",
2444 ipa3_usb_teth_prot_to_string(teth_prot));
2445 result = -EINVAL;
2446 goto bad_params;
2447 }
2448 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2449 NULL;
2450 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2451 IPA_USB_TETH_PROT_INVALID;
2452 IPA_USB_DBG("deinitialized %s\n",
2453 ipa3_usb_teth_prot_to_string(teth_prot));
2454 break;
2455 default:
2456 IPA_USB_ERR("unexpected tethering protocol\n");
2457 result = -EINVAL;
2458 goto bad_params;
2459 }
2460
2461 if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
2462 (ipa3_usb_ctx->num_init_prot == 0)) {
2463 if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
2464 IPA_USB_ERR("failed to change state to invalid\n");
Michael Adisumarta3e350812017-09-18 14:54:36 -07002465 if (ipa_pm_is_used()) {
2466 ipa3_usb_deregister_pm(ttype);
2467 } else {
2468 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002469 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002470 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
2471 false;
2472 ipa_rm_delete_resource(
Amir Levy9659e592016-10-27 18:08:27 +03002473 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
Michael Adisumarta3e350812017-09-18 14:54:36 -07002474 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
2475 false;
2476 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
2477 }
Amir Levy9659e592016-10-27 18:08:27 +03002478 }
2479
2480 IPA_USB_DBG_LOW("exit\n");
2481 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2482 return 0;
2483
2484bad_params:
2485 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2486 return result;
2487}
2488EXPORT_SYMBOL(ipa_usb_deinit_teth_prot);
2489
Ghanim Fodi93a61112016-10-05 11:59:18 +03002490/* Assumes lock already acquired */
2491static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03002492 enum ipa_usb_teth_prot teth_prot)
2493{
2494 int result = 0;
Ghanim Fodi93a61112016-10-05 11:59:18 +03002495 enum ipa3_usb_transport_type ttype;
2496
2497 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2498
2499 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) {
2500 IPA_USB_ERR("Illegal operation.\n");
2501 result = -EPERM;
2502 goto fail_exit;
2503 }
2504
2505 IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n",
2506 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2507 "DPL channel":"Data Tethering channels");
2508
2509 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2510 result = -EINVAL;
2511 goto fail_exit;
2512 }
2513
2514 /* Stop DL/DPL channel */
2515 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2516 if (result) {
2517 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2518 goto fail_exit;
2519 }
2520
2521 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2522 /* Stop UL channel */
2523 result = ipa3_xdci_disconnect(ul_clnt_hdl, true,
2524 ipa3_usb_ctx->qmi_req_id);
2525 if (result) {
2526 IPA_USB_ERR("failed disconnect UL channel\n");
2527 goto start_dl;
2528 }
2529 ipa3_usb_ctx->qmi_req_id++;
2530 }
2531
2532 /* Disconnect tethering protocol */
2533 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2534 if (result)
2535 goto start_ul;
2536
Michael Adisumarta3e350812017-09-18 14:54:36 -07002537 if (ipa_pm_is_used())
2538 result = ipa_pm_deactivate_sync(
2539 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2540 else
2541 result = ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002542 if (result) {
2543 IPA_USB_ERR("failed to release PROD.\n");
2544 goto connect_teth;
2545 }
2546
2547 /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */
2548 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype))
2549 IPA_USB_ERR("failed to change state to suspend no rwakeup\n");
2550
2551 IPA_USB_DBG_LOW("exit\n");
2552 return 0;
2553
2554connect_teth:
2555 (void)ipa3_usb_connect_teth_prot(teth_prot);
2556start_ul:
2557 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
2558 (void)ipa3_xdci_connect(ul_clnt_hdl);
2559start_dl:
2560 (void)ipa3_xdci_connect(dl_clnt_hdl);
2561fail_exit:
2562 return result;
2563}
2564
2565int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2566 enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup)
2567{
2568 int result = 0;
Amir Levy9659e592016-10-27 18:08:27 +03002569 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03002570 enum ipa3_usb_transport_type ttype;
2571
2572 mutex_lock(&ipa3_usb_ctx->general_mutex);
2573 IPA_USB_DBG_LOW("entry\n");
Ghanim Fodi93a61112016-10-05 11:59:18 +03002574
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002575 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002576 IPA_USB_ERR("bad parameters.\n");
2577 result = -EINVAL;
2578 goto bad_params;
2579 }
2580
Ghanim Fodi93a61112016-10-05 11:59:18 +03002581 if (!with_remote_wakeup) {
2582 result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl,
2583 dl_clnt_hdl, teth_prot);
2584 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2585 return result;
2586 }
2587
Amir Levy9659e592016-10-27 18:08:27 +03002588 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2589
Ghanim Fodi93a61112016-10-05 11:59:18 +03002590 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002591 IPA_USB_ERR("Illegal operation.\n");
2592 result = -EPERM;
2593 goto bad_params;
2594 }
2595
2596 IPA_USB_DBG("Start suspend sequence: %s\n",
2597 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2598 "DPL channel":"Data Tethering channels");
2599
2600 /* Change state to SUSPEND_REQUESTED */
2601 if (!ipa3_usb_set_state(IPA_USB_SUSPEND_REQUESTED, false, ttype)) {
2602 IPA_USB_ERR(
2603 "fail changing state to suspend_req.\n");
2604 result = -EFAULT;
2605 goto bad_params;
2606 }
2607
2608 /* Stop UL channel & suspend DL/DPL EP */
2609 result = ipa3_xdci_suspend(ul_clnt_hdl, dl_clnt_hdl,
2610 true,
2611 ipa3_usb_ctx->qmi_req_id, IPA3_USB_IS_TTYPE_DPL(ttype));
2612 if (result) {
2613 IPA_USB_ERR("failed to suspend\n");
2614 goto suspend_fail;
2615 }
2616 ipa3_usb_ctx->qmi_req_id++;
2617
Michael Adisumarta3e350812017-09-18 14:54:36 -07002618 if (ipa_pm_is_used())
2619 result = ipa_pm_deactivate_sync(
2620 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2621 else
2622 result = ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002623 if (result) {
2624 IPA_USB_ERR("failed to release PROD\n");
2625 goto release_prod_fail;
2626 }
2627
Skylar Changdf5f2342017-06-05 09:27:48 -07002628 /* Check if DL/DPL data pending */
Amir Levy9659e592016-10-27 18:08:27 +03002629 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Skylar Changdf5f2342017-06-05 09:27:48 -07002630 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
2631 IPA_USB_CONS_GRANTED &&
2632 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2633
2634 IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
2635 queue_work(ipa3_usb_ctx->wq,
2636 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2637 &ipa3_usb_dpl_notify_remote_wakeup_work :
2638 &ipa3_usb_notify_remote_wakeup_work);
2639 }
Amir Levy9659e592016-10-27 18:08:27 +03002640 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +03002641
Amir Levy9659e592016-10-27 18:08:27 +03002642 /* Change state to SUSPENDED */
2643 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
2644 IPA_USB_ERR("failed to change state to suspended\n");
2645
2646 /* Check if DL/DPL data pending */
2647 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2648 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2649 IPA_USB_DBG_LOW(
2650 "DL/DPL data is pending, invoking remote wakeup\n");
2651 queue_work(ipa3_usb_ctx->wq, IPA3_USB_IS_TTYPE_DPL(ttype) ?
2652 &ipa3_usb_dpl_notify_remote_wakeup_work :
2653 &ipa3_usb_notify_remote_wakeup_work);
2654 }
2655 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2656
2657 IPA_USB_DBG_LOW("exit\n");
2658 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2659 return 0;
2660
2661release_prod_fail:
2662 ipa3_xdci_resume(ul_clnt_hdl, dl_clnt_hdl,
2663 IPA3_USB_IS_TTYPE_DPL(ttype));
2664suspend_fail:
2665 /* Change state back to CONNECTED */
2666 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true, ttype))
2667 IPA_USB_ERR("failed to change state back to connected\n");
2668bad_params:
2669 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2670 return result;
2671}
2672EXPORT_SYMBOL(ipa_usb_xdci_suspend);
2673
Ghanim Fodi93a61112016-10-05 11:59:18 +03002674/* Assumes lock already acquired */
2675static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2676 enum ipa_usb_teth_prot teth_prot)
2677{
2678 int result = -EFAULT;
2679 enum ipa3_usb_transport_type ttype;
2680
2681 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2682
2683 IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n",
2684 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2685 "DPL channel":"Data Tethering channels");
2686
2687 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002688 if (ipa_pm_is_used())
2689 result = ipa_pm_activate_sync(
2690 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2691 else
2692 result = ipa3_usb_request_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002693 if (result)
2694 goto fail_exit;
2695
2696 /* Connect tethering protocol */
2697 result = ipa3_usb_connect_teth_prot(teth_prot);
2698 if (result) {
2699 IPA_USB_ERR("failed to connect teth protocol\n");
2700 goto release_prod;
2701 }
2702
2703 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2704 /* Start UL channel */
2705 result = ipa3_xdci_connect(ul_clnt_hdl);
2706 if (result) {
2707 IPA_USB_ERR("failed to start UL channel.\n");
2708 goto disconn_teth;
2709 }
2710 }
2711
2712 /* Start DL/DPL channel */
2713 result = ipa3_xdci_connect(dl_clnt_hdl);
2714 if (result) {
2715 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2716 goto stop_ul;
2717 }
2718
2719 /* Change state to CONNECTED */
2720 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2721 IPA_USB_ERR("failed to change state to connected\n");
2722 result = -EFAULT;
2723 goto stop_dl;
2724 }
2725
2726 return 0;
2727
2728stop_dl:
2729 (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2730stop_ul:
2731 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2732 (void)ipa3_xdci_disconnect(ul_clnt_hdl, true,
2733 ipa3_usb_ctx->qmi_req_id);
2734 ipa3_usb_ctx->qmi_req_id++;
2735 }
2736disconn_teth:
2737 (void)ipa3_usb_disconnect_teth_prot(teth_prot);
2738release_prod:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002739 if (ipa_pm_is_used())
2740 (void)ipa_pm_deactivate_sync(
2741 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2742 else
2743 (void)ipa3_usb_release_prod(ttype);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002744fail_exit:
2745 return result;
2746}
2747
Amir Levy9659e592016-10-27 18:08:27 +03002748int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2749 enum ipa_usb_teth_prot teth_prot)
2750{
2751 int result = -EFAULT;
2752 enum ipa3_usb_state prev_state;
2753 unsigned long flags;
2754 enum ipa3_usb_transport_type ttype;
2755
2756 mutex_lock(&ipa3_usb_ctx->general_mutex);
2757 IPA_USB_DBG_LOW("entry\n");
2758
Skylar Changc5e2b7e2017-08-29 10:54:04 -07002759 if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
Amir Levy9659e592016-10-27 18:08:27 +03002760 IPA_USB_ERR("bad parameters.\n");
2761 result = -EINVAL;
2762 goto bad_params;
2763 }
2764
2765 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2766
Ghanim Fodi93a61112016-10-05 11:59:18 +03002767 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002768 IPA_USB_ERR("Illegal operation.\n");
2769 result = -EPERM;
2770 goto bad_params;
2771 }
2772
Amir Levy9659e592016-10-27 18:08:27 +03002773 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2774 prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2775 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002776 if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) {
2777 result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl,
2778 dl_clnt_hdl, teth_prot);
2779 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2780 return result;
2781 }
2782
2783 IPA_USB_DBG("Start resume sequence: %s\n",
2784 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2785 "DPL channel" : "Data Tethering channels");
Amir Levy9659e592016-10-27 18:08:27 +03002786
2787 /* Change state to RESUME_IN_PROGRESS */
2788 if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) {
2789 IPA_USB_ERR("failed to change state to resume_in_progress\n");
2790 result = -EFAULT;
2791 goto bad_params;
2792 }
2793
2794 /* Request USB_PROD */
Michael Adisumarta3e350812017-09-18 14:54:36 -07002795 if (ipa_pm_is_used())
2796 result = ipa_pm_activate_sync(
2797 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2798 else
2799 result = ipa3_usb_request_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002800 if (result)
2801 goto prod_req_fail;
2802
2803 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2804 /* Start UL channel */
2805 result = ipa3_start_gsi_channel(ul_clnt_hdl);
2806 if (result) {
2807 IPA_USB_ERR("failed to start UL channel.\n");
2808 goto start_ul_fail;
2809 }
2810 }
2811
Skylar Changdf5f2342017-06-05 09:27:48 -07002812 /* Start DL/DPL channel */
2813 result = ipa3_start_gsi_channel(dl_clnt_hdl);
2814 if (result) {
2815 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2816 goto start_dl_fail;
Amir Levy9659e592016-10-27 18:08:27 +03002817 }
2818
2819 /* Change state to CONNECTED */
2820 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2821 IPA_USB_ERR("failed to change state to connected\n");
2822 result = -EFAULT;
2823 goto state_change_connected_fail;
2824 }
2825
2826 IPA_USB_DBG_LOW("exit\n");
2827 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2828 return 0;
2829
2830state_change_connected_fail:
Skylar Changdf5f2342017-06-05 09:27:48 -07002831 result = ipa3_stop_gsi_channel(dl_clnt_hdl);
2832 if (result)
2833 IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
2834 result);
Amir Levy9659e592016-10-27 18:08:27 +03002835start_dl_fail:
2836 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2837 result = ipa3_stop_gsi_channel(ul_clnt_hdl);
2838 if (result)
2839 IPA_USB_ERR("Error stopping UL channel: %d\n", result);
2840 }
2841start_ul_fail:
Michael Adisumarta3e350812017-09-18 14:54:36 -07002842 if (ipa_pm_is_used())
2843 ipa_pm_deactivate_sync(
2844 ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
2845 else
2846 ipa3_usb_release_prod(ttype);
Amir Levy9659e592016-10-27 18:08:27 +03002847prod_req_fail:
2848 /* Change state back to prev_state */
2849 if (!ipa3_usb_set_state(prev_state, true, ttype))
2850 IPA_USB_ERR("failed to change state back to %s\n",
2851 ipa3_usb_state_to_string(prev_state));
2852bad_params:
2853 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2854 return result;
2855}
2856EXPORT_SYMBOL(ipa_usb_xdci_resume);
2857
2858static int __init ipa3_usb_init(void)
2859{
2860 int i;
2861 unsigned long flags;
2862 int res;
2863
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002864 pr_debug("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002865 ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL);
2866 if (ipa3_usb_ctx == NULL) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002867 pr_err("failed to allocate memory\n");
2868 pr_err(":ipa_usb init failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03002869 return -EFAULT;
2870 }
2871 memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context));
2872
2873 for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++)
2874 ipa3_usb_ctx->teth_prot_ctx[i].state =
2875 IPA_USB_TETH_PROT_INVALID;
2876 ipa3_usb_ctx->num_init_prot = 0;
2877 init_completion(&ipa3_usb_ctx->dev_ready_comp);
2878 ipa3_usb_ctx->qmi_req_id = 0;
2879 spin_lock_init(&ipa3_usb_ctx->state_lock);
2880 ipa3_usb_ctx->dl_data_pending = false;
2881 mutex_init(&ipa3_usb_ctx->general_mutex);
2882
Michael Adisumarta3e350812017-09-18 14:54:36 -07002883 if (ipa_pm_is_used()) {
2884 struct ipa3_usb_pm_context *pm_ctx;
2885
2886 pm_ctx =
2887 &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
2888 pm_ctx->hdl = ~0;
2889 pm_ctx->remote_wakeup_work =
2890 &ipa3_usb_notify_remote_wakeup_work;
2891 pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
2892 pm_ctx->hdl = ~0;
2893 pm_ctx->remote_wakeup_work =
2894 &ipa3_usb_dpl_notify_remote_wakeup_work;
2895 }
2896
Amir Levy9659e592016-10-27 18:08:27 +03002897 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2898 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
2899 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
2900 init_completion(&ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_comp);
2901 ipa3_usb_ctx->ttype_ctx[i].user_data = NULL;
2902 }
2903
2904 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2905 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2906 ipa3_usb_ctx->ttype_ctx[i].state = IPA_USB_INVALID;
2907 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_state =
2908 IPA_USB_CONS_RELEASED;
2909 }
2910 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2911
2912 ipa3_usb_ctx->wq = create_singlethread_workqueue("ipa_usb_wq");
2913 if (!ipa3_usb_ctx->wq) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002914 pr_err("failed to create workqueue\n");
Amir Levy9659e592016-10-27 18:08:27 +03002915 res = -EFAULT;
2916 goto ipa_usb_workqueue_fail;
2917 }
2918
2919 ipa_usb_debugfs_init();
2920
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002921 pr_info("exit: IPA_USB init success!\n");
Amir Levy9659e592016-10-27 18:08:27 +03002922
2923 return 0;
2924
2925ipa_usb_workqueue_fail:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002926 pr_err(":init failed (%d)\n", -res);
Amir Levy9659e592016-10-27 18:08:27 +03002927 kfree(ipa3_usb_ctx);
2928 return res;
2929}
2930
2931static void ipa3_usb_exit(void)
2932{
2933 IPA_USB_DBG_LOW("IPA_USB exit\n");
2934 ipa_usb_debugfs_remove();
2935 kfree(ipa3_usb_ctx);
2936}
2937
2938arch_initcall(ipa3_usb_init);
2939module_exit(ipa3_usb_exit);
2940
2941MODULE_LICENSE("GPL v2");
2942MODULE_DESCRIPTION("IPA USB client driver");