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