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