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