blob: 8cd2fd6d4f13a62aed6272a40aa5d4f1e7268717 [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
27struct bus_search_type {
28 struct list_head link;
29 struct list_head node_list;
30};
31
32struct handle_type {
33 int num_entries;
34 struct msm_bus_client **cl_list;
35};
36
37static struct handle_type handle_list;
38static LIST_HEAD(input_list);
39static LIST_HEAD(apply_list);
40static LIST_HEAD(commit_list);
41
42DEFINE_RT_MUTEX(msm_bus_adhoc_lock);
43
44static bool chk_bl_list(struct list_head *black_list, unsigned int id)
45{
46 struct msm_bus_node_device_type *bus_node = NULL;
47
48 list_for_each_entry(bus_node, black_list, link) {
49 if (bus_node->node_info->id == id)
50 return true;
51 }
52 return false;
53}
54
55static void copy_remaining_nodes(struct list_head *edge_list, struct list_head
56 *traverse_list, struct list_head *route_list)
57{
58 struct bus_search_type *search_node;
59
60 if (list_empty(edge_list) && list_empty(traverse_list))
61 return;
62
63 search_node = kzalloc(sizeof(struct bus_search_type), GFP_KERNEL);
64 INIT_LIST_HEAD(&search_node->node_list);
65 list_splice_init(edge_list, traverse_list);
66 list_splice_init(traverse_list, &search_node->node_list);
67 list_add_tail(&search_node->link, route_list);
68}
69
70/*
71 * Duplicate instantiaion from msm_bus_arb.c. Todo there needs to be a
72 * "util" file for these common func/macros.
73 *
74 */
75uint64_t msm_bus_div64(unsigned int w, uint64_t bw)
76{
77 uint64_t *b = &bw;
78
79 if ((bw > 0) && (bw < w))
80 return 1;
81
82 switch (w) {
83 case 0:
84 WARN(1, "AXI: Divide by 0 attempted\n");
85 case 1: return bw;
86 case 2: return (bw >> 1);
87 case 4: return (bw >> 2);
88 case 8: return (bw >> 3);
89 case 16: return (bw >> 4);
90 case 32: return (bw >> 5);
91 }
92
93 do_div(*b, w);
94 return *b;
95}
96
97int msm_bus_device_match_adhoc(struct device *dev, void *id)
98{
99 int ret = 0;
100 struct msm_bus_node_device_type *bnode = to_msm_bus_node(dev);
101
102 if (bnode)
103 ret = (bnode->node_info->id == *(unsigned int *)id);
104 else
105 ret = 0;
106
107 return ret;
108}
109
110static void bcm_add_bus_req(struct device *dev)
111{
112 struct msm_bus_node_device_type *cur_dev = NULL;
113 struct msm_bus_node_device_type *bcm_dev = NULL;
114 struct link_node *lnode;
115 int lnode_idx = -1;
116 int max_num_lnodes = 0;
117 int i;
118
119 cur_dev = to_msm_bus_node(dev);
120 if (!cur_dev) {
121 MSM_BUS_ERR("%s: Null device ptr", __func__);
122 goto exit_bcm_add_bus_req;
123 }
124
125 if (!cur_dev->node_info->num_bcm_devs)
126 goto exit_bcm_add_bus_req;
127
128 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
129 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
130 max_num_lnodes = bcm_dev->bcmdev->num_bus_devs;
131
132 if (!bcm_dev->num_lnodes) {
133 bcm_dev->lnode_list = devm_kzalloc(dev,
134 sizeof(struct link_node) * max_num_lnodes,
135 GFP_KERNEL);
136 if (!bcm_dev->lnode_list)
137 goto exit_bcm_add_bus_req;
138
139 lnode = bcm_dev->lnode_list;
140 bcm_dev->num_lnodes = max_num_lnodes;
141 lnode_idx = 0;
142 } else {
143 int i;
144
145 for (i = 0; i < bcm_dev->num_lnodes; i++) {
146 if (!bcm_dev->lnode_list[i].in_use)
147 break;
148 }
149
150 if (i < bcm_dev->num_lnodes) {
151 lnode = &bcm_dev->lnode_list[i];
152 lnode_idx = i;
153 } else {
154 struct link_node *realloc_list;
155 size_t cur_size = sizeof(struct link_node) *
156 bcm_dev->num_lnodes;
157
158 bcm_dev->num_lnodes += NUM_LNODES;
159 realloc_list = msm_bus_realloc_devmem(
160 dev,
161 bcm_dev->lnode_list,
162 cur_size,
163 sizeof(struct link_node) *
164 bcm_dev->num_lnodes,
165 GFP_KERNEL);
166
167 if (!realloc_list)
168 goto exit_bcm_add_bus_req;
169
170 bcm_dev->lnode_list = realloc_list;
171 lnode = &bcm_dev->lnode_list[i];
172 lnode_idx = i;
173 }
174 }
175
176 lnode->in_use = 1;
177 lnode->bus_dev_id = cur_dev->node_info->id;
178 cur_dev->node_info->bcm_req_idx = lnode_idx;
179 memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
180 memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
181 MSM_BUS_ERR("%s: Added %d entry to bcm %d @ %d\n", __func__,
182 lnode->bus_dev_id, bcm_dev->node_info->id, lnode_idx);
183 }
184
185exit_bcm_add_bus_req:
186 return;
187}
188
189static int gen_lnode(struct device *dev,
190 int next_hop, int prev_idx, const char *cl_name)
191{
192 struct link_node *lnode;
193 struct msm_bus_node_device_type *cur_dev = NULL;
194 int lnode_idx = -1;
195
196 if (!dev)
197 goto exit_gen_lnode;
198
199 cur_dev = to_msm_bus_node(dev);
200 if (!cur_dev) {
201 MSM_BUS_ERR("%s: Null device ptr", __func__);
202 goto exit_gen_lnode;
203 }
204
205 if (!cur_dev->num_lnodes) {
206 cur_dev->lnode_list = devm_kzalloc(dev,
207 sizeof(struct link_node) * NUM_LNODES,
208 GFP_KERNEL);
209 if (!cur_dev->lnode_list)
210 goto exit_gen_lnode;
211
212 lnode = cur_dev->lnode_list;
213 cur_dev->num_lnodes = NUM_LNODES;
214 lnode_idx = 0;
215 } else {
216 int i;
217
218 for (i = 0; i < cur_dev->num_lnodes; i++) {
219 if (!cur_dev->lnode_list[i].in_use)
220 break;
221 }
222
223 if (i < cur_dev->num_lnodes) {
224 lnode = &cur_dev->lnode_list[i];
225 lnode_idx = i;
226 } else {
227 struct link_node *realloc_list;
228 size_t cur_size = sizeof(struct link_node) *
229 cur_dev->num_lnodes;
230
231 cur_dev->num_lnodes += NUM_LNODES;
232 realloc_list = msm_bus_realloc_devmem(
233 dev,
234 cur_dev->lnode_list,
235 cur_size,
236 sizeof(struct link_node) *
237 cur_dev->num_lnodes, GFP_KERNEL);
238
239 if (!realloc_list)
240 goto exit_gen_lnode;
241
242 cur_dev->lnode_list = realloc_list;
243 lnode = &cur_dev->lnode_list[i];
244 lnode_idx = i;
245 }
246 }
247
248 lnode->in_use = 1;
249 lnode->cl_name = cl_name;
250 if (next_hop == cur_dev->node_info->id) {
251 lnode->next = -1;
252 lnode->next_dev = NULL;
253 } else {
254 lnode->next = prev_idx;
255 lnode->next_dev = bus_find_device(&msm_bus_type, NULL,
256 (void *) &next_hop,
257 msm_bus_device_match_adhoc);
258 }
259
260 memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
261 memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
262
263exit_gen_lnode:
264 return lnode_idx;
265}
266
267static int remove_lnode(struct msm_bus_node_device_type *cur_dev,
268 int lnode_idx)
269{
270 int ret = 0;
271
272 if (!cur_dev) {
273 MSM_BUS_ERR("%s: Null device ptr", __func__);
274 ret = -ENODEV;
275 goto exit_remove_lnode;
276 }
277
278 if (lnode_idx != -1) {
279 if (!cur_dev->num_lnodes ||
280 (lnode_idx > (cur_dev->num_lnodes - 1))) {
281 MSM_BUS_ERR("%s: Invalid Idx %d, num_lnodes %d",
282 __func__, lnode_idx, cur_dev->num_lnodes);
283 ret = -ENODEV;
284 goto exit_remove_lnode;
285 }
286
287 cur_dev->lnode_list[lnode_idx].next = -1;
288 cur_dev->lnode_list[lnode_idx].next_dev = NULL;
289 cur_dev->lnode_list[lnode_idx].in_use = 0;
290 cur_dev->lnode_list[lnode_idx].cl_name = NULL;
291 }
292
293exit_remove_lnode:
294 return ret;
295}
296
297static int prune_path(struct list_head *route_list, int dest, int src,
298 struct list_head *black_list, int found,
299 const char *cl_name)
300{
301 struct bus_search_type *search_node, *temp_search_node;
302 struct msm_bus_node_device_type *bus_node;
303 struct list_head *bl_list;
304 struct list_head *temp_bl_list;
305 int search_dev_id = dest;
306 struct device *dest_dev = bus_find_device(&msm_bus_type, NULL,
307 (void *) &dest,
308 msm_bus_device_match_adhoc);
309 int lnode_hop = -1;
310
311 if (!found)
312 goto reset_links;
313
314 if (!dest_dev) {
315 MSM_BUS_ERR("%s: Can't find dest dev %d", __func__, dest);
316 goto exit_prune_path;
317 }
318 MSM_BUS_ERR("%s: dest dev %d", __func__, dest);
319
320 lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop, cl_name);
321 bcm_add_bus_req(dest_dev);
322
323 list_for_each_entry_reverse(search_node, route_list, link) {
324 list_for_each_entry(bus_node, &search_node->node_list, link) {
325 unsigned int i;
326
327 for (i = 0; i < bus_node->node_info->num_connections;
328 i++) {
329 if (bus_node->node_info->connections[i] ==
330 search_dev_id) {
331 dest_dev = bus_find_device(
332 &msm_bus_type,
333 NULL,
334 (void *)
335 &bus_node->node_info->
336 id,
337 msm_bus_device_match_adhoc);
338
339 if (!dest_dev) {
340 lnode_hop = -1;
341 goto reset_links;
342 }
343
344 lnode_hop = gen_lnode(dest_dev,
345 search_dev_id,
346 lnode_hop, cl_name);
347 bcm_add_bus_req(dest_dev);
348 search_dev_id =
349 bus_node->node_info->id;
350 break;
351 }
352 }
353 }
354 }
355reset_links:
356 list_for_each_entry_safe(search_node, temp_search_node, route_list,
357 link) {
358 list_for_each_entry(bus_node, &search_node->node_list, link)
359 bus_node->node_info->is_traversed = false;
360
361 list_del(&search_node->link);
362 kfree(search_node);
363 }
364
365 list_for_each_safe(bl_list, temp_bl_list, black_list)
366 list_del(bl_list);
367
368exit_prune_path:
369 return lnode_hop;
370}
371
372static void setup_bl_list(struct msm_bus_node_device_type *node,
373 struct list_head *black_list)
374{
375 unsigned int i;
376
377 for (i = 0; i < node->node_info->num_blist; i++) {
378 struct msm_bus_node_device_type *bdev;
379
380 bdev = to_msm_bus_node(node->node_info->black_connections[i]);
381 list_add_tail(&bdev->link, black_list);
382 }
383}
384
385static int getpath(struct device *src_dev, int dest, const char *cl_name)
386{
387 struct list_head traverse_list;
388 struct list_head edge_list;
389 struct list_head route_list;
390 struct list_head black_list;
391 struct msm_bus_node_device_type *src_node;
392 struct bus_search_type *search_node;
393 int found = 0;
394 int depth_index = 0;
395 int first_hop = -1;
396 int src;
397
398 INIT_LIST_HEAD(&traverse_list);
399 INIT_LIST_HEAD(&edge_list);
400 INIT_LIST_HEAD(&route_list);
401 INIT_LIST_HEAD(&black_list);
402
403 if (!src_dev) {
404 MSM_BUS_ERR("%s: Cannot locate src dev ", __func__);
405 goto exit_getpath;
406 }
407
408 src_node = to_msm_bus_node(src_dev);
409 if (!src_node) {
410 MSM_BUS_ERR("%s:Fatal, Source node not found", __func__);
411 goto exit_getpath;
412 }
413 src = src_node->node_info->id;
414 list_add_tail(&src_node->link, &traverse_list);
415
416 while ((!found && !list_empty(&traverse_list))) {
417 struct msm_bus_node_device_type *bus_node = NULL;
418 /* Locate dest_id in the traverse list */
419 list_for_each_entry(bus_node, &traverse_list, link) {
420 if (bus_node->node_info->id == dest) {
421 found = 1;
422 break;
423 }
424 }
425
426 if (!found) {
427 unsigned int i;
428 /* Setup the new edge list */
429 list_for_each_entry(bus_node, &traverse_list, link) {
430 /* Setup list of black-listed nodes */
431 setup_bl_list(bus_node, &black_list);
432
433 for (i = 0; i < bus_node->node_info->
434 num_connections; i++) {
435 bool skip;
436 struct msm_bus_node_device_type
437 *node_conn;
438 node_conn =
439 to_msm_bus_node(bus_node->node_info->
440 dev_connections[i]);
441 if (node_conn->node_info->
442 is_traversed) {
443 MSM_BUS_ERR("Circ Path %d\n",
444 node_conn->node_info->id);
445 goto reset_traversed;
446 }
447 skip = chk_bl_list(&black_list,
448 bus_node->node_info->
449 connections[i]);
450 if (!skip) {
451 list_add_tail(&node_conn->link,
452 &edge_list);
453 node_conn->node_info->
454 is_traversed = true;
455 }
456 }
457 }
458
459 /* Keep tabs of the previous search list */
460 search_node = kzalloc(sizeof(struct bus_search_type),
461 GFP_KERNEL);
462 INIT_LIST_HEAD(&search_node->node_list);
463 list_splice_init(&traverse_list,
464 &search_node->node_list);
465 /* Add the previous search list to a route list */
466 list_add_tail(&search_node->link, &route_list);
467 /* Advancing the list depth */
468 depth_index++;
469 list_splice_init(&edge_list, &traverse_list);
470 }
471 }
472reset_traversed:
473 copy_remaining_nodes(&edge_list, &traverse_list, &route_list);
474 first_hop = prune_path(&route_list, dest, src, &black_list, found,
475 cl_name);
476
477exit_getpath:
478 return first_hop;
479}
480
481static void bcm_update_bus_req(struct device *dev, int ctx)
482{
483 struct msm_bus_node_device_type *cur_dev = NULL;
484 struct msm_bus_node_device_type *bcm_dev = NULL;
485 int i;
486 uint64_t max_ib = 0;
487 uint64_t max_ab = 0;
488 int lnode_idx = 0;
489
490 cur_dev = to_msm_bus_node(dev);
491 if (!cur_dev) {
492 MSM_BUS_ERR("%s: Null device ptr", __func__);
493 goto exit_bcm_update_bus_req;
494 }
495
496 if (!cur_dev->node_info->num_bcm_devs)
497 goto exit_bcm_update_bus_req;
498
499 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
500 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
501
502 if (!bcm_dev)
503 goto exit_bcm_update_bus_req;
504
505 lnode_idx = cur_dev->node_info->bcm_req_idx;
506 bcm_dev->lnode_list[lnode_idx].lnode_ib[ctx] =
507 msm_bus_div64(cur_dev->node_info->agg_params.buswidth,
508 cur_dev->node_bw[ctx].max_ib *
509 (uint64_t)bcm_dev->bcmdev->width);
510
511 bcm_dev->lnode_list[lnode_idx].lnode_ab[ctx] =
512 msm_bus_div64(cur_dev->node_info->agg_params.buswidth,
David Dai0d014432016-11-10 12:57:44 -0800513 cur_dev->node_bw[ctx].sum_ab *
David Dai04ce4202016-09-26 16:24:13 -0700514 (uint64_t)bcm_dev->bcmdev->width);
515
516 for (i = 0; i < bcm_dev->num_lnodes; i++) {
517 if (ctx == ACTIVE_CTX) {
518 max_ib = max(max_ib,
519 max(bcm_dev->lnode_list[i].lnode_ib[ACTIVE_CTX],
520 bcm_dev->lnode_list[i].lnode_ib[DUAL_CTX]));
521
522 max_ab = max(max_ab,
523 bcm_dev->lnode_list[i].lnode_ab[ACTIVE_CTX] +
524 bcm_dev->lnode_list[i].lnode_ab[DUAL_CTX]);
525 } else {
526 max_ib = max(max_ib,
527 bcm_dev->lnode_list[i].lnode_ib[ctx]);
528 max_ab = max(max_ab,
529 bcm_dev->lnode_list[i].lnode_ab[ctx]);
530 }
531 }
532
533 bcm_dev->node_bw[ctx].max_ab = max_ab;
534 bcm_dev->node_bw[ctx].max_ib = max_ib;
535 }
536exit_bcm_update_bus_req:
537 return;
538}
539
540int bcm_remove_handoff_req(struct device *dev, void *data)
541{
542 struct msm_bus_node_device_type *bcm_dev = NULL;
543 int i;
544 uint64_t max_ib = 0;
545 uint64_t max_ab = 0;
546 int ret = 0;
547
548 rt_mutex_lock(&msm_bus_adhoc_lock);
549
550 bcm_dev = to_msm_bus_node(dev);
551 if (!bcm_dev) {
552 MSM_BUS_ERR("%s: Null device ptr", __func__);
553 goto exit_bcm_remove_handoff_req;
554 }
555
556 if (!bcm_dev->node_info->is_bcm_dev)
557 goto exit_bcm_remove_handoff_req;
558
David Dai04ce4202016-09-26 16:24:13 -0700559 for (i = 0; i < bcm_dev->num_lnodes; i++) {
560 max_ib = max(max_ib,
561 bcm_dev->lnode_list[i].lnode_ib[0]);
562 max_ab = max(max_ab,
563 bcm_dev->lnode_list[i].lnode_ab[0]);
564 }
565
566 bcm_dev->node_bw[0].max_ab = max_ab;
567 bcm_dev->node_bw[0].max_ib = max_ib;
568
569exit_bcm_remove_handoff_req:
570 rt_mutex_unlock(&msm_bus_adhoc_lock);
571 return ret;
572}
573
574
575
576static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev,
577 int ctx)
578{
579 int i;
580 uint64_t max_ib = 0;
581 uint64_t sum_ab = 0;
582
583 if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) {
584 MSM_BUS_ERR("Bus node pointer is Invalid");
585 goto exit_agg_bus_req;
586 }
587
588 for (i = 0; i < bus_dev->num_lnodes; i++) {
589 max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
590 sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
591 }
592
593 bus_dev->node_bw[ctx].sum_ab = sum_ab;
594 bus_dev->node_bw[ctx].max_ib = max_ib;
595
596exit_agg_bus_req:
597 return;
598}
599
600
601static void del_inp_list(struct list_head *list)
602{
603 struct rule_update_path_info *rule_node;
604 struct rule_update_path_info *rule_node_tmp;
605
606 list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) {
607 list_del(&rule_node->link);
608 rule_node->added = false;
609 }
610}
611
612static void del_op_list(struct list_head *list)
613{
614 struct rule_apply_rcm_info *rule;
615 struct rule_apply_rcm_info *rule_tmp;
616
617 list_for_each_entry_safe(rule, rule_tmp, list, link)
618 list_del(&rule->link);
619}
620
621static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit)
622{
623 struct rule_apply_rcm_info *rule;
624 struct device *dev = NULL;
625 struct msm_bus_node_device_type *dev_info = NULL;
626 int ret = 0;
627
628 list_for_each_entry(rule, list, link) {
629 if (!rule)
630 continue;
631
632 if (rule && (rule->after_clk_commit != after_clk_commit))
633 continue;
634
635 dev = bus_find_device(&msm_bus_type, NULL,
636 (void *) &rule->id,
637 msm_bus_device_match_adhoc);
638
639 if (!dev) {
640 MSM_BUS_ERR("Can't find dev node for %d", rule->id);
641 continue;
642 }
643 dev_info = to_msm_bus_node(dev);
644
645 ret = msm_bus_enable_limiter(dev_info, rule->throttle,
646 rule->lim_bw);
647 if (ret)
648 MSM_BUS_ERR("Failed to set limiter for %d", rule->id);
649 }
650
651 return ret;
652}
653
654static void commit_data(void)
655{
656 bool rules_registered = msm_rule_are_rules_registered();
657
658 if (rules_registered) {
659 msm_rules_update_path(&input_list, &apply_list);
660 msm_bus_apply_rules(&apply_list, false);
661 }
662
663 msm_bus_commit_data(&commit_list);
664
665 if (rules_registered) {
666 msm_bus_apply_rules(&apply_list, true);
667 del_inp_list(&input_list);
668 del_op_list(&apply_list);
669 }
670 INIT_LIST_HEAD(&input_list);
671 INIT_LIST_HEAD(&apply_list);
672 INIT_LIST_HEAD(&commit_list);
673}
674
675static void add_node_to_clist(struct msm_bus_node_device_type *node)
676{
677 struct msm_bus_node_device_type *node_parent =
678 to_msm_bus_node(node->node_info->bus_device);
679
680 if (!node->dirty) {
681 list_add_tail(&node->link, &commit_list);
682 node->dirty = true;
683 }
684
685 if (!node_parent->dirty) {
686 list_add_tail(&node_parent->link, &commit_list);
687 node_parent->dirty = true;
688 }
689}
690
691static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
692 uint64_t act_req_bw, uint64_t slp_req_ib,
693 uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw,
694 int src_idx, int ctx)
695{
696 struct device *next_dev = NULL;
697 struct link_node *lnode = NULL;
698 struct msm_bus_node_device_type *dev_info = NULL;
699 int curr_idx;
700 int ret = 0;
701 struct rule_update_path_info *rule_node;
702 bool rules_registered = msm_rule_are_rules_registered();
703
704 if (IS_ERR_OR_NULL(src_dev)) {
705 MSM_BUS_ERR("%s: No source device", __func__);
706 ret = -ENODEV;
707 goto exit_update_path;
708 }
709
710 next_dev = src_dev;
711
712 if (src_idx < 0) {
713 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
714 ret = -ENXIO;
715 goto exit_update_path;
716 }
717 curr_idx = src_idx;
718
719 while (next_dev) {
720 int i;
721
722 dev_info = to_msm_bus_node(next_dev);
723
724 if (curr_idx >= dev_info->num_lnodes) {
725 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
726 __func__, curr_idx, dev_info->num_lnodes);
727 ret = -ENXIO;
728 goto exit_update_path;
729 }
730
731 lnode = &dev_info->lnode_list[curr_idx];
732 if (!lnode) {
733 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
734 __func__, curr_idx);
735 ret = -ENXIO;
736 goto exit_update_path;
737 }
738 lnode->lnode_ib[ACTIVE_CTX] = act_req_ib;
739 lnode->lnode_ab[ACTIVE_CTX] = act_req_bw;
740 lnode->lnode_ib[DUAL_CTX] = slp_req_ib;
741 lnode->lnode_ab[DUAL_CTX] = slp_req_bw;
742
743 for (i = 0; i < NUM_CTX; i++) {
744 aggregate_bus_req(dev_info, i);
745 bcm_update_bus_req(next_dev, i);
746 }
747
748 add_node_to_clist(dev_info);
749
750 if (rules_registered) {
751 rule_node = &dev_info->node_info->rule;
752 rule_node->id = dev_info->node_info->id;
753 rule_node->ib = dev_info->node_bw[ACTIVE_CTX].max_ib;
754 rule_node->ab = dev_info->node_bw[ACTIVE_CTX].sum_ab;
755 rule_node->clk =
756 dev_info->node_bw[ACTIVE_CTX].cur_clk_hz;
757 if (!rule_node->added) {
758 list_add_tail(&rule_node->link, &input_list);
759 rule_node->added = true;
760 }
761 }
762
763 next_dev = lnode->next_dev;
764 curr_idx = lnode->next;
765 }
766
767exit_update_path:
768 return ret;
769}
770
771static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib,
772 uint64_t cur_ab, int src_idx, int active_only)
773{
774 struct device *next_dev = NULL;
775 struct link_node *lnode = NULL;
776 struct msm_bus_node_device_type *dev_info = NULL;
777 int ret = 0;
778 int cur_idx = src_idx;
779 int next_idx;
780
781 /* Update the current path to zero out all request from
782 * this cient on all paths
783 */
784 if (!src_dev) {
785 MSM_BUS_ERR("%s: Can't find source device", __func__);
786 ret = -ENODEV;
787 goto exit_remove_path;
788 }
789
790 ret = update_path(src_dev, dst, 0, 0, 0, 0, cur_ib, cur_ab, src_idx,
791 active_only);
792 if (ret) {
793 MSM_BUS_ERR("%s: Error zeroing out path ctx %d",
794 __func__, ACTIVE_CTX);
795 goto exit_remove_path;
796 }
797
798 next_dev = src_dev;
799
800 while (next_dev) {
801 dev_info = to_msm_bus_node(next_dev);
802 lnode = &dev_info->lnode_list[cur_idx];
803 next_idx = lnode->next;
804 next_dev = lnode->next_dev;
805 remove_lnode(dev_info, cur_idx);
806 cur_idx = next_idx;
807 }
808
809exit_remove_path:
810 return ret;
811}
812
813static void getpath_debug(int src, int curr, int active_only)
814{
815 struct device *dev_node;
816 struct device *dev_it;
817 unsigned int hop = 1;
818 int idx;
819 struct msm_bus_node_device_type *devinfo;
820 int i;
821
822 dev_node = bus_find_device(&msm_bus_type, NULL,
823 (void *) &src,
824 msm_bus_device_match_adhoc);
825
826 if (!dev_node) {
827 MSM_BUS_ERR("SRC NOT FOUND %d", src);
828 return;
829 }
830
831 idx = curr;
832 devinfo = to_msm_bus_node(dev_node);
833 dev_it = dev_node;
834
835 MSM_BUS_ERR("Route list Src %d", src);
836 while (dev_it) {
837 struct msm_bus_node_device_type *busdev =
838 to_msm_bus_node(devinfo->node_info->bus_device);
839
840 MSM_BUS_ERR("Hop[%d] at Device %d ctx %d", hop,
841 devinfo->node_info->id, active_only);
842
843 for (i = 0; i < NUM_CTX; i++) {
844 MSM_BUS_ERR("dev info sel ib %llu",
845 devinfo->node_bw[i].cur_clk_hz);
846 MSM_BUS_ERR("dev info sel ab %llu",
847 devinfo->node_bw[i].sum_ab);
848 }
849
850 dev_it = devinfo->lnode_list[idx].next_dev;
851 idx = devinfo->lnode_list[idx].next;
852 if (dev_it)
853 devinfo = to_msm_bus_node(dev_it);
854
855 MSM_BUS_ERR("Bus Device %d", busdev->node_info->id);
856 MSM_BUS_ERR("Bus Clock %llu", busdev->clk[active_only].rate);
857
858 if (idx < 0)
859 break;
860 hop++;
861 }
862}
863
864static void unregister_client_adhoc(uint32_t cl)
865{
866 int i;
867 struct msm_bus_scale_pdata *pdata;
868 int lnode, src, curr, dest;
869 uint64_t cur_clk, cur_bw;
870 struct msm_bus_client *client;
871 struct device *src_dev;
872
873 rt_mutex_lock(&msm_bus_adhoc_lock);
874 if (!cl) {
875 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
876 __func__);
877 goto exit_unregister_client;
878 }
879 client = handle_list.cl_list[cl];
880 pdata = client->pdata;
881 if (!pdata) {
882 MSM_BUS_ERR("%s: Null pdata passed to unregister\n",
883 __func__);
884 goto exit_unregister_client;
885 }
886
887 curr = client->curr;
888 if (curr >= pdata->num_usecases) {
889 MSM_BUS_ERR("Invalid index Defaulting curr to 0");
890 curr = 0;
891 }
892
David Dai04ce4202016-09-26 16:24:13 -0700893 for (i = 0; i < pdata->usecase->num_paths; i++) {
894 src = client->pdata->usecase[curr].vectors[i].src;
895 dest = client->pdata->usecase[curr].vectors[i].dst;
896
897 lnode = client->src_pnode[i];
898 src_dev = client->src_devs[i];
899 cur_clk = client->pdata->usecase[curr].vectors[i].ib;
900 cur_bw = client->pdata->usecase[curr].vectors[i].ab;
901 remove_path(src_dev, dest, cur_clk, cur_bw, lnode,
902 pdata->active_only);
903 }
904 commit_data();
905 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl);
906 kfree(client->src_pnode);
907 kfree(client->src_devs);
908 kfree(client);
909 handle_list.cl_list[cl] = NULL;
910exit_unregister_client:
911 rt_mutex_unlock(&msm_bus_adhoc_lock);
912}
913
914static int alloc_handle_lst(int size)
915{
916 int ret = 0;
917 struct msm_bus_client **t_cl_list;
918
919 if (!handle_list.num_entries) {
920 t_cl_list = kzalloc(sizeof(struct msm_bus_client *)
921 * NUM_CL_HANDLES, GFP_KERNEL);
922 if (ZERO_OR_NULL_PTR(t_cl_list)) {
923 ret = -ENOMEM;
924 MSM_BUS_ERR("%s: Failed to allocate handles list",
925 __func__);
926 goto exit_alloc_handle_lst;
927 }
928 handle_list.cl_list = t_cl_list;
929 handle_list.num_entries += NUM_CL_HANDLES;
930 } else {
931 t_cl_list = krealloc(handle_list.cl_list,
932 sizeof(struct msm_bus_client *) *
933 (handle_list.num_entries + NUM_CL_HANDLES),
934 GFP_KERNEL);
935 if (ZERO_OR_NULL_PTR(t_cl_list)) {
936 ret = -ENOMEM;
937 MSM_BUS_ERR("%s: Failed to allocate handles list",
938 __func__);
939 goto exit_alloc_handle_lst;
940 }
941
942 handle_list.cl_list = t_cl_list;
943 memset(&handle_list.cl_list[handle_list.num_entries], 0,
944 NUM_CL_HANDLES * sizeof(struct msm_bus_client *));
945 handle_list.num_entries += NUM_CL_HANDLES;
946 }
947exit_alloc_handle_lst:
948 return ret;
949}
950
951static uint32_t gen_handle(struct msm_bus_client *client)
952{
953 uint32_t handle = 0;
954 int i;
955 int ret = 0;
956
957 for (i = 0; i < handle_list.num_entries; i++) {
958 if (i && !handle_list.cl_list[i]) {
959 handle = i;
960 break;
961 }
962 }
963
964 if (!handle) {
965 ret = alloc_handle_lst(NUM_CL_HANDLES);
966
967 if (ret) {
968 MSM_BUS_ERR("%s: Failed to allocate handle list",
969 __func__);
970 goto exit_gen_handle;
971 }
972 handle = i + 1;
973 }
974 handle_list.cl_list[handle] = client;
975exit_gen_handle:
976 return handle;
977}
978
979static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata)
980{
981 int src, dest;
982 int i;
983 struct msm_bus_client *client = NULL;
984 int *lnode;
985 struct device *dev;
986 uint32_t handle = 0;
987
988 rt_mutex_lock(&msm_bus_adhoc_lock);
989 client = kzalloc(sizeof(struct msm_bus_client), GFP_KERNEL);
990 if (!client) {
991 MSM_BUS_ERR("%s: Error allocating client data", __func__);
992 goto exit_register_client;
993 }
994 client->pdata = pdata;
995
996 lnode = kcalloc(pdata->usecase->num_paths, sizeof(int), GFP_KERNEL);
997 if (ZERO_OR_NULL_PTR(lnode)) {
998 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
999 goto exit_lnode_malloc_fail;
1000 }
1001 client->src_pnode = lnode;
1002
1003 client->src_devs = kcalloc(pdata->usecase->num_paths,
1004 sizeof(struct device *), GFP_KERNEL);
1005 if (IS_ERR_OR_NULL(client->src_devs)) {
1006 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
1007 goto exit_src_dev_malloc_fail;
1008 }
1009 client->curr = -1;
1010
1011 for (i = 0; i < pdata->usecase->num_paths; i++) {
1012 src = pdata->usecase->vectors[i].src;
1013 dest = pdata->usecase->vectors[i].dst;
1014
1015 if ((src < 0) || (dest < 0)) {
1016 MSM_BUS_ERR("%s:Invalid src/dst.src %d dest %d",
1017 __func__, src, dest);
1018 goto exit_invalid_data;
1019 }
1020 dev = bus_find_device(&msm_bus_type, NULL,
1021 (void *) &src,
1022 msm_bus_device_match_adhoc);
1023 if (IS_ERR_OR_NULL(dev)) {
1024 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1025 __func__, src, dest);
1026 goto exit_invalid_data;
1027 }
1028 client->src_devs[i] = dev;
1029
1030 MSM_BUS_ERR("%s:find path.src %d dest %d",
1031 __func__, src, dest);
1032
1033 lnode[i] = getpath(dev, dest, client->pdata->name);
1034 if (lnode[i] < 0) {
1035 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1036 __func__, src, dest);
1037 goto exit_invalid_data;
1038 }
1039 }
1040
1041 handle = gen_handle(client);
1042 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_REGISTER,
1043 handle);
1044 MSM_BUS_ERR("%s:Client handle %d %s", __func__, handle,
1045 client->pdata->name);
1046 rt_mutex_unlock(&msm_bus_adhoc_lock);
1047 return handle;
1048exit_invalid_data:
1049 kfree(client->src_devs);
1050exit_src_dev_malloc_fail:
1051 kfree(lnode);
1052exit_lnode_malloc_fail:
1053 kfree(client);
1054exit_register_client:
1055 rt_mutex_unlock(&msm_bus_adhoc_lock);
1056 return handle;
1057}
1058
1059static int update_client_paths(struct msm_bus_client *client, bool log_trns,
1060 unsigned int idx)
1061{
1062 int lnode, src, dest, cur_idx;
1063 uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw;
1064 int i, ret = 0;
1065 struct msm_bus_scale_pdata *pdata;
1066 struct device *src_dev;
1067
1068 if (!client) {
1069 MSM_BUS_ERR("Client handle Null");
1070 ret = -ENXIO;
1071 goto exit_update_client_paths;
1072 }
1073
1074 pdata = client->pdata;
1075 if (!pdata) {
1076 MSM_BUS_ERR("Client pdata Null");
1077 ret = -ENXIO;
1078 goto exit_update_client_paths;
1079 }
1080
1081 cur_idx = client->curr;
1082 client->curr = idx;
1083 for (i = 0; i < pdata->usecase->num_paths; i++) {
1084 src = pdata->usecase[idx].vectors[i].src;
1085 dest = pdata->usecase[idx].vectors[i].dst;
1086
1087 lnode = client->src_pnode[i];
1088 src_dev = client->src_devs[i];
1089 req_clk = client->pdata->usecase[idx].vectors[i].ib;
1090 req_bw = client->pdata->usecase[idx].vectors[i].ab;
1091 if (cur_idx < 0) {
1092 curr_clk = 0;
1093 curr_bw = 0;
1094 } else {
1095 curr_clk =
1096 client->pdata->usecase[cur_idx].vectors[i].ib;
1097 curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab;
1098 MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
1099 curr_bw, curr_clk);
1100 }
1101
1102 if (pdata->active_only) {
1103 slp_clk = 0;
1104 slp_bw = 0;
1105 } else {
1106 slp_clk = req_clk;
1107 slp_bw = req_bw;
David Dai0d014432016-11-10 12:57:44 -08001108 req_clk = 0;
1109 req_bw = 0;
David Dai04ce4202016-09-26 16:24:13 -07001110 }
1111
1112 ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk,
1113 slp_bw, curr_clk, curr_bw, lnode, pdata->active_only);
1114
1115 if (ret) {
1116 MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
1117 __func__, ret, pdata->active_only);
1118 goto exit_update_client_paths;
1119 }
1120
1121 if (log_trns)
1122 getpath_debug(src, lnode, pdata->active_only);
1123 }
1124 commit_data();
1125exit_update_client_paths:
1126 return ret;
1127}
1128
1129static int update_context(uint32_t cl, bool active_only,
1130 unsigned int ctx_idx)
1131{
1132 int ret = 0;
1133 struct msm_bus_scale_pdata *pdata;
1134 struct msm_bus_client *client;
1135
1136 rt_mutex_lock(&msm_bus_adhoc_lock);
1137 if (!cl) {
1138 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1139 ret = -ENXIO;
1140 goto exit_update_context;
1141 }
1142
1143 client = handle_list.cl_list[cl];
1144 if (!client) {
1145 ret = -ENXIO;
1146 goto exit_update_context;
1147 }
1148
1149 pdata = client->pdata;
1150 if (!pdata) {
1151 ret = -ENXIO;
1152 goto exit_update_context;
1153 }
1154 if (pdata->active_only == active_only) {
1155 MSM_BUS_ERR("No change in context(%d==%d), skip\n",
1156 pdata->active_only, active_only);
1157 ret = -ENXIO;
1158 goto exit_update_context;
1159 }
1160
1161 if (ctx_idx >= pdata->num_usecases) {
1162 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1163 cl, ctx_idx);
1164 ret = -ENXIO;
1165 goto exit_update_context;
1166 }
1167
1168 pdata->active_only = active_only;
1169
1170 msm_bus_dbg_client_data(client->pdata, ctx_idx, cl);
1171 ret = update_client_paths(client, false, ctx_idx);
1172 if (ret) {
1173 pr_err("%s: Err updating path\n", __func__);
1174 goto exit_update_context;
1175 }
1176
1177// trace_bus_update_request_end(pdata->name);
1178
1179exit_update_context:
1180 rt_mutex_unlock(&msm_bus_adhoc_lock);
1181 return ret;
1182}
1183
1184static int update_request_adhoc(uint32_t cl, unsigned int index)
1185{
1186 int ret = 0;
1187 struct msm_bus_scale_pdata *pdata;
1188 struct msm_bus_client *client;
1189 const char *test_cl = "Null";
1190 bool log_transaction = false;
1191
1192 rt_mutex_lock(&msm_bus_adhoc_lock);
1193
1194 if (!cl) {
1195 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1196 ret = -ENXIO;
1197 goto exit_update_request;
1198 }
1199
1200 client = handle_list.cl_list[cl];
1201 if (!client) {
1202 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1203 ret = -ENXIO;
1204 goto exit_update_request;
1205 }
1206
1207 pdata = client->pdata;
1208 if (!pdata) {
1209 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1210 __func__);
1211 ret = -ENXIO;
1212 goto exit_update_request;
1213 }
1214
1215 if (index >= pdata->num_usecases) {
1216 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1217 cl, index);
1218 ret = -ENXIO;
1219 goto exit_update_request;
1220 }
1221
1222 if (client->curr == index) {
1223 MSM_BUS_DBG("%s: Not updating client request idx %d unchanged",
1224 __func__, index);
1225 goto exit_update_request;
1226 }
1227
1228 if (!strcmp(test_cl, pdata->name))
1229 log_transaction = true;
1230
1231 MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
1232 cl, index, client->curr, client->pdata->usecase->num_paths);
1233 msm_bus_dbg_client_data(client->pdata, index, cl);
1234 ret = update_client_paths(client, log_transaction, index);
1235 if (ret) {
1236 pr_err("%s: Err updating path\n", __func__);
1237 goto exit_update_request;
1238 }
1239
1240// trace_bus_update_request_end(pdata->name);
1241
1242exit_update_request:
1243 rt_mutex_unlock(&msm_bus_adhoc_lock);
1244 return ret;
1245}
1246
1247static void free_cl_mem(struct msm_bus_client_handle *cl)
1248{
1249 if (cl) {
1250 kfree(cl->name);
1251 kfree(cl);
1252 cl = NULL;
1253 }
1254}
1255
1256static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
1257{
1258 int ret = 0;
1259 char *test_cl = "test-client";
1260 bool log_transaction = false;
1261 u64 slp_ib, slp_ab;
1262
1263 rt_mutex_lock(&msm_bus_adhoc_lock);
1264
1265 if (!cl) {
1266 MSM_BUS_ERR("%s: Invalid client handle %p", __func__, cl);
1267 ret = -ENXIO;
1268 goto exit_update_request;
1269 }
1270
1271 if (!strcmp(test_cl, cl->name))
1272 log_transaction = true;
1273
1274 msm_bus_dbg_rec_transaction(cl, ab, ib);
1275
1276 if ((cl->cur_act_ib == ib) && (cl->cur_act_ab == ab)) {
1277 MSM_BUS_DBG("%s:no change in request", cl->name);
1278 goto exit_update_request;
1279 }
1280
1281 if (cl->active_only) {
1282 slp_ib = 0;
1283 slp_ab = 0;
1284 } else {
1285 slp_ib = ib;
1286 slp_ab = ab;
1287 }
1288
1289 ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab,
1290 cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only);
1291
1292 if (ret) {
1293 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1294 __func__, ret, cl->active_only);
1295 goto exit_update_request;
1296 }
1297
1298 commit_data();
1299 cl->cur_act_ib = ib;
1300 cl->cur_act_ab = ab;
1301 cl->cur_slp_ib = slp_ib;
1302 cl->cur_slp_ab = slp_ab;
1303
1304 if (log_transaction)
1305 getpath_debug(cl->mas, cl->first_hop, cl->active_only);
1306// trace_bus_update_request_end(cl->name);
1307exit_update_request:
1308 rt_mutex_unlock(&msm_bus_adhoc_lock);
1309
1310 return ret;
1311}
1312
1313static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
1314 u64 act_ib, u64 slp_ib, u64 slp_ab)
1315{
1316 int ret = 0;
1317
1318 rt_mutex_lock(&msm_bus_adhoc_lock);
1319 if (!cl) {
1320 MSM_BUS_ERR("Invalid client handle %p", cl);
1321 ret = -ENXIO;
1322 goto exit_change_context;
1323 }
1324
1325 if ((cl->cur_act_ib == act_ib) &&
1326 (cl->cur_act_ab == act_ab) &&
1327 (cl->cur_slp_ib == slp_ib) &&
1328 (cl->cur_slp_ab == slp_ab)) {
1329 MSM_BUS_ERR("No change in vote");
1330 goto exit_change_context;
1331 }
1332
1333 if (!slp_ab && !slp_ib)
1334 cl->active_only = true;
1335 msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib);
1336 ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab,
1337 cl->cur_act_ab, cl->cur_act_ab, cl->first_hop,
1338 cl->active_only);
1339 if (ret) {
1340 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1341 __func__, ret, cl->active_only);
1342 goto exit_change_context;
1343 }
1344 commit_data();
1345 cl->cur_act_ib = act_ib;
1346 cl->cur_act_ab = act_ab;
1347 cl->cur_slp_ib = slp_ib;
1348 cl->cur_slp_ab = slp_ab;
1349// trace_bus_update_request_end(cl->name);
1350exit_change_context:
1351 rt_mutex_unlock(&msm_bus_adhoc_lock);
1352 return ret;
1353}
1354
1355static void unregister_adhoc(struct msm_bus_client_handle *cl)
1356{
1357 rt_mutex_lock(&msm_bus_adhoc_lock);
1358 if (!cl) {
1359 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
1360 __func__);
1361 goto exit_unregister_client;
1362 }
1363
1364 MSM_BUS_DBG("%s: Unregistering client %p", __func__, cl);
1365
1366 remove_path(cl->mas_dev, cl->slv, cl->cur_act_ib, cl->cur_act_ab,
1367 cl->first_hop, cl->active_only);
1368 commit_data();
1369 msm_bus_dbg_remove_client(cl);
1370 kfree(cl);
David Dai0d014432016-11-10 12:57:44 -08001371 MSM_BUS_DBG("%s: Unregistered client", __func__);
David Dai04ce4202016-09-26 16:24:13 -07001372exit_unregister_client:
1373 rt_mutex_unlock(&msm_bus_adhoc_lock);
1374}
1375
1376static struct msm_bus_client_handle*
1377register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only)
1378{
1379 struct msm_bus_client_handle *client = NULL;
1380 int len = 0;
1381
1382 rt_mutex_lock(&msm_bus_adhoc_lock);
1383
1384 if (!(mas && slv && name)) {
1385 pr_err("%s: Error: src dst name num_paths are required",
1386 __func__);
1387 goto exit_register;
1388 }
1389
1390 client = kzalloc(sizeof(struct msm_bus_client_handle), GFP_KERNEL);
1391 if (!client) {
1392 MSM_BUS_ERR("%s: Error allocating client data", __func__);
1393 goto exit_register;
1394 }
1395
1396 len = strnlen(name, MAX_STR_CL);
1397 client->name = kzalloc((len + 1), GFP_KERNEL);
1398 if (!client->name) {
1399 MSM_BUS_ERR("%s: Error allocating client name buf", __func__);
1400 free_cl_mem(client);
1401 goto exit_register;
1402 }
1403 strlcpy(client->name, name, MAX_STR_CL);
1404 client->active_only = active_only;
1405
1406 client->mas = mas;
1407 client->slv = slv;
1408
1409 client->mas_dev = bus_find_device(&msm_bus_type, NULL,
1410 (void *) &mas,
1411 msm_bus_device_match_adhoc);
1412 if (IS_ERR_OR_NULL(client->mas_dev)) {
1413 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1414 __func__, client->mas, client->slv);
1415 free_cl_mem(client);
1416 goto exit_register;
1417 }
1418
1419 client->first_hop = getpath(client->mas_dev, client->slv, client->name);
1420 if (client->first_hop < 0) {
1421 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1422 __func__, client->mas, client->slv);
1423 free_cl_mem(client);
1424 goto exit_register;
1425 }
1426
1427 MSM_BUS_DBG("%s:Client handle %p %s", __func__, client,
1428 client->name);
1429 msm_bus_dbg_add_client(client);
1430exit_register:
1431 rt_mutex_unlock(&msm_bus_adhoc_lock);
1432 return client;
1433}
1434/**
1435 * msm_bus_arb_setops_adhoc() : Setup the bus arbitration ops
1436 * @ arb_ops: pointer to the arb ops.
1437 */
1438void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops)
1439{
1440 arb_ops->register_client = register_client_adhoc;
1441 arb_ops->update_request = update_request_adhoc;
1442 arb_ops->unregister_client = unregister_client_adhoc;
1443 arb_ops->update_context = update_context;
1444
1445 arb_ops->register_cl = register_adhoc;
1446 arb_ops->unregister = unregister_adhoc;
1447 arb_ops->update_bw = update_bw_adhoc;
1448 arb_ops->update_bw_context = update_bw_context;
1449}