blob: 69936232100f4ad1ad793012e28db6ddef0981c0 [file] [log] [blame]
David Dai0d014432016-11-10 12:57:44 -08001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
David Dai04ce4202016-09-26 16:24:13 -07002 *
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#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/list.h>
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/rtmutex.h>
18#include <linux/clk.h>
19#include <linux/msm-bus.h>
20#include "msm_bus_core.h"
21#include "msm_bus_rpmh.h"
22
23#define NUM_CL_HANDLES 50
24#define NUM_LNODES 3
25#define MAX_STR_CL 50
26
David Daibee66232017-03-31 19:05:39 -070027#define MSM_BUS_MAS_ALC 144
28
David Dai04ce4202016-09-26 16:24:13 -070029struct bus_search_type {
30 struct list_head link;
31 struct list_head node_list;
32};
33
34struct handle_type {
35 int num_entries;
36 struct msm_bus_client **cl_list;
37};
38
39static struct handle_type handle_list;
40static LIST_HEAD(input_list);
41static LIST_HEAD(apply_list);
42static LIST_HEAD(commit_list);
David Dai9d66f3f2016-11-23 15:33:06 -080043static LIST_HEAD(query_list);
David Dai04ce4202016-09-26 16:24:13 -070044
45DEFINE_RT_MUTEX(msm_bus_adhoc_lock);
46
47static bool chk_bl_list(struct list_head *black_list, unsigned int id)
48{
49 struct msm_bus_node_device_type *bus_node = NULL;
50
51 list_for_each_entry(bus_node, black_list, link) {
52 if (bus_node->node_info->id == id)
53 return true;
54 }
55 return false;
56}
57
58static void copy_remaining_nodes(struct list_head *edge_list, struct list_head
59 *traverse_list, struct list_head *route_list)
60{
61 struct bus_search_type *search_node;
62
63 if (list_empty(edge_list) && list_empty(traverse_list))
64 return;
65
66 search_node = kzalloc(sizeof(struct bus_search_type), GFP_KERNEL);
67 INIT_LIST_HEAD(&search_node->node_list);
68 list_splice_init(edge_list, traverse_list);
69 list_splice_init(traverse_list, &search_node->node_list);
70 list_add_tail(&search_node->link, route_list);
71}
72
73/*
74 * Duplicate instantiaion from msm_bus_arb.c. Todo there needs to be a
75 * "util" file for these common func/macros.
76 *
77 */
David Dai607fbc42017-03-02 16:22:36 -080078uint64_t msm_bus_div64(uint64_t num, unsigned int base)
David Dai04ce4202016-09-26 16:24:13 -070079{
David Dai607fbc42017-03-02 16:22:36 -080080 uint64_t *n = &num;
David Dai04ce4202016-09-26 16:24:13 -070081
David Dai607fbc42017-03-02 16:22:36 -080082 if ((num > 0) && (num < base))
David Dai04ce4202016-09-26 16:24:13 -070083 return 1;
84
David Dai607fbc42017-03-02 16:22:36 -080085 switch (base) {
David Dai04ce4202016-09-26 16:24:13 -070086 case 0:
87 WARN(1, "AXI: Divide by 0 attempted\n");
David Dai607fbc42017-03-02 16:22:36 -080088 case 1: return num;
89 case 2: return (num >> 1);
90 case 4: return (num >> 2);
91 case 8: return (num >> 3);
92 case 16: return (num >> 4);
93 case 32: return (num >> 5);
David Dai04ce4202016-09-26 16:24:13 -070094 }
95
David Dai607fbc42017-03-02 16:22:36 -080096 do_div(*n, base);
97 return *n;
David Dai04ce4202016-09-26 16:24:13 -070098}
99
100int msm_bus_device_match_adhoc(struct device *dev, void *id)
101{
102 int ret = 0;
103 struct msm_bus_node_device_type *bnode = to_msm_bus_node(dev);
104
105 if (bnode)
106 ret = (bnode->node_info->id == *(unsigned int *)id);
107 else
108 ret = 0;
109
110 return ret;
111}
112
113static void bcm_add_bus_req(struct device *dev)
114{
115 struct msm_bus_node_device_type *cur_dev = NULL;
116 struct msm_bus_node_device_type *bcm_dev = NULL;
117 struct link_node *lnode;
118 int lnode_idx = -1;
119 int max_num_lnodes = 0;
120 int i;
121
122 cur_dev = to_msm_bus_node(dev);
123 if (!cur_dev) {
124 MSM_BUS_ERR("%s: Null device ptr", __func__);
125 goto exit_bcm_add_bus_req;
126 }
127
David Daibee66232017-03-31 19:05:39 -0700128 if (cur_dev->node_info->bcm_req_idx != -1)
129 goto exit_bcm_add_bus_req;
130
David Dai04ce4202016-09-26 16:24:13 -0700131 if (!cur_dev->node_info->num_bcm_devs)
132 goto exit_bcm_add_bus_req;
133
134 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
135 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
136 max_num_lnodes = bcm_dev->bcmdev->num_bus_devs;
137
138 if (!bcm_dev->num_lnodes) {
139 bcm_dev->lnode_list = devm_kzalloc(dev,
140 sizeof(struct link_node) * max_num_lnodes,
141 GFP_KERNEL);
142 if (!bcm_dev->lnode_list)
143 goto exit_bcm_add_bus_req;
144
145 lnode = bcm_dev->lnode_list;
146 bcm_dev->num_lnodes = max_num_lnodes;
147 lnode_idx = 0;
148 } else {
149 int i;
150
151 for (i = 0; i < bcm_dev->num_lnodes; i++) {
152 if (!bcm_dev->lnode_list[i].in_use)
153 break;
154 }
155
156 if (i < bcm_dev->num_lnodes) {
157 lnode = &bcm_dev->lnode_list[i];
158 lnode_idx = i;
159 } else {
160 struct link_node *realloc_list;
161 size_t cur_size = sizeof(struct link_node) *
162 bcm_dev->num_lnodes;
163
164 bcm_dev->num_lnodes += NUM_LNODES;
165 realloc_list = msm_bus_realloc_devmem(
166 dev,
167 bcm_dev->lnode_list,
168 cur_size,
169 sizeof(struct link_node) *
170 bcm_dev->num_lnodes,
171 GFP_KERNEL);
172
173 if (!realloc_list)
174 goto exit_bcm_add_bus_req;
175
176 bcm_dev->lnode_list = realloc_list;
177 lnode = &bcm_dev->lnode_list[i];
178 lnode_idx = i;
179 }
180 }
181
182 lnode->in_use = 1;
183 lnode->bus_dev_id = cur_dev->node_info->id;
184 cur_dev->node_info->bcm_req_idx = lnode_idx;
185 memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
186 memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
David Dai04ce4202016-09-26 16:24:13 -0700187 }
188
189exit_bcm_add_bus_req:
190 return;
191}
192
193static int gen_lnode(struct device *dev,
194 int next_hop, int prev_idx, const char *cl_name)
195{
196 struct link_node *lnode;
197 struct msm_bus_node_device_type *cur_dev = NULL;
198 int lnode_idx = -1;
199
200 if (!dev)
201 goto exit_gen_lnode;
202
203 cur_dev = to_msm_bus_node(dev);
204 if (!cur_dev) {
205 MSM_BUS_ERR("%s: Null device ptr", __func__);
206 goto exit_gen_lnode;
207 }
208
209 if (!cur_dev->num_lnodes) {
210 cur_dev->lnode_list = devm_kzalloc(dev,
211 sizeof(struct link_node) * NUM_LNODES,
212 GFP_KERNEL);
213 if (!cur_dev->lnode_list)
214 goto exit_gen_lnode;
215
216 lnode = cur_dev->lnode_list;
217 cur_dev->num_lnodes = NUM_LNODES;
218 lnode_idx = 0;
219 } else {
220 int i;
221
222 for (i = 0; i < cur_dev->num_lnodes; i++) {
223 if (!cur_dev->lnode_list[i].in_use)
224 break;
225 }
226
227 if (i < cur_dev->num_lnodes) {
228 lnode = &cur_dev->lnode_list[i];
229 lnode_idx = i;
230 } else {
231 struct link_node *realloc_list;
232 size_t cur_size = sizeof(struct link_node) *
233 cur_dev->num_lnodes;
234
235 cur_dev->num_lnodes += NUM_LNODES;
236 realloc_list = msm_bus_realloc_devmem(
237 dev,
238 cur_dev->lnode_list,
239 cur_size,
240 sizeof(struct link_node) *
241 cur_dev->num_lnodes, GFP_KERNEL);
242
243 if (!realloc_list)
244 goto exit_gen_lnode;
245
246 cur_dev->lnode_list = realloc_list;
247 lnode = &cur_dev->lnode_list[i];
248 lnode_idx = i;
249 }
250 }
251
252 lnode->in_use = 1;
253 lnode->cl_name = cl_name;
254 if (next_hop == cur_dev->node_info->id) {
255 lnode->next = -1;
256 lnode->next_dev = NULL;
257 } else {
258 lnode->next = prev_idx;
259 lnode->next_dev = bus_find_device(&msm_bus_type, NULL,
260 (void *) &next_hop,
261 msm_bus_device_match_adhoc);
262 }
263
264 memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
265 memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
266
267exit_gen_lnode:
268 return lnode_idx;
269}
270
271static int remove_lnode(struct msm_bus_node_device_type *cur_dev,
272 int lnode_idx)
273{
274 int ret = 0;
275
276 if (!cur_dev) {
277 MSM_BUS_ERR("%s: Null device ptr", __func__);
278 ret = -ENODEV;
279 goto exit_remove_lnode;
280 }
281
282 if (lnode_idx != -1) {
283 if (!cur_dev->num_lnodes ||
284 (lnode_idx > (cur_dev->num_lnodes - 1))) {
285 MSM_BUS_ERR("%s: Invalid Idx %d, num_lnodes %d",
286 __func__, lnode_idx, cur_dev->num_lnodes);
287 ret = -ENODEV;
288 goto exit_remove_lnode;
289 }
290
291 cur_dev->lnode_list[lnode_idx].next = -1;
292 cur_dev->lnode_list[lnode_idx].next_dev = NULL;
293 cur_dev->lnode_list[lnode_idx].in_use = 0;
294 cur_dev->lnode_list[lnode_idx].cl_name = NULL;
295 }
296
297exit_remove_lnode:
298 return ret;
299}
300
301static int prune_path(struct list_head *route_list, int dest, int src,
302 struct list_head *black_list, int found,
303 const char *cl_name)
304{
305 struct bus_search_type *search_node, *temp_search_node;
306 struct msm_bus_node_device_type *bus_node;
307 struct list_head *bl_list;
308 struct list_head *temp_bl_list;
309 int search_dev_id = dest;
310 struct device *dest_dev = bus_find_device(&msm_bus_type, NULL,
311 (void *) &dest,
312 msm_bus_device_match_adhoc);
313 int lnode_hop = -1;
314
315 if (!found)
316 goto reset_links;
317
318 if (!dest_dev) {
319 MSM_BUS_ERR("%s: Can't find dest dev %d", __func__, dest);
320 goto exit_prune_path;
321 }
David Dai04ce4202016-09-26 16:24:13 -0700322
323 lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop, cl_name);
324 bcm_add_bus_req(dest_dev);
325
326 list_for_each_entry_reverse(search_node, route_list, link) {
327 list_for_each_entry(bus_node, &search_node->node_list, link) {
328 unsigned int i;
329
330 for (i = 0; i < bus_node->node_info->num_connections;
331 i++) {
332 if (bus_node->node_info->connections[i] ==
333 search_dev_id) {
334 dest_dev = bus_find_device(
335 &msm_bus_type,
336 NULL,
337 (void *)
338 &bus_node->node_info->
339 id,
340 msm_bus_device_match_adhoc);
341
342 if (!dest_dev) {
343 lnode_hop = -1;
344 goto reset_links;
345 }
346
347 lnode_hop = gen_lnode(dest_dev,
348 search_dev_id,
349 lnode_hop, cl_name);
350 bcm_add_bus_req(dest_dev);
351 search_dev_id =
352 bus_node->node_info->id;
353 break;
354 }
355 }
356 }
357 }
358reset_links:
359 list_for_each_entry_safe(search_node, temp_search_node, route_list,
360 link) {
361 list_for_each_entry(bus_node, &search_node->node_list, link)
362 bus_node->node_info->is_traversed = false;
363
364 list_del(&search_node->link);
365 kfree(search_node);
366 }
367
368 list_for_each_safe(bl_list, temp_bl_list, black_list)
369 list_del(bl_list);
370
371exit_prune_path:
372 return lnode_hop;
373}
374
375static void setup_bl_list(struct msm_bus_node_device_type *node,
376 struct list_head *black_list)
377{
378 unsigned int i;
379
380 for (i = 0; i < node->node_info->num_blist; i++) {
381 struct msm_bus_node_device_type *bdev;
382
383 bdev = to_msm_bus_node(node->node_info->black_connections[i]);
384 list_add_tail(&bdev->link, black_list);
385 }
386}
387
388static int getpath(struct device *src_dev, int dest, const char *cl_name)
389{
390 struct list_head traverse_list;
391 struct list_head edge_list;
392 struct list_head route_list;
393 struct list_head black_list;
394 struct msm_bus_node_device_type *src_node;
395 struct bus_search_type *search_node;
396 int found = 0;
397 int depth_index = 0;
398 int first_hop = -1;
399 int src;
400
401 INIT_LIST_HEAD(&traverse_list);
402 INIT_LIST_HEAD(&edge_list);
403 INIT_LIST_HEAD(&route_list);
404 INIT_LIST_HEAD(&black_list);
405
406 if (!src_dev) {
407 MSM_BUS_ERR("%s: Cannot locate src dev ", __func__);
408 goto exit_getpath;
409 }
410
411 src_node = to_msm_bus_node(src_dev);
412 if (!src_node) {
413 MSM_BUS_ERR("%s:Fatal, Source node not found", __func__);
414 goto exit_getpath;
415 }
416 src = src_node->node_info->id;
417 list_add_tail(&src_node->link, &traverse_list);
418
419 while ((!found && !list_empty(&traverse_list))) {
420 struct msm_bus_node_device_type *bus_node = NULL;
421 /* Locate dest_id in the traverse list */
422 list_for_each_entry(bus_node, &traverse_list, link) {
423 if (bus_node->node_info->id == dest) {
424 found = 1;
425 break;
426 }
427 }
428
429 if (!found) {
430 unsigned int i;
431 /* Setup the new edge list */
432 list_for_each_entry(bus_node, &traverse_list, link) {
433 /* Setup list of black-listed nodes */
434 setup_bl_list(bus_node, &black_list);
435
436 for (i = 0; i < bus_node->node_info->
437 num_connections; i++) {
438 bool skip;
439 struct msm_bus_node_device_type
440 *node_conn;
441 node_conn =
442 to_msm_bus_node(bus_node->node_info->
443 dev_connections[i]);
444 if (node_conn->node_info->
445 is_traversed) {
446 MSM_BUS_ERR("Circ Path %d\n",
447 node_conn->node_info->id);
448 goto reset_traversed;
449 }
450 skip = chk_bl_list(&black_list,
451 bus_node->node_info->
452 connections[i]);
453 if (!skip) {
454 list_add_tail(&node_conn->link,
455 &edge_list);
456 node_conn->node_info->
457 is_traversed = true;
458 }
459 }
460 }
461
462 /* Keep tabs of the previous search list */
463 search_node = kzalloc(sizeof(struct bus_search_type),
464 GFP_KERNEL);
465 INIT_LIST_HEAD(&search_node->node_list);
466 list_splice_init(&traverse_list,
467 &search_node->node_list);
468 /* Add the previous search list to a route list */
469 list_add_tail(&search_node->link, &route_list);
470 /* Advancing the list depth */
471 depth_index++;
472 list_splice_init(&edge_list, &traverse_list);
473 }
474 }
475reset_traversed:
476 copy_remaining_nodes(&edge_list, &traverse_list, &route_list);
477 first_hop = prune_path(&route_list, dest, src, &black_list, found,
478 cl_name);
479
480exit_getpath:
481 return first_hop;
482}
483
484static void bcm_update_bus_req(struct device *dev, int ctx)
485{
486 struct msm_bus_node_device_type *cur_dev = NULL;
487 struct msm_bus_node_device_type *bcm_dev = NULL;
488 int i;
489 uint64_t max_ib = 0;
490 uint64_t max_ab = 0;
491 int lnode_idx = 0;
492
493 cur_dev = to_msm_bus_node(dev);
494 if (!cur_dev) {
495 MSM_BUS_ERR("%s: Null device ptr", __func__);
496 goto exit_bcm_update_bus_req;
497 }
498
499 if (!cur_dev->node_info->num_bcm_devs)
500 goto exit_bcm_update_bus_req;
501
502 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
503 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
504
505 if (!bcm_dev)
506 goto exit_bcm_update_bus_req;
507
508 lnode_idx = cur_dev->node_info->bcm_req_idx;
509 bcm_dev->lnode_list[lnode_idx].lnode_ib[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800510 msm_bus_div64(cur_dev->node_bw[ctx].max_ib *
511 (uint64_t)bcm_dev->bcmdev->width,
512 cur_dev->node_info->agg_params.buswidth);
David Dai04ce4202016-09-26 16:24:13 -0700513
514 bcm_dev->lnode_list[lnode_idx].lnode_ab[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800515 msm_bus_div64(cur_dev->node_bw[ctx].sum_ab *
516 (uint64_t)bcm_dev->bcmdev->width,
517 cur_dev->node_info->agg_params.buswidth *
518 cur_dev->node_info->agg_params.num_aggports);
David Dai04ce4202016-09-26 16:24:13 -0700519
520 for (i = 0; i < bcm_dev->num_lnodes; i++) {
521 if (ctx == ACTIVE_CTX) {
522 max_ib = max(max_ib,
523 max(bcm_dev->lnode_list[i].lnode_ib[ACTIVE_CTX],
524 bcm_dev->lnode_list[i].lnode_ib[DUAL_CTX]));
David Dai04ce4202016-09-26 16:24:13 -0700525 max_ab = max(max_ab,
526 bcm_dev->lnode_list[i].lnode_ab[ACTIVE_CTX] +
527 bcm_dev->lnode_list[i].lnode_ab[DUAL_CTX]);
528 } else {
529 max_ib = max(max_ib,
530 bcm_dev->lnode_list[i].lnode_ib[ctx]);
531 max_ab = max(max_ab,
532 bcm_dev->lnode_list[i].lnode_ab[ctx]);
533 }
534 }
David Dai04ce4202016-09-26 16:24:13 -0700535 bcm_dev->node_bw[ctx].max_ab = max_ab;
536 bcm_dev->node_bw[ctx].max_ib = max_ib;
David Daibee66232017-03-31 19:05:39 -0700537
538 max_ab = msm_bus_div64(max_ab, bcm_dev->bcmdev->unit_size);
539 max_ib = msm_bus_div64(max_ib, bcm_dev->bcmdev->unit_size);
540
541 bcm_dev->node_vec[ctx].vec_a = max_ab;
542 bcm_dev->node_vec[ctx].vec_b = max_ib;
David Dai04ce4202016-09-26 16:24:13 -0700543 }
544exit_bcm_update_bus_req:
545 return;
546}
547
David Dai9d66f3f2016-11-23 15:33:06 -0800548static void bcm_query_bus_req(struct device *dev, int ctx)
549{
550 struct msm_bus_node_device_type *cur_dev = NULL;
551 struct msm_bus_node_device_type *bcm_dev = NULL;
552 int i;
553 uint64_t max_query_ib = 0;
554 uint64_t max_query_ab = 0;
555 int lnode_idx = 0;
556
557 cur_dev = to_msm_bus_node(dev);
558 if (!cur_dev) {
559 MSM_BUS_ERR("%s: Null device ptr", __func__);
560 goto exit_bcm_query_bus_req;
561 }
562
563 if (!cur_dev->node_info->num_bcm_devs)
564 goto exit_bcm_query_bus_req;
565
566 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
567 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
568
569 if (!bcm_dev)
570 goto exit_bcm_query_bus_req;
571
572 lnode_idx = cur_dev->node_info->bcm_req_idx;
573 bcm_dev->lnode_list[lnode_idx].lnode_query_ib[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800574 msm_bus_div64(cur_dev->node_bw[ctx].max_query_ib *
575 (uint64_t)bcm_dev->bcmdev->width,
576 cur_dev->node_info->agg_params.buswidth);
David Dai9d66f3f2016-11-23 15:33:06 -0800577
578 bcm_dev->lnode_list[lnode_idx].lnode_query_ab[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800579 msm_bus_div64(cur_dev->node_bw[ctx].sum_query_ab *
580 (uint64_t)bcm_dev->bcmdev->width,
David Dai489b0d72017-03-14 13:05:01 -0700581 cur_dev->node_info->agg_params.num_aggports *
David Dai607fbc42017-03-02 16:22:36 -0800582 cur_dev->node_info->agg_params.buswidth);
David Dai9d66f3f2016-11-23 15:33:06 -0800583
584 for (i = 0; i < bcm_dev->num_lnodes; i++) {
585 if (ctx == ACTIVE_CTX) {
586 max_query_ib = max(max_query_ib,
587 max(bcm_dev->lnode_list[i].
588 lnode_query_ib[ACTIVE_CTX],
589 bcm_dev->lnode_list[i].
590 lnode_query_ib[DUAL_CTX]));
591
592 max_query_ab = max(max_query_ab,
593 bcm_dev->lnode_list[i].
594 lnode_query_ab[ACTIVE_CTX] +
595 bcm_dev->lnode_list[i].
596 lnode_query_ab[DUAL_CTX]);
597 } else {
598 max_query_ib = max(max_query_ib,
599 bcm_dev->lnode_list[i].
600 lnode_query_ib[ctx]);
601 max_query_ab = max(max_query_ab,
602 bcm_dev->lnode_list[i].
603 lnode_query_ab[ctx]);
604 }
605 }
606
David Daibee66232017-03-31 19:05:39 -0700607 max_query_ab = msm_bus_div64(max_query_ab,
608 bcm_dev->bcmdev->unit_size);
609 max_query_ib = msm_bus_div64(max_query_ib,
610 bcm_dev->bcmdev->unit_size);
611
David Dai9d66f3f2016-11-23 15:33:06 -0800612 bcm_dev->node_bw[ctx].max_query_ab = max_query_ab;
613 bcm_dev->node_bw[ctx].max_query_ib = max_query_ib;
David Dai9d66f3f2016-11-23 15:33:06 -0800614 }
615exit_bcm_query_bus_req:
616 return;
617}
618
David Daibee66232017-03-31 19:05:39 -0700619static void bcm_update_alc_req(struct msm_bus_node_device_type *dev, int ctx)
620{
621 struct msm_bus_node_device_type *bcm_dev = NULL;
622 int i;
623 uint64_t max_alc = 0;
David Dai9d66f3f2016-11-23 15:33:06 -0800624
David Daibee66232017-03-31 19:05:39 -0700625 if (!dev || !to_msm_bus_node(dev->node_info->bus_device)) {
626 MSM_BUS_ERR("Bus node pointer is Invalid");
627 goto exit_bcm_update_alc_req;
628 }
629
630 for (i = 0; i < dev->num_lnodes; i++)
631 max_alc = max(max_alc, dev->lnode_list[i].alc_idx[ctx]);
632
633 dev->node_bw[ctx].max_alc = max_alc;
634
635 bcm_dev = to_msm_bus_node(dev->node_info->bcm_devs[0]);
636
637 if (ctx == ACTIVE_CTX) {
638 max_alc = max(max_alc,
639 max(dev->node_bw[ACTIVE_CTX].max_alc,
640 dev->node_bw[DUAL_CTX].max_alc));
641 } else {
642 max_alc = dev->node_bw[ctx].max_alc;
643 }
644
645 bcm_dev->node_bw[ctx].max_alc = max_alc;
646 bcm_dev->node_vec[ctx].vec_a = max_alc;
647 bcm_dev->node_vec[ctx].vec_b = 0;
648
649exit_bcm_update_alc_req:
650 return;
651}
David Dai9d66f3f2016-11-23 15:33:06 -0800652
David Dai04ce4202016-09-26 16:24:13 -0700653int bcm_remove_handoff_req(struct device *dev, void *data)
654{
655 struct msm_bus_node_device_type *bcm_dev = NULL;
656 int i;
657 uint64_t max_ib = 0;
658 uint64_t max_ab = 0;
659 int ret = 0;
660
661 rt_mutex_lock(&msm_bus_adhoc_lock);
662
663 bcm_dev = to_msm_bus_node(dev);
664 if (!bcm_dev) {
665 MSM_BUS_ERR("%s: Null device ptr", __func__);
666 goto exit_bcm_remove_handoff_req;
667 }
668
669 if (!bcm_dev->node_info->is_bcm_dev)
670 goto exit_bcm_remove_handoff_req;
671
David Dai04ce4202016-09-26 16:24:13 -0700672 for (i = 0; i < bcm_dev->num_lnodes; i++) {
673 max_ib = max(max_ib,
674 bcm_dev->lnode_list[i].lnode_ib[0]);
675 max_ab = max(max_ab,
676 bcm_dev->lnode_list[i].lnode_ab[0]);
677 }
678
679 bcm_dev->node_bw[0].max_ab = max_ab;
680 bcm_dev->node_bw[0].max_ib = max_ib;
681
682exit_bcm_remove_handoff_req:
683 rt_mutex_unlock(&msm_bus_adhoc_lock);
684 return ret;
685}
686
David Dai04ce4202016-09-26 16:24:13 -0700687static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev,
688 int ctx)
689{
690 int i;
691 uint64_t max_ib = 0;
692 uint64_t sum_ab = 0;
693
694 if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) {
695 MSM_BUS_ERR("Bus node pointer is Invalid");
696 goto exit_agg_bus_req;
697 }
698
699 for (i = 0; i < bus_dev->num_lnodes; i++) {
700 max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
701 sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
702 }
703
704 bus_dev->node_bw[ctx].sum_ab = sum_ab;
705 bus_dev->node_bw[ctx].max_ib = max_ib;
706
707exit_agg_bus_req:
708 return;
709}
710
David Dai9d66f3f2016-11-23 15:33:06 -0800711static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev,
712 int ctx)
713{
714 int i;
715 uint64_t max_ib = 0;
716 uint64_t sum_ab = 0;
717
718 if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) {
719 MSM_BUS_ERR("Bus node pointer is Invalid");
720 goto exit_agg_bus_req;
721 }
722
723 for (i = 0; i < bus_dev->num_lnodes; i++) {
724 max_ib = max(max_ib,
725 bus_dev->lnode_list[i].lnode_query_ib[ctx]);
726 sum_ab += bus_dev->lnode_list[i].lnode_query_ab[ctx];
727 }
728
David Dai9d66f3f2016-11-23 15:33:06 -0800729 bus_dev->node_bw[ctx].sum_query_ab = sum_ab;
730 bus_dev->node_bw[ctx].max_query_ib = max_ib;
731
732exit_agg_bus_req:
733 return;
734}
David Dai04ce4202016-09-26 16:24:13 -0700735
736static void del_inp_list(struct list_head *list)
737{
738 struct rule_update_path_info *rule_node;
739 struct rule_update_path_info *rule_node_tmp;
740
741 list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) {
742 list_del(&rule_node->link);
743 rule_node->added = false;
744 }
745}
746
747static void del_op_list(struct list_head *list)
748{
749 struct rule_apply_rcm_info *rule;
750 struct rule_apply_rcm_info *rule_tmp;
751
752 list_for_each_entry_safe(rule, rule_tmp, list, link)
753 list_del(&rule->link);
754}
755
756static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit)
757{
758 struct rule_apply_rcm_info *rule;
759 struct device *dev = NULL;
760 struct msm_bus_node_device_type *dev_info = NULL;
761 int ret = 0;
762
763 list_for_each_entry(rule, list, link) {
764 if (!rule)
765 continue;
766
767 if (rule && (rule->after_clk_commit != after_clk_commit))
768 continue;
769
770 dev = bus_find_device(&msm_bus_type, NULL,
771 (void *) &rule->id,
772 msm_bus_device_match_adhoc);
773
774 if (!dev) {
775 MSM_BUS_ERR("Can't find dev node for %d", rule->id);
776 continue;
777 }
778 dev_info = to_msm_bus_node(dev);
779
780 ret = msm_bus_enable_limiter(dev_info, rule->throttle,
781 rule->lim_bw);
782 if (ret)
783 MSM_BUS_ERR("Failed to set limiter for %d", rule->id);
784 }
785
786 return ret;
787}
788
789static void commit_data(void)
790{
791 bool rules_registered = msm_rule_are_rules_registered();
792
793 if (rules_registered) {
794 msm_rules_update_path(&input_list, &apply_list);
795 msm_bus_apply_rules(&apply_list, false);
796 }
797
798 msm_bus_commit_data(&commit_list);
799
800 if (rules_registered) {
801 msm_bus_apply_rules(&apply_list, true);
802 del_inp_list(&input_list);
803 del_op_list(&apply_list);
804 }
805 INIT_LIST_HEAD(&input_list);
806 INIT_LIST_HEAD(&apply_list);
807 INIT_LIST_HEAD(&commit_list);
808}
809
810static void add_node_to_clist(struct msm_bus_node_device_type *node)
811{
812 struct msm_bus_node_device_type *node_parent =
813 to_msm_bus_node(node->node_info->bus_device);
814
815 if (!node->dirty) {
816 list_add_tail(&node->link, &commit_list);
817 node->dirty = true;
818 }
819
820 if (!node_parent->dirty) {
821 list_add_tail(&node_parent->link, &commit_list);
822 node_parent->dirty = true;
823 }
824}
825
David Dai9d66f3f2016-11-23 15:33:06 -0800826static void add_node_to_query_list(struct msm_bus_node_device_type *node)
827{
828 if (!node->query_dirty) {
829 list_add_tail(&node->query_link, &query_list);
830 node->query_dirty = true;
831 }
832}
833
David Dai04ce4202016-09-26 16:24:13 -0700834static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
835 uint64_t act_req_bw, uint64_t slp_req_ib,
836 uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw,
837 int src_idx, int ctx)
838{
839 struct device *next_dev = NULL;
840 struct link_node *lnode = NULL;
841 struct msm_bus_node_device_type *dev_info = NULL;
842 int curr_idx;
843 int ret = 0;
844 struct rule_update_path_info *rule_node;
845 bool rules_registered = msm_rule_are_rules_registered();
846
847 if (IS_ERR_OR_NULL(src_dev)) {
848 MSM_BUS_ERR("%s: No source device", __func__);
849 ret = -ENODEV;
850 goto exit_update_path;
851 }
852
853 next_dev = src_dev;
854
855 if (src_idx < 0) {
856 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
857 ret = -ENXIO;
858 goto exit_update_path;
859 }
860 curr_idx = src_idx;
861
862 while (next_dev) {
863 int i;
864
865 dev_info = to_msm_bus_node(next_dev);
866
867 if (curr_idx >= dev_info->num_lnodes) {
868 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
869 __func__, curr_idx, dev_info->num_lnodes);
870 ret = -ENXIO;
871 goto exit_update_path;
872 }
873
874 lnode = &dev_info->lnode_list[curr_idx];
875 if (!lnode) {
876 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
877 __func__, curr_idx);
878 ret = -ENXIO;
879 goto exit_update_path;
880 }
881 lnode->lnode_ib[ACTIVE_CTX] = act_req_ib;
882 lnode->lnode_ab[ACTIVE_CTX] = act_req_bw;
883 lnode->lnode_ib[DUAL_CTX] = slp_req_ib;
884 lnode->lnode_ab[DUAL_CTX] = slp_req_bw;
885
886 for (i = 0; i < NUM_CTX; i++) {
887 aggregate_bus_req(dev_info, i);
888 bcm_update_bus_req(next_dev, i);
889 }
890
891 add_node_to_clist(dev_info);
892
893 if (rules_registered) {
894 rule_node = &dev_info->node_info->rule;
895 rule_node->id = dev_info->node_info->id;
896 rule_node->ib = dev_info->node_bw[ACTIVE_CTX].max_ib;
897 rule_node->ab = dev_info->node_bw[ACTIVE_CTX].sum_ab;
898 rule_node->clk =
899 dev_info->node_bw[ACTIVE_CTX].cur_clk_hz;
900 if (!rule_node->added) {
901 list_add_tail(&rule_node->link, &input_list);
902 rule_node->added = true;
903 }
904 }
905
906 next_dev = lnode->next_dev;
907 curr_idx = lnode->next;
908 }
909
910exit_update_path:
911 return ret;
912}
913
David Daibee66232017-03-31 19:05:39 -0700914static int update_alc_vote(struct device *alc_dev, uint64_t act_req_fa_lat,
915 uint64_t act_req_idle_time, uint64_t slp_req_fa_lat,
916 uint64_t slp_req_idle_time, uint64_t cur_fa_lat,
917 uint64_t cur_idle_time, int idx, int ctx)
918{
919 struct link_node *lnode = NULL;
920 struct msm_bus_node_device_type *dev_info = NULL;
921 int curr_idx, i;
922 int ret = 0;
923
924 if (IS_ERR_OR_NULL(alc_dev)) {
925 MSM_BUS_ERR("%s: No source device", __func__);
926 ret = -ENODEV;
927 goto exit_update_alc_vote;
928 }
929
930 if (idx < 0) {
931 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, idx);
932 ret = -ENXIO;
933 goto exit_update_alc_vote;
934 }
935
936 dev_info = to_msm_bus_node(alc_dev);
937 curr_idx = idx;
938
939 if (curr_idx >= dev_info->num_lnodes) {
940 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
941 __func__, curr_idx, dev_info->num_lnodes);
942 ret = -ENXIO;
943 goto exit_update_alc_vote;
944 }
945
946 lnode = &dev_info->lnode_list[curr_idx];
947 if (!lnode) {
948 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
949 __func__, curr_idx);
950 ret = -ENXIO;
951 goto exit_update_alc_vote;
952 }
953
954 /*
955 * Add aggregation and mapping logic once LUT is avail.
956 * Use default values for time being.
957 */
958 lnode->alc_idx[ACTIVE_CTX] = 12;
959 lnode->alc_idx[DUAL_CTX] = 0;
960
961 for (i = 0; i < NUM_CTX; i++)
962 bcm_update_alc_req(dev_info, i);
963
964 add_node_to_clist(dev_info);
965
966exit_update_alc_vote:
967 return ret;
968}
969
970
David Dai9d66f3f2016-11-23 15:33:06 -0800971static int query_path(struct device *src_dev, int dest, uint64_t act_req_ib,
972 uint64_t act_req_bw, uint64_t slp_req_ib,
973 uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw,
974 int src_idx)
975{
976 struct device *next_dev = NULL;
977 struct link_node *lnode = NULL;
978 struct msm_bus_node_device_type *dev_info = NULL;
979 int curr_idx;
980 int ret = 0;
981
982 if (IS_ERR_OR_NULL(src_dev)) {
983 MSM_BUS_ERR("%s: No source device", __func__);
984 ret = -ENODEV;
985 goto exit_query_path;
986 }
987
988 next_dev = src_dev;
989
990 if (src_idx < 0) {
991 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
992 ret = -ENXIO;
993 goto exit_query_path;
994 }
995 curr_idx = src_idx;
996
997 while (next_dev) {
998 int i;
999
1000 dev_info = to_msm_bus_node(next_dev);
1001
1002 if (curr_idx >= dev_info->num_lnodes) {
1003 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
1004 __func__, curr_idx, dev_info->num_lnodes);
1005 ret = -ENXIO;
1006 goto exit_query_path;
1007 }
1008
1009 lnode = &dev_info->lnode_list[curr_idx];
1010 if (!lnode) {
1011 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
1012 __func__, curr_idx);
1013 ret = -ENXIO;
1014 goto exit_query_path;
1015 }
1016 lnode->lnode_query_ib[ACTIVE_CTX] = act_req_ib;
1017 lnode->lnode_query_ab[ACTIVE_CTX] = act_req_bw;
1018 lnode->lnode_query_ib[DUAL_CTX] = slp_req_ib;
1019 lnode->lnode_query_ab[DUAL_CTX] = slp_req_bw;
1020
1021 for (i = 0; i < NUM_CTX; i++) {
1022 aggregate_bus_query_req(dev_info, i);
1023 bcm_query_bus_req(next_dev, i);
1024 }
1025
1026 add_node_to_query_list(dev_info);
1027
1028 next_dev = lnode->next_dev;
1029 curr_idx = lnode->next;
1030 }
1031
1032exit_query_path:
1033 return ret;
1034}
1035
David Dai04ce4202016-09-26 16:24:13 -07001036static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib,
1037 uint64_t cur_ab, int src_idx, int active_only)
1038{
1039 struct device *next_dev = NULL;
1040 struct link_node *lnode = NULL;
1041 struct msm_bus_node_device_type *dev_info = NULL;
1042 int ret = 0;
1043 int cur_idx = src_idx;
1044 int next_idx;
1045
1046 /* Update the current path to zero out all request from
1047 * this cient on all paths
1048 */
1049 if (!src_dev) {
1050 MSM_BUS_ERR("%s: Can't find source device", __func__);
1051 ret = -ENODEV;
1052 goto exit_remove_path;
1053 }
1054
1055 ret = update_path(src_dev, dst, 0, 0, 0, 0, cur_ib, cur_ab, src_idx,
1056 active_only);
1057 if (ret) {
1058 MSM_BUS_ERR("%s: Error zeroing out path ctx %d",
1059 __func__, ACTIVE_CTX);
1060 goto exit_remove_path;
1061 }
1062
1063 next_dev = src_dev;
1064
1065 while (next_dev) {
1066 dev_info = to_msm_bus_node(next_dev);
1067 lnode = &dev_info->lnode_list[cur_idx];
1068 next_idx = lnode->next;
1069 next_dev = lnode->next_dev;
1070 remove_lnode(dev_info, cur_idx);
1071 cur_idx = next_idx;
1072 }
1073
1074exit_remove_path:
1075 return ret;
1076}
1077
1078static void getpath_debug(int src, int curr, int active_only)
1079{
1080 struct device *dev_node;
1081 struct device *dev_it;
1082 unsigned int hop = 1;
1083 int idx;
1084 struct msm_bus_node_device_type *devinfo;
1085 int i;
1086
1087 dev_node = bus_find_device(&msm_bus_type, NULL,
1088 (void *) &src,
1089 msm_bus_device_match_adhoc);
1090
1091 if (!dev_node) {
1092 MSM_BUS_ERR("SRC NOT FOUND %d", src);
1093 return;
1094 }
1095
1096 idx = curr;
1097 devinfo = to_msm_bus_node(dev_node);
1098 dev_it = dev_node;
1099
1100 MSM_BUS_ERR("Route list Src %d", src);
1101 while (dev_it) {
1102 struct msm_bus_node_device_type *busdev =
1103 to_msm_bus_node(devinfo->node_info->bus_device);
1104
1105 MSM_BUS_ERR("Hop[%d] at Device %d ctx %d", hop,
1106 devinfo->node_info->id, active_only);
1107
1108 for (i = 0; i < NUM_CTX; i++) {
1109 MSM_BUS_ERR("dev info sel ib %llu",
1110 devinfo->node_bw[i].cur_clk_hz);
1111 MSM_BUS_ERR("dev info sel ab %llu",
1112 devinfo->node_bw[i].sum_ab);
1113 }
1114
1115 dev_it = devinfo->lnode_list[idx].next_dev;
1116 idx = devinfo->lnode_list[idx].next;
1117 if (dev_it)
1118 devinfo = to_msm_bus_node(dev_it);
1119
1120 MSM_BUS_ERR("Bus Device %d", busdev->node_info->id);
1121 MSM_BUS_ERR("Bus Clock %llu", busdev->clk[active_only].rate);
1122
1123 if (idx < 0)
1124 break;
1125 hop++;
1126 }
1127}
1128
1129static void unregister_client_adhoc(uint32_t cl)
1130{
1131 int i;
1132 struct msm_bus_scale_pdata *pdata;
1133 int lnode, src, curr, dest;
1134 uint64_t cur_clk, cur_bw;
1135 struct msm_bus_client *client;
1136 struct device *src_dev;
1137
1138 rt_mutex_lock(&msm_bus_adhoc_lock);
1139 if (!cl) {
1140 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
1141 __func__);
1142 goto exit_unregister_client;
1143 }
1144 client = handle_list.cl_list[cl];
1145 pdata = client->pdata;
1146 if (!pdata) {
1147 MSM_BUS_ERR("%s: Null pdata passed to unregister\n",
1148 __func__);
1149 goto exit_unregister_client;
1150 }
1151
1152 curr = client->curr;
1153 if (curr >= pdata->num_usecases) {
1154 MSM_BUS_ERR("Invalid index Defaulting curr to 0");
1155 curr = 0;
1156 }
1157
David Dai04ce4202016-09-26 16:24:13 -07001158 for (i = 0; i < pdata->usecase->num_paths; i++) {
1159 src = client->pdata->usecase[curr].vectors[i].src;
1160 dest = client->pdata->usecase[curr].vectors[i].dst;
1161
1162 lnode = client->src_pnode[i];
1163 src_dev = client->src_devs[i];
1164 cur_clk = client->pdata->usecase[curr].vectors[i].ib;
1165 cur_bw = client->pdata->usecase[curr].vectors[i].ab;
1166 remove_path(src_dev, dest, cur_clk, cur_bw, lnode,
1167 pdata->active_only);
1168 }
1169 commit_data();
1170 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl);
1171 kfree(client->src_pnode);
1172 kfree(client->src_devs);
1173 kfree(client);
1174 handle_list.cl_list[cl] = NULL;
1175exit_unregister_client:
1176 rt_mutex_unlock(&msm_bus_adhoc_lock);
1177}
1178
1179static int alloc_handle_lst(int size)
1180{
1181 int ret = 0;
1182 struct msm_bus_client **t_cl_list;
1183
1184 if (!handle_list.num_entries) {
1185 t_cl_list = kzalloc(sizeof(struct msm_bus_client *)
1186 * NUM_CL_HANDLES, GFP_KERNEL);
1187 if (ZERO_OR_NULL_PTR(t_cl_list)) {
1188 ret = -ENOMEM;
1189 MSM_BUS_ERR("%s: Failed to allocate handles list",
1190 __func__);
1191 goto exit_alloc_handle_lst;
1192 }
1193 handle_list.cl_list = t_cl_list;
1194 handle_list.num_entries += NUM_CL_HANDLES;
1195 } else {
1196 t_cl_list = krealloc(handle_list.cl_list,
1197 sizeof(struct msm_bus_client *) *
1198 (handle_list.num_entries + NUM_CL_HANDLES),
1199 GFP_KERNEL);
1200 if (ZERO_OR_NULL_PTR(t_cl_list)) {
1201 ret = -ENOMEM;
1202 MSM_BUS_ERR("%s: Failed to allocate handles list",
1203 __func__);
1204 goto exit_alloc_handle_lst;
1205 }
1206
1207 handle_list.cl_list = t_cl_list;
1208 memset(&handle_list.cl_list[handle_list.num_entries], 0,
1209 NUM_CL_HANDLES * sizeof(struct msm_bus_client *));
1210 handle_list.num_entries += NUM_CL_HANDLES;
1211 }
1212exit_alloc_handle_lst:
1213 return ret;
1214}
1215
1216static uint32_t gen_handle(struct msm_bus_client *client)
1217{
1218 uint32_t handle = 0;
1219 int i;
1220 int ret = 0;
1221
1222 for (i = 0; i < handle_list.num_entries; i++) {
1223 if (i && !handle_list.cl_list[i]) {
1224 handle = i;
1225 break;
1226 }
1227 }
1228
1229 if (!handle) {
1230 ret = alloc_handle_lst(NUM_CL_HANDLES);
1231
1232 if (ret) {
1233 MSM_BUS_ERR("%s: Failed to allocate handle list",
1234 __func__);
1235 goto exit_gen_handle;
1236 }
1237 handle = i + 1;
1238 }
1239 handle_list.cl_list[handle] = client;
1240exit_gen_handle:
1241 return handle;
1242}
1243
1244static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata)
1245{
1246 int src, dest;
1247 int i;
1248 struct msm_bus_client *client = NULL;
1249 int *lnode;
1250 struct device *dev;
1251 uint32_t handle = 0;
1252
1253 rt_mutex_lock(&msm_bus_adhoc_lock);
1254 client = kzalloc(sizeof(struct msm_bus_client), GFP_KERNEL);
1255 if (!client) {
1256 MSM_BUS_ERR("%s: Error allocating client data", __func__);
1257 goto exit_register_client;
1258 }
1259 client->pdata = pdata;
1260
David Daibee66232017-03-31 19:05:39 -07001261 if (pdata->alc) {
1262 client->curr = -1;
1263 lnode = kzalloc(sizeof(int), GFP_KERNEL);
1264
1265 if (ZERO_OR_NULL_PTR(lnode)) {
1266 MSM_BUS_ERR("%s: Error allocating lnode!", __func__);
1267 goto exit_lnode_malloc_fail;
1268 }
1269 client->src_pnode = lnode;
1270
1271 client->src_devs = kzalloc(sizeof(struct device *),
1272 GFP_KERNEL);
1273 if (IS_ERR_OR_NULL(client->src_devs)) {
1274 MSM_BUS_ERR("%s: Error allocating src_dev!", __func__);
1275 goto exit_src_dev_malloc_fail;
1276 }
1277 src = MSM_BUS_MAS_ALC;
1278 dev = bus_find_device(&msm_bus_type, NULL,
1279 (void *) &src,
1280 msm_bus_device_match_adhoc);
1281 if (IS_ERR_OR_NULL(dev)) {
1282 MSM_BUS_ERR("%s:Failed to find alc device",
1283 __func__);
1284 goto exit_invalid_data;
1285 }
1286 gen_lnode(dev, MSM_BUS_MAS_ALC, 0, pdata->name);
1287 bcm_add_bus_req(dev);
1288
1289 client->src_devs[0] = dev;
1290
1291 handle = gen_handle(client);
1292 goto exit_register_client;
1293 }
1294
David Dai04ce4202016-09-26 16:24:13 -07001295 lnode = kcalloc(pdata->usecase->num_paths, sizeof(int), GFP_KERNEL);
1296 if (ZERO_OR_NULL_PTR(lnode)) {
1297 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
1298 goto exit_lnode_malloc_fail;
1299 }
1300 client->src_pnode = lnode;
1301
1302 client->src_devs = kcalloc(pdata->usecase->num_paths,
1303 sizeof(struct device *), GFP_KERNEL);
1304 if (IS_ERR_OR_NULL(client->src_devs)) {
1305 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
1306 goto exit_src_dev_malloc_fail;
1307 }
1308 client->curr = -1;
1309
1310 for (i = 0; i < pdata->usecase->num_paths; i++) {
1311 src = pdata->usecase->vectors[i].src;
1312 dest = pdata->usecase->vectors[i].dst;
1313
1314 if ((src < 0) || (dest < 0)) {
1315 MSM_BUS_ERR("%s:Invalid src/dst.src %d dest %d",
1316 __func__, src, dest);
1317 goto exit_invalid_data;
1318 }
1319 dev = bus_find_device(&msm_bus_type, NULL,
1320 (void *) &src,
1321 msm_bus_device_match_adhoc);
1322 if (IS_ERR_OR_NULL(dev)) {
1323 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1324 __func__, src, dest);
1325 goto exit_invalid_data;
1326 }
1327 client->src_devs[i] = dev;
1328
1329 MSM_BUS_ERR("%s:find path.src %d dest %d",
1330 __func__, src, dest);
1331
1332 lnode[i] = getpath(dev, dest, client->pdata->name);
1333 if (lnode[i] < 0) {
1334 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1335 __func__, src, dest);
1336 goto exit_invalid_data;
1337 }
1338 }
1339
1340 handle = gen_handle(client);
1341 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_REGISTER,
1342 handle);
1343 MSM_BUS_ERR("%s:Client handle %d %s", __func__, handle,
1344 client->pdata->name);
1345 rt_mutex_unlock(&msm_bus_adhoc_lock);
1346 return handle;
1347exit_invalid_data:
1348 kfree(client->src_devs);
1349exit_src_dev_malloc_fail:
1350 kfree(lnode);
1351exit_lnode_malloc_fail:
1352 kfree(client);
1353exit_register_client:
1354 rt_mutex_unlock(&msm_bus_adhoc_lock);
1355 return handle;
1356}
1357
1358static int update_client_paths(struct msm_bus_client *client, bool log_trns,
1359 unsigned int idx)
1360{
1361 int lnode, src, dest, cur_idx;
1362 uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw;
1363 int i, ret = 0;
1364 struct msm_bus_scale_pdata *pdata;
1365 struct device *src_dev;
1366
1367 if (!client) {
1368 MSM_BUS_ERR("Client handle Null");
1369 ret = -ENXIO;
1370 goto exit_update_client_paths;
1371 }
1372
1373 pdata = client->pdata;
1374 if (!pdata) {
1375 MSM_BUS_ERR("Client pdata Null");
1376 ret = -ENXIO;
1377 goto exit_update_client_paths;
1378 }
1379
1380 cur_idx = client->curr;
1381 client->curr = idx;
1382 for (i = 0; i < pdata->usecase->num_paths; i++) {
1383 src = pdata->usecase[idx].vectors[i].src;
1384 dest = pdata->usecase[idx].vectors[i].dst;
1385
1386 lnode = client->src_pnode[i];
1387 src_dev = client->src_devs[i];
1388 req_clk = client->pdata->usecase[idx].vectors[i].ib;
1389 req_bw = client->pdata->usecase[idx].vectors[i].ab;
1390 if (cur_idx < 0) {
1391 curr_clk = 0;
1392 curr_bw = 0;
1393 } else {
1394 curr_clk =
1395 client->pdata->usecase[cur_idx].vectors[i].ib;
1396 curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab;
1397 MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
1398 curr_bw, curr_clk);
1399 }
1400
1401 if (pdata->active_only) {
1402 slp_clk = 0;
1403 slp_bw = 0;
1404 } else {
1405 slp_clk = req_clk;
1406 slp_bw = req_bw;
David Dai0d014432016-11-10 12:57:44 -08001407 req_clk = 0;
1408 req_bw = 0;
David Dai04ce4202016-09-26 16:24:13 -07001409 }
1410
1411 ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk,
1412 slp_bw, curr_clk, curr_bw, lnode, pdata->active_only);
1413
1414 if (ret) {
1415 MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
1416 __func__, ret, pdata->active_only);
1417 goto exit_update_client_paths;
1418 }
1419
1420 if (log_trns)
1421 getpath_debug(src, lnode, pdata->active_only);
1422 }
1423 commit_data();
1424exit_update_client_paths:
1425 return ret;
1426}
1427
David Daibee66232017-03-31 19:05:39 -07001428static int update_client_alc(struct msm_bus_client *client, bool log_trns,
1429 unsigned int idx)
1430{
1431 int lnode, cur_idx;
1432 uint64_t req_idle_time, req_fal, dual_idle_time, dual_fal,
1433 cur_idle_time, cur_fal;
1434 int ret = 0;
1435 struct msm_bus_scale_pdata *pdata;
1436 struct device *src_dev;
1437
1438 if (!client) {
1439 MSM_BUS_ERR("Client handle Null");
1440 ret = -ENXIO;
1441 goto exit_update_client_alc;
1442 }
1443
1444 pdata = client->pdata;
1445 if (!pdata) {
1446 MSM_BUS_ERR("Client pdata Null");
1447 ret = -ENXIO;
1448 goto exit_update_client_alc;
1449 }
1450
1451 cur_idx = client->curr;
1452 client->curr = idx;
1453 req_fal = pdata->usecase_lat[idx].fal_ns;
1454 req_idle_time = pdata->usecase_lat[idx].idle_t_ns;
1455 lnode = client->src_pnode[0];
1456 src_dev = client->src_devs[0];
1457
1458 if (pdata->active_only) {
1459 dual_fal = 0;
1460 dual_idle_time = 0;
1461 } else {
1462 dual_fal = req_fal;
1463 dual_idle_time = req_idle_time;
1464 }
1465
1466 ret = update_alc_vote(src_dev, req_fal, req_idle_time, dual_fal,
1467 dual_idle_time, cur_fal, cur_idle_time, lnode,
1468 pdata->active_only);
1469
1470 if (ret) {
1471 MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
1472 __func__, ret, pdata->active_only);
1473 goto exit_update_client_alc;
1474 }
1475 commit_data();
1476exit_update_client_alc:
1477 return ret;
1478}
1479
David Dai9d66f3f2016-11-23 15:33:06 -08001480static int query_usecase(struct msm_bus_client *client, bool log_trns,
1481 unsigned int idx,
1482 struct msm_bus_tcs_usecase *tcs_usecase)
1483{
1484 int lnode, src, dest, cur_idx;
David Dai489b0d72017-03-14 13:05:01 -07001485 uint64_t req_clk, req_bw, curr_clk, curr_bw;
David Dai9d66f3f2016-11-23 15:33:06 -08001486 int i, ret = 0;
1487 struct msm_bus_scale_pdata *pdata;
1488 struct device *src_dev;
1489 struct msm_bus_node_device_type *node = NULL;
1490 struct msm_bus_node_device_type *node_tmp = NULL;
1491
1492 if (!client) {
1493 MSM_BUS_ERR("Client handle Null");
1494 ret = -ENXIO;
1495 goto exit_query_usecase;
1496 }
1497
1498 pdata = client->pdata;
1499 if (!pdata) {
1500 MSM_BUS_ERR("Client pdata Null");
1501 ret = -ENXIO;
1502 goto exit_query_usecase;
1503 }
1504
1505 cur_idx = client->curr;
1506 client->curr = idx;
1507 for (i = 0; i < pdata->usecase->num_paths; i++) {
1508 src = pdata->usecase[idx].vectors[i].src;
1509 dest = pdata->usecase[idx].vectors[i].dst;
1510
1511 lnode = client->src_pnode[i];
1512 src_dev = client->src_devs[i];
1513 req_clk = client->pdata->usecase[idx].vectors[i].ib;
1514 req_bw = client->pdata->usecase[idx].vectors[i].ab;
1515 if (cur_idx < 0) {
1516 curr_clk = 0;
1517 curr_bw = 0;
1518 } else {
1519 curr_clk =
1520 client->pdata->usecase[cur_idx].vectors[i].ib;
1521 curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab;
1522 MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
1523 curr_bw, curr_clk);
1524 }
1525
David Dai489b0d72017-03-14 13:05:01 -07001526 ret = query_path(src_dev, dest, req_clk, req_bw, 0,
1527 0, curr_clk, curr_bw, lnode);
David Dai9d66f3f2016-11-23 15:33:06 -08001528
1529 if (ret) {
1530 MSM_BUS_ERR("%s: Query path failed! %d ctx %d\n",
1531 __func__, ret, pdata->active_only);
1532 goto exit_query_usecase;
1533 }
1534 }
1535 msm_bus_query_gen(&query_list, tcs_usecase);
1536 INIT_LIST_HEAD(&query_list);
1537
1538 for (i = 0; i < pdata->usecase->num_paths; i++) {
1539 src = pdata->usecase[idx].vectors[i].src;
1540 dest = pdata->usecase[idx].vectors[i].dst;
1541
1542 lnode = client->src_pnode[i];
1543 src_dev = client->src_devs[i];
1544
1545 ret = query_path(src_dev, dest, 0, 0, 0, 0,
1546 curr_clk, curr_bw, lnode);
1547
1548 if (ret) {
1549 MSM_BUS_ERR("%s: Clear query path failed! %d ctx %d\n",
1550 __func__, ret, pdata->active_only);
1551 goto exit_query_usecase;
1552 }
1553 }
1554
1555 list_for_each_entry_safe(node, node_tmp, &query_list, query_link) {
1556 node->query_dirty = false;
1557 list_del_init(&node->query_link);
1558 }
1559
1560 INIT_LIST_HEAD(&query_list);
1561
1562exit_query_usecase:
1563 return ret;
1564}
1565
David Dai04ce4202016-09-26 16:24:13 -07001566static int update_context(uint32_t cl, bool active_only,
1567 unsigned int ctx_idx)
1568{
1569 int ret = 0;
1570 struct msm_bus_scale_pdata *pdata;
1571 struct msm_bus_client *client;
1572
1573 rt_mutex_lock(&msm_bus_adhoc_lock);
1574 if (!cl) {
1575 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1576 ret = -ENXIO;
1577 goto exit_update_context;
1578 }
1579
1580 client = handle_list.cl_list[cl];
1581 if (!client) {
1582 ret = -ENXIO;
1583 goto exit_update_context;
1584 }
1585
1586 pdata = client->pdata;
1587 if (!pdata) {
1588 ret = -ENXIO;
1589 goto exit_update_context;
1590 }
1591 if (pdata->active_only == active_only) {
1592 MSM_BUS_ERR("No change in context(%d==%d), skip\n",
1593 pdata->active_only, active_only);
1594 ret = -ENXIO;
1595 goto exit_update_context;
1596 }
1597
1598 if (ctx_idx >= pdata->num_usecases) {
1599 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1600 cl, ctx_idx);
1601 ret = -ENXIO;
1602 goto exit_update_context;
1603 }
1604
1605 pdata->active_only = active_only;
1606
1607 msm_bus_dbg_client_data(client->pdata, ctx_idx, cl);
1608 ret = update_client_paths(client, false, ctx_idx);
1609 if (ret) {
1610 pr_err("%s: Err updating path\n", __func__);
1611 goto exit_update_context;
1612 }
1613
1614// trace_bus_update_request_end(pdata->name);
1615
1616exit_update_context:
1617 rt_mutex_unlock(&msm_bus_adhoc_lock);
1618 return ret;
1619}
1620
1621static int update_request_adhoc(uint32_t cl, unsigned int index)
1622{
1623 int ret = 0;
1624 struct msm_bus_scale_pdata *pdata;
1625 struct msm_bus_client *client;
1626 const char *test_cl = "Null";
1627 bool log_transaction = false;
1628
1629 rt_mutex_lock(&msm_bus_adhoc_lock);
1630
1631 if (!cl) {
1632 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1633 ret = -ENXIO;
1634 goto exit_update_request;
1635 }
1636
1637 client = handle_list.cl_list[cl];
1638 if (!client) {
1639 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1640 ret = -ENXIO;
1641 goto exit_update_request;
1642 }
1643
1644 pdata = client->pdata;
1645 if (!pdata) {
1646 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1647 __func__);
1648 ret = -ENXIO;
1649 goto exit_update_request;
1650 }
1651
1652 if (index >= pdata->num_usecases) {
1653 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1654 cl, index);
1655 ret = -ENXIO;
1656 goto exit_update_request;
1657 }
1658
1659 if (client->curr == index) {
1660 MSM_BUS_DBG("%s: Not updating client request idx %d unchanged",
1661 __func__, index);
1662 goto exit_update_request;
1663 }
1664
1665 if (!strcmp(test_cl, pdata->name))
1666 log_transaction = true;
1667
1668 MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
1669 cl, index, client->curr, client->pdata->usecase->num_paths);
David Daibee66232017-03-31 19:05:39 -07001670
1671 if (pdata->alc)
1672 ret = update_client_alc(client, log_transaction, index);
1673 else {
1674 msm_bus_dbg_client_data(client->pdata, index, cl);
1675 ret = update_client_paths(client, log_transaction, index);
1676 }
David Dai04ce4202016-09-26 16:24:13 -07001677 if (ret) {
1678 pr_err("%s: Err updating path\n", __func__);
1679 goto exit_update_request;
1680 }
1681
1682// trace_bus_update_request_end(pdata->name);
1683
1684exit_update_request:
1685 rt_mutex_unlock(&msm_bus_adhoc_lock);
1686 return ret;
1687}
1688
David Dai9d66f3f2016-11-23 15:33:06 -08001689static int query_client_usecase(struct msm_bus_tcs_usecase *tcs_usecase,
1690 uint32_t cl, unsigned int index)
1691{
1692 int ret = 0;
1693 struct msm_bus_scale_pdata *pdata;
1694 struct msm_bus_client *client;
1695 const char *test_cl = "Null";
1696 bool log_transaction = false;
1697
1698 rt_mutex_lock(&msm_bus_adhoc_lock);
1699
1700 if (!cl) {
1701 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1702 ret = -ENXIO;
1703 goto exit_query_client_usecase;
1704 }
1705
1706 client = handle_list.cl_list[cl];
1707 if (!client) {
1708 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1709 ret = -ENXIO;
1710 goto exit_query_client_usecase;
1711 }
1712
1713 pdata = client->pdata;
1714 if (!pdata) {
1715 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1716 __func__);
1717 ret = -ENXIO;
1718 goto exit_query_client_usecase;
1719 }
1720
1721 if (index >= pdata->num_usecases) {
1722 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1723 cl, index);
1724 ret = -ENXIO;
1725 goto exit_query_client_usecase;
1726 }
1727
1728 if (!strcmp(test_cl, pdata->name))
1729 log_transaction = true;
1730
1731 MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
1732 cl, index, client->curr, client->pdata->usecase->num_paths);
1733 ret = query_usecase(client, log_transaction, index, tcs_usecase);
1734 if (ret) {
1735 pr_err("%s: Err updating path\n", __func__);
1736 goto exit_query_client_usecase;
1737 }
1738
1739// trace_bus_update_request_end(pdata->name);
1740
1741exit_query_client_usecase:
1742 rt_mutex_unlock(&msm_bus_adhoc_lock);
1743 return ret;
1744}
1745
1746static int query_client_usecase_all(struct msm_bus_tcs_handle *tcs_handle,
1747 uint32_t cl)
1748{
1749 int ret = 0;
1750 struct msm_bus_scale_pdata *pdata;
1751 struct msm_bus_client *client;
1752 const char *test_cl = "Null";
1753 bool log_transaction = false;
1754 int i = 0;
1755
1756 rt_mutex_lock(&msm_bus_adhoc_lock);
1757
1758 if (!cl) {
1759 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1760 ret = -ENXIO;
1761 goto exit_query_client_usecase_all;
1762 }
1763
1764 client = handle_list.cl_list[cl];
1765 if (!client) {
1766 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1767 ret = -ENXIO;
1768 goto exit_query_client_usecase_all;
1769 }
1770
1771 pdata = client->pdata;
1772 if (!pdata) {
1773 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1774 __func__);
1775 ret = -ENXIO;
1776 goto exit_query_client_usecase_all;
1777 }
1778
1779 if (!strcmp(test_cl, pdata->name))
1780 log_transaction = true;
1781
1782 MSM_BUS_ERR("%s: query_start", __func__);
1783 for (i = 0; i < pdata->num_usecases; i++)
1784 query_usecase(client, log_transaction, i,
1785 &tcs_handle->usecases[i]);
1786 tcs_handle->num_usecases = pdata->num_usecases;
1787
1788 if (ret) {
1789 pr_err("%s: Err updating path\n", __func__);
1790 goto exit_query_client_usecase_all;
1791 }
1792
1793// trace_bus_update_request_end(pdata->name);
1794
1795exit_query_client_usecase_all:
1796 rt_mutex_unlock(&msm_bus_adhoc_lock);
1797 return ret;
1798}
1799
David Dai04ce4202016-09-26 16:24:13 -07001800static void free_cl_mem(struct msm_bus_client_handle *cl)
1801{
1802 if (cl) {
1803 kfree(cl->name);
1804 kfree(cl);
1805 cl = NULL;
1806 }
1807}
1808
1809static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
1810{
1811 int ret = 0;
1812 char *test_cl = "test-client";
1813 bool log_transaction = false;
1814 u64 slp_ib, slp_ab;
1815
1816 rt_mutex_lock(&msm_bus_adhoc_lock);
1817
1818 if (!cl) {
1819 MSM_BUS_ERR("%s: Invalid client handle %p", __func__, cl);
1820 ret = -ENXIO;
1821 goto exit_update_request;
1822 }
1823
1824 if (!strcmp(test_cl, cl->name))
1825 log_transaction = true;
1826
1827 msm_bus_dbg_rec_transaction(cl, ab, ib);
1828
1829 if ((cl->cur_act_ib == ib) && (cl->cur_act_ab == ab)) {
1830 MSM_BUS_DBG("%s:no change in request", cl->name);
1831 goto exit_update_request;
1832 }
1833
1834 if (cl->active_only) {
1835 slp_ib = 0;
1836 slp_ab = 0;
1837 } else {
1838 slp_ib = ib;
1839 slp_ab = ab;
1840 }
1841
1842 ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab,
1843 cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only);
1844
1845 if (ret) {
1846 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1847 __func__, ret, cl->active_only);
1848 goto exit_update_request;
1849 }
1850
1851 commit_data();
1852 cl->cur_act_ib = ib;
1853 cl->cur_act_ab = ab;
1854 cl->cur_slp_ib = slp_ib;
1855 cl->cur_slp_ab = slp_ab;
1856
1857 if (log_transaction)
1858 getpath_debug(cl->mas, cl->first_hop, cl->active_only);
1859// trace_bus_update_request_end(cl->name);
1860exit_update_request:
1861 rt_mutex_unlock(&msm_bus_adhoc_lock);
1862
1863 return ret;
1864}
1865
1866static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
1867 u64 act_ib, u64 slp_ib, u64 slp_ab)
1868{
1869 int ret = 0;
1870
1871 rt_mutex_lock(&msm_bus_adhoc_lock);
1872 if (!cl) {
1873 MSM_BUS_ERR("Invalid client handle %p", cl);
1874 ret = -ENXIO;
1875 goto exit_change_context;
1876 }
1877
1878 if ((cl->cur_act_ib == act_ib) &&
1879 (cl->cur_act_ab == act_ab) &&
1880 (cl->cur_slp_ib == slp_ib) &&
1881 (cl->cur_slp_ab == slp_ab)) {
1882 MSM_BUS_ERR("No change in vote");
1883 goto exit_change_context;
1884 }
1885
1886 if (!slp_ab && !slp_ib)
1887 cl->active_only = true;
1888 msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib);
1889 ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab,
1890 cl->cur_act_ab, cl->cur_act_ab, cl->first_hop,
1891 cl->active_only);
1892 if (ret) {
1893 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1894 __func__, ret, cl->active_only);
1895 goto exit_change_context;
1896 }
1897 commit_data();
1898 cl->cur_act_ib = act_ib;
1899 cl->cur_act_ab = act_ab;
1900 cl->cur_slp_ib = slp_ib;
1901 cl->cur_slp_ab = slp_ab;
1902// trace_bus_update_request_end(cl->name);
1903exit_change_context:
1904 rt_mutex_unlock(&msm_bus_adhoc_lock);
1905 return ret;
1906}
1907
1908static void unregister_adhoc(struct msm_bus_client_handle *cl)
1909{
1910 rt_mutex_lock(&msm_bus_adhoc_lock);
1911 if (!cl) {
1912 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
1913 __func__);
1914 goto exit_unregister_client;
1915 }
1916
1917 MSM_BUS_DBG("%s: Unregistering client %p", __func__, cl);
1918
1919 remove_path(cl->mas_dev, cl->slv, cl->cur_act_ib, cl->cur_act_ab,
1920 cl->first_hop, cl->active_only);
1921 commit_data();
1922 msm_bus_dbg_remove_client(cl);
1923 kfree(cl);
David Dai0d014432016-11-10 12:57:44 -08001924 MSM_BUS_DBG("%s: Unregistered client", __func__);
David Dai04ce4202016-09-26 16:24:13 -07001925exit_unregister_client:
1926 rt_mutex_unlock(&msm_bus_adhoc_lock);
1927}
1928
1929static struct msm_bus_client_handle*
1930register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only)
1931{
1932 struct msm_bus_client_handle *client = NULL;
1933 int len = 0;
1934
1935 rt_mutex_lock(&msm_bus_adhoc_lock);
1936
1937 if (!(mas && slv && name)) {
1938 pr_err("%s: Error: src dst name num_paths are required",
1939 __func__);
1940 goto exit_register;
1941 }
1942
1943 client = kzalloc(sizeof(struct msm_bus_client_handle), GFP_KERNEL);
1944 if (!client) {
1945 MSM_BUS_ERR("%s: Error allocating client data", __func__);
1946 goto exit_register;
1947 }
1948
1949 len = strnlen(name, MAX_STR_CL);
1950 client->name = kzalloc((len + 1), GFP_KERNEL);
1951 if (!client->name) {
1952 MSM_BUS_ERR("%s: Error allocating client name buf", __func__);
1953 free_cl_mem(client);
1954 goto exit_register;
1955 }
1956 strlcpy(client->name, name, MAX_STR_CL);
1957 client->active_only = active_only;
1958
1959 client->mas = mas;
1960 client->slv = slv;
1961
1962 client->mas_dev = bus_find_device(&msm_bus_type, NULL,
1963 (void *) &mas,
1964 msm_bus_device_match_adhoc);
1965 if (IS_ERR_OR_NULL(client->mas_dev)) {
1966 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1967 __func__, client->mas, client->slv);
1968 free_cl_mem(client);
1969 goto exit_register;
1970 }
1971
1972 client->first_hop = getpath(client->mas_dev, client->slv, client->name);
1973 if (client->first_hop < 0) {
1974 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1975 __func__, client->mas, client->slv);
1976 free_cl_mem(client);
1977 goto exit_register;
1978 }
1979
1980 MSM_BUS_DBG("%s:Client handle %p %s", __func__, client,
1981 client->name);
1982 msm_bus_dbg_add_client(client);
1983exit_register:
1984 rt_mutex_unlock(&msm_bus_adhoc_lock);
1985 return client;
1986}
1987/**
1988 * msm_bus_arb_setops_adhoc() : Setup the bus arbitration ops
1989 * @ arb_ops: pointer to the arb ops.
1990 */
1991void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops)
1992{
1993 arb_ops->register_client = register_client_adhoc;
1994 arb_ops->update_request = update_request_adhoc;
1995 arb_ops->unregister_client = unregister_client_adhoc;
1996 arb_ops->update_context = update_context;
1997
1998 arb_ops->register_cl = register_adhoc;
1999 arb_ops->unregister = unregister_adhoc;
2000 arb_ops->update_bw = update_bw_adhoc;
2001 arb_ops->update_bw_context = update_bw_context;
David Dai9d66f3f2016-11-23 15:33:06 -08002002 arb_ops->query_usecase = query_client_usecase;
2003 arb_ops->query_usecase_all = query_client_usecase_all;
David Dai04ce4202016-09-26 16:24:13 -07002004}