blob: 205a7565b9b9d6c5f1f64a9a32f0dc4470c9db72 [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
122enum ipa3_usb_state {
123 IPA_USB_INVALID,
124 IPA_USB_INITIALIZED,
125 IPA_USB_CONNECTED,
126 IPA_USB_STOPPED,
127 IPA_USB_SUSPEND_REQUESTED,
Amir Levy9659e592016-10-27 18:08:27 +0300128 IPA_USB_SUSPENDED,
Ghanim Fodi93a61112016-10-05 11:59:18 +0300129 IPA_USB_SUSPENDED_NO_RWAKEUP,
Amir Levy9659e592016-10-27 18:08:27 +0300130 IPA_USB_RESUME_IN_PROGRESS
131};
132
133enum ipa3_usb_transport_type {
134 IPA_USB_TRANSPORT_TETH,
135 IPA_USB_TRANSPORT_DPL,
136 IPA_USB_TRANSPORT_MAX
137};
138
139/* Get transport type from tethering protocol */
140#define IPA3_USB_GET_TTYPE(__teth_prot) \
141 (((__teth_prot) == IPA_USB_DIAG) ? \
142 IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH)
143
144/* Does the given transport type is DPL? */
145#define IPA3_USB_IS_TTYPE_DPL(__ttype) \
146 ((__ttype) == IPA_USB_TRANSPORT_DPL)
147
Ghanim Fodi93a61112016-10-05 11:59:18 +0300148struct ipa3_usb_teth_prot_conn_params {
149 u32 usb_to_ipa_clnt_hdl;
150 u32 ipa_to_usb_clnt_hdl;
151 struct ipa_usb_teth_prot_params params;
152};
153
Amir Levy9659e592016-10-27 18:08:27 +0300154/**
155 * Transport type - could be either data tethering or DPL
156 * Each transport has it's own RM resources and statuses
157 */
158struct ipa3_usb_transport_type_ctx {
159 struct ipa3_usb_rm_context rm_ctx;
160 int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
161 void *user_data;
162 enum ipa3_usb_state state;
Amir Levy9659e592016-10-27 18:08:27 +0300163 struct ipa_usb_xdci_chan_params ch_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300164 struct ipa3_usb_teth_prot_conn_params teth_conn_params;
Amir Levy9659e592016-10-27 18:08:27 +0300165};
166
167struct ipa3_usb_smmu_reg_map {
168 int cnt;
169 phys_addr_t addr;
170};
171
172struct ipa3_usb_context {
173 struct ipa3_usb_teth_prot_context
174 teth_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE];
175 int num_init_prot; /* without dpl */
176 struct teth_bridge_init_params teth_bridge_params;
177 struct completion dev_ready_comp;
178 u32 qmi_req_id;
179 spinlock_t state_lock;
180 bool dl_data_pending;
181 struct workqueue_struct *wq;
182 struct mutex general_mutex;
183 struct ipa3_usb_transport_type_ctx
184 ttype_ctx[IPA_USB_TRANSPORT_MAX];
185 struct dentry *dfile_state_info;
186 struct dentry *dent;
187 struct ipa3_usb_smmu_reg_map smmu_reg_map;
188};
189
190enum ipa3_usb_op {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300191 IPA_USB_OP_INIT_TETH_PROT,
192 IPA_USB_OP_REQUEST_CHANNEL,
193 IPA_USB_OP_CONNECT,
194 IPA_USB_OP_DISCONNECT,
195 IPA_USB_OP_RELEASE_CHANNEL,
196 IPA_USB_OP_DEINIT_TETH_PROT,
197 IPA_USB_OP_SUSPEND,
198 IPA_USB_OP_SUSPEND_NO_RWAKEUP,
199 IPA_USB_OP_RESUME
Amir Levy9659e592016-10-27 18:08:27 +0300200};
201
202struct ipa3_usb_status_dbg_info {
203 const char *teth_state;
204 const char *dpl_state;
205 int num_init_prot;
206 const char *inited_prots[IPA_USB_MAX_TETH_PROT_SIZE];
207 const char *teth_connected_prot;
208 const char *dpl_connected_prot;
209 const char *teth_cons_state;
210 const char *dpl_cons_state;
211};
212
213static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work);
214static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work);
Amir Levy9659e592016-10-27 18:08:27 +0300215static DECLARE_WORK(ipa3_usb_notify_remote_wakeup_work,
216 ipa3_usb_wq_notify_remote_wakeup);
217static DECLARE_WORK(ipa3_usb_dpl_notify_remote_wakeup_work,
218 ipa3_usb_wq_dpl_notify_remote_wakeup);
Amir Levy9659e592016-10-27 18:08:27 +0300219
220struct ipa3_usb_context *ipa3_usb_ctx;
221
222static char *ipa3_usb_op_to_string(enum ipa3_usb_op op)
223{
224 switch (op) {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300225 case IPA_USB_OP_INIT_TETH_PROT:
226 return "IPA_USB_OP_INIT_TETH_PROT";
227 case IPA_USB_OP_REQUEST_CHANNEL:
228 return "IPA_USB_OP_REQUEST_CHANNEL";
229 case IPA_USB_OP_CONNECT:
230 return "IPA_USB_OP_CONNECT";
231 case IPA_USB_OP_DISCONNECT:
232 return "IPA_USB_OP_DISCONNECT";
233 case IPA_USB_OP_RELEASE_CHANNEL:
234 return "IPA_USB_OP_RELEASE_CHANNEL";
235 case IPA_USB_OP_DEINIT_TETH_PROT:
236 return "IPA_USB_OP_DEINIT_TETH_PROT";
237 case IPA_USB_OP_SUSPEND:
238 return "IPA_USB_OP_SUSPEND";
239 case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
240 return "IPA_USB_OP_SUSPEND_NO_RWAKEUP";
241 case IPA_USB_OP_RESUME:
242 return "IPA_USB_OP_RESUME";
Amir Levy9659e592016-10-27 18:08:27 +0300243 }
244
245 return "UNSUPPORTED";
246}
247
248static char *ipa3_usb_state_to_string(enum ipa3_usb_state state)
249{
250 switch (state) {
251 case IPA_USB_INVALID:
252 return "IPA_USB_INVALID";
253 case IPA_USB_INITIALIZED:
254 return "IPA_USB_INITIALIZED";
255 case IPA_USB_CONNECTED:
256 return "IPA_USB_CONNECTED";
257 case IPA_USB_STOPPED:
258 return "IPA_USB_STOPPED";
259 case IPA_USB_SUSPEND_REQUESTED:
260 return "IPA_USB_SUSPEND_REQUESTED";
Amir Levy9659e592016-10-27 18:08:27 +0300261 case IPA_USB_SUSPENDED:
262 return "IPA_USB_SUSPENDED";
Ghanim Fodi93a61112016-10-05 11:59:18 +0300263 case IPA_USB_SUSPENDED_NO_RWAKEUP:
264 return "IPA_USB_SUSPENDED_NO_RWAKEUP";
Amir Levy9659e592016-10-27 18:08:27 +0300265 case IPA_USB_RESUME_IN_PROGRESS:
266 return "IPA_USB_RESUME_IN_PROGRESS";
267 }
268
269 return "UNSUPPORTED";
270}
271
272static char *ipa3_usb_notify_event_to_string(enum ipa_usb_notify_event event)
273{
274 switch (event) {
275 case IPA_USB_DEVICE_READY:
276 return "IPA_USB_DEVICE_READY";
277 case IPA_USB_REMOTE_WAKEUP:
278 return "IPA_USB_REMOTE_WAKEUP";
279 case IPA_USB_SUSPEND_COMPLETED:
280 return "IPA_USB_SUSPEND_COMPLETED";
281 }
282
283 return "UNSUPPORTED";
284}
285
286static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit,
287 enum ipa3_usb_transport_type ttype)
288{
289 unsigned long flags;
290 int state_legal = false;
291 enum ipa3_usb_state state;
292 struct ipa3_usb_rm_context *rm_ctx;
293
294 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
295 state = ipa3_usb_ctx->ttype_ctx[ttype].state;
296 switch (new_state) {
297 case IPA_USB_INVALID:
298 if (state == IPA_USB_INITIALIZED)
299 state_legal = true;
300 break;
301 case IPA_USB_INITIALIZED:
302 if (state == IPA_USB_STOPPED || state == IPA_USB_INVALID ||
303 ((!IPA3_USB_IS_TTYPE_DPL(ttype)) &&
304 (state == IPA_USB_INITIALIZED)))
305 state_legal = true;
306 break;
307 case IPA_USB_CONNECTED:
308 if (state == IPA_USB_INITIALIZED ||
309 state == IPA_USB_STOPPED ||
310 state == IPA_USB_RESUME_IN_PROGRESS ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300311 state == IPA_USB_SUSPENDED_NO_RWAKEUP ||
Amir Levy9659e592016-10-27 18:08:27 +0300312 /*
313 * In case of failure during suspend request
314 * handling, state is reverted to connected.
315 */
Skylar Changdf5f2342017-06-05 09:27:48 -0700316 (err_permit && state == IPA_USB_SUSPEND_REQUESTED))
Amir Levy9659e592016-10-27 18:08:27 +0300317 state_legal = true;
318 break;
319 case IPA_USB_STOPPED:
Skylar Changdf5f2342017-06-05 09:27:48 -0700320 if (state == IPA_USB_CONNECTED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300321 state == IPA_USB_SUSPENDED ||
322 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300323 state_legal = true;
324 break;
325 case IPA_USB_SUSPEND_REQUESTED:
326 if (state == IPA_USB_CONNECTED)
327 state_legal = true;
328 break;
Amir Levy9659e592016-10-27 18:08:27 +0300329 case IPA_USB_SUSPENDED:
330 if (state == IPA_USB_SUSPEND_REQUESTED ||
Amir Levy9659e592016-10-27 18:08:27 +0300331 /*
332 * In case of failure during resume, state is reverted
333 * to original, which could be suspended. Allow it
334 */
335 (err_permit && state == IPA_USB_RESUME_IN_PROGRESS))
336 state_legal = true;
337 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300338 case IPA_USB_SUSPENDED_NO_RWAKEUP:
339 if (state == IPA_USB_CONNECTED)
340 state_legal = true;
341 break;
Amir Levy9659e592016-10-27 18:08:27 +0300342 case IPA_USB_RESUME_IN_PROGRESS:
Skylar Changdf5f2342017-06-05 09:27:48 -0700343 if (state == IPA_USB_SUSPENDED)
Amir Levy9659e592016-10-27 18:08:27 +0300344 state_legal = true;
345 break;
346 default:
347 state_legal = false;
348 break;
349
350 }
351 if (state_legal) {
352 if (state != new_state) {
353 IPA_USB_DBG("ipa_usb %s state changed %s -> %s\n",
354 IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL" : "",
355 ipa3_usb_state_to_string(state),
356 ipa3_usb_state_to_string(new_state));
357 ipa3_usb_ctx->ttype_ctx[ttype].state = new_state;
358 }
359 } else {
360 IPA_USB_ERR("invalid state change %s -> %s\n",
361 ipa3_usb_state_to_string(state),
362 ipa3_usb_state_to_string(new_state));
363 }
364
365 if (state_legal && (new_state == IPA_USB_CONNECTED)) {
366 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
367 if ((rm_ctx->cons_state == IPA_USB_CONS_GRANTED) ||
368 rm_ctx->cons_requested_released) {
369 rm_ctx->cons_requested = false;
370 rm_ctx->cons_requested_released =
371 false;
372 }
373 /* Notify RM that consumer is granted */
374 if (rm_ctx->cons_requested) {
375 ipa_rm_notify_completion(
376 IPA_RM_RESOURCE_GRANTED,
377 rm_ctx->cons_params.name);
378 rm_ctx->cons_state = IPA_USB_CONS_GRANTED;
379 rm_ctx->cons_requested = false;
380 }
381 }
382
383 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
384 return state_legal;
385}
386
387static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op,
388 enum ipa3_usb_transport_type ttype)
389{
390 unsigned long flags;
391 bool is_legal = false;
392 enum ipa3_usb_state state;
393 bool is_dpl;
394
395 if (ipa3_usb_ctx == NULL) {
396 IPA_USB_ERR("ipa_usb_ctx is not initialized!\n");
397 return false;
398 }
399
400 is_dpl = IPA3_USB_IS_TTYPE_DPL(ttype);
401
402 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
403 state = ipa3_usb_ctx->ttype_ctx[ttype].state;
404 switch (op) {
Ghanim Fodi93a61112016-10-05 11:59:18 +0300405 case IPA_USB_OP_INIT_TETH_PROT:
Amir Levy9659e592016-10-27 18:08:27 +0300406 if (state == IPA_USB_INVALID ||
407 (!is_dpl && state == IPA_USB_INITIALIZED))
408 is_legal = true;
409 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300410 case IPA_USB_OP_REQUEST_CHANNEL:
Amir Levy9659e592016-10-27 18:08:27 +0300411 if (state == IPA_USB_INITIALIZED)
412 is_legal = true;
413 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300414 case IPA_USB_OP_CONNECT:
Amir Levy9659e592016-10-27 18:08:27 +0300415 if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED)
416 is_legal = true;
417 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300418 case IPA_USB_OP_DISCONNECT:
Amir Levy9659e592016-10-27 18:08:27 +0300419 if (state == IPA_USB_CONNECTED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300420 state == IPA_USB_SUSPENDED ||
421 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300422 is_legal = true;
423 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300424 case IPA_USB_OP_RELEASE_CHANNEL:
Amir Levy9659e592016-10-27 18:08:27 +0300425 /* when releasing 1st channel state will be changed already */
426 if (state == IPA_USB_STOPPED ||
427 (!is_dpl && state == IPA_USB_INITIALIZED))
428 is_legal = true;
429 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300430 case IPA_USB_OP_DEINIT_TETH_PROT:
Amir Levy9659e592016-10-27 18:08:27 +0300431 /*
432 * For data tethering we should allow deinit an inited protocol
433 * always. E.g. rmnet is inited and rndis is connected.
434 * USB can deinit rmnet first and then disconnect rndis
435 * on cable disconnect.
436 */
437 if (!is_dpl || state == IPA_USB_INITIALIZED)
438 is_legal = true;
439 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300440 case IPA_USB_OP_SUSPEND:
Amir Levy9659e592016-10-27 18:08:27 +0300441 if (state == IPA_USB_CONNECTED)
442 is_legal = true;
443 break;
Ghanim Fodi93a61112016-10-05 11:59:18 +0300444 case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
445 if (state == IPA_USB_CONNECTED)
446 is_legal = true;
447 break;
448 case IPA_USB_OP_RESUME:
Amir Levy9659e592016-10-27 18:08:27 +0300449 if (state == IPA_USB_SUSPENDED ||
Ghanim Fodi93a61112016-10-05 11:59:18 +0300450 state == IPA_USB_SUSPENDED_NO_RWAKEUP)
Amir Levy9659e592016-10-27 18:08:27 +0300451 is_legal = true;
452 break;
453 default:
454 is_legal = false;
455 break;
456 }
457
458 if (!is_legal) {
459 IPA_USB_ERR("Illegal %s operation: state=%s operation=%s\n",
460 is_dpl ? "DPL" : "",
461 ipa3_usb_state_to_string(state),
462 ipa3_usb_op_to_string(op));
463 }
464
465 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
466 return is_legal;
467}
468
469static void ipa3_usb_notify_do(enum ipa3_usb_transport_type ttype,
470 enum ipa_usb_notify_event event)
471{
472 int (*cb)(enum ipa_usb_notify_event, void *user_data);
473 void *user_data;
474 int res;
475
476 IPA_USB_DBG("Trying to notify USB with %s\n",
477 ipa3_usb_notify_event_to_string(event));
478
479 cb = ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb;
480 user_data = ipa3_usb_ctx->ttype_ctx[ttype].user_data;
481
482 if (cb) {
483 res = cb(event, user_data);
484 IPA_USB_DBG("Notified USB with %s. is_dpl=%d result=%d\n",
485 ipa3_usb_notify_event_to_string(event),
486 IPA3_USB_IS_TTYPE_DPL(ttype), res);
487 }
488}
489
490/*
491 * This call-back is called from ECM or RNDIS drivers.
492 * Both drivers are data tethering drivers and not DPL
493 */
494void ipa3_usb_device_ready_notify_cb(void)
495{
496 IPA_USB_DBG_LOW("entry\n");
497 ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH,
498 IPA_USB_DEVICE_READY);
499 IPA_USB_DBG_LOW("exit\n");
500}
501
502static void ipa3_usb_prod_notify_cb_do(enum ipa_rm_event event,
503 enum ipa3_usb_transport_type ttype)
504{
505 struct ipa3_usb_rm_context *rm_ctx;
506
507 IPA_USB_DBG_LOW("entry\n");
508
509 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
510
511 switch (event) {
512 case IPA_RM_RESOURCE_GRANTED:
513 IPA_USB_DBG(":%s granted\n",
514 ipa_rm_resource_str(rm_ctx->prod_params.name));
515 complete_all(&rm_ctx->prod_comp);
516 break;
517 case IPA_RM_RESOURCE_RELEASED:
518 IPA_USB_DBG(":%s released\n",
519 ipa_rm_resource_str(rm_ctx->prod_params.name));
520 complete_all(&rm_ctx->prod_comp);
521 break;
522 }
523 IPA_USB_DBG_LOW("exit\n");
524}
525
526static void ipa3_usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
527 unsigned long data)
528{
529 ipa3_usb_prod_notify_cb_do(event, IPA_USB_TRANSPORT_TETH);
530}
531
532static void ipa3_usb_dpl_dummy_prod_notify_cb(void *user_data,
533 enum ipa_rm_event event, unsigned long data)
534{
535 ipa3_usb_prod_notify_cb_do(event, IPA_USB_TRANSPORT_TETH);
536}
537
538static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work)
539{
540 ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH, IPA_USB_REMOTE_WAKEUP);
541}
542
543static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work)
544{
545 ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_REMOTE_WAKEUP);
546}
547
Amir Levy9659e592016-10-27 18:08:27 +0300548static int ipa3_usb_cons_request_resource_cb_do(
549 enum ipa3_usb_transport_type ttype,
550 struct work_struct *remote_wakeup_work)
551{
552 struct ipa3_usb_rm_context *rm_ctx;
553 unsigned long flags;
554 int result;
555
556 IPA_USB_DBG_LOW("entry\n");
557 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
558 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
559 IPA_USB_DBG("state is %s\n",
560 ipa3_usb_state_to_string(
561 ipa3_usb_ctx->ttype_ctx[ttype].state));
562 switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
563 case IPA_USB_CONNECTED:
Ghanim Fodi93a61112016-10-05 11:59:18 +0300564 case IPA_USB_SUSPENDED_NO_RWAKEUP:
Amir Levy9659e592016-10-27 18:08:27 +0300565 rm_ctx->cons_state = IPA_USB_CONS_GRANTED;
566 result = 0;
567 break;
568 case IPA_USB_SUSPEND_REQUESTED:
569 rm_ctx->cons_requested = true;
570 if (rm_ctx->cons_state == IPA_USB_CONS_GRANTED)
571 result = 0;
572 else
573 result = -EINPROGRESS;
574 break;
Amir Levy9659e592016-10-27 18:08:27 +0300575 case IPA_USB_SUSPENDED:
576 if (!rm_ctx->cons_requested) {
577 rm_ctx->cons_requested = true;
578 queue_work(ipa3_usb_ctx->wq, remote_wakeup_work);
579 }
580 result = -EINPROGRESS;
581 break;
582 default:
583 rm_ctx->cons_requested = true;
584 result = -EINPROGRESS;
585 break;
586 }
587 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
588 IPA_USB_DBG_LOW("exit with %d\n", result);
589 return result;
590}
591
592static int ipa3_usb_cons_request_resource_cb(void)
593{
594 return ipa3_usb_cons_request_resource_cb_do(IPA_USB_TRANSPORT_TETH,
595 &ipa3_usb_notify_remote_wakeup_work);
596}
597
598static int ipa3_usb_dpl_cons_request_resource_cb(void)
599{
600 return ipa3_usb_cons_request_resource_cb_do(IPA_USB_TRANSPORT_DPL,
601 &ipa3_usb_dpl_notify_remote_wakeup_work);
602}
603
604static int ipa3_usb_cons_release_resource_cb_do(
605 enum ipa3_usb_transport_type ttype)
606{
607 unsigned long flags;
608 struct ipa3_usb_rm_context *rm_ctx;
609
610 IPA_USB_DBG_LOW("entry\n");
611 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
612 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
613 IPA_USB_DBG("state is %s\n",
614 ipa3_usb_state_to_string(
615 ipa3_usb_ctx->ttype_ctx[ttype].state));
616 switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
Skylar Changdf5f2342017-06-05 09:27:48 -0700617 case IPA_USB_SUSPENDED:
Amir Levy9659e592016-10-27 18:08:27 +0300618 /* Proceed with the suspend if no DL/DPL data */
619 if (rm_ctx->cons_requested)
620 rm_ctx->cons_requested_released = true;
Amir Levy9659e592016-10-27 18:08:27 +0300621 break;
622 case IPA_USB_SUSPEND_REQUESTED:
623 if (rm_ctx->cons_requested)
624 rm_ctx->cons_requested_released = true;
625 break;
626 case IPA_USB_STOPPED:
627 case IPA_USB_RESUME_IN_PROGRESS:
Ghanim Fodi93a61112016-10-05 11:59:18 +0300628 case IPA_USB_SUSPENDED_NO_RWAKEUP:
Amir Levy9659e592016-10-27 18:08:27 +0300629 if (rm_ctx->cons_requested)
630 rm_ctx->cons_requested = false;
631 break;
632 case IPA_USB_CONNECTED:
633 case IPA_USB_INITIALIZED:
634 break;
635 default:
636 IPA_USB_ERR("received cons_release_cb in bad state: %s!\n",
637 ipa3_usb_state_to_string(
638 ipa3_usb_ctx->ttype_ctx[ttype].state));
639 WARN_ON(1);
640 break;
641 }
642
643 rm_ctx->cons_state = IPA_USB_CONS_RELEASED;
644 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
645 IPA_USB_DBG_LOW("exit\n");
646 return 0;
647}
648
649static int ipa3_usb_cons_release_resource_cb(void)
650{
651 return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_TETH);
652}
653
654static int ipa3_usb_dpl_cons_release_resource_cb(void)
655{
656 return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_DPL);
657}
658
659static char *ipa3_usb_teth_prot_to_string(enum ipa_usb_teth_prot teth_prot)
660{
661 switch (teth_prot) {
662 case IPA_USB_RNDIS:
663 return "rndis_ipa";
664 case IPA_USB_ECM:
665 return "ecm_ipa";
666 case IPA_USB_RMNET:
667 case IPA_USB_MBIM:
668 return "teth_bridge";
669 case IPA_USB_DIAG:
670 return "dpl";
671 default:
672 break;
673 }
674
675 return "unsupported";
676}
677
678static char *ipa3_usb_teth_bridge_prot_to_string(
679 enum ipa_usb_teth_prot teth_prot)
680{
681 switch (teth_prot) {
682 case IPA_USB_RMNET:
683 return "rmnet";
684 case IPA_USB_MBIM:
685 return "mbim";
686 default:
687 break;
688 }
689
690 return "unsupported";
691}
692
693static int ipa3_usb_init_teth_bridge(void)
694{
695 int result;
696
697 result = teth_bridge_init(&ipa3_usb_ctx->teth_bridge_params);
698 if (result) {
699 IPA_USB_ERR("Failed to initialize teth_bridge.\n");
700 return result;
701 }
702
703 return 0;
704}
705
706static int ipa3_usb_create_rm_resources(enum ipa3_usb_transport_type ttype)
707{
708 struct ipa3_usb_rm_context *rm_ctx;
709 int result = -EFAULT;
710 bool created = false;
711
712 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
713
714 /* create PROD */
715 if (!rm_ctx->prod_valid) {
716 rm_ctx->prod_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
717 IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD :
718 IPA_RM_RESOURCE_USB_PROD;
Skylar Chang448d8b82017-08-08 17:30:32 -0700719 rm_ctx->prod_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300720 rm_ctx->prod_params.reg_params.user_data = NULL;
721 rm_ctx->prod_params.reg_params.notify_cb =
722 IPA3_USB_IS_TTYPE_DPL(ttype) ?
723 ipa3_usb_dpl_dummy_prod_notify_cb :
724 ipa3_usb_prod_notify_cb;
725 rm_ctx->prod_params.request_resource = NULL;
726 rm_ctx->prod_params.release_resource = NULL;
727 result = ipa_rm_create_resource(&rm_ctx->prod_params);
728 if (result) {
729 IPA_USB_ERR("Failed to create %s RM resource\n",
730 ipa_rm_resource_str(rm_ctx->prod_params.name));
731 return result;
732 }
733 rm_ctx->prod_valid = true;
734 created = true;
735 IPA_USB_DBG("Created %s RM resource\n",
736 ipa_rm_resource_str(rm_ctx->prod_params.name));
737 }
738
739 /* Create CONS */
740 if (!rm_ctx->cons_valid) {
741 rm_ctx->cons_params.name = IPA3_USB_IS_TTYPE_DPL(ttype) ?
742 IPA_RM_RESOURCE_USB_DPL_CONS :
743 IPA_RM_RESOURCE_USB_CONS;
Skylar Chang448d8b82017-08-08 17:30:32 -0700744 rm_ctx->cons_params.floor_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +0300745 rm_ctx->cons_params.reg_params.user_data = NULL;
746 rm_ctx->cons_params.reg_params.notify_cb = NULL;
747 rm_ctx->cons_params.request_resource =
748 IPA3_USB_IS_TTYPE_DPL(ttype) ?
749 ipa3_usb_dpl_cons_request_resource_cb :
750 ipa3_usb_cons_request_resource_cb;
751 rm_ctx->cons_params.release_resource =
752 IPA3_USB_IS_TTYPE_DPL(ttype) ?
753 ipa3_usb_dpl_cons_release_resource_cb :
754 ipa3_usb_cons_release_resource_cb;
755 result = ipa_rm_create_resource(&rm_ctx->cons_params);
756 if (result) {
757 IPA_USB_ERR("Failed to create %s RM resource\n",
758 ipa_rm_resource_str(rm_ctx->cons_params.name));
759 goto create_cons_rsc_fail;
760 }
761 rm_ctx->cons_valid = true;
762 IPA_USB_DBG("Created %s RM resource\n",
763 ipa_rm_resource_str(rm_ctx->cons_params.name));
764 }
765
766 return 0;
767
768create_cons_rsc_fail:
769 if (created) {
770 rm_ctx->prod_valid = false;
771 ipa_rm_delete_resource(rm_ctx->prod_params.name);
772 }
773 return result;
774}
775
776int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
777 struct ipa_usb_teth_params *teth_params,
778 int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event,
779 void *),
780 void *user_data)
781{
782 int result = -EFAULT;
783 enum ipa3_usb_transport_type ttype;
784
785 mutex_lock(&ipa3_usb_ctx->general_mutex);
786 IPA_USB_DBG_LOW("entry\n");
787 if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE ||
788 ((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) &&
789 teth_params == NULL) || ipa_usb_notify_cb == NULL ||
790 user_data == NULL) {
791 IPA_USB_ERR("bad parameters.\n");
792 result = -EINVAL;
793 goto bad_params;
794 }
795
796 ttype = IPA3_USB_GET_TTYPE(teth_prot);
797
Ghanim Fodi93a61112016-10-05 11:59:18 +0300798 if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +0300799 IPA_USB_ERR("Illegal operation.\n");
800 result = -EPERM;
801 goto bad_params;
802 }
803
804 /* Create IPA RM USB resources */
805 result = ipa3_usb_create_rm_resources(ttype);
806 if (result) {
807 IPA_USB_ERR("Failed creating IPA RM USB resources\n");
808 goto bad_params;
809 }
810
811 if (!ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb) {
812 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb =
813 ipa_usb_notify_cb;
814 } else if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
815 if (ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb !=
816 ipa_usb_notify_cb) {
817 IPA_USB_ERR("Got different notify_cb\n");
818 result = -EINVAL;
819 goto bad_params;
820 }
821 } else {
822 IPA_USB_ERR("Already has dpl_notify_cb\n");
823 result = -EINVAL;
824 goto bad_params;
825 }
826
827 /* Initialize tethering protocol */
828 switch (teth_prot) {
829 case IPA_USB_RNDIS:
830 case IPA_USB_ECM:
831 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
832 IPA_USB_TETH_PROT_INVALID) {
833 IPA_USB_DBG("%s already initialized\n",
834 ipa3_usb_teth_prot_to_string(teth_prot));
835 result = -EPERM;
836 goto bad_params;
837 }
838 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
839 if (teth_prot == IPA_USB_RNDIS) {
840 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
841 teth_prot_params.rndis.device_ready_notify =
842 ipa3_usb_device_ready_notify_cb;
843 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
844 teth_prot_params.rndis.host_ethaddr,
845 teth_params->host_ethaddr,
846 sizeof(teth_params->host_ethaddr));
847 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
848 teth_prot_params.rndis.device_ethaddr,
849 teth_params->device_ethaddr,
850 sizeof(teth_params->device_ethaddr));
851
852 result = rndis_ipa_init(&ipa3_usb_ctx->
853 teth_prot_ctx[teth_prot].
854 teth_prot_params.rndis);
855 if (result) {
856 IPA_USB_ERR("Failed to initialize %s\n",
857 ipa3_usb_teth_prot_to_string(
858 teth_prot));
859 goto teth_prot_init_fail;
860 }
861 } else {
862 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
863 teth_prot_params.ecm.device_ready_notify =
864 ipa3_usb_device_ready_notify_cb;
865 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
866 teth_prot_params.ecm.host_ethaddr,
867 teth_params->host_ethaddr,
868 sizeof(teth_params->host_ethaddr));
869 memcpy(ipa3_usb_ctx->teth_prot_ctx[teth_prot].
870 teth_prot_params.ecm.device_ethaddr,
871 teth_params->device_ethaddr,
872 sizeof(teth_params->device_ethaddr));
873
874 result = ecm_ipa_init(&ipa3_usb_ctx->
875 teth_prot_ctx[teth_prot].teth_prot_params.ecm);
876 if (result) {
877 IPA_USB_ERR("Failed to initialize %s\n",
878 ipa3_usb_teth_prot_to_string(
879 teth_prot));
880 goto teth_prot_init_fail;
881 }
882 }
883 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
884 IPA_USB_TETH_PROT_INITIALIZED;
885 ipa3_usb_ctx->num_init_prot++;
886 IPA_USB_DBG("initialized %s\n",
887 ipa3_usb_teth_prot_to_string(teth_prot));
888 break;
889 case IPA_USB_RMNET:
890 case IPA_USB_MBIM:
891 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
892 IPA_USB_TETH_PROT_INVALID) {
893 IPA_USB_DBG("%s already initialized\n",
894 ipa3_usb_teth_prot_to_string(teth_prot));
895 result = -EPERM;
896 goto bad_params;
897 }
898 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
899 result = ipa3_usb_init_teth_bridge();
900 if (result)
901 goto teth_prot_init_fail;
902 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
903 IPA_USB_TETH_PROT_INITIALIZED;
904 ipa3_usb_ctx->num_init_prot++;
905 IPA_USB_DBG("initialized %s %s\n",
906 ipa3_usb_teth_prot_to_string(teth_prot),
907 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
908 break;
909 case IPA_USB_DIAG:
910 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
911 IPA_USB_TETH_PROT_INVALID) {
912 IPA_USB_DBG("DPL already initialized\n");
913 result = -EPERM;
914 goto bad_params;
915 }
916 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
917 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
918 IPA_USB_TETH_PROT_INITIALIZED;
919 IPA_USB_DBG("initialized DPL\n");
920 break;
921 default:
922 IPA_USB_ERR("unexpected tethering protocol\n");
923 result = -EINVAL;
924 goto bad_params;
925 }
926
927 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
928 IPA_USB_ERR("failed to change state to initialized\n");
929
930 IPA_USB_DBG_LOW("exit\n");
931 mutex_unlock(&ipa3_usb_ctx->general_mutex);
932 return 0;
933
934teth_prot_init_fail:
935 if ((IPA3_USB_IS_TTYPE_DPL(ttype))
936 || (ipa3_usb_ctx->num_init_prot == 0)) {
937 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
938 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
939 ipa_rm_delete_resource(
940 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
941 ipa_rm_delete_resource(
942 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
943 }
944bad_params:
945 mutex_unlock(&ipa3_usb_ctx->general_mutex);
946 return result;
947}
948EXPORT_SYMBOL(ipa_usb_init_teth_prot);
949
950void ipa3_usb_gsi_evt_err_cb(struct gsi_evt_err_notify *notify)
951{
952 IPA_USB_DBG_LOW("entry\n");
953 if (!notify)
954 return;
955 IPA_USB_ERR("Received event error %d, description: %d\n",
956 notify->evt_id, notify->err_desc);
957 IPA_USB_DBG_LOW("exit\n");
958}
959
960void ipa3_usb_gsi_chan_err_cb(struct gsi_chan_err_notify *notify)
961{
962 IPA_USB_DBG_LOW("entry\n");
963 if (!notify)
964 return;
965 IPA_USB_ERR("Received channel error %d, description: %d\n",
966 notify->evt_id, notify->err_desc);
967 IPA_USB_DBG_LOW("exit\n");
968}
969
970static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
971{
972 IPA_USB_DBG_LOW("gevntcount_low_addr = %x\n",
973 params->gevntcount_low_addr);
974 IPA_USB_DBG_LOW("gevntcount_hi_addr = %x\n",
975 params->gevntcount_hi_addr);
976 IPA_USB_DBG_LOW("dir = %d\n", params->dir);
977 IPA_USB_DBG_LOW("xfer_ring_len = %d\n", params->xfer_ring_len);
978 IPA_USB_DBG_LOW("xfer_ring_base_addr = %llx\n",
979 params->xfer_ring_base_addr);
980 IPA_USB_DBG_LOW("last_trb_addr_iova = %x\n",
981 params->xfer_scratch.last_trb_addr_iova);
982 IPA_USB_DBG_LOW("const_buffer_size = %d\n",
983 params->xfer_scratch.const_buffer_size);
984 IPA_USB_DBG_LOW("depcmd_low_addr = %x\n",
985 params->xfer_scratch.depcmd_low_addr);
986 IPA_USB_DBG_LOW("depcmd_hi_addr = %x\n",
987 params->xfer_scratch.depcmd_hi_addr);
988
989 if (params->client >= IPA_CLIENT_MAX ||
990 params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE ||
991 params->xfer_ring_len % GSI_CHAN_RE_SIZE_16B ||
992 params->xfer_scratch.const_buffer_size < 1 ||
993 params->xfer_scratch.const_buffer_size > 31) {
994 IPA_USB_ERR("Invalid params\n");
995 return false;
996 }
997 switch (params->teth_prot) {
998 case IPA_USB_DIAG:
999 if (!IPA_CLIENT_IS_CONS(params->client)) {
1000 IPA_USB_ERR("DPL supports only DL channel\n");
1001 return false;
1002 }
1003 case IPA_USB_RNDIS:
1004 case IPA_USB_ECM:
1005 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1006 IPA_USB_TETH_PROT_INVALID) {
1007 IPA_USB_ERR("%s is not initialized\n",
1008 ipa3_usb_teth_prot_to_string(
1009 params->teth_prot));
1010 return false;
1011 }
1012 break;
1013 case IPA_USB_RMNET:
1014 case IPA_USB_MBIM:
1015 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1016 IPA_USB_TETH_PROT_INVALID) {
1017 IPA_USB_ERR("%s is not initialized\n",
1018 ipa3_usb_teth_bridge_prot_to_string(
1019 params->teth_prot));
1020 return false;
1021 }
1022 break;
1023 default:
1024 IPA_USB_ERR("Unknown tethering protocol (%d)\n",
1025 params->teth_prot);
1026 return false;
1027 }
1028 return true;
1029}
1030
1031static int ipa3_usb_smmu_map_xdci_channel(
1032 struct ipa_usb_xdci_chan_params *params, bool map)
1033{
1034 int result;
1035 u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE);
1036 u32 xfer_scratch_r =
1037 rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
1038
1039 if (gevntcount_r != xfer_scratch_r) {
1040 IPA_USB_ERR("No support more than 1 page map for USB regs\n");
1041 WARN_ON(1);
1042 return -EINVAL;
1043 }
1044
1045 if (map) {
1046 if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
1047 ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r;
1048 result = ipa3_smmu_map_peer_reg(
1049 ipa3_usb_ctx->smmu_reg_map.addr, true);
1050 if (result) {
1051 IPA_USB_ERR("failed to map USB regs %d\n",
1052 result);
1053 return result;
1054 }
1055 } else {
1056 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1057 IPA_USB_ERR(
1058 "No support for map different reg\n");
1059 return -EINVAL;
1060 }
1061 }
1062 ipa3_usb_ctx->smmu_reg_map.cnt++;
1063 } else {
1064 if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
1065 IPA_USB_ERR(
1066 "No support for map different reg\n");
1067 return -EINVAL;
1068 }
1069
1070 if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
1071 result = ipa3_smmu_map_peer_reg(
1072 ipa3_usb_ctx->smmu_reg_map.addr, false);
1073 if (result) {
1074 IPA_USB_ERR("failed to unmap USB regs %d\n",
1075 result);
1076 return result;
1077 }
1078 }
1079 ipa3_usb_ctx->smmu_reg_map.cnt--;
1080 }
1081
1082 result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
1083 params->xfer_ring_base_addr, params->xfer_ring_len, map);
1084 if (result) {
1085 IPA_USB_ERR("failed to map Xfer ring %d\n", result);
1086 return result;
1087 }
1088
1089 result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova,
1090 params->data_buff_base_addr, params->data_buff_base_len, map);
1091 if (result) {
1092 IPA_USB_ERR("failed to map TRBs buff %d\n", result);
1093 return result;
1094 }
1095
1096 return 0;
1097}
1098
1099static int ipa3_usb_request_xdci_channel(
1100 struct ipa_usb_xdci_chan_params *params,
1101 struct ipa_req_chan_out_params *out_params)
1102{
1103 int result = -EFAULT;
1104 struct ipa_request_gsi_channel_params chan_params;
1105 enum ipa3_usb_transport_type ttype;
1106
1107 IPA_USB_DBG_LOW("entry\n");
1108 if (params == NULL || out_params == NULL ||
1109 !ipa3_usb_check_chan_params(params)) {
1110 IPA_USB_ERR("bad parameters\n");
1111 return -EINVAL;
1112 }
1113
1114 ttype = IPA3_USB_GET_TTYPE(params->teth_prot);
1115
Ghanim Fodi93a61112016-10-05 11:59:18 +03001116 if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001117 IPA_USB_ERR("Illegal operation\n");
1118 return -EPERM;
1119 }
1120
1121 memset(&chan_params, 0, sizeof(struct ipa_request_gsi_channel_params));
1122 memcpy(&chan_params.ipa_ep_cfg, &params->ipa_ep_cfg,
1123 sizeof(struct ipa_ep_cfg));
1124 chan_params.client = params->client;
1125 switch (params->teth_prot) {
1126 case IPA_USB_RNDIS:
1127 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1128 teth_prot_params.rndis.private;
1129 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1130 chan_params.notify =
1131 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1132 teth_prot_params.rndis.ipa_tx_notify;
1133 else
1134 chan_params.notify =
1135 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1136 teth_prot_params.rndis.ipa_rx_notify;
1137 chan_params.skip_ep_cfg =
1138 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1139 teth_prot_params.rndis.skip_ep_cfg;
1140 break;
1141 case IPA_USB_ECM:
1142 chan_params.priv = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1143 teth_prot_params.ecm.private;
1144 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1145 chan_params.notify =
1146 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1147 teth_prot_params.ecm.ecm_ipa_tx_dp_notify;
1148 else
1149 chan_params.notify =
1150 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1151 teth_prot_params.ecm.ecm_ipa_rx_dp_notify;
1152 chan_params.skip_ep_cfg =
1153 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1154 teth_prot_params.ecm.skip_ep_cfg;
1155 break;
1156 case IPA_USB_RMNET:
1157 case IPA_USB_MBIM:
1158 chan_params.priv =
1159 ipa3_usb_ctx->teth_bridge_params.private_data;
1160 chan_params.notify =
1161 ipa3_usb_ctx->teth_bridge_params.usb_notify_cb;
1162 chan_params.skip_ep_cfg =
1163 ipa3_usb_ctx->teth_bridge_params.skip_ep_cfg;
1164 break;
1165 case IPA_USB_DIAG:
1166 chan_params.priv = NULL;
1167 chan_params.notify = NULL;
1168 chan_params.skip_ep_cfg = true;
1169 break;
1170 default:
1171 break;
1172 }
1173
1174 result = ipa3_usb_smmu_map_xdci_channel(params, true);
1175 if (result) {
1176 IPA_USB_ERR("failed to smmu map %d\n", result);
1177 return result;
1178 }
1179
1180 /* store channel params for SMMU unmap */
1181 ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params;
1182
1183 chan_params.keep_ipa_awake = params->keep_ipa_awake;
1184 chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV;
1185 chan_params.evt_ring_params.intr = GSI_INTR_IRQ;
1186 chan_params.evt_ring_params.re_size = GSI_EVT_RING_RE_SIZE_16B;
1187 chan_params.evt_ring_params.ring_len = params->xfer_ring_len -
1188 chan_params.evt_ring_params.re_size;
1189 chan_params.evt_ring_params.ring_base_addr =
1190 params->xfer_ring_base_addr;
1191 chan_params.evt_ring_params.ring_base_vaddr = NULL;
1192 chan_params.evt_ring_params.int_modt = 0;
1193 chan_params.evt_ring_params.int_modt = 0;
1194 chan_params.evt_ring_params.intvec = 0;
1195 chan_params.evt_ring_params.msi_addr = 0;
1196 chan_params.evt_ring_params.rp_update_addr = 0;
1197 chan_params.evt_ring_params.exclusive = true;
1198 chan_params.evt_ring_params.err_cb = ipa3_usb_gsi_evt_err_cb;
1199 chan_params.evt_ring_params.user_data = NULL;
1200 chan_params.evt_scratch.xdci.gevntcount_low_addr =
1201 params->gevntcount_low_addr;
1202 chan_params.evt_scratch.xdci.gevntcount_hi_addr =
1203 params->gevntcount_hi_addr;
1204 chan_params.chan_params.prot = GSI_CHAN_PROT_XDCI;
1205 chan_params.chan_params.dir = params->dir;
1206 /* chan_id is set in ipa3_request_gsi_channel() */
1207 chan_params.chan_params.re_size = GSI_CHAN_RE_SIZE_16B;
1208 chan_params.chan_params.ring_len = params->xfer_ring_len;
1209 chan_params.chan_params.ring_base_addr =
1210 params->xfer_ring_base_addr;
1211 chan_params.chan_params.ring_base_vaddr = NULL;
1212 chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE;
1213 chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG;
1214 if (params->dir == GSI_CHAN_DIR_FROM_GSI)
1215 chan_params.chan_params.low_weight =
1216 IPA_USB_DL_CHAN_LOW_WEIGHT;
1217 else
1218 chan_params.chan_params.low_weight =
1219 IPA_USB_UL_CHAN_LOW_WEIGHT;
1220 chan_params.chan_params.xfer_cb = NULL;
1221 chan_params.chan_params.err_cb = ipa3_usb_gsi_chan_err_cb;
1222 chan_params.chan_params.chan_user_data = NULL;
1223 chan_params.chan_scratch.xdci.last_trb_addr =
1224 params->xfer_scratch.last_trb_addr_iova;
1225 /* xferrscidx will be updated later */
1226 chan_params.chan_scratch.xdci.xferrscidx = 0;
1227 chan_params.chan_scratch.xdci.const_buffer_size =
1228 params->xfer_scratch.const_buffer_size;
1229 chan_params.chan_scratch.xdci.depcmd_low_addr =
1230 params->xfer_scratch.depcmd_low_addr;
1231 chan_params.chan_scratch.xdci.depcmd_hi_addr =
1232 params->xfer_scratch.depcmd_hi_addr;
1233 chan_params.chan_scratch.xdci.outstanding_threshold =
1234 ((params->teth_prot == IPA_USB_MBIM) ? 1 : 2) *
1235 chan_params.chan_params.re_size;
1236 /* max_outstanding_tre is set in ipa3_request_gsi_channel() */
1237 result = ipa3_request_gsi_channel(&chan_params, out_params);
1238 if (result) {
1239 IPA_USB_ERR("failed to allocate GSI channel\n");
1240 ipa3_usb_smmu_map_xdci_channel(params, false);
1241 return result;
1242 }
1243
1244 IPA_USB_DBG_LOW("exit\n");
1245 return 0;
1246}
1247
1248static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
1249 enum ipa3_usb_transport_type ttype)
1250{
1251 int result = 0;
1252
1253 IPA_USB_DBG_LOW("entry\n");
1254 if (ttype > IPA_USB_TRANSPORT_MAX) {
1255 IPA_USB_ERR("bad parameter.\n");
1256 return -EINVAL;
1257 }
1258
Ghanim Fodi93a61112016-10-05 11:59:18 +03001259 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001260 IPA_USB_ERR("Illegal operation.\n");
1261 return -EPERM;
1262 }
1263
1264 /* Release channel */
1265 result = ipa3_release_gsi_channel(clnt_hdl);
1266 if (result) {
1267 IPA_USB_ERR("failed to deallocate channel.\n");
1268 return result;
1269 }
1270
1271 result = ipa3_usb_smmu_map_xdci_channel(
1272 &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false);
1273
1274 /* Change ipa_usb state to INITIALIZED */
1275 if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
1276 IPA_USB_ERR("failed to change state to initialized\n");
1277
1278 IPA_USB_DBG_LOW("exit\n");
1279 return 0;
1280}
1281
1282static int ipa3_usb_request_prod(enum ipa3_usb_transport_type ttype)
1283{
1284 int result;
1285 struct ipa3_usb_rm_context *rm_ctx;
1286 const char *rsrc_str;
1287
1288 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1289 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1290
1291 IPA_USB_DBG_LOW("requesting %s\n", rsrc_str);
1292 init_completion(&rm_ctx->prod_comp);
1293 result = ipa_rm_request_resource(rm_ctx->prod_params.name);
1294 if (result) {
1295 if (result != -EINPROGRESS) {
1296 IPA_USB_ERR("failed to request %s: %d\n",
1297 rsrc_str, result);
1298 return result;
1299 }
1300 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1301 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1302 if (result == 0) {
1303 IPA_USB_ERR("timeout request %s\n", rsrc_str);
1304 return -ETIME;
1305 }
1306 }
1307
1308 IPA_USB_DBG_LOW("%s granted\n", rsrc_str);
1309 return 0;
1310}
1311
1312static int ipa3_usb_release_prod(enum ipa3_usb_transport_type ttype)
1313{
1314 int result;
1315 struct ipa3_usb_rm_context *rm_ctx;
1316 const char *rsrc_str;
1317
1318 rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
1319 rsrc_str = ipa_rm_resource_str(rm_ctx->prod_params.name);
1320
1321 IPA_USB_DBG_LOW("releasing %s\n", rsrc_str);
1322
1323 init_completion(&rm_ctx->prod_comp);
1324 result = ipa_rm_release_resource(rm_ctx->prod_params.name);
1325 if (result) {
1326 if (result != -EINPROGRESS) {
1327 IPA_USB_ERR("failed to release %s: %d\n",
1328 rsrc_str, result);
1329 return result;
1330 }
1331 result = wait_for_completion_timeout(&rm_ctx->prod_comp,
1332 msecs_to_jiffies(IPA_USB_RM_TIMEOUT_MSEC));
1333 if (result == 0) {
1334 IPA_USB_ERR("timeout release %s\n", rsrc_str);
1335 return -ETIME;
1336 }
1337 }
1338
1339 IPA_USB_DBG_LOW("%s released\n", rsrc_str);
1340 return 0;
1341}
1342
1343static bool ipa3_usb_check_connect_params(
1344 struct ipa_usb_xdci_connect_params_internal *params)
1345{
1346 IPA_USB_DBG_LOW("ul xferrscidx = %d\n", params->usb_to_ipa_xferrscidx);
1347 IPA_USB_DBG_LOW("dl xferrscidx = %d\n", params->ipa_to_usb_xferrscidx);
1348 IPA_USB_DBG_LOW("max_supported_bandwidth_mbps = %d\n",
1349 params->max_supported_bandwidth_mbps);
1350
1351 if (params->max_pkt_size < IPA_USB_HIGH_SPEED_512B ||
1352 params->max_pkt_size > IPA_USB_SUPER_SPEED_1024B ||
1353 params->ipa_to_usb_xferrscidx < 0 ||
1354 params->ipa_to_usb_xferrscidx > 127 ||
1355 (params->teth_prot != IPA_USB_DIAG &&
1356 (params->usb_to_ipa_xferrscidx < 0 ||
1357 params->usb_to_ipa_xferrscidx > 127)) ||
1358 params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
1359 IPA_USB_ERR("Invalid params\n");
1360 return false;
1361 }
1362
1363 if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
1364 IPA_USB_TETH_PROT_INVALID) {
1365 IPA_USB_ERR("%s is not initialized\n",
1366 ipa3_usb_teth_prot_to_string(
1367 params->teth_prot));
1368 return false;
1369 }
1370
1371 return true;
1372}
1373
1374static int ipa3_usb_connect_teth_bridge(
1375 struct teth_bridge_connect_params *params)
1376{
1377 int result;
1378
1379 result = teth_bridge_connect(params);
1380 if (result) {
1381 IPA_USB_ERR("failed to connect teth_bridge (%s)\n",
1382 params->tethering_mode == TETH_TETHERING_MODE_RMNET ?
1383 "rmnet" : "mbim");
1384 return result;
1385 }
1386
1387 return 0;
1388}
1389
1390static int ipa3_usb_connect_dpl(void)
1391{
1392 int res = 0;
1393
1394 /*
1395 * Add DPL dependency to RM dependency graph, first add_dependency call
1396 * is sync in order to make sure the IPA clocks are up before we
1397 * continue and notify the USB driver it may continue.
1398 */
1399 res = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1400 IPA_RM_RESOURCE_Q6_CONS);
1401 if (res < 0) {
1402 IPA_USB_ERR("ipa_rm_add_dependency_sync() failed.\n");
1403 return res;
1404 }
1405
1406 /*
1407 * this add_dependency call can't be sync since it will block until DPL
1408 * status is connected (which can happen only later in the flow),
1409 * the clocks are already up so the call doesn't need to block.
1410 */
1411 res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
1412 IPA_RM_RESOURCE_USB_DPL_CONS);
1413 if (res < 0 && res != -EINPROGRESS) {
1414 IPA_USB_ERR("ipa_rm_add_dependency() failed.\n");
1415 ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1416 IPA_RM_RESOURCE_Q6_CONS);
1417 return res;
1418 }
1419
1420 return 0;
1421}
1422
Ghanim Fodi93a61112016-10-05 11:59:18 +03001423static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
Amir Levy9659e592016-10-27 18:08:27 +03001424{
1425 int result;
1426 struct teth_bridge_connect_params teth_bridge_params;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001427 struct ipa3_usb_teth_prot_conn_params *teth_conn_params;
1428 enum ipa3_usb_transport_type ttype;
Amir Levy9659e592016-10-27 18:08:27 +03001429
Ghanim Fodi93a61112016-10-05 11:59:18 +03001430 IPA_USB_DBG("connecting protocol = %s\n",
1431 ipa3_usb_teth_prot_to_string(teth_prot));
1432
1433 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1434
1435 teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params);
1436
1437 switch (teth_prot) {
Amir Levy9659e592016-10-27 18:08:27 +03001438 case IPA_USB_RNDIS:
1439 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state ==
1440 IPA_USB_TETH_PROT_CONNECTED) {
1441 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001442 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001443 break;
1444 }
1445 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1446 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data;
1447 result = rndis_ipa_pipe_connect_notify(
Ghanim Fodi93a61112016-10-05 11:59:18 +03001448 teth_conn_params->usb_to_ipa_clnt_hdl,
1449 teth_conn_params->ipa_to_usb_clnt_hdl,
1450 teth_conn_params->params.max_xfer_size_bytes_to_dev,
1451 teth_conn_params->params.max_packet_number_to_dev,
1452 teth_conn_params->params.max_xfer_size_bytes_to_host,
Amir Levy9659e592016-10-27 18:08:27 +03001453 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
1454 teth_prot_params.rndis.private);
1455 if (result) {
1456 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001457 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001458 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1459 return result;
1460 }
1461 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state =
1462 IPA_USB_TETH_PROT_CONNECTED;
1463 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001464 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001465 break;
1466 case IPA_USB_ECM:
1467 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state ==
1468 IPA_USB_TETH_PROT_CONNECTED) {
1469 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001470 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001471 break;
1472 }
1473 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
1474 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data;
Ghanim Fodi93a61112016-10-05 11:59:18 +03001475 result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl,
1476 teth_conn_params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001477 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
1478 teth_prot_params.ecm.private);
1479 if (result) {
1480 IPA_USB_ERR("failed to connect %s.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001481 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001482 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1483 return result;
1484 }
1485 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state =
1486 IPA_USB_TETH_PROT_CONNECTED;
1487 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001488 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001489 break;
1490 case IPA_USB_RMNET:
1491 case IPA_USB_MBIM:
Ghanim Fodi93a61112016-10-05 11:59:18 +03001492 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
Amir Levy9659e592016-10-27 18:08:27 +03001493 IPA_USB_TETH_PROT_CONNECTED) {
1494 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001495 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001496 break;
1497 }
1498 result = ipa3_usb_init_teth_bridge();
1499 if (result)
1500 return result;
1501
1502 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001503 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
Amir Levy9659e592016-10-27 18:08:27 +03001504 user_data;
1505 teth_bridge_params.ipa_usb_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001506 teth_conn_params->ipa_to_usb_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001507 teth_bridge_params.usb_ipa_pipe_hdl =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001508 teth_conn_params->usb_to_ipa_clnt_hdl;
Amir Levy9659e592016-10-27 18:08:27 +03001509 teth_bridge_params.tethering_mode =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001510 (teth_prot == IPA_USB_RMNET) ?
Amir Levy9659e592016-10-27 18:08:27 +03001511 (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
1512 teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
1513 result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
1514 if (result) {
1515 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1516 return result;
1517 }
Ghanim Fodi93a61112016-10-05 11:59:18 +03001518 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
Amir Levy9659e592016-10-27 18:08:27 +03001519 IPA_USB_TETH_PROT_CONNECTED;
1520 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1521 IPA_USB_DBG("%s (%s) is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001522 ipa3_usb_teth_prot_to_string(teth_prot),
1523 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001524 break;
1525 case IPA_USB_DIAG:
1526 if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state ==
1527 IPA_USB_TETH_PROT_CONNECTED) {
1528 IPA_USB_DBG("%s is already connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001529 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001530 break;
1531 }
1532
1533 ipa3_usb_ctx->ttype_ctx[ttype].user_data =
Ghanim Fodi93a61112016-10-05 11:59:18 +03001534 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data;
Amir Levy9659e592016-10-27 18:08:27 +03001535 result = ipa3_usb_connect_dpl();
1536 if (result) {
1537 IPA_USB_ERR("Failed connecting DPL result=%d\n",
1538 result);
1539 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1540 return result;
1541 }
1542 ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state =
1543 IPA_USB_TETH_PROT_CONNECTED;
1544 ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
1545 IPA_USB_DBG("%s is connected.\n",
Ghanim Fodi93a61112016-10-05 11:59:18 +03001546 ipa3_usb_teth_prot_to_string(teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03001547 break;
1548 default:
1549 IPA_USB_ERR("Invalid tethering protocol\n");
1550 return -EFAULT;
1551 }
1552
1553 return 0;
1554}
1555
1556static int ipa3_usb_disconnect_teth_bridge(void)
1557{
1558 int result;
1559
1560 result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
1561 if (result) {
1562 IPA_USB_ERR("failed to disconnect teth_bridge.\n");
1563 return result;
1564 }
1565
1566 return 0;
1567}
1568
1569static int ipa3_usb_disconnect_dpl(void)
1570{
1571 int res;
1572
1573 /* Remove DPL RM dependency */
1574 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
1575 IPA_RM_RESOURCE_Q6_CONS);
1576 if (res)
1577 IPA_USB_ERR("deleting DPL_DUMMY_PROD rsrc dependency fail\n");
1578
1579 res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
1580 IPA_RM_RESOURCE_USB_DPL_CONS);
1581 if (res)
1582 IPA_USB_ERR("deleting DPL_CONS rsrc dependencty fail\n");
1583
1584 return 0;
1585}
1586
1587static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
1588{
1589 int result = 0;
1590 enum ipa3_usb_transport_type ttype;
1591
1592 ttype = IPA3_USB_GET_TTYPE(teth_prot);
1593
1594 switch (teth_prot) {
1595 case IPA_USB_RNDIS:
1596 case IPA_USB_ECM:
1597 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1598 IPA_USB_TETH_PROT_CONNECTED) {
1599 IPA_USB_DBG("%s is not connected.\n",
1600 ipa3_usb_teth_prot_to_string(teth_prot));
1601 return -EPERM;
1602 }
1603 if (teth_prot == IPA_USB_RNDIS) {
1604 result = rndis_ipa_pipe_disconnect_notify(
1605 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1606 teth_prot_params.rndis.private);
1607 } else {
1608 result = ecm_ipa_disconnect(
1609 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
1610 teth_prot_params.ecm.private);
1611 }
1612 if (result) {
1613 IPA_USB_ERR("failed to disconnect %s.\n",
1614 ipa3_usb_teth_prot_to_string(teth_prot));
1615 break;
1616 }
1617 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1618 IPA_USB_TETH_PROT_INITIALIZED;
1619 IPA_USB_DBG("disconnected %s\n",
1620 ipa3_usb_teth_prot_to_string(teth_prot));
1621 break;
1622 case IPA_USB_RMNET:
1623 case IPA_USB_MBIM:
1624 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1625 IPA_USB_TETH_PROT_CONNECTED) {
1626 IPA_USB_DBG("%s (%s) is not connected.\n",
1627 ipa3_usb_teth_prot_to_string(teth_prot),
1628 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1629 return -EPERM;
1630 }
1631 result = ipa3_usb_disconnect_teth_bridge();
1632 if (result)
1633 break;
1634
1635 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1636 IPA_USB_TETH_PROT_INITIALIZED;
1637 IPA_USB_DBG("disconnected %s (%s)\n",
1638 ipa3_usb_teth_prot_to_string(teth_prot),
1639 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
1640 break;
1641 case IPA_USB_DIAG:
1642 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
1643 IPA_USB_TETH_PROT_CONNECTED) {
1644 IPA_USB_DBG("%s is not connected.\n",
1645 ipa3_usb_teth_prot_to_string(teth_prot));
1646 return -EPERM;
1647 }
1648 result = ipa3_usb_disconnect_dpl();
1649 if (result)
1650 break;
1651 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
1652 IPA_USB_TETH_PROT_INITIALIZED;
1653 IPA_USB_DBG("disconnected %s\n",
1654 ipa3_usb_teth_prot_to_string(teth_prot));
1655 break;
1656 default:
1657 break;
1658 }
1659
1660 ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
1661 return result;
1662}
1663
1664static int ipa3_usb_xdci_connect_internal(
1665 struct ipa_usb_xdci_connect_params_internal *params)
1666{
1667 int result = -EFAULT;
1668 struct ipa_rm_perf_profile profile;
1669 enum ipa3_usb_transport_type ttype;
1670
1671 IPA_USB_DBG_LOW("entry\n");
1672 if (params == NULL || !ipa3_usb_check_connect_params(params)) {
1673 IPA_USB_ERR("bad parameters.\n");
1674 return -EINVAL;
1675 }
1676
1677 ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
1678 IPA_USB_TRANSPORT_TETH;
1679
Ghanim Fodi93a61112016-10-05 11:59:18 +03001680 if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03001681 IPA_USB_ERR("Illegal operation.\n");
1682 return -EPERM;
1683 }
1684
Ghanim Fodi93a61112016-10-05 11:59:18 +03001685 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl
1686 = params->ipa_to_usb_clnt_hdl;
1687 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
1688 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.
1689 usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl;
1690 ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params
1691 = params->teth_prot_params;
1692
Amir Levy9659e592016-10-27 18:08:27 +03001693 /* Set EE xDCI specific scratch */
1694 result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
1695 if (result) {
1696 IPA_USB_ERR("failed setting xDCI EE scratch field\n");
1697 return result;
1698 }
1699
1700 /* Set RM PROD & CONS perf profile */
1701 profile.max_supported_bandwidth_mbps =
1702 params->max_supported_bandwidth_mbps;
1703 result = ipa_rm_set_perf_profile(
1704 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
1705 &profile);
1706 if (result) {
1707 IPA_USB_ERR("failed to set %s perf profile\n",
1708 ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
1709 rm_ctx.prod_params.name));
1710 return result;
1711 }
1712 result = ipa_rm_set_perf_profile(
1713 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
1714 &profile);
1715 if (result) {
1716 IPA_USB_ERR("failed to set %s perf profile\n",
1717 ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
1718 rm_ctx.cons_params.name));
1719 return result;
1720 }
1721
1722 /* Request PROD */
1723 result = ipa3_usb_request_prod(ttype);
1724 if (result)
1725 return result;
1726
1727 if (params->teth_prot != IPA_USB_DIAG) {
1728 /* Start UL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001729 result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001730 params->usb_to_ipa_xferrscidx,
1731 params->usb_to_ipa_xferrscidx_valid);
1732 if (result) {
1733 IPA_USB_ERR("failed to connect UL channel.\n");
1734 goto connect_ul_fail;
1735 }
1736 }
1737
1738 /* Start DL/DPL channel */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001739 result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03001740 params->ipa_to_usb_xferrscidx,
1741 params->ipa_to_usb_xferrscidx_valid);
1742 if (result) {
1743 IPA_USB_ERR("failed to connect DL/DPL channel.\n");
1744 goto connect_dl_fail;
1745 }
1746
1747 /* Connect tethering protocol */
Ghanim Fodi93a61112016-10-05 11:59:18 +03001748 result = ipa3_usb_connect_teth_prot(params->teth_prot);
Amir Levy9659e592016-10-27 18:08:27 +03001749 if (result) {
1750 IPA_USB_ERR("failed to connect teth protocol\n");
1751 goto connect_teth_prot_fail;
1752 }
1753
1754 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
1755 IPA_USB_ERR(
1756 "failed to change state to connected\n");
1757 goto state_change_connected_fail;
1758 }
1759
1760 IPA_USB_DBG_LOW("exit\n");
1761 return 0;
1762
1763state_change_connected_fail:
1764 ipa3_usb_disconnect_teth_prot(params->teth_prot);
1765connect_teth_prot_fail:
1766 ipa3_xdci_disconnect(params->ipa_to_usb_clnt_hdl, false, -1);
1767 ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
1768 ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
1769connect_dl_fail:
1770 if (params->teth_prot != IPA_USB_DIAG) {
1771 ipa3_xdci_disconnect(params->usb_to_ipa_clnt_hdl, false, -1);
1772 ipa3_reset_gsi_channel(params->usb_to_ipa_clnt_hdl);
1773 ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
1774 }
1775connect_ul_fail:
1776 ipa3_usb_release_prod(ttype);
1777 return result;
1778}
1779
1780#ifdef CONFIG_DEBUG_FS
1781static char dbg_buff[IPA_USB_MAX_MSG_LEN];
1782
1783static char *ipa3_usb_cons_state_to_string(enum ipa3_usb_cons_state state)
1784{
1785 switch (state) {
1786 case IPA_USB_CONS_GRANTED:
1787 return "CONS_GRANTED";
1788 case IPA_USB_CONS_RELEASED:
1789 return "CONS_RELEASED";
1790 }
1791
1792 return "UNSUPPORTED";
1793}
1794
1795static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status)
1796{
1797 int res;
1798 int i;
1799 unsigned long flags;
1800
1801 IPA_USB_DBG_LOW("entry\n");
1802
1803 if (ipa3_usb_ctx == NULL) {
1804 IPA_USB_ERR("IPA USB was not inited yet\n");
1805 return -EFAULT;
1806 }
1807
1808 mutex_lock(&ipa3_usb_ctx->general_mutex);
1809
1810 if (!status) {
1811 IPA_USB_ERR("Invalid input\n");
1812 res = -EINVAL;
1813 goto bail;
1814 }
1815
1816 memset(status, 0, sizeof(struct ipa3_usb_status_dbg_info));
1817
1818 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
1819 status->teth_state = ipa3_usb_state_to_string(
1820 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].state);
1821 status->dpl_state = ipa3_usb_state_to_string(
1822 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].state);
1823 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].rm_ctx.cons_valid)
1824 status->teth_cons_state = ipa3_usb_cons_state_to_string(
1825 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].
1826 rm_ctx.cons_state);
1827 if (ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].rm_ctx.cons_valid)
1828 status->dpl_cons_state = ipa3_usb_cons_state_to_string(
1829 ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].
1830 rm_ctx.cons_state);
1831 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
1832
1833 for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) {
1834 if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1835 IPA_USB_TETH_PROT_INITIALIZED) {
1836 if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM))
1837 status->inited_prots[status->num_init_prot++] =
1838 ipa3_usb_teth_bridge_prot_to_string(i);
1839 else
1840 status->inited_prots[status->num_init_prot++] =
1841 ipa3_usb_teth_prot_to_string(i);
1842 } else if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
1843 IPA_USB_TETH_PROT_CONNECTED) {
1844 switch (i) {
1845 case IPA_USB_RMNET:
1846 case IPA_USB_MBIM:
1847 status->teth_connected_prot =
1848 ipa3_usb_teth_bridge_prot_to_string(i);
1849 break;
1850 case IPA_USB_DIAG:
1851 status->dpl_connected_prot =
1852 ipa3_usb_teth_prot_to_string(i);
1853 break;
1854 default:
1855 status->teth_connected_prot =
1856 ipa3_usb_teth_prot_to_string(i);
1857 }
1858 }
1859 }
1860
1861 res = 0;
1862 IPA_USB_DBG_LOW("exit\n");
1863bail:
1864 mutex_unlock(&ipa3_usb_ctx->general_mutex);
1865 return res;
1866}
1867
1868static ssize_t ipa3_read_usb_state_info(struct file *file, char __user *ubuf,
1869 size_t count, loff_t *ppos)
1870{
1871 struct ipa3_usb_status_dbg_info status;
1872 int result;
1873 int nbytes;
1874 int cnt = 0;
1875 int i;
1876
1877 result = ipa3_usb_get_status_dbg_info(&status);
1878 if (result) {
1879 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
1880 "Fail to read IPA USB status\n");
1881 cnt += nbytes;
1882 } else {
1883 nbytes = scnprintf(dbg_buff, IPA_USB_MAX_MSG_LEN,
1884 "Tethering Data State: %s\n"
1885 "DPL State: %s\n"
1886 "Protocols in Initialized State: ",
1887 status.teth_state,
1888 status.dpl_state);
1889 cnt += nbytes;
1890
1891 for (i = 0 ; i < status.num_init_prot ; i++) {
1892 nbytes = scnprintf(dbg_buff + cnt,
1893 IPA_USB_MAX_MSG_LEN - cnt,
1894 "%s ", status.inited_prots[i]);
1895 cnt += nbytes;
1896 }
1897 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
1898 status.num_init_prot ? "\n" : "None\n");
1899 cnt += nbytes;
1900
1901 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
1902 "Protocols in Connected State: ");
1903 cnt += nbytes;
1904 if (status.teth_connected_prot) {
1905 nbytes = scnprintf(dbg_buff + cnt,
1906 IPA_USB_MAX_MSG_LEN - cnt,
1907 "%s ", status.teth_connected_prot);
1908 cnt += nbytes;
1909 }
1910 if (status.dpl_connected_prot) {
1911 nbytes = scnprintf(dbg_buff + cnt,
1912 IPA_USB_MAX_MSG_LEN - cnt,
1913 "%s ", status.dpl_connected_prot);
1914 cnt += nbytes;
1915 }
1916 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
1917 (status.teth_connected_prot ||
1918 status.dpl_connected_prot) ? "\n" : "None\n");
1919 cnt += nbytes;
1920
1921 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
1922 "USB Tethering Consumer State: %s\n",
1923 status.teth_cons_state ?
1924 status.teth_cons_state : "Invalid");
1925 cnt += nbytes;
1926
1927 nbytes = scnprintf(dbg_buff + cnt, IPA_USB_MAX_MSG_LEN - cnt,
1928 "DPL Consumer State: %s\n",
1929 status.dpl_cons_state ? status.dpl_cons_state :
1930 "Invalid");
1931 cnt += nbytes;
1932 }
1933
1934 return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
1935}
1936
1937const struct file_operations ipa3_ipa_usb_ops = {
1938 .read = ipa3_read_usb_state_info,
1939};
1940
1941static void ipa_usb_debugfs_init(void)
1942{
1943 const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
1944
1945 ipa3_usb_ctx->dent = debugfs_create_dir("ipa_usb", 0);
1946 if (IS_ERR(ipa3_usb_ctx->dent)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001947 pr_err("fail to create folder in debug_fs.\n");
Amir Levy9659e592016-10-27 18:08:27 +03001948 return;
1949 }
1950
1951 ipa3_usb_ctx->dfile_state_info = debugfs_create_file("state_info",
1952 read_only_mode, ipa3_usb_ctx->dent, 0,
1953 &ipa3_ipa_usb_ops);
1954 if (!ipa3_usb_ctx->dfile_state_info ||
1955 IS_ERR(ipa3_usb_ctx->dfile_state_info)) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001956 pr_err("failed to create file for state_info\n");
Amir Levy9659e592016-10-27 18:08:27 +03001957 goto fail;
1958 }
1959
1960 return;
1961
1962fail:
1963 debugfs_remove_recursive(ipa3_usb_ctx->dent);
1964 ipa3_usb_ctx->dent = NULL;
1965}
1966
1967static void ipa_usb_debugfs_remove(void)
1968{
1969 if (IS_ERR(ipa3_usb_ctx->dent)) {
1970 IPA_USB_ERR("ipa_usb debugfs folder was not created.\n");
1971 return;
1972 }
1973
1974 debugfs_remove_recursive(ipa3_usb_ctx->dent);
1975}
1976#else /* CONFIG_DEBUG_FS */
1977static void ipa_usb_debugfs_init(void){}
1978static void ipa_usb_debugfs_remove(void){}
1979#endif /* CONFIG_DEBUG_FS */
1980
1981
1982
1983int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
1984 struct ipa_usb_xdci_chan_params *dl_chan_params,
1985 struct ipa_req_chan_out_params *ul_out_params,
1986 struct ipa_req_chan_out_params *dl_out_params,
1987 struct ipa_usb_xdci_connect_params *connect_params)
1988{
1989 int result = -EFAULT;
1990 struct ipa_usb_xdci_connect_params_internal conn_params;
1991
1992 mutex_lock(&ipa3_usb_ctx->general_mutex);
1993 IPA_USB_DBG_LOW("entry\n");
1994 if (connect_params == NULL || dl_chan_params == NULL ||
1995 dl_out_params == NULL ||
1996 (connect_params->teth_prot != IPA_USB_DIAG &&
1997 (ul_chan_params == NULL || ul_out_params == NULL))) {
1998 IPA_USB_ERR("bad parameters.\n");
1999 result = -EINVAL;
2000 goto bad_params;
2001 }
2002
2003 if (connect_params->teth_prot != IPA_USB_DIAG) {
2004 result = ipa3_usb_request_xdci_channel(ul_chan_params,
2005 ul_out_params);
2006 if (result) {
2007 IPA_USB_ERR("failed to allocate UL channel.\n");
2008 goto bad_params;
2009 }
2010 }
2011
2012 result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params);
2013 if (result) {
2014 IPA_USB_ERR("failed to allocate DL/DPL channel.\n");
2015 goto alloc_dl_chan_fail;
2016 }
2017
2018 memset(&conn_params, 0,
2019 sizeof(struct ipa_usb_xdci_connect_params_internal));
2020 conn_params.max_pkt_size = connect_params->max_pkt_size;
2021 conn_params.ipa_to_usb_clnt_hdl = dl_out_params->clnt_hdl;
2022 conn_params.ipa_to_usb_xferrscidx =
2023 connect_params->ipa_to_usb_xferrscidx;
2024 conn_params.ipa_to_usb_xferrscidx_valid =
2025 connect_params->ipa_to_usb_xferrscidx_valid;
2026 if (connect_params->teth_prot != IPA_USB_DIAG) {
2027 conn_params.usb_to_ipa_clnt_hdl = ul_out_params->clnt_hdl;
2028 conn_params.usb_to_ipa_xferrscidx =
2029 connect_params->usb_to_ipa_xferrscidx;
2030 conn_params.usb_to_ipa_xferrscidx_valid =
2031 connect_params->usb_to_ipa_xferrscidx_valid;
2032 }
2033 conn_params.teth_prot = connect_params->teth_prot;
2034 conn_params.teth_prot_params = connect_params->teth_prot_params;
2035 conn_params.max_supported_bandwidth_mbps =
2036 connect_params->max_supported_bandwidth_mbps;
2037 result = ipa3_usb_xdci_connect_internal(&conn_params);
2038 if (result) {
2039 IPA_USB_ERR("failed to connect.\n");
2040 goto connect_fail;
2041 }
2042
2043 IPA_USB_DBG_LOW("exit\n");
2044 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2045 return 0;
2046
2047connect_fail:
2048 ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002049 IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002050alloc_dl_chan_fail:
2051 if (connect_params->teth_prot != IPA_USB_DIAG)
2052 ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002053 IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot));
Amir Levy9659e592016-10-27 18:08:27 +03002054bad_params:
2055 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2056 return result;
2057}
2058EXPORT_SYMBOL(ipa_usb_xdci_connect);
2059
2060static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
2061{
2062 if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
2063 IPA_USB_ERR("bad parameter.\n");
2064 return -EFAULT;
2065 }
2066
2067 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2068 IPA_USB_TETH_PROT_CONNECTED) {
2069 IPA_USB_ERR("%s is not connected.\n",
2070 ipa3_usb_teth_prot_to_string(teth_prot));
2071 return -EFAULT;
2072 }
2073
2074 return 0;
2075}
2076
Ghanim Fodi93a61112016-10-05 11:59:18 +03002077/* Assumes lock already acquired */
2078static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2079 enum ipa_usb_teth_prot teth_prot)
2080{
2081 int result = 0;
2082 enum ipa3_usb_transport_type ttype;
2083
2084 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2085
2086 IPA_USB_DBG_LOW("entry\n");
2087
2088 /* Reset DL channel */
2089 result = ipa3_reset_gsi_channel(dl_clnt_hdl);
2090 if (result) {
2091 IPA_USB_ERR("failed to reset DL channel.\n");
2092 return result;
2093 }
2094
2095 /* Reset DL event ring */
2096 result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
2097 if (result) {
2098 IPA_USB_ERR("failed to reset DL event ring.\n");
2099 return result;
2100 }
2101
2102 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2103 /* Reset UL channel */
2104 result = ipa3_reset_gsi_channel(ul_clnt_hdl);
2105 if (result) {
2106 IPA_USB_ERR("failed to reset UL channel.\n");
2107 return result;
2108 }
2109
2110 /* Reset UL event ring */
2111 result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
2112 if (result) {
2113 IPA_USB_ERR("failed to reset UL event ring.\n");
2114 return result;
2115 }
2116 }
2117
2118 /* Change state to STOPPED */
2119 if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
2120 IPA_USB_ERR("failed to change state to stopped\n");
2121
2122 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2123 result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
2124 if (result) {
2125 IPA_USB_ERR("failed to release UL channel.\n");
2126 return result;
2127 }
2128 }
2129
2130 result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
2131 if (result) {
2132 IPA_USB_ERR("failed to release DL channel.\n");
2133 return result;
2134 }
2135
2136 IPA_USB_DBG_LOW("exit\n");
2137
2138 return 0;
2139}
2140
Amir Levy9659e592016-10-27 18:08:27 +03002141int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2142 enum ipa_usb_teth_prot teth_prot)
2143{
2144 int result = 0;
2145 struct ipa_ep_cfg_holb holb_cfg;
2146 unsigned long flags;
2147 enum ipa3_usb_state orig_state;
2148 enum ipa3_usb_transport_type ttype;
2149
2150 mutex_lock(&ipa3_usb_ctx->general_mutex);
2151 IPA_USB_DBG_LOW("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002152
2153 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2154
Ghanim Fodi93a61112016-10-05 11:59:18 +03002155 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002156 IPA_USB_ERR("Illegal operation.\n");
2157 result = -EPERM;
2158 goto bad_params;
2159 }
2160
2161 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002162 if (ipa3_usb_ctx->ttype_ctx[ttype].state ==
2163 IPA_USB_SUSPENDED_NO_RWAKEUP) {
2164 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2165 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2166 teth_prot);
2167 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2168 return result;
2169 }
2170
2171 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2172 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2173 result = -EINVAL;
2174 goto bad_params;
2175 }
2176
Amir Levy9659e592016-10-27 18:08:27 +03002177 if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
2178 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2179 /* Stop DL/DPL channel */
2180 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2181 if (result) {
2182 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2183 goto bad_params;
2184 }
2185 } else {
2186 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2187 memset(&holb_cfg, 0, sizeof(holb_cfg));
2188 holb_cfg.en = IPA_HOLB_TMR_EN;
2189 holb_cfg.tmr_val = 0;
2190 ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);
2191 }
2192
2193 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2194 orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2195 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
Skylar Changdf5f2342017-06-05 09:27:48 -07002196 if (orig_state != IPA_USB_SUSPENDED) {
Amir Levy9659e592016-10-27 18:08:27 +03002197 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2198 flags);
2199 /* Stop UL channel */
2200 result = ipa3_xdci_disconnect(ul_clnt_hdl,
2201 true,
2202 ipa3_usb_ctx->qmi_req_id);
2203 if (result) {
2204 IPA_USB_ERR("failed disconnect UL channel\n");
2205 goto bad_params;
2206 }
2207 ipa3_usb_ctx->qmi_req_id++;
2208 } else
2209 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
2210 flags);
2211 } else
2212 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2213
Ghanim Fodi93a61112016-10-05 11:59:18 +03002214 result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
2215 teth_prot);
2216 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03002217 goto bad_params;
Amir Levy9659e592016-10-27 18:08:27 +03002218
2219 /* Disconnect tethering protocol */
2220 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2221 if (result)
2222 goto bad_params;
2223
Skylar Changdf5f2342017-06-05 09:27:48 -07002224 if (orig_state != IPA_USB_SUSPENDED) {
Amir Levy9659e592016-10-27 18:08:27 +03002225 result = ipa3_usb_release_prod(ttype);
2226 if (result) {
2227 IPA_USB_ERR("failed to release PROD.\n");
2228 goto bad_params;
2229 }
2230 }
2231
2232 IPA_USB_DBG_LOW("exit\n");
2233 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2234 return 0;
2235
2236bad_params:
2237 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2238 return result;
2239
2240}
2241EXPORT_SYMBOL(ipa_usb_xdci_disconnect);
2242
2243int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
2244{
2245 int result = -EFAULT;
2246 enum ipa3_usb_transport_type ttype;
2247
2248 mutex_lock(&ipa3_usb_ctx->general_mutex);
2249 IPA_USB_DBG_LOW("entry\n");
2250 if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
2251 IPA_USB_ERR("bad parameters.\n");
2252 result = -EINVAL;
2253 goto bad_params;
2254 }
2255
2256 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2257
Ghanim Fodi93a61112016-10-05 11:59:18 +03002258 if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002259 IPA_USB_ERR("Illegal operation.\n");
2260 result = -EPERM;
2261 goto bad_params;
2262 }
2263
2264 /* Clean-up tethering protocol */
2265 switch (teth_prot) {
2266 case IPA_USB_RNDIS:
2267 case IPA_USB_ECM:
2268 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2269 IPA_USB_TETH_PROT_INITIALIZED) {
2270 IPA_USB_ERR("%s is not initialized\n",
2271 ipa3_usb_teth_prot_to_string(teth_prot));
2272 result = -EINVAL;
2273 goto bad_params;
2274 }
2275 if (teth_prot == IPA_USB_RNDIS)
2276 rndis_ipa_cleanup(
2277 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2278 teth_prot_params.rndis.private);
2279 else
2280 ecm_ipa_cleanup(
2281 ipa3_usb_ctx->teth_prot_ctx[teth_prot].
2282 teth_prot_params.ecm.private);
2283 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = NULL;
2284 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2285 IPA_USB_TETH_PROT_INVALID;
2286 ipa3_usb_ctx->num_init_prot--;
2287 IPA_USB_DBG("deinitialized %s\n",
2288 ipa3_usb_teth_prot_to_string(teth_prot));
2289 break;
2290 case IPA_USB_RMNET:
2291 case IPA_USB_MBIM:
2292 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2293 IPA_USB_TETH_PROT_INITIALIZED) {
2294 IPA_USB_ERR("%s (%s) is not initialized\n",
2295 ipa3_usb_teth_prot_to_string(teth_prot),
2296 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2297 result = -EINVAL;
2298 goto bad_params;
2299 }
2300
2301 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2302 NULL;
2303 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2304 IPA_USB_TETH_PROT_INVALID;
2305 ipa3_usb_ctx->num_init_prot--;
2306 IPA_USB_DBG("deinitialized %s (%s)\n",
2307 ipa3_usb_teth_prot_to_string(teth_prot),
2308 ipa3_usb_teth_bridge_prot_to_string(teth_prot));
2309 break;
2310 case IPA_USB_DIAG:
2311 if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
2312 IPA_USB_TETH_PROT_INITIALIZED) {
2313 IPA_USB_ERR("%s is not initialized\n",
2314 ipa3_usb_teth_prot_to_string(teth_prot));
2315 result = -EINVAL;
2316 goto bad_params;
2317 }
2318 ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
2319 NULL;
2320 ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
2321 IPA_USB_TETH_PROT_INVALID;
2322 IPA_USB_DBG("deinitialized %s\n",
2323 ipa3_usb_teth_prot_to_string(teth_prot));
2324 break;
2325 default:
2326 IPA_USB_ERR("unexpected tethering protocol\n");
2327 result = -EINVAL;
2328 goto bad_params;
2329 }
2330
2331 if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
2332 (ipa3_usb_ctx->num_init_prot == 0)) {
2333 if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
2334 IPA_USB_ERR("failed to change state to invalid\n");
2335 ipa_rm_delete_resource(
2336 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
2337 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
2338 ipa_rm_delete_resource(
2339 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
2340 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
2341 ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
2342 }
2343
2344 IPA_USB_DBG_LOW("exit\n");
2345 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2346 return 0;
2347
2348bad_params:
2349 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2350 return result;
2351}
2352EXPORT_SYMBOL(ipa_usb_deinit_teth_prot);
2353
Ghanim Fodi93a61112016-10-05 11:59:18 +03002354/* Assumes lock already acquired */
2355static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
Amir Levy9659e592016-10-27 18:08:27 +03002356 enum ipa_usb_teth_prot teth_prot)
2357{
2358 int result = 0;
Ghanim Fodi93a61112016-10-05 11:59:18 +03002359 enum ipa3_usb_transport_type ttype;
2360
2361 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2362
2363 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) {
2364 IPA_USB_ERR("Illegal operation.\n");
2365 result = -EPERM;
2366 goto fail_exit;
2367 }
2368
2369 IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n",
2370 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2371 "DPL channel":"Data Tethering channels");
2372
2373 if (ipa3_usb_check_disconnect_prot(teth_prot)) {
2374 result = -EINVAL;
2375 goto fail_exit;
2376 }
2377
2378 /* Stop DL/DPL channel */
2379 result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2380 if (result) {
2381 IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
2382 goto fail_exit;
2383 }
2384
2385 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2386 /* Stop UL channel */
2387 result = ipa3_xdci_disconnect(ul_clnt_hdl, true,
2388 ipa3_usb_ctx->qmi_req_id);
2389 if (result) {
2390 IPA_USB_ERR("failed disconnect UL channel\n");
2391 goto start_dl;
2392 }
2393 ipa3_usb_ctx->qmi_req_id++;
2394 }
2395
2396 /* Disconnect tethering protocol */
2397 result = ipa3_usb_disconnect_teth_prot(teth_prot);
2398 if (result)
2399 goto start_ul;
2400
2401 result = ipa3_usb_release_prod(ttype);
2402 if (result) {
2403 IPA_USB_ERR("failed to release PROD.\n");
2404 goto connect_teth;
2405 }
2406
2407 /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */
2408 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype))
2409 IPA_USB_ERR("failed to change state to suspend no rwakeup\n");
2410
2411 IPA_USB_DBG_LOW("exit\n");
2412 return 0;
2413
2414connect_teth:
2415 (void)ipa3_usb_connect_teth_prot(teth_prot);
2416start_ul:
2417 if (!IPA3_USB_IS_TTYPE_DPL(ttype))
2418 (void)ipa3_xdci_connect(ul_clnt_hdl);
2419start_dl:
2420 (void)ipa3_xdci_connect(dl_clnt_hdl);
2421fail_exit:
2422 return result;
2423}
2424
2425int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2426 enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup)
2427{
2428 int result = 0;
Amir Levy9659e592016-10-27 18:08:27 +03002429 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03002430 enum ipa3_usb_transport_type ttype;
2431
2432 mutex_lock(&ipa3_usb_ctx->general_mutex);
2433 IPA_USB_DBG_LOW("entry\n");
Ghanim Fodi93a61112016-10-05 11:59:18 +03002434
Amir Levy9659e592016-10-27 18:08:27 +03002435 if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
2436 IPA_USB_ERR("bad parameters.\n");
2437 result = -EINVAL;
2438 goto bad_params;
2439 }
2440
Ghanim Fodi93a61112016-10-05 11:59:18 +03002441 if (!with_remote_wakeup) {
2442 result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl,
2443 dl_clnt_hdl, teth_prot);
2444 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2445 return result;
2446 }
2447
Amir Levy9659e592016-10-27 18:08:27 +03002448 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2449
Ghanim Fodi93a61112016-10-05 11:59:18 +03002450 if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002451 IPA_USB_ERR("Illegal operation.\n");
2452 result = -EPERM;
2453 goto bad_params;
2454 }
2455
2456 IPA_USB_DBG("Start suspend sequence: %s\n",
2457 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2458 "DPL channel":"Data Tethering channels");
2459
2460 /* Change state to SUSPEND_REQUESTED */
2461 if (!ipa3_usb_set_state(IPA_USB_SUSPEND_REQUESTED, false, ttype)) {
2462 IPA_USB_ERR(
2463 "fail changing state to suspend_req.\n");
2464 result = -EFAULT;
2465 goto bad_params;
2466 }
2467
2468 /* Stop UL channel & suspend DL/DPL EP */
2469 result = ipa3_xdci_suspend(ul_clnt_hdl, dl_clnt_hdl,
2470 true,
2471 ipa3_usb_ctx->qmi_req_id, IPA3_USB_IS_TTYPE_DPL(ttype));
2472 if (result) {
2473 IPA_USB_ERR("failed to suspend\n");
2474 goto suspend_fail;
2475 }
2476 ipa3_usb_ctx->qmi_req_id++;
2477
2478 result = ipa3_usb_release_prod(ttype);
2479 if (result) {
2480 IPA_USB_ERR("failed to release PROD\n");
2481 goto release_prod_fail;
2482 }
2483
Skylar Changdf5f2342017-06-05 09:27:48 -07002484 /* Check if DL/DPL data pending */
Amir Levy9659e592016-10-27 18:08:27 +03002485 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
Skylar Changdf5f2342017-06-05 09:27:48 -07002486 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
2487 IPA_USB_CONS_GRANTED &&
2488 ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2489
2490 IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
2491 queue_work(ipa3_usb_ctx->wq,
2492 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2493 &ipa3_usb_dpl_notify_remote_wakeup_work :
2494 &ipa3_usb_notify_remote_wakeup_work);
2495 }
Amir Levy9659e592016-10-27 18:08:27 +03002496 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +03002497
Amir Levy9659e592016-10-27 18:08:27 +03002498 /* Change state to SUSPENDED */
2499 if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
2500 IPA_USB_ERR("failed to change state to suspended\n");
2501
2502 /* Check if DL/DPL data pending */
2503 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2504 if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
2505 IPA_USB_DBG_LOW(
2506 "DL/DPL data is pending, invoking remote wakeup\n");
2507 queue_work(ipa3_usb_ctx->wq, IPA3_USB_IS_TTYPE_DPL(ttype) ?
2508 &ipa3_usb_dpl_notify_remote_wakeup_work :
2509 &ipa3_usb_notify_remote_wakeup_work);
2510 }
2511 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2512
2513 IPA_USB_DBG_LOW("exit\n");
2514 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2515 return 0;
2516
2517release_prod_fail:
2518 ipa3_xdci_resume(ul_clnt_hdl, dl_clnt_hdl,
2519 IPA3_USB_IS_TTYPE_DPL(ttype));
2520suspend_fail:
2521 /* Change state back to CONNECTED */
2522 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true, ttype))
2523 IPA_USB_ERR("failed to change state back to connected\n");
2524bad_params:
2525 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2526 return result;
2527}
2528EXPORT_SYMBOL(ipa_usb_xdci_suspend);
2529
Ghanim Fodi93a61112016-10-05 11:59:18 +03002530/* Assumes lock already acquired */
2531static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2532 enum ipa_usb_teth_prot teth_prot)
2533{
2534 int result = -EFAULT;
2535 enum ipa3_usb_transport_type ttype;
2536
2537 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2538
2539 IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n",
2540 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2541 "DPL channel":"Data Tethering channels");
2542
2543 /* Request USB_PROD */
2544 result = ipa3_usb_request_prod(ttype);
2545 if (result)
2546 goto fail_exit;
2547
2548 /* Connect tethering protocol */
2549 result = ipa3_usb_connect_teth_prot(teth_prot);
2550 if (result) {
2551 IPA_USB_ERR("failed to connect teth protocol\n");
2552 goto release_prod;
2553 }
2554
2555 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2556 /* Start UL channel */
2557 result = ipa3_xdci_connect(ul_clnt_hdl);
2558 if (result) {
2559 IPA_USB_ERR("failed to start UL channel.\n");
2560 goto disconn_teth;
2561 }
2562 }
2563
2564 /* Start DL/DPL channel */
2565 result = ipa3_xdci_connect(dl_clnt_hdl);
2566 if (result) {
2567 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2568 goto stop_ul;
2569 }
2570
2571 /* Change state to CONNECTED */
2572 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2573 IPA_USB_ERR("failed to change state to connected\n");
2574 result = -EFAULT;
2575 goto stop_dl;
2576 }
2577
2578 return 0;
2579
2580stop_dl:
2581 (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
2582stop_ul:
2583 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2584 (void)ipa3_xdci_disconnect(ul_clnt_hdl, true,
2585 ipa3_usb_ctx->qmi_req_id);
2586 ipa3_usb_ctx->qmi_req_id++;
2587 }
2588disconn_teth:
2589 (void)ipa3_usb_disconnect_teth_prot(teth_prot);
2590release_prod:
2591 (void)ipa3_usb_release_prod(ttype);
2592fail_exit:
2593 return result;
2594}
2595
Amir Levy9659e592016-10-27 18:08:27 +03002596int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
2597 enum ipa_usb_teth_prot teth_prot)
2598{
2599 int result = -EFAULT;
2600 enum ipa3_usb_state prev_state;
2601 unsigned long flags;
2602 enum ipa3_usb_transport_type ttype;
2603
2604 mutex_lock(&ipa3_usb_ctx->general_mutex);
2605 IPA_USB_DBG_LOW("entry\n");
2606
2607 if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
2608 IPA_USB_ERR("bad parameters.\n");
2609 result = -EINVAL;
2610 goto bad_params;
2611 }
2612
2613 ttype = IPA3_USB_GET_TTYPE(teth_prot);
2614
Ghanim Fodi93a61112016-10-05 11:59:18 +03002615 if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) {
Amir Levy9659e592016-10-27 18:08:27 +03002616 IPA_USB_ERR("Illegal operation.\n");
2617 result = -EPERM;
2618 goto bad_params;
2619 }
2620
Amir Levy9659e592016-10-27 18:08:27 +03002621 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2622 prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
2623 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
Ghanim Fodi93a61112016-10-05 11:59:18 +03002624 if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) {
2625 result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl,
2626 dl_clnt_hdl, teth_prot);
2627 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2628 return result;
2629 }
2630
2631 IPA_USB_DBG("Start resume sequence: %s\n",
2632 IPA3_USB_IS_TTYPE_DPL(ttype) ?
2633 "DPL channel" : "Data Tethering channels");
Amir Levy9659e592016-10-27 18:08:27 +03002634
2635 /* Change state to RESUME_IN_PROGRESS */
2636 if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) {
2637 IPA_USB_ERR("failed to change state to resume_in_progress\n");
2638 result = -EFAULT;
2639 goto bad_params;
2640 }
2641
2642 /* Request USB_PROD */
2643 result = ipa3_usb_request_prod(ttype);
2644 if (result)
2645 goto prod_req_fail;
2646
2647 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2648 /* Start UL channel */
2649 result = ipa3_start_gsi_channel(ul_clnt_hdl);
2650 if (result) {
2651 IPA_USB_ERR("failed to start UL channel.\n");
2652 goto start_ul_fail;
2653 }
2654 }
2655
Skylar Changdf5f2342017-06-05 09:27:48 -07002656 /* Start DL/DPL channel */
2657 result = ipa3_start_gsi_channel(dl_clnt_hdl);
2658 if (result) {
2659 IPA_USB_ERR("failed to start DL/DPL channel.\n");
2660 goto start_dl_fail;
Amir Levy9659e592016-10-27 18:08:27 +03002661 }
2662
2663 /* Change state to CONNECTED */
2664 if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
2665 IPA_USB_ERR("failed to change state to connected\n");
2666 result = -EFAULT;
2667 goto state_change_connected_fail;
2668 }
2669
2670 IPA_USB_DBG_LOW("exit\n");
2671 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2672 return 0;
2673
2674state_change_connected_fail:
Skylar Changdf5f2342017-06-05 09:27:48 -07002675 result = ipa3_stop_gsi_channel(dl_clnt_hdl);
2676 if (result)
2677 IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
2678 result);
Amir Levy9659e592016-10-27 18:08:27 +03002679start_dl_fail:
2680 if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
2681 result = ipa3_stop_gsi_channel(ul_clnt_hdl);
2682 if (result)
2683 IPA_USB_ERR("Error stopping UL channel: %d\n", result);
2684 }
2685start_ul_fail:
2686 ipa3_usb_release_prod(ttype);
2687prod_req_fail:
2688 /* Change state back to prev_state */
2689 if (!ipa3_usb_set_state(prev_state, true, ttype))
2690 IPA_USB_ERR("failed to change state back to %s\n",
2691 ipa3_usb_state_to_string(prev_state));
2692bad_params:
2693 mutex_unlock(&ipa3_usb_ctx->general_mutex);
2694 return result;
2695}
2696EXPORT_SYMBOL(ipa_usb_xdci_resume);
2697
2698static int __init ipa3_usb_init(void)
2699{
2700 int i;
2701 unsigned long flags;
2702 int res;
2703
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002704 pr_debug("entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03002705 ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL);
2706 if (ipa3_usb_ctx == NULL) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002707 pr_err("failed to allocate memory\n");
2708 pr_err(":ipa_usb init failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03002709 return -EFAULT;
2710 }
2711 memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context));
2712
2713 for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++)
2714 ipa3_usb_ctx->teth_prot_ctx[i].state =
2715 IPA_USB_TETH_PROT_INVALID;
2716 ipa3_usb_ctx->num_init_prot = 0;
2717 init_completion(&ipa3_usb_ctx->dev_ready_comp);
2718 ipa3_usb_ctx->qmi_req_id = 0;
2719 spin_lock_init(&ipa3_usb_ctx->state_lock);
2720 ipa3_usb_ctx->dl_data_pending = false;
2721 mutex_init(&ipa3_usb_ctx->general_mutex);
2722
2723 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2724 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
2725 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
2726 init_completion(&ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_comp);
2727 ipa3_usb_ctx->ttype_ctx[i].user_data = NULL;
2728 }
2729
2730 spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
2731 for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
2732 ipa3_usb_ctx->ttype_ctx[i].state = IPA_USB_INVALID;
2733 ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_state =
2734 IPA_USB_CONS_RELEASED;
2735 }
2736 spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
2737
2738 ipa3_usb_ctx->wq = create_singlethread_workqueue("ipa_usb_wq");
2739 if (!ipa3_usb_ctx->wq) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002740 pr_err("failed to create workqueue\n");
Amir Levy9659e592016-10-27 18:08:27 +03002741 res = -EFAULT;
2742 goto ipa_usb_workqueue_fail;
2743 }
2744
2745 ipa_usb_debugfs_init();
2746
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002747 pr_info("exit: IPA_USB init success!\n");
Amir Levy9659e592016-10-27 18:08:27 +03002748
2749 return 0;
2750
2751ipa_usb_workqueue_fail:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002752 pr_err(":init failed (%d)\n", -res);
Amir Levy9659e592016-10-27 18:08:27 +03002753 kfree(ipa3_usb_ctx);
2754 return res;
2755}
2756
2757static void ipa3_usb_exit(void)
2758{
2759 IPA_USB_DBG_LOW("IPA_USB exit\n");
2760 ipa_usb_debugfs_remove();
2761 kfree(ipa3_usb_ctx);
2762}
2763
2764arch_initcall(ipa3_usb_init);
2765module_exit(ipa3_usb_exit);
2766
2767MODULE_LICENSE("GPL v2");
2768MODULE_DESCRIPTION("IPA USB client driver");