blob: e90012de136922753254e3b2326f5b4914ececab [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 Daia55b46e2017-05-08 10:31:31 -070027#define MSM_BUS_MAS_ALC 144
28#define MSM_BUS_RSC_APPS 8000
29#define MSM_BUS_RSC_DISP 8001
30#define BCM_TCS_CMD_ACV_APPS 0x8
David Daibee66232017-03-31 19:05:39 -070031
David Dai04ce4202016-09-26 16:24:13 -070032struct bus_search_type {
33 struct list_head link;
34 struct list_head node_list;
35};
36
37struct handle_type {
38 int num_entries;
39 struct msm_bus_client **cl_list;
40};
41
42static struct handle_type handle_list;
43static LIST_HEAD(input_list);
44static LIST_HEAD(apply_list);
45static LIST_HEAD(commit_list);
David Dai62c04a62017-04-12 19:05:49 -070046static LIST_HEAD(late_init_clist);
David Dai9d66f3f2016-11-23 15:33:06 -080047static LIST_HEAD(query_list);
David Dai04ce4202016-09-26 16:24:13 -070048
49DEFINE_RT_MUTEX(msm_bus_adhoc_lock);
50
51static bool chk_bl_list(struct list_head *black_list, unsigned int id)
52{
53 struct msm_bus_node_device_type *bus_node = NULL;
54
55 list_for_each_entry(bus_node, black_list, link) {
56 if (bus_node->node_info->id == id)
57 return true;
58 }
59 return false;
60}
61
62static void copy_remaining_nodes(struct list_head *edge_list, struct list_head
63 *traverse_list, struct list_head *route_list)
64{
65 struct bus_search_type *search_node;
66
67 if (list_empty(edge_list) && list_empty(traverse_list))
68 return;
69
70 search_node = kzalloc(sizeof(struct bus_search_type), GFP_KERNEL);
71 INIT_LIST_HEAD(&search_node->node_list);
72 list_splice_init(edge_list, traverse_list);
73 list_splice_init(traverse_list, &search_node->node_list);
74 list_add_tail(&search_node->link, route_list);
75}
76
77/*
78 * Duplicate instantiaion from msm_bus_arb.c. Todo there needs to be a
79 * "util" file for these common func/macros.
80 *
81 */
David Dai607fbc42017-03-02 16:22:36 -080082uint64_t msm_bus_div64(uint64_t num, unsigned int base)
David Dai04ce4202016-09-26 16:24:13 -070083{
David Dai607fbc42017-03-02 16:22:36 -080084 uint64_t *n = &num;
David Dai04ce4202016-09-26 16:24:13 -070085
David Dai607fbc42017-03-02 16:22:36 -080086 if ((num > 0) && (num < base))
David Dai04ce4202016-09-26 16:24:13 -070087 return 1;
88
David Dai607fbc42017-03-02 16:22:36 -080089 switch (base) {
David Dai04ce4202016-09-26 16:24:13 -070090 case 0:
91 WARN(1, "AXI: Divide by 0 attempted\n");
David Dai607fbc42017-03-02 16:22:36 -080092 case 1: return num;
93 case 2: return (num >> 1);
94 case 4: return (num >> 2);
95 case 8: return (num >> 3);
96 case 16: return (num >> 4);
97 case 32: return (num >> 5);
David Dai04ce4202016-09-26 16:24:13 -070098 }
99
David Dai607fbc42017-03-02 16:22:36 -0800100 do_div(*n, base);
101 return *n;
David Dai04ce4202016-09-26 16:24:13 -0700102}
103
104int msm_bus_device_match_adhoc(struct device *dev, void *id)
105{
106 int ret = 0;
107 struct msm_bus_node_device_type *bnode = to_msm_bus_node(dev);
108
109 if (bnode)
110 ret = (bnode->node_info->id == *(unsigned int *)id);
111 else
112 ret = 0;
113
114 return ret;
115}
116
117static void bcm_add_bus_req(struct device *dev)
118{
119 struct msm_bus_node_device_type *cur_dev = NULL;
120 struct msm_bus_node_device_type *bcm_dev = NULL;
121 struct link_node *lnode;
122 int lnode_idx = -1;
123 int max_num_lnodes = 0;
124 int i;
125
126 cur_dev = to_msm_bus_node(dev);
127 if (!cur_dev) {
128 MSM_BUS_ERR("%s: Null device ptr", __func__);
129 goto exit_bcm_add_bus_req;
130 }
131
132 if (!cur_dev->node_info->num_bcm_devs)
133 goto exit_bcm_add_bus_req;
134
135 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
David Daia55b46e2017-05-08 10:31:31 -0700136 if (cur_dev->node_info->bcm_req_idx[i] != -1)
137 continue;
David Dai04ce4202016-09-26 16:24:13 -0700138 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
139 max_num_lnodes = bcm_dev->bcmdev->num_bus_devs;
David Dai04ce4202016-09-26 16:24:13 -0700140 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;
David Daia55b46e2017-05-08 10:31:31 -0700186 cur_dev->node_info->bcm_req_idx[i] = lnode_idx;
David Dai04ce4202016-09-26 16:24:13 -0700187 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
David Daia55b46e2017-05-08 10:31:31 -0700486static void bcm_update_acv_req(struct msm_bus_node_device_type *cur_rsc,
487 uint64_t max_ab, uint64_t max_ib,
488 uint64_t *vec_a, uint64_t *vec_b,
489 uint32_t *acv, int ctx)
490{
491 uint32_t acv_bmsk = 0;
492 /*
493 * Base ACV voting on current RSC until mapping is set up in commanddb
494 * that allows us to vote ACV based on master.
495 */
496
497 if (cur_rsc->node_info->id == MSM_BUS_RSC_APPS)
498 acv_bmsk = BCM_TCS_CMD_ACV_APPS;
499
500 if (max_ab == 0 && max_ib == 0)
501 *acv = *acv & ~acv_bmsk;
502 else
503 *acv = *acv | acv_bmsk;
504 *vec_a = 0;
505 *vec_b = *acv;
506}
507
David Dai04ce4202016-09-26 16:24:13 -0700508static void bcm_update_bus_req(struct device *dev, int ctx)
509{
510 struct msm_bus_node_device_type *cur_dev = NULL;
511 struct msm_bus_node_device_type *bcm_dev = NULL;
David Daia55b46e2017-05-08 10:31:31 -0700512 struct msm_bus_node_device_type *cur_rsc = NULL;
513
514 int i, j;
David Dai04ce4202016-09-26 16:24:13 -0700515 uint64_t max_ib = 0;
516 uint64_t max_ab = 0;
517 int lnode_idx = 0;
518
519 cur_dev = to_msm_bus_node(dev);
520 if (!cur_dev) {
521 MSM_BUS_ERR("%s: Null device ptr", __func__);
522 goto exit_bcm_update_bus_req;
523 }
524
525 if (!cur_dev->node_info->num_bcm_devs)
526 goto exit_bcm_update_bus_req;
527
528 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
529 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
530
531 if (!bcm_dev)
532 goto exit_bcm_update_bus_req;
533
David Daia55b46e2017-05-08 10:31:31 -0700534 lnode_idx = cur_dev->node_info->bcm_req_idx[i];
David Dai04ce4202016-09-26 16:24:13 -0700535 bcm_dev->lnode_list[lnode_idx].lnode_ib[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800536 msm_bus_div64(cur_dev->node_bw[ctx].max_ib *
537 (uint64_t)bcm_dev->bcmdev->width,
538 cur_dev->node_info->agg_params.buswidth);
David Dai04ce4202016-09-26 16:24:13 -0700539
540 bcm_dev->lnode_list[lnode_idx].lnode_ab[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800541 msm_bus_div64(cur_dev->node_bw[ctx].sum_ab *
542 (uint64_t)bcm_dev->bcmdev->width,
543 cur_dev->node_info->agg_params.buswidth *
544 cur_dev->node_info->agg_params.num_aggports);
David Dai04ce4202016-09-26 16:24:13 -0700545
David Daia55b46e2017-05-08 10:31:31 -0700546 for (j = 0; j < bcm_dev->num_lnodes; j++) {
David Dai04ce4202016-09-26 16:24:13 -0700547 if (ctx == ACTIVE_CTX) {
548 max_ib = max(max_ib,
David Daia55b46e2017-05-08 10:31:31 -0700549 max(bcm_dev->lnode_list[j].lnode_ib[ACTIVE_CTX],
550 bcm_dev->lnode_list[j].lnode_ib[DUAL_CTX]));
David Dai04ce4202016-09-26 16:24:13 -0700551 max_ab = max(max_ab,
David Daia55b46e2017-05-08 10:31:31 -0700552 bcm_dev->lnode_list[j].lnode_ab[ACTIVE_CTX] +
553 bcm_dev->lnode_list[j].lnode_ab[DUAL_CTX]);
David Dai04ce4202016-09-26 16:24:13 -0700554 } else {
555 max_ib = max(max_ib,
David Daia55b46e2017-05-08 10:31:31 -0700556 bcm_dev->lnode_list[j].lnode_ib[ctx]);
David Dai04ce4202016-09-26 16:24:13 -0700557 max_ab = max(max_ab,
David Daia55b46e2017-05-08 10:31:31 -0700558 bcm_dev->lnode_list[j].lnode_ab[ctx]);
David Dai04ce4202016-09-26 16:24:13 -0700559 }
560 }
David Dai04ce4202016-09-26 16:24:13 -0700561 bcm_dev->node_bw[ctx].max_ab = max_ab;
562 bcm_dev->node_bw[ctx].max_ib = max_ib;
David Daibee66232017-03-31 19:05:39 -0700563
564 max_ab = msm_bus_div64(max_ab, bcm_dev->bcmdev->unit_size);
565 max_ib = msm_bus_div64(max_ib, bcm_dev->bcmdev->unit_size);
566
David Daia55b46e2017-05-08 10:31:31 -0700567 if (bcm_dev->node_info->id == MSM_BUS_BCM_ACV) {
568 cur_rsc = to_msm_bus_node(bcm_dev->node_info->
569 rsc_devs[0]);
570 bcm_update_acv_req(cur_rsc, max_ab, max_ib,
571 &bcm_dev->node_vec[ctx].vec_a,
572 &bcm_dev->node_vec[ctx].vec_b,
573 &cur_rsc->rscdev->acv[ctx], ctx);
574
575 } else {
576 bcm_dev->node_vec[ctx].vec_a = max_ab;
577 bcm_dev->node_vec[ctx].vec_b = max_ib;
578 }
David Dai04ce4202016-09-26 16:24:13 -0700579 }
580exit_bcm_update_bus_req:
581 return;
582}
583
David Dai9d66f3f2016-11-23 15:33:06 -0800584static void bcm_query_bus_req(struct device *dev, int ctx)
585{
586 struct msm_bus_node_device_type *cur_dev = NULL;
587 struct msm_bus_node_device_type *bcm_dev = NULL;
David Daia55b46e2017-05-08 10:31:31 -0700588 struct msm_bus_node_device_type *cur_rsc = NULL;
589 int i, j;
David Dai9d66f3f2016-11-23 15:33:06 -0800590 uint64_t max_query_ib = 0;
591 uint64_t max_query_ab = 0;
592 int lnode_idx = 0;
593
594 cur_dev = to_msm_bus_node(dev);
595 if (!cur_dev) {
596 MSM_BUS_ERR("%s: Null device ptr", __func__);
597 goto exit_bcm_query_bus_req;
598 }
599
600 if (!cur_dev->node_info->num_bcm_devs)
601 goto exit_bcm_query_bus_req;
602
603 for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) {
604 bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]);
605
606 if (!bcm_dev)
607 goto exit_bcm_query_bus_req;
608
David Daia55b46e2017-05-08 10:31:31 -0700609 lnode_idx = cur_dev->node_info->bcm_req_idx[i];
David Dai9d66f3f2016-11-23 15:33:06 -0800610 bcm_dev->lnode_list[lnode_idx].lnode_query_ib[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800611 msm_bus_div64(cur_dev->node_bw[ctx].max_query_ib *
612 (uint64_t)bcm_dev->bcmdev->width,
613 cur_dev->node_info->agg_params.buswidth);
David Dai9d66f3f2016-11-23 15:33:06 -0800614
615 bcm_dev->lnode_list[lnode_idx].lnode_query_ab[ctx] =
David Dai607fbc42017-03-02 16:22:36 -0800616 msm_bus_div64(cur_dev->node_bw[ctx].sum_query_ab *
617 (uint64_t)bcm_dev->bcmdev->width,
David Dai489b0d72017-03-14 13:05:01 -0700618 cur_dev->node_info->agg_params.num_aggports *
David Dai607fbc42017-03-02 16:22:36 -0800619 cur_dev->node_info->agg_params.buswidth);
David Dai9d66f3f2016-11-23 15:33:06 -0800620
David Daia55b46e2017-05-08 10:31:31 -0700621 for (j = 0; j < bcm_dev->num_lnodes; j++) {
David Dai9d66f3f2016-11-23 15:33:06 -0800622 if (ctx == ACTIVE_CTX) {
623 max_query_ib = max(max_query_ib,
David Daia55b46e2017-05-08 10:31:31 -0700624 max(bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800625 lnode_query_ib[ACTIVE_CTX],
David Daia55b46e2017-05-08 10:31:31 -0700626 bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800627 lnode_query_ib[DUAL_CTX]));
628
629 max_query_ab = max(max_query_ab,
David Daia55b46e2017-05-08 10:31:31 -0700630 bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800631 lnode_query_ab[ACTIVE_CTX] +
David Daia55b46e2017-05-08 10:31:31 -0700632 bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800633 lnode_query_ab[DUAL_CTX]);
634 } else {
635 max_query_ib = max(max_query_ib,
David Daia55b46e2017-05-08 10:31:31 -0700636 bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800637 lnode_query_ib[ctx]);
638 max_query_ab = max(max_query_ab,
David Daia55b46e2017-05-08 10:31:31 -0700639 bcm_dev->lnode_list[j].
David Dai9d66f3f2016-11-23 15:33:06 -0800640 lnode_query_ab[ctx]);
641 }
642 }
643
David Daibee66232017-03-31 19:05:39 -0700644 max_query_ab = msm_bus_div64(max_query_ab,
645 bcm_dev->bcmdev->unit_size);
646 max_query_ib = msm_bus_div64(max_query_ib,
647 bcm_dev->bcmdev->unit_size);
648
David Daia55b46e2017-05-08 10:31:31 -0700649 if (bcm_dev->node_info->id == MSM_BUS_BCM_ACV) {
650 cur_rsc = to_msm_bus_node(bcm_dev->node_info->
651 rsc_devs[0]);
652 bcm_update_acv_req(cur_rsc, max_query_ab, max_query_ib,
653 &bcm_dev->node_vec[ctx].query_vec_a,
654 &bcm_dev->node_vec[ctx].query_vec_b,
655 &cur_rsc->rscdev->query_acv[ctx], ctx);
656 } else {
657 bcm_dev->node_vec[ctx].query_vec_a = max_query_ab;
658 bcm_dev->node_vec[ctx].query_vec_b = max_query_ib;
659 }
660
David Dai9d66f3f2016-11-23 15:33:06 -0800661 bcm_dev->node_bw[ctx].max_query_ab = max_query_ab;
662 bcm_dev->node_bw[ctx].max_query_ib = max_query_ib;
David Dai9d66f3f2016-11-23 15:33:06 -0800663 }
664exit_bcm_query_bus_req:
665 return;
666}
667
David Daibee66232017-03-31 19:05:39 -0700668static void bcm_update_alc_req(struct msm_bus_node_device_type *dev, int ctx)
669{
670 struct msm_bus_node_device_type *bcm_dev = NULL;
671 int i;
672 uint64_t max_alc = 0;
David Dai9d66f3f2016-11-23 15:33:06 -0800673
David Daibee66232017-03-31 19:05:39 -0700674 if (!dev || !to_msm_bus_node(dev->node_info->bus_device)) {
675 MSM_BUS_ERR("Bus node pointer is Invalid");
676 goto exit_bcm_update_alc_req;
677 }
678
679 for (i = 0; i < dev->num_lnodes; i++)
680 max_alc = max(max_alc, dev->lnode_list[i].alc_idx[ctx]);
681
682 dev->node_bw[ctx].max_alc = max_alc;
683
684 bcm_dev = to_msm_bus_node(dev->node_info->bcm_devs[0]);
685
686 if (ctx == ACTIVE_CTX) {
687 max_alc = max(max_alc,
688 max(dev->node_bw[ACTIVE_CTX].max_alc,
689 dev->node_bw[DUAL_CTX].max_alc));
690 } else {
691 max_alc = dev->node_bw[ctx].max_alc;
692 }
693
694 bcm_dev->node_bw[ctx].max_alc = max_alc;
695 bcm_dev->node_vec[ctx].vec_a = max_alc;
696 bcm_dev->node_vec[ctx].vec_b = 0;
697
698exit_bcm_update_alc_req:
699 return;
700}
David Dai9d66f3f2016-11-23 15:33:06 -0800701
David Dai04ce4202016-09-26 16:24:13 -0700702int bcm_remove_handoff_req(struct device *dev, void *data)
703{
David Dai62c04a62017-04-12 19:05:49 -0700704 struct msm_bus_node_device_type *bus_dev = NULL;
705 struct msm_bus_node_device_type *cur_bcm = NULL;
706 struct msm_bus_node_device_type *cur_rsc = NULL;
David Dai04ce4202016-09-26 16:24:13 -0700707 int ret = 0;
708
David Dai62c04a62017-04-12 19:05:49 -0700709 bus_dev = to_msm_bus_node(dev);
710 if (bus_dev->node_info->is_bcm_dev ||
711 bus_dev->node_info->is_fab_dev ||
712 bus_dev->node_info->is_rsc_dev)
David Dai04ce4202016-09-26 16:24:13 -0700713 goto exit_bcm_remove_handoff_req;
714
David Dai62c04a62017-04-12 19:05:49 -0700715 if (bus_dev->node_info->num_bcm_devs) {
716 cur_bcm = to_msm_bus_node(bus_dev->node_info->bcm_devs[0]);
717 if (cur_bcm->node_info->num_rsc_devs) {
718 cur_rsc =
719 to_msm_bus_node(cur_bcm->node_info->rsc_devs[0]);
720 if (cur_rsc->node_info->id != MSM_BUS_RSC_APPS)
721 goto exit_bcm_remove_handoff_req;
722 }
David Dai04ce4202016-09-26 16:24:13 -0700723 }
724
David Dai62c04a62017-04-12 19:05:49 -0700725 if (!bus_dev->dirty) {
726 list_add_tail(&bus_dev->link, &late_init_clist);
727 bus_dev->dirty = true;
728 }
David Dai04ce4202016-09-26 16:24:13 -0700729
730exit_bcm_remove_handoff_req:
David Dai04ce4202016-09-26 16:24:13 -0700731 return ret;
732}
733
David Dai04ce4202016-09-26 16:24:13 -0700734static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev,
735 int ctx)
736{
737 int i;
738 uint64_t max_ib = 0;
739 uint64_t sum_ab = 0;
740
741 if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) {
742 MSM_BUS_ERR("Bus node pointer is Invalid");
743 goto exit_agg_bus_req;
744 }
745
746 for (i = 0; i < bus_dev->num_lnodes; i++) {
747 max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
748 sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
749 }
750
751 bus_dev->node_bw[ctx].sum_ab = sum_ab;
752 bus_dev->node_bw[ctx].max_ib = max_ib;
753
754exit_agg_bus_req:
755 return;
756}
757
David Dai9d66f3f2016-11-23 15:33:06 -0800758static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev,
759 int ctx)
760{
761 int i;
762 uint64_t max_ib = 0;
763 uint64_t sum_ab = 0;
764
765 if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) {
766 MSM_BUS_ERR("Bus node pointer is Invalid");
767 goto exit_agg_bus_req;
768 }
769
770 for (i = 0; i < bus_dev->num_lnodes; i++) {
771 max_ib = max(max_ib,
772 bus_dev->lnode_list[i].lnode_query_ib[ctx]);
773 sum_ab += bus_dev->lnode_list[i].lnode_query_ab[ctx];
774 }
775
David Dai9d66f3f2016-11-23 15:33:06 -0800776 bus_dev->node_bw[ctx].sum_query_ab = sum_ab;
777 bus_dev->node_bw[ctx].max_query_ib = max_ib;
778
779exit_agg_bus_req:
780 return;
781}
David Dai04ce4202016-09-26 16:24:13 -0700782
783static void del_inp_list(struct list_head *list)
784{
785 struct rule_update_path_info *rule_node;
786 struct rule_update_path_info *rule_node_tmp;
787
788 list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) {
789 list_del(&rule_node->link);
790 rule_node->added = false;
791 }
792}
793
794static void del_op_list(struct list_head *list)
795{
796 struct rule_apply_rcm_info *rule;
797 struct rule_apply_rcm_info *rule_tmp;
798
799 list_for_each_entry_safe(rule, rule_tmp, list, link)
800 list_del(&rule->link);
801}
802
803static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit)
804{
805 struct rule_apply_rcm_info *rule;
806 struct device *dev = NULL;
807 struct msm_bus_node_device_type *dev_info = NULL;
808 int ret = 0;
809
810 list_for_each_entry(rule, list, link) {
811 if (!rule)
812 continue;
813
814 if (rule && (rule->after_clk_commit != after_clk_commit))
815 continue;
816
817 dev = bus_find_device(&msm_bus_type, NULL,
818 (void *) &rule->id,
819 msm_bus_device_match_adhoc);
820
821 if (!dev) {
822 MSM_BUS_ERR("Can't find dev node for %d", rule->id);
823 continue;
824 }
825 dev_info = to_msm_bus_node(dev);
826
827 ret = msm_bus_enable_limiter(dev_info, rule->throttle,
828 rule->lim_bw);
829 if (ret)
830 MSM_BUS_ERR("Failed to set limiter for %d", rule->id);
831 }
832
833 return ret;
834}
835
836static void commit_data(void)
837{
838 bool rules_registered = msm_rule_are_rules_registered();
839
840 if (rules_registered) {
841 msm_rules_update_path(&input_list, &apply_list);
842 msm_bus_apply_rules(&apply_list, false);
843 }
844
845 msm_bus_commit_data(&commit_list);
846
847 if (rules_registered) {
848 msm_bus_apply_rules(&apply_list, true);
849 del_inp_list(&input_list);
850 del_op_list(&apply_list);
851 }
852 INIT_LIST_HEAD(&input_list);
853 INIT_LIST_HEAD(&apply_list);
854 INIT_LIST_HEAD(&commit_list);
855}
856
David Dai68c72502017-07-07 19:56:01 -0700857int commit_late_init_data(bool lock)
David Dai62c04a62017-04-12 19:05:49 -0700858{
David Daibe2827a2017-06-05 16:20:32 -0700859 int rc;
David Dai68c72502017-07-07 19:56:01 -0700860
861 if (lock) {
862 rt_mutex_lock(&msm_bus_adhoc_lock);
863 return 0;
864 }
865
David Daibe2827a2017-06-05 16:20:32 -0700866 rc = bus_for_each_dev(&msm_bus_type, NULL, NULL,
867 bcm_remove_handoff_req);
David Dai62c04a62017-04-12 19:05:49 -0700868
869 msm_bus_commit_data(&late_init_clist);
870 INIT_LIST_HEAD(&late_init_clist);
871
872 rt_mutex_unlock(&msm_bus_adhoc_lock);
David Daibe2827a2017-06-05 16:20:32 -0700873 return rc;
David Dai62c04a62017-04-12 19:05:49 -0700874}
875
876
877
David Dai04ce4202016-09-26 16:24:13 -0700878static void add_node_to_clist(struct msm_bus_node_device_type *node)
879{
880 struct msm_bus_node_device_type *node_parent =
881 to_msm_bus_node(node->node_info->bus_device);
882
883 if (!node->dirty) {
884 list_add_tail(&node->link, &commit_list);
885 node->dirty = true;
886 }
887
888 if (!node_parent->dirty) {
889 list_add_tail(&node_parent->link, &commit_list);
890 node_parent->dirty = true;
891 }
892}
893
David Dai9d66f3f2016-11-23 15:33:06 -0800894static void add_node_to_query_list(struct msm_bus_node_device_type *node)
895{
896 if (!node->query_dirty) {
897 list_add_tail(&node->query_link, &query_list);
898 node->query_dirty = true;
899 }
900}
901
David Dai04ce4202016-09-26 16:24:13 -0700902static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
903 uint64_t act_req_bw, uint64_t slp_req_ib,
904 uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw,
905 int src_idx, int ctx)
906{
907 struct device *next_dev = NULL;
908 struct link_node *lnode = NULL;
909 struct msm_bus_node_device_type *dev_info = NULL;
910 int curr_idx;
911 int ret = 0;
912 struct rule_update_path_info *rule_node;
913 bool rules_registered = msm_rule_are_rules_registered();
914
915 if (IS_ERR_OR_NULL(src_dev)) {
916 MSM_BUS_ERR("%s: No source device", __func__);
917 ret = -ENODEV;
918 goto exit_update_path;
919 }
920
921 next_dev = src_dev;
922
923 if (src_idx < 0) {
924 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
925 ret = -ENXIO;
926 goto exit_update_path;
927 }
928 curr_idx = src_idx;
929
930 while (next_dev) {
931 int i;
932
933 dev_info = to_msm_bus_node(next_dev);
934
935 if (curr_idx >= dev_info->num_lnodes) {
936 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
937 __func__, curr_idx, dev_info->num_lnodes);
938 ret = -ENXIO;
939 goto exit_update_path;
940 }
941
942 lnode = &dev_info->lnode_list[curr_idx];
943 if (!lnode) {
944 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
945 __func__, curr_idx);
946 ret = -ENXIO;
947 goto exit_update_path;
948 }
949 lnode->lnode_ib[ACTIVE_CTX] = act_req_ib;
950 lnode->lnode_ab[ACTIVE_CTX] = act_req_bw;
951 lnode->lnode_ib[DUAL_CTX] = slp_req_ib;
952 lnode->lnode_ab[DUAL_CTX] = slp_req_bw;
953
954 for (i = 0; i < NUM_CTX; i++) {
955 aggregate_bus_req(dev_info, i);
956 bcm_update_bus_req(next_dev, i);
957 }
958
959 add_node_to_clist(dev_info);
960
961 if (rules_registered) {
962 rule_node = &dev_info->node_info->rule;
963 rule_node->id = dev_info->node_info->id;
964 rule_node->ib = dev_info->node_bw[ACTIVE_CTX].max_ib;
965 rule_node->ab = dev_info->node_bw[ACTIVE_CTX].sum_ab;
966 rule_node->clk =
967 dev_info->node_bw[ACTIVE_CTX].cur_clk_hz;
968 if (!rule_node->added) {
969 list_add_tail(&rule_node->link, &input_list);
970 rule_node->added = true;
971 }
972 }
973
974 next_dev = lnode->next_dev;
975 curr_idx = lnode->next;
976 }
977
978exit_update_path:
979 return ret;
980}
981
David Daibee66232017-03-31 19:05:39 -0700982static int update_alc_vote(struct device *alc_dev, uint64_t act_req_fa_lat,
983 uint64_t act_req_idle_time, uint64_t slp_req_fa_lat,
984 uint64_t slp_req_idle_time, uint64_t cur_fa_lat,
985 uint64_t cur_idle_time, int idx, int ctx)
986{
987 struct link_node *lnode = NULL;
988 struct msm_bus_node_device_type *dev_info = NULL;
989 int curr_idx, i;
990 int ret = 0;
991
992 if (IS_ERR_OR_NULL(alc_dev)) {
993 MSM_BUS_ERR("%s: No source device", __func__);
994 ret = -ENODEV;
995 goto exit_update_alc_vote;
996 }
997
998 if (idx < 0) {
999 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, idx);
1000 ret = -ENXIO;
1001 goto exit_update_alc_vote;
1002 }
1003
1004 dev_info = to_msm_bus_node(alc_dev);
1005 curr_idx = idx;
1006
1007 if (curr_idx >= dev_info->num_lnodes) {
1008 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
1009 __func__, curr_idx, dev_info->num_lnodes);
1010 ret = -ENXIO;
1011 goto exit_update_alc_vote;
1012 }
1013
1014 lnode = &dev_info->lnode_list[curr_idx];
1015 if (!lnode) {
1016 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
1017 __func__, curr_idx);
1018 ret = -ENXIO;
1019 goto exit_update_alc_vote;
1020 }
1021
1022 /*
1023 * Add aggregation and mapping logic once LUT is avail.
1024 * Use default values for time being.
1025 */
1026 lnode->alc_idx[ACTIVE_CTX] = 12;
1027 lnode->alc_idx[DUAL_CTX] = 0;
1028
1029 for (i = 0; i < NUM_CTX; i++)
1030 bcm_update_alc_req(dev_info, i);
1031
1032 add_node_to_clist(dev_info);
1033
1034exit_update_alc_vote:
1035 return ret;
1036}
1037
1038
David Dai9d66f3f2016-11-23 15:33:06 -08001039static int query_path(struct device *src_dev, int dest, uint64_t act_req_ib,
1040 uint64_t act_req_bw, uint64_t slp_req_ib,
1041 uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw,
1042 int src_idx)
1043{
1044 struct device *next_dev = NULL;
1045 struct link_node *lnode = NULL;
1046 struct msm_bus_node_device_type *dev_info = NULL;
1047 int curr_idx;
1048 int ret = 0;
1049
1050 if (IS_ERR_OR_NULL(src_dev)) {
1051 MSM_BUS_ERR("%s: No source device", __func__);
1052 ret = -ENODEV;
1053 goto exit_query_path;
1054 }
1055
1056 next_dev = src_dev;
1057
1058 if (src_idx < 0) {
1059 MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
1060 ret = -ENXIO;
1061 goto exit_query_path;
1062 }
1063 curr_idx = src_idx;
1064
1065 while (next_dev) {
1066 int i;
1067
1068 dev_info = to_msm_bus_node(next_dev);
1069
1070 if (curr_idx >= dev_info->num_lnodes) {
1071 MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
1072 __func__, curr_idx, dev_info->num_lnodes);
1073 ret = -ENXIO;
1074 goto exit_query_path;
1075 }
1076
1077 lnode = &dev_info->lnode_list[curr_idx];
1078 if (!lnode) {
1079 MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d",
1080 __func__, curr_idx);
1081 ret = -ENXIO;
1082 goto exit_query_path;
1083 }
1084 lnode->lnode_query_ib[ACTIVE_CTX] = act_req_ib;
1085 lnode->lnode_query_ab[ACTIVE_CTX] = act_req_bw;
1086 lnode->lnode_query_ib[DUAL_CTX] = slp_req_ib;
1087 lnode->lnode_query_ab[DUAL_CTX] = slp_req_bw;
1088
1089 for (i = 0; i < NUM_CTX; i++) {
1090 aggregate_bus_query_req(dev_info, i);
1091 bcm_query_bus_req(next_dev, i);
1092 }
1093
1094 add_node_to_query_list(dev_info);
1095
1096 next_dev = lnode->next_dev;
1097 curr_idx = lnode->next;
1098 }
1099
1100exit_query_path:
1101 return ret;
1102}
1103
David Dai04ce4202016-09-26 16:24:13 -07001104static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib,
1105 uint64_t cur_ab, int src_idx, int active_only)
1106{
1107 struct device *next_dev = NULL;
1108 struct link_node *lnode = NULL;
1109 struct msm_bus_node_device_type *dev_info = NULL;
1110 int ret = 0;
1111 int cur_idx = src_idx;
1112 int next_idx;
1113
1114 /* Update the current path to zero out all request from
1115 * this cient on all paths
1116 */
1117 if (!src_dev) {
1118 MSM_BUS_ERR("%s: Can't find source device", __func__);
1119 ret = -ENODEV;
1120 goto exit_remove_path;
1121 }
1122
1123 ret = update_path(src_dev, dst, 0, 0, 0, 0, cur_ib, cur_ab, src_idx,
1124 active_only);
1125 if (ret) {
1126 MSM_BUS_ERR("%s: Error zeroing out path ctx %d",
1127 __func__, ACTIVE_CTX);
1128 goto exit_remove_path;
1129 }
1130
1131 next_dev = src_dev;
1132
1133 while (next_dev) {
1134 dev_info = to_msm_bus_node(next_dev);
1135 lnode = &dev_info->lnode_list[cur_idx];
1136 next_idx = lnode->next;
1137 next_dev = lnode->next_dev;
1138 remove_lnode(dev_info, cur_idx);
1139 cur_idx = next_idx;
1140 }
1141
1142exit_remove_path:
1143 return ret;
1144}
1145
1146static void getpath_debug(int src, int curr, int active_only)
1147{
1148 struct device *dev_node;
1149 struct device *dev_it;
1150 unsigned int hop = 1;
1151 int idx;
1152 struct msm_bus_node_device_type *devinfo;
1153 int i;
1154
1155 dev_node = bus_find_device(&msm_bus_type, NULL,
1156 (void *) &src,
1157 msm_bus_device_match_adhoc);
1158
1159 if (!dev_node) {
1160 MSM_BUS_ERR("SRC NOT FOUND %d", src);
1161 return;
1162 }
1163
1164 idx = curr;
1165 devinfo = to_msm_bus_node(dev_node);
1166 dev_it = dev_node;
1167
1168 MSM_BUS_ERR("Route list Src %d", src);
1169 while (dev_it) {
1170 struct msm_bus_node_device_type *busdev =
1171 to_msm_bus_node(devinfo->node_info->bus_device);
1172
1173 MSM_BUS_ERR("Hop[%d] at Device %d ctx %d", hop,
1174 devinfo->node_info->id, active_only);
1175
1176 for (i = 0; i < NUM_CTX; i++) {
1177 MSM_BUS_ERR("dev info sel ib %llu",
1178 devinfo->node_bw[i].cur_clk_hz);
1179 MSM_BUS_ERR("dev info sel ab %llu",
1180 devinfo->node_bw[i].sum_ab);
1181 }
1182
1183 dev_it = devinfo->lnode_list[idx].next_dev;
1184 idx = devinfo->lnode_list[idx].next;
1185 if (dev_it)
1186 devinfo = to_msm_bus_node(dev_it);
1187
1188 MSM_BUS_ERR("Bus Device %d", busdev->node_info->id);
1189 MSM_BUS_ERR("Bus Clock %llu", busdev->clk[active_only].rate);
1190
1191 if (idx < 0)
1192 break;
1193 hop++;
1194 }
1195}
1196
1197static void unregister_client_adhoc(uint32_t cl)
1198{
1199 int i;
1200 struct msm_bus_scale_pdata *pdata;
1201 int lnode, src, curr, dest;
1202 uint64_t cur_clk, cur_bw;
1203 struct msm_bus_client *client;
1204 struct device *src_dev;
1205
1206 rt_mutex_lock(&msm_bus_adhoc_lock);
1207 if (!cl) {
1208 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
1209 __func__);
1210 goto exit_unregister_client;
1211 }
1212 client = handle_list.cl_list[cl];
1213 pdata = client->pdata;
1214 if (!pdata) {
1215 MSM_BUS_ERR("%s: Null pdata passed to unregister\n",
1216 __func__);
1217 goto exit_unregister_client;
1218 }
1219
1220 curr = client->curr;
1221 if (curr >= pdata->num_usecases) {
1222 MSM_BUS_ERR("Invalid index Defaulting curr to 0");
1223 curr = 0;
1224 }
1225
David Dai04ce4202016-09-26 16:24:13 -07001226 for (i = 0; i < pdata->usecase->num_paths; i++) {
1227 src = client->pdata->usecase[curr].vectors[i].src;
1228 dest = client->pdata->usecase[curr].vectors[i].dst;
1229
1230 lnode = client->src_pnode[i];
1231 src_dev = client->src_devs[i];
1232 cur_clk = client->pdata->usecase[curr].vectors[i].ib;
1233 cur_bw = client->pdata->usecase[curr].vectors[i].ab;
1234 remove_path(src_dev, dest, cur_clk, cur_bw, lnode,
1235 pdata->active_only);
1236 }
1237 commit_data();
1238 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl);
1239 kfree(client->src_pnode);
1240 kfree(client->src_devs);
1241 kfree(client);
1242 handle_list.cl_list[cl] = NULL;
1243exit_unregister_client:
1244 rt_mutex_unlock(&msm_bus_adhoc_lock);
1245}
1246
1247static int alloc_handle_lst(int size)
1248{
1249 int ret = 0;
1250 struct msm_bus_client **t_cl_list;
1251
1252 if (!handle_list.num_entries) {
1253 t_cl_list = kzalloc(sizeof(struct msm_bus_client *)
1254 * NUM_CL_HANDLES, GFP_KERNEL);
1255 if (ZERO_OR_NULL_PTR(t_cl_list)) {
1256 ret = -ENOMEM;
1257 MSM_BUS_ERR("%s: Failed to allocate handles list",
1258 __func__);
1259 goto exit_alloc_handle_lst;
1260 }
1261 handle_list.cl_list = t_cl_list;
1262 handle_list.num_entries += NUM_CL_HANDLES;
1263 } else {
1264 t_cl_list = krealloc(handle_list.cl_list,
1265 sizeof(struct msm_bus_client *) *
1266 (handle_list.num_entries + NUM_CL_HANDLES),
1267 GFP_KERNEL);
1268 if (ZERO_OR_NULL_PTR(t_cl_list)) {
1269 ret = -ENOMEM;
1270 MSM_BUS_ERR("%s: Failed to allocate handles list",
1271 __func__);
1272 goto exit_alloc_handle_lst;
1273 }
1274
1275 handle_list.cl_list = t_cl_list;
1276 memset(&handle_list.cl_list[handle_list.num_entries], 0,
1277 NUM_CL_HANDLES * sizeof(struct msm_bus_client *));
1278 handle_list.num_entries += NUM_CL_HANDLES;
1279 }
1280exit_alloc_handle_lst:
1281 return ret;
1282}
1283
1284static uint32_t gen_handle(struct msm_bus_client *client)
1285{
1286 uint32_t handle = 0;
1287 int i;
1288 int ret = 0;
1289
1290 for (i = 0; i < handle_list.num_entries; i++) {
1291 if (i && !handle_list.cl_list[i]) {
1292 handle = i;
1293 break;
1294 }
1295 }
1296
1297 if (!handle) {
1298 ret = alloc_handle_lst(NUM_CL_HANDLES);
1299
1300 if (ret) {
1301 MSM_BUS_ERR("%s: Failed to allocate handle list",
1302 __func__);
1303 goto exit_gen_handle;
1304 }
1305 handle = i + 1;
1306 }
1307 handle_list.cl_list[handle] = client;
1308exit_gen_handle:
1309 return handle;
1310}
1311
1312static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata)
1313{
1314 int src, dest;
1315 int i;
1316 struct msm_bus_client *client = NULL;
1317 int *lnode;
1318 struct device *dev;
1319 uint32_t handle = 0;
1320
1321 rt_mutex_lock(&msm_bus_adhoc_lock);
1322 client = kzalloc(sizeof(struct msm_bus_client), GFP_KERNEL);
1323 if (!client) {
1324 MSM_BUS_ERR("%s: Error allocating client data", __func__);
1325 goto exit_register_client;
1326 }
1327 client->pdata = pdata;
1328
David Daibee66232017-03-31 19:05:39 -07001329 if (pdata->alc) {
1330 client->curr = -1;
1331 lnode = kzalloc(sizeof(int), GFP_KERNEL);
1332
1333 if (ZERO_OR_NULL_PTR(lnode)) {
1334 MSM_BUS_ERR("%s: Error allocating lnode!", __func__);
1335 goto exit_lnode_malloc_fail;
1336 }
1337 client->src_pnode = lnode;
1338
1339 client->src_devs = kzalloc(sizeof(struct device *),
1340 GFP_KERNEL);
1341 if (IS_ERR_OR_NULL(client->src_devs)) {
1342 MSM_BUS_ERR("%s: Error allocating src_dev!", __func__);
1343 goto exit_src_dev_malloc_fail;
1344 }
1345 src = MSM_BUS_MAS_ALC;
1346 dev = bus_find_device(&msm_bus_type, NULL,
1347 (void *) &src,
1348 msm_bus_device_match_adhoc);
1349 if (IS_ERR_OR_NULL(dev)) {
1350 MSM_BUS_ERR("%s:Failed to find alc device",
1351 __func__);
1352 goto exit_invalid_data;
1353 }
1354 gen_lnode(dev, MSM_BUS_MAS_ALC, 0, pdata->name);
1355 bcm_add_bus_req(dev);
1356
1357 client->src_devs[0] = dev;
1358
1359 handle = gen_handle(client);
1360 goto exit_register_client;
1361 }
1362
David Dai04ce4202016-09-26 16:24:13 -07001363 lnode = kcalloc(pdata->usecase->num_paths, sizeof(int), GFP_KERNEL);
1364 if (ZERO_OR_NULL_PTR(lnode)) {
1365 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
1366 goto exit_lnode_malloc_fail;
1367 }
1368 client->src_pnode = lnode;
1369
1370 client->src_devs = kcalloc(pdata->usecase->num_paths,
1371 sizeof(struct device *), GFP_KERNEL);
1372 if (IS_ERR_OR_NULL(client->src_devs)) {
1373 MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
1374 goto exit_src_dev_malloc_fail;
1375 }
1376 client->curr = -1;
1377
1378 for (i = 0; i < pdata->usecase->num_paths; i++) {
1379 src = pdata->usecase->vectors[i].src;
1380 dest = pdata->usecase->vectors[i].dst;
1381
1382 if ((src < 0) || (dest < 0)) {
1383 MSM_BUS_ERR("%s:Invalid src/dst.src %d dest %d",
1384 __func__, src, dest);
1385 goto exit_invalid_data;
1386 }
1387 dev = bus_find_device(&msm_bus_type, NULL,
1388 (void *) &src,
1389 msm_bus_device_match_adhoc);
1390 if (IS_ERR_OR_NULL(dev)) {
1391 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1392 __func__, src, dest);
1393 goto exit_invalid_data;
1394 }
1395 client->src_devs[i] = dev;
1396
1397 MSM_BUS_ERR("%s:find path.src %d dest %d",
1398 __func__, src, dest);
1399
1400 lnode[i] = getpath(dev, dest, client->pdata->name);
1401 if (lnode[i] < 0) {
1402 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
1403 __func__, src, dest);
1404 goto exit_invalid_data;
1405 }
1406 }
1407
1408 handle = gen_handle(client);
1409 msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_REGISTER,
1410 handle);
1411 MSM_BUS_ERR("%s:Client handle %d %s", __func__, handle,
1412 client->pdata->name);
1413 rt_mutex_unlock(&msm_bus_adhoc_lock);
1414 return handle;
1415exit_invalid_data:
1416 kfree(client->src_devs);
1417exit_src_dev_malloc_fail:
1418 kfree(lnode);
1419exit_lnode_malloc_fail:
1420 kfree(client);
1421exit_register_client:
1422 rt_mutex_unlock(&msm_bus_adhoc_lock);
1423 return handle;
1424}
1425
1426static int update_client_paths(struct msm_bus_client *client, bool log_trns,
1427 unsigned int idx)
1428{
1429 int lnode, src, dest, cur_idx;
1430 uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw;
1431 int i, ret = 0;
1432 struct msm_bus_scale_pdata *pdata;
1433 struct device *src_dev;
1434
1435 if (!client) {
1436 MSM_BUS_ERR("Client handle Null");
1437 ret = -ENXIO;
1438 goto exit_update_client_paths;
1439 }
1440
1441 pdata = client->pdata;
1442 if (!pdata) {
1443 MSM_BUS_ERR("Client pdata Null");
1444 ret = -ENXIO;
1445 goto exit_update_client_paths;
1446 }
1447
1448 cur_idx = client->curr;
1449 client->curr = idx;
1450 for (i = 0; i < pdata->usecase->num_paths; i++) {
1451 src = pdata->usecase[idx].vectors[i].src;
1452 dest = pdata->usecase[idx].vectors[i].dst;
1453
1454 lnode = client->src_pnode[i];
1455 src_dev = client->src_devs[i];
1456 req_clk = client->pdata->usecase[idx].vectors[i].ib;
1457 req_bw = client->pdata->usecase[idx].vectors[i].ab;
1458 if (cur_idx < 0) {
1459 curr_clk = 0;
1460 curr_bw = 0;
1461 } else {
1462 curr_clk =
1463 client->pdata->usecase[cur_idx].vectors[i].ib;
1464 curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab;
1465 MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
1466 curr_bw, curr_clk);
1467 }
1468
1469 if (pdata->active_only) {
1470 slp_clk = 0;
1471 slp_bw = 0;
1472 } else {
1473 slp_clk = req_clk;
1474 slp_bw = req_bw;
David Dai0d014432016-11-10 12:57:44 -08001475 req_clk = 0;
1476 req_bw = 0;
David Dai04ce4202016-09-26 16:24:13 -07001477 }
1478
1479 ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk,
1480 slp_bw, curr_clk, curr_bw, lnode, pdata->active_only);
1481
1482 if (ret) {
1483 MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
1484 __func__, ret, pdata->active_only);
1485 goto exit_update_client_paths;
1486 }
1487
1488 if (log_trns)
1489 getpath_debug(src, lnode, pdata->active_only);
1490 }
1491 commit_data();
1492exit_update_client_paths:
1493 return ret;
1494}
1495
David Daibee66232017-03-31 19:05:39 -07001496static int update_client_alc(struct msm_bus_client *client, bool log_trns,
1497 unsigned int idx)
1498{
1499 int lnode, cur_idx;
1500 uint64_t req_idle_time, req_fal, dual_idle_time, dual_fal,
1501 cur_idle_time, cur_fal;
1502 int ret = 0;
1503 struct msm_bus_scale_pdata *pdata;
1504 struct device *src_dev;
1505
1506 if (!client) {
1507 MSM_BUS_ERR("Client handle Null");
1508 ret = -ENXIO;
1509 goto exit_update_client_alc;
1510 }
1511
1512 pdata = client->pdata;
1513 if (!pdata) {
1514 MSM_BUS_ERR("Client pdata Null");
1515 ret = -ENXIO;
1516 goto exit_update_client_alc;
1517 }
1518
1519 cur_idx = client->curr;
1520 client->curr = idx;
1521 req_fal = pdata->usecase_lat[idx].fal_ns;
1522 req_idle_time = pdata->usecase_lat[idx].idle_t_ns;
1523 lnode = client->src_pnode[0];
1524 src_dev = client->src_devs[0];
1525
1526 if (pdata->active_only) {
1527 dual_fal = 0;
1528 dual_idle_time = 0;
1529 } else {
1530 dual_fal = req_fal;
1531 dual_idle_time = req_idle_time;
1532 }
1533
1534 ret = update_alc_vote(src_dev, req_fal, req_idle_time, dual_fal,
1535 dual_idle_time, cur_fal, cur_idle_time, lnode,
1536 pdata->active_only);
1537
1538 if (ret) {
1539 MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
1540 __func__, ret, pdata->active_only);
1541 goto exit_update_client_alc;
1542 }
1543 commit_data();
1544exit_update_client_alc:
1545 return ret;
1546}
1547
David Dai9d66f3f2016-11-23 15:33:06 -08001548static int query_usecase(struct msm_bus_client *client, bool log_trns,
1549 unsigned int idx,
1550 struct msm_bus_tcs_usecase *tcs_usecase)
1551{
1552 int lnode, src, dest, cur_idx;
David Dai489b0d72017-03-14 13:05:01 -07001553 uint64_t req_clk, req_bw, curr_clk, curr_bw;
David Dai9d66f3f2016-11-23 15:33:06 -08001554 int i, ret = 0;
1555 struct msm_bus_scale_pdata *pdata;
1556 struct device *src_dev;
1557 struct msm_bus_node_device_type *node = NULL;
1558 struct msm_bus_node_device_type *node_tmp = NULL;
1559
1560 if (!client) {
1561 MSM_BUS_ERR("Client handle Null");
1562 ret = -ENXIO;
1563 goto exit_query_usecase;
1564 }
1565
1566 pdata = client->pdata;
1567 if (!pdata) {
1568 MSM_BUS_ERR("Client pdata Null");
1569 ret = -ENXIO;
1570 goto exit_query_usecase;
1571 }
1572
1573 cur_idx = client->curr;
1574 client->curr = idx;
1575 for (i = 0; i < pdata->usecase->num_paths; i++) {
1576 src = pdata->usecase[idx].vectors[i].src;
1577 dest = pdata->usecase[idx].vectors[i].dst;
1578
1579 lnode = client->src_pnode[i];
1580 src_dev = client->src_devs[i];
1581 req_clk = client->pdata->usecase[idx].vectors[i].ib;
1582 req_bw = client->pdata->usecase[idx].vectors[i].ab;
1583 if (cur_idx < 0) {
1584 curr_clk = 0;
1585 curr_bw = 0;
1586 } else {
1587 curr_clk =
1588 client->pdata->usecase[cur_idx].vectors[i].ib;
1589 curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab;
1590 MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
1591 curr_bw, curr_clk);
1592 }
1593
David Dai489b0d72017-03-14 13:05:01 -07001594 ret = query_path(src_dev, dest, req_clk, req_bw, 0,
1595 0, curr_clk, curr_bw, lnode);
David Dai9d66f3f2016-11-23 15:33:06 -08001596
1597 if (ret) {
1598 MSM_BUS_ERR("%s: Query path failed! %d ctx %d\n",
1599 __func__, ret, pdata->active_only);
1600 goto exit_query_usecase;
1601 }
1602 }
1603 msm_bus_query_gen(&query_list, tcs_usecase);
1604 INIT_LIST_HEAD(&query_list);
1605
1606 for (i = 0; i < pdata->usecase->num_paths; i++) {
1607 src = pdata->usecase[idx].vectors[i].src;
1608 dest = pdata->usecase[idx].vectors[i].dst;
1609
1610 lnode = client->src_pnode[i];
1611 src_dev = client->src_devs[i];
1612
1613 ret = query_path(src_dev, dest, 0, 0, 0, 0,
1614 curr_clk, curr_bw, lnode);
1615
1616 if (ret) {
1617 MSM_BUS_ERR("%s: Clear query path failed! %d ctx %d\n",
1618 __func__, ret, pdata->active_only);
1619 goto exit_query_usecase;
1620 }
1621 }
1622
1623 list_for_each_entry_safe(node, node_tmp, &query_list, query_link) {
1624 node->query_dirty = false;
1625 list_del_init(&node->query_link);
1626 }
1627
1628 INIT_LIST_HEAD(&query_list);
1629
1630exit_query_usecase:
1631 return ret;
1632}
1633
David Dai04ce4202016-09-26 16:24:13 -07001634static int update_context(uint32_t cl, bool active_only,
1635 unsigned int ctx_idx)
1636{
1637 int ret = 0;
1638 struct msm_bus_scale_pdata *pdata;
1639 struct msm_bus_client *client;
1640
1641 rt_mutex_lock(&msm_bus_adhoc_lock);
1642 if (!cl) {
1643 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1644 ret = -ENXIO;
1645 goto exit_update_context;
1646 }
1647
1648 client = handle_list.cl_list[cl];
1649 if (!client) {
1650 ret = -ENXIO;
1651 goto exit_update_context;
1652 }
1653
1654 pdata = client->pdata;
1655 if (!pdata) {
1656 ret = -ENXIO;
1657 goto exit_update_context;
1658 }
1659 if (pdata->active_only == active_only) {
1660 MSM_BUS_ERR("No change in context(%d==%d), skip\n",
1661 pdata->active_only, active_only);
1662 ret = -ENXIO;
1663 goto exit_update_context;
1664 }
1665
1666 if (ctx_idx >= pdata->num_usecases) {
1667 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1668 cl, ctx_idx);
1669 ret = -ENXIO;
1670 goto exit_update_context;
1671 }
1672
1673 pdata->active_only = active_only;
1674
1675 msm_bus_dbg_client_data(client->pdata, ctx_idx, cl);
1676 ret = update_client_paths(client, false, ctx_idx);
1677 if (ret) {
1678 pr_err("%s: Err updating path\n", __func__);
1679 goto exit_update_context;
1680 }
1681
1682// trace_bus_update_request_end(pdata->name);
1683
1684exit_update_context:
1685 rt_mutex_unlock(&msm_bus_adhoc_lock);
1686 return ret;
1687}
1688
1689static int update_request_adhoc(uint32_t cl, unsigned int index)
1690{
1691 int ret = 0;
1692 struct msm_bus_scale_pdata *pdata;
1693 struct msm_bus_client *client;
1694 const char *test_cl = "Null";
1695 bool log_transaction = false;
1696
1697 rt_mutex_lock(&msm_bus_adhoc_lock);
1698
1699 if (!cl) {
1700 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1701 ret = -ENXIO;
1702 goto exit_update_request;
1703 }
1704
1705 client = handle_list.cl_list[cl];
1706 if (!client) {
1707 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1708 ret = -ENXIO;
1709 goto exit_update_request;
1710 }
1711
1712 pdata = client->pdata;
1713 if (!pdata) {
1714 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1715 __func__);
1716 ret = -ENXIO;
1717 goto exit_update_request;
1718 }
1719
1720 if (index >= pdata->num_usecases) {
1721 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1722 cl, index);
1723 ret = -ENXIO;
1724 goto exit_update_request;
1725 }
1726
1727 if (client->curr == index) {
1728 MSM_BUS_DBG("%s: Not updating client request idx %d unchanged",
1729 __func__, index);
1730 goto exit_update_request;
1731 }
1732
1733 if (!strcmp(test_cl, pdata->name))
1734 log_transaction = true;
1735
1736 MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
1737 cl, index, client->curr, client->pdata->usecase->num_paths);
David Daibee66232017-03-31 19:05:39 -07001738
1739 if (pdata->alc)
1740 ret = update_client_alc(client, log_transaction, index);
1741 else {
1742 msm_bus_dbg_client_data(client->pdata, index, cl);
1743 ret = update_client_paths(client, log_transaction, index);
1744 }
David Dai04ce4202016-09-26 16:24:13 -07001745 if (ret) {
1746 pr_err("%s: Err updating path\n", __func__);
1747 goto exit_update_request;
1748 }
1749
1750// trace_bus_update_request_end(pdata->name);
1751
1752exit_update_request:
1753 rt_mutex_unlock(&msm_bus_adhoc_lock);
1754 return ret;
1755}
1756
David Dai9d66f3f2016-11-23 15:33:06 -08001757static int query_client_usecase(struct msm_bus_tcs_usecase *tcs_usecase,
1758 uint32_t cl, unsigned int index)
1759{
1760 int ret = 0;
1761 struct msm_bus_scale_pdata *pdata;
1762 struct msm_bus_client *client;
1763 const char *test_cl = "Null";
1764 bool log_transaction = false;
1765
1766 rt_mutex_lock(&msm_bus_adhoc_lock);
1767
1768 if (!cl) {
1769 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1770 ret = -ENXIO;
1771 goto exit_query_client_usecase;
1772 }
1773
1774 client = handle_list.cl_list[cl];
1775 if (!client) {
1776 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1777 ret = -ENXIO;
1778 goto exit_query_client_usecase;
1779 }
1780
1781 pdata = client->pdata;
1782 if (!pdata) {
1783 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1784 __func__);
1785 ret = -ENXIO;
1786 goto exit_query_client_usecase;
1787 }
1788
1789 if (index >= pdata->num_usecases) {
1790 MSM_BUS_ERR("Client %u passed invalid index: %d\n",
1791 cl, index);
1792 ret = -ENXIO;
1793 goto exit_query_client_usecase;
1794 }
1795
1796 if (!strcmp(test_cl, pdata->name))
1797 log_transaction = true;
1798
1799 MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
1800 cl, index, client->curr, client->pdata->usecase->num_paths);
1801 ret = query_usecase(client, log_transaction, index, tcs_usecase);
1802 if (ret) {
1803 pr_err("%s: Err updating path\n", __func__);
1804 goto exit_query_client_usecase;
1805 }
1806
1807// trace_bus_update_request_end(pdata->name);
1808
1809exit_query_client_usecase:
1810 rt_mutex_unlock(&msm_bus_adhoc_lock);
1811 return ret;
1812}
1813
1814static int query_client_usecase_all(struct msm_bus_tcs_handle *tcs_handle,
1815 uint32_t cl)
1816{
1817 int ret = 0;
1818 struct msm_bus_scale_pdata *pdata;
1819 struct msm_bus_client *client;
1820 const char *test_cl = "Null";
1821 bool log_transaction = false;
1822 int i = 0;
1823
1824 rt_mutex_lock(&msm_bus_adhoc_lock);
1825
1826 if (!cl) {
1827 MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
1828 ret = -ENXIO;
1829 goto exit_query_client_usecase_all;
1830 }
1831
1832 client = handle_list.cl_list[cl];
1833 if (!client) {
1834 MSM_BUS_ERR("%s: Invalid client pointer ", __func__);
1835 ret = -ENXIO;
1836 goto exit_query_client_usecase_all;
1837 }
1838
1839 pdata = client->pdata;
1840 if (!pdata) {
1841 MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
1842 __func__);
1843 ret = -ENXIO;
1844 goto exit_query_client_usecase_all;
1845 }
1846
1847 if (!strcmp(test_cl, pdata->name))
1848 log_transaction = true;
1849
1850 MSM_BUS_ERR("%s: query_start", __func__);
1851 for (i = 0; i < pdata->num_usecases; i++)
1852 query_usecase(client, log_transaction, i,
1853 &tcs_handle->usecases[i]);
1854 tcs_handle->num_usecases = pdata->num_usecases;
1855
1856 if (ret) {
1857 pr_err("%s: Err updating path\n", __func__);
1858 goto exit_query_client_usecase_all;
1859 }
1860
1861// trace_bus_update_request_end(pdata->name);
1862
1863exit_query_client_usecase_all:
1864 rt_mutex_unlock(&msm_bus_adhoc_lock);
1865 return ret;
1866}
1867
David Dai04ce4202016-09-26 16:24:13 -07001868static void free_cl_mem(struct msm_bus_client_handle *cl)
1869{
1870 if (cl) {
1871 kfree(cl->name);
1872 kfree(cl);
1873 cl = NULL;
1874 }
1875}
1876
1877static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
1878{
1879 int ret = 0;
1880 char *test_cl = "test-client";
1881 bool log_transaction = false;
1882 u64 slp_ib, slp_ab;
1883
1884 rt_mutex_lock(&msm_bus_adhoc_lock);
1885
1886 if (!cl) {
1887 MSM_BUS_ERR("%s: Invalid client handle %p", __func__, cl);
1888 ret = -ENXIO;
1889 goto exit_update_request;
1890 }
1891
1892 if (!strcmp(test_cl, cl->name))
1893 log_transaction = true;
1894
1895 msm_bus_dbg_rec_transaction(cl, ab, ib);
1896
1897 if ((cl->cur_act_ib == ib) && (cl->cur_act_ab == ab)) {
1898 MSM_BUS_DBG("%s:no change in request", cl->name);
1899 goto exit_update_request;
1900 }
1901
1902 if (cl->active_only) {
1903 slp_ib = 0;
1904 slp_ab = 0;
1905 } else {
1906 slp_ib = ib;
1907 slp_ab = ab;
1908 }
1909
1910 ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab,
1911 cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only);
1912
1913 if (ret) {
1914 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1915 __func__, ret, cl->active_only);
1916 goto exit_update_request;
1917 }
1918
1919 commit_data();
1920 cl->cur_act_ib = ib;
1921 cl->cur_act_ab = ab;
1922 cl->cur_slp_ib = slp_ib;
1923 cl->cur_slp_ab = slp_ab;
1924
1925 if (log_transaction)
1926 getpath_debug(cl->mas, cl->first_hop, cl->active_only);
1927// trace_bus_update_request_end(cl->name);
1928exit_update_request:
1929 rt_mutex_unlock(&msm_bus_adhoc_lock);
1930
1931 return ret;
1932}
1933
1934static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
1935 u64 act_ib, u64 slp_ib, u64 slp_ab)
1936{
1937 int ret = 0;
1938
1939 rt_mutex_lock(&msm_bus_adhoc_lock);
1940 if (!cl) {
1941 MSM_BUS_ERR("Invalid client handle %p", cl);
1942 ret = -ENXIO;
1943 goto exit_change_context;
1944 }
1945
1946 if ((cl->cur_act_ib == act_ib) &&
1947 (cl->cur_act_ab == act_ab) &&
1948 (cl->cur_slp_ib == slp_ib) &&
1949 (cl->cur_slp_ab == slp_ab)) {
1950 MSM_BUS_ERR("No change in vote");
1951 goto exit_change_context;
1952 }
1953
1954 if (!slp_ab && !slp_ib)
1955 cl->active_only = true;
1956 msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib);
1957 ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab,
1958 cl->cur_act_ab, cl->cur_act_ab, cl->first_hop,
1959 cl->active_only);
1960 if (ret) {
1961 MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
1962 __func__, ret, cl->active_only);
1963 goto exit_change_context;
1964 }
1965 commit_data();
1966 cl->cur_act_ib = act_ib;
1967 cl->cur_act_ab = act_ab;
1968 cl->cur_slp_ib = slp_ib;
1969 cl->cur_slp_ab = slp_ab;
1970// trace_bus_update_request_end(cl->name);
1971exit_change_context:
1972 rt_mutex_unlock(&msm_bus_adhoc_lock);
1973 return ret;
1974}
1975
1976static void unregister_adhoc(struct msm_bus_client_handle *cl)
1977{
1978 rt_mutex_lock(&msm_bus_adhoc_lock);
1979 if (!cl) {
1980 MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
1981 __func__);
1982 goto exit_unregister_client;
1983 }
1984
1985 MSM_BUS_DBG("%s: Unregistering client %p", __func__, cl);
1986
1987 remove_path(cl->mas_dev, cl->slv, cl->cur_act_ib, cl->cur_act_ab,
1988 cl->first_hop, cl->active_only);
1989 commit_data();
1990 msm_bus_dbg_remove_client(cl);
1991 kfree(cl);
David Dai0d014432016-11-10 12:57:44 -08001992 MSM_BUS_DBG("%s: Unregistered client", __func__);
David Dai04ce4202016-09-26 16:24:13 -07001993exit_unregister_client:
1994 rt_mutex_unlock(&msm_bus_adhoc_lock);
1995}
1996
1997static struct msm_bus_client_handle*
1998register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only)
1999{
2000 struct msm_bus_client_handle *client = NULL;
2001 int len = 0;
2002
2003 rt_mutex_lock(&msm_bus_adhoc_lock);
2004
2005 if (!(mas && slv && name)) {
2006 pr_err("%s: Error: src dst name num_paths are required",
2007 __func__);
2008 goto exit_register;
2009 }
2010
2011 client = kzalloc(sizeof(struct msm_bus_client_handle), GFP_KERNEL);
2012 if (!client) {
2013 MSM_BUS_ERR("%s: Error allocating client data", __func__);
2014 goto exit_register;
2015 }
2016
2017 len = strnlen(name, MAX_STR_CL);
2018 client->name = kzalloc((len + 1), GFP_KERNEL);
2019 if (!client->name) {
2020 MSM_BUS_ERR("%s: Error allocating client name buf", __func__);
2021 free_cl_mem(client);
2022 goto exit_register;
2023 }
2024 strlcpy(client->name, name, MAX_STR_CL);
2025 client->active_only = active_only;
2026
2027 client->mas = mas;
2028 client->slv = slv;
2029
2030 client->mas_dev = bus_find_device(&msm_bus_type, NULL,
2031 (void *) &mas,
2032 msm_bus_device_match_adhoc);
2033 if (IS_ERR_OR_NULL(client->mas_dev)) {
2034 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
2035 __func__, client->mas, client->slv);
2036 free_cl_mem(client);
2037 goto exit_register;
2038 }
2039
2040 client->first_hop = getpath(client->mas_dev, client->slv, client->name);
2041 if (client->first_hop < 0) {
2042 MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
2043 __func__, client->mas, client->slv);
2044 free_cl_mem(client);
2045 goto exit_register;
2046 }
2047
2048 MSM_BUS_DBG("%s:Client handle %p %s", __func__, client,
2049 client->name);
2050 msm_bus_dbg_add_client(client);
2051exit_register:
2052 rt_mutex_unlock(&msm_bus_adhoc_lock);
2053 return client;
2054}
2055/**
2056 * msm_bus_arb_setops_adhoc() : Setup the bus arbitration ops
2057 * @ arb_ops: pointer to the arb ops.
2058 */
2059void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops)
2060{
2061 arb_ops->register_client = register_client_adhoc;
2062 arb_ops->update_request = update_request_adhoc;
2063 arb_ops->unregister_client = unregister_client_adhoc;
2064 arb_ops->update_context = update_context;
2065
2066 arb_ops->register_cl = register_adhoc;
2067 arb_ops->unregister = unregister_adhoc;
2068 arb_ops->update_bw = update_bw_adhoc;
2069 arb_ops->update_bw_context = update_bw_context;
David Dai9d66f3f2016-11-23 15:33:06 -08002070 arb_ops->query_usecase = query_client_usecase;
2071 arb_ops->query_usecase_all = query_client_usecase_all;
David Dai04ce4202016-09-26 16:24:13 -07002072}