blob: 80a39b57503f2bb31e2e7a23a650adad60c1117b [file] [log] [blame]
Michael Adisumartaf0424822018-01-15 16:15:33 -08001/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
Michael Adisumartac06df412017-09-19 10:10:35 -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
13#include <linux/debugfs.h>
14#include "ipa_pm.h"
15#include "ipa_i.h"
16
17static const char *client_state_to_str[IPA_PM_STATE_MAX] = {
18 __stringify(IPA_PM_DEACTIVATED),
19 __stringify(IPA_PM_DEACTIVATE_IN_PROGRESS),
20 __stringify(IPA_PM_ACTIVATE_IN_PROGRESS),
21 __stringify(IPA_PM_ACTIVATED),
22 __stringify(IPA_PM_ACTIVATED_PENDING_DEACTIVATION),
23 __stringify(IPA_PM_ACTIVATED_TIMER_SET),
24 __stringify(IPA_PM_ACTIVATED_PENDING_RESCHEDULE),
25};
26
27static const char *ipa_pm_group_to_str[IPA_PM_GROUP_MAX] = {
28 __stringify(IPA_PM_GROUP_DEFAULT),
29 __stringify(IPA_PM_GROUP_APPS),
30 __stringify(IPA_PM_GROUP_MODEM),
31};
32
33
34#define IPA_PM_DRV_NAME "ipa_pm"
35
36#define IPA_PM_DBG(fmt, args...) \
37 do { \
38 pr_debug(IPA_PM_DRV_NAME " %s:%d " fmt, \
39 __func__, __LINE__, ## args); \
40 IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
41 IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
42 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
43 IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
44 } while (0)
45#define IPA_PM_DBG_LOW(fmt, args...) \
46 do { \
47 pr_debug(IPA_PM_DRV_NAME " %s:%d " fmt, \
48 __func__, __LINE__, ## args); \
49 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
50 IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
51 } while (0)
52#define IPA_PM_ERR(fmt, args...) \
53 do { \
54 pr_err(IPA_PM_DRV_NAME " %s:%d " fmt, \
55 __func__, __LINE__, ## args); \
56 IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
57 IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
58 IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
59 IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
60 } while (0)
61#define IPA_PM_DBG_STATE(hdl, name, state) \
62 IPA_PM_DBG_LOW("Client[%d] %s: %s\n", hdl, name, \
63 client_state_to_str[state])
64
65
66#if IPA_PM_MAX_CLIENTS > 32
67#error max client greater than 32 all bitmask types should be changed
68#endif
69
70/*
71 * struct ipa_pm_exception_list - holds information about an exception
72 * @pending: number of clients in exception that have not yet been adctivated
73 * @bitmask: bitmask of the clients in the exception based on handle
74 * @threshold: the threshold values for the exception
75 */
76struct ipa_pm_exception_list {
77 char clients[IPA_PM_MAX_EX_CL];
78 int pending;
79 u32 bitmask;
80 int threshold[IPA_PM_THRESHOLD_MAX];
81};
82
83/*
84 * struct clk_scaling_db - holds information about threshholds and exceptions
85 * @lock: lock the bitmasks and thresholds
86 * @exception_list: pointer to the list of exceptions
87 * @work: work for clock scaling algorithm
88 * @active_client_bitmask: the bits represent handles in the clients array that
89 * contain non-null client
90 * @threshold_size: size of the throughput threshold
91 * @exception_size: size of the exception list
92 * @cur_vote: idx of the threshold
93 * @default_threshold: the thresholds used if no exception passes
94 * @current_threshold: the current threshold of the clock plan
95 */
96struct clk_scaling_db {
97 spinlock_t lock;
98 struct ipa_pm_exception_list exception_list[IPA_PM_EXCEPTION_MAX];
99 struct work_struct work;
100 u32 active_client_bitmask;
101 int threshold_size;
102 int exception_size;
103 int cur_vote;
104 int default_threshold[IPA_PM_THRESHOLD_MAX];
105 int *current_threshold;
106};
107
108/*
109 * ipa_pm state names
110 *
111 * Timer free states:
112 * @IPA_PM_DEACTIVATED: client starting state when registered
113 * @IPA_PM_DEACTIVATE_IN_PROGRESS: deactivate was called in progress of a client
114 * activating
115 * @IPA_PM_ACTIVATE_IN_PROGRESS: client is being activated by work_queue
116 * @IPA_PM_ACTIVATED: client is activated without any timers
117 *
118 * Timer set states:
119 * @IPA_PM_ACTIVATED_PENDING_DEACTIVATION: moves to deactivate once timer pass
120 * @IPA_PM_ACTIVATED_TIMER_SET: client was activated while timer was set, so
121 * when the timer pass, client will still be activated
122 *@IPA_PM_ACTIVATED_PENDING_RESCHEDULE: state signifying extended timer when
123 * a client is deferred_deactivated when a time ris still active
124 */
125enum ipa_pm_state {
126 IPA_PM_DEACTIVATED,
127 IPA_PM_DEACTIVATE_IN_PROGRESS,
128 IPA_PM_ACTIVATE_IN_PROGRESS,
129 IPA_PM_ACTIVATED,
130 IPA_PM_ACTIVATED_PENDING_DEACTIVATION,
131 IPA_PM_ACTIVATED_TIMER_SET,
132 IPA_PM_ACTIVATED_PENDING_RESCHEDULE,
133};
134
135#define IPA_PM_STATE_ACTIVE(state) \
136 (state == IPA_PM_ACTIVATED ||\
137 state == IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||\
138 state == IPA_PM_ACTIVATED_TIMER_SET ||\
139 state == IPA_PM_ACTIVATED_PENDING_RESCHEDULE)
140
141#define IPA_PM_STATE_IN_PROGRESS(state) \
142 (state == IPA_PM_ACTIVATE_IN_PROGRESS \
143 || state == IPA_PM_DEACTIVATE_IN_PROGRESS)
144
145/*
146 * struct ipa_pm_client - holds information about a specific IPA client
147 * @name: string name of the client
148 * @callback: pointer to the client's callback function
149 * @callback_params: pointer to the client's callback parameters
150 * @state: Activation state of the client
151 * @skip_clk_vote: 0 if client votes for clock when activated, 1 if no vote
152 * @group: the ipa_pm_group the client belongs to
153 * @hdl: handle of the client
154 * @throughput: the throughput of the client for clock scaling
155 * @state_lock: spinlock to lock the pm_states
156 * @activate_work: work for activate (blocking case)
157 * @deactivate work: delayed work for deferred_deactivate function
158 * @complete: generic wait-for-completion handler
159 */
160struct ipa_pm_client {
161 char name[IPA_PM_MAX_EX_CL];
162 void (*callback)(void*, enum ipa_pm_cb_event);
163 void *callback_params;
164 enum ipa_pm_state state;
165 bool skip_clk_vote;
166 int group;
167 int hdl;
168 int throughput;
169 spinlock_t state_lock;
170 struct work_struct activate_work;
171 struct delayed_work deactivate_work;
172 struct completion complete;
173};
174
175/*
176 * struct ipa_pm_ctx - global ctx that will hold the client arrays and tput info
177 * @clients: array to the clients with the handle as its index
178 * @clients_by_pipe: array to the clients with endpoint as the index
179 * @wq: work queue for deferred deactivate, activate, and clk_scaling work
180 8 @clk_scaling: pointer to clock scaling database
181 * @client_mutex: global mutex to lock the client arrays
182 * @aggragated_tput: aggragated tput value of all valid activated clients
183 * @group_tput: combined throughput for the groups
184 */
185struct ipa_pm_ctx {
186 struct ipa_pm_client *clients[IPA_PM_MAX_CLIENTS];
187 struct ipa_pm_client *clients_by_pipe[IPA3_MAX_NUM_PIPES];
188 struct workqueue_struct *wq;
189 struct clk_scaling_db clk_scaling;
190 struct mutex client_mutex;
191 int aggregated_tput;
192 int group_tput[IPA_PM_GROUP_MAX];
193};
194
195static struct ipa_pm_ctx *ipa_pm_ctx;
196
197/**
198 * pop_max_from_array() -pop the max and move the last element to where the
199 * max was popped
200 * @arr: array to be searched for max
201 * @n: size of the array
202 *
203 * Returns: max value of the array
204 */
205static int pop_max_from_array(int *arr, int *n)
206{
207 int i;
208 int max, max_idx;
209
210 max_idx = *n - 1;
211 max = 0;
212
213 if (*n == 0)
214 return 0;
215
216 for (i = 0; i < *n; i++) {
217 if (arr[i] > max) {
218 max = arr[i];
219 max_idx = i;
220 }
221 }
222 (*n)--;
223 arr[max_idx] = arr[*n];
224
225 return max;
226}
227
228/**
229 * calculate_throughput() - calculate the aggregated throughput
230 * based on active clients
231 *
232 * Returns: aggregated tput value
233 */
234static int calculate_throughput(void)
235{
236 int client_tput[IPA_PM_MAX_CLIENTS] = { 0 };
237 bool group_voted[IPA_PM_GROUP_MAX] = { false };
238 int i, n;
239 int max, second_max, aggregated_tput;
240 struct ipa_pm_client *client;
241
242 /* Create a basic array to hold throughputs*/
Michael Adisumartaf0424822018-01-15 16:15:33 -0800243 for (i = 1, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700244 client = ipa_pm_ctx->clients[i];
245 if (client != NULL && IPA_PM_STATE_ACTIVE(client->state)) {
246 /* default case */
247 if (client->group == IPA_PM_GROUP_DEFAULT) {
248 client_tput[n++] = client->throughput;
249 } else if (group_voted[client->group] == false) {
250 client_tput[n++] = ipa_pm_ctx->group_tput
251 [client->group];
252 group_voted[client->group] = true;
253 }
254 }
255 }
256 /*the array will only use n+1 spots. n will be the last index used*/
257
258 aggregated_tput = 0;
259
260 /**
261 * throughput algorithm:
262 * 1) pop the max and second_max
263 * 2) add the 2nd max to aggregated tput
264 * 3) insert the value of max - 2nd max
265 * 4) repeat until array is of size 1
266 */
267 while (n > 1) {
268 max = pop_max_from_array(client_tput, &n);
269 second_max = pop_max_from_array(client_tput, &n);
270 client_tput[n++] = max - second_max;
271 aggregated_tput += second_max;
272 }
273
274 IPA_PM_DBG_LOW("Aggregated throughput: %d\n", aggregated_tput);
275
276 return aggregated_tput;
277}
278
279/**
280 * deactivate_client() - turn off the bit in the active client bitmask based on
281 * the handle passed in
282 * @hdl: The index of the client to be deactivated
283 */
284static void deactivate_client(u32 hdl)
285{
286 unsigned long flags;
287
288 spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
289 ipa_pm_ctx->clk_scaling.active_client_bitmask &= ~(1 << hdl);
290 spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
291 IPA_PM_DBG_LOW("active bitmask: %x\n",
292 ipa_pm_ctx->clk_scaling.active_client_bitmask);
293}
294
295/**
296 * activate_client() - turn on the bit in the active client bitmask based on
297 * the handle passed in
298 * @hdl: The index of the client to be activated
299 */
300static void activate_client(u32 hdl)
301{
302 unsigned long flags;
303
304 spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
305 ipa_pm_ctx->clk_scaling.active_client_bitmask |= (1 << hdl);
306 spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
307 IPA_PM_DBG_LOW("active bitmask: %x\n",
308 ipa_pm_ctx->clk_scaling.active_client_bitmask);
309}
310
311/**
312 * deactivate_client() - get threshold
313 *
314 * Returns: threshold of the exception that passes or default if none pass
315 */
316static void set_current_threshold(void)
317{
318 int i;
319 struct clk_scaling_db *clk;
320 struct ipa_pm_exception_list *exception;
321 unsigned long flags;
322
323 clk = &ipa_pm_ctx->clk_scaling;
324
325 spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
326 for (i = 0; i < clk->exception_size; i++) {
327 exception = &clk->exception_list[i];
328 if (exception->pending == 0 && (exception->bitmask
329 & ~clk->active_client_bitmask) == 0) {
330 spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock,
331 flags);
332 clk->current_threshold = exception->threshold;
333 IPA_PM_DBG("Exception %d set\n", i);
334 return;
335 }
336 }
337 clk->current_threshold = clk->default_threshold;
338 spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
339}
340
341/**
342 * do_clk_scaling() - set the clock based on the activated clients
343 *
344 * Returns: 0 if success, negative otherwise
345 */
346static int do_clk_scaling(void)
347{
348 int i, tput;
349 int new_th_idx = 1;
350 struct clk_scaling_db *clk_scaling;
351
352 clk_scaling = &ipa_pm_ctx->clk_scaling;
353
354 mutex_lock(&ipa_pm_ctx->client_mutex);
Michael Adisumarta03f3ab62017-12-20 15:26:49 -0800355 IPA_PM_DBG_LOW("clock scaling started\n");
Michael Adisumartac06df412017-09-19 10:10:35 -0700356 tput = calculate_throughput();
357 ipa_pm_ctx->aggregated_tput = tput;
358 set_current_threshold();
359
360 mutex_unlock(&ipa_pm_ctx->client_mutex);
361
362 for (i = 0; i < clk_scaling->threshold_size; i++) {
363 if (tput > clk_scaling->current_threshold[i])
364 new_th_idx++;
365 }
366
Michael Adisumarta03f3ab62017-12-20 15:26:49 -0800367 IPA_PM_DBG_LOW("old idx was at %d\n", ipa_pm_ctx->clk_scaling.cur_vote);
Michael Adisumartac06df412017-09-19 10:10:35 -0700368
369
370 if (ipa_pm_ctx->clk_scaling.cur_vote != new_th_idx) {
371 ipa_pm_ctx->clk_scaling.cur_vote = new_th_idx;
372 ipa3_set_clock_plan_from_pm(ipa_pm_ctx->clk_scaling.cur_vote);
373 }
374
Michael Adisumarta03f3ab62017-12-20 15:26:49 -0800375 IPA_PM_DBG_LOW("new idx is at %d\n", ipa_pm_ctx->clk_scaling.cur_vote);
Michael Adisumartac06df412017-09-19 10:10:35 -0700376
377 return 0;
378}
379
380/**
381 * clock_scaling_func() - set the clock on a work queue
382 */
383static void clock_scaling_func(struct work_struct *work)
384{
385 do_clk_scaling();
386}
387
388/**
389 * activate_work_func - activate a client and vote for clock on a work queue
390 */
391static void activate_work_func(struct work_struct *work)
392{
393 struct ipa_pm_client *client;
394 bool dec_clk = false;
395 unsigned long flags;
396
397 client = container_of(work, struct ipa_pm_client, activate_work);
398 if (!client->skip_clk_vote)
399 IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
400
401 spin_lock_irqsave(&client->state_lock, flags);
402 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
403 if (client->state == IPA_PM_ACTIVATE_IN_PROGRESS) {
404 client->state = IPA_PM_ACTIVATED;
405 } else if (client->state == IPA_PM_DEACTIVATE_IN_PROGRESS) {
406 client->state = IPA_PM_DEACTIVATED;
407 dec_clk = true;
408 } else {
409 IPA_PM_ERR("unexpected state %d\n", client->state);
410 WARN_ON(1);
411 }
412 spin_unlock_irqrestore(&client->state_lock, flags);
413
414 complete_all(&client->complete);
415
416 if (dec_clk) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700417 if (!client->skip_clk_vote)
418 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
419
420 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
421 return;
422 }
423
424 activate_client(client->hdl);
425
426 mutex_lock(&ipa_pm_ctx->client_mutex);
Michael Adisumartace75fc72017-10-04 11:42:11 -0700427 if (client->callback) {
428 client->callback(client->callback_params,
429 IPA_PM_CLIENT_ACTIVATED);
430 } else {
431 IPA_PM_ERR("client has no callback");
432 WARN_ON(1);
433 }
Michael Adisumartac06df412017-09-19 10:10:35 -0700434 mutex_unlock(&ipa_pm_ctx->client_mutex);
435
436 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
437 do_clk_scaling();
438}
439
440/**
441 * delayed_deferred_deactivate_work_func - deferred deactivate on a work queue
442 */
443static void delayed_deferred_deactivate_work_func(struct work_struct *work)
444{
445 struct delayed_work *dwork;
446 struct ipa_pm_client *client;
447 unsigned long flags;
448
449 dwork = container_of(work, struct delayed_work, work);
450 client = container_of(dwork, struct ipa_pm_client, deactivate_work);
451
452 spin_lock_irqsave(&client->state_lock, flags);
453 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
454 switch (client->state) {
455 case IPA_PM_ACTIVATED_TIMER_SET:
456 client->state = IPA_PM_ACTIVATED;
457 goto bail;
458 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
459 queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
460 msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
461 client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
462 goto bail;
463 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
464 client->state = IPA_PM_DEACTIVATED;
465 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
466 spin_unlock_irqrestore(&client->state_lock, flags);
Michael Adisumartac06df412017-09-19 10:10:35 -0700467 if (!client->skip_clk_vote)
468 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
469
470 deactivate_client(client->hdl);
471 do_clk_scaling();
472 return;
473 default:
474 IPA_PM_ERR("unexpected state %d\n", client->state);
475 WARN_ON(1);
476 goto bail;
477 }
478
479bail:
480 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
481 spin_unlock_irqrestore(&client->state_lock, flags);
482}
483
484static int find_next_open_array_element(const char *name)
485{
486 int i, n;
487
488 n = -ENOBUFS;
489
Michael Adisumartaf0424822018-01-15 16:15:33 -0800490 /* 0 is not a valid handle */
491 for (i = IPA_PM_MAX_CLIENTS - 1; i >= 1; i--) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700492 if (ipa_pm_ctx->clients[i] == NULL) {
493 n = i;
494 continue;
495 }
496
497 if (strlen(name) == strlen(ipa_pm_ctx->clients[i]->name))
498 if (!strcmp(name, ipa_pm_ctx->clients[i]->name))
499 return -EEXIST;
500 }
501 return n;
502}
503
504/**
505 * add_client_to_exception_list() - add client to the exception list and
506 * update pending if necessary
507 * @hdl: index of the IPA client
508 *
509 * Returns: 0 if success, negative otherwise
510 */
511static int add_client_to_exception_list(u32 hdl)
512{
513 int i;
514 struct ipa_pm_exception_list *exception;
515
516 mutex_lock(&ipa_pm_ctx->client_mutex);
517 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
518 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
519 if (strnstr(exception->clients, ipa_pm_ctx->clients[hdl]->name,
520 strlen(exception->clients))) {
521 exception->pending--;
522
523 if (exception->pending < 0) {
524 WARN_ON(1);
525 exception->pending = 0;
526 mutex_unlock(&ipa_pm_ctx->client_mutex);
527 return -EPERM;
528 }
529 exception->bitmask |= (1 << hdl);
530 }
531 }
532 IPA_PM_DBG("%s added to exception list\n",
533 ipa_pm_ctx->clients[hdl]->name);
534 mutex_unlock(&ipa_pm_ctx->client_mutex);
535
536 return 0;
537}
538
539/**
540 * remove_client_to_exception_list() - remove client from the exception list and
541 * update pending if necessary
542 * @hdl: index of the IPA client
543 *
544 * Returns: 0 if success, negative otherwise
545 */
546static int remove_client_from_exception_list(u32 hdl)
547{
548 int i;
549 struct ipa_pm_exception_list *exception;
550
551 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
552 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
553 if (exception->bitmask & (1 << hdl)) {
554 exception->pending++;
555 exception->bitmask &= ~(1 << hdl);
556 }
557 }
558 IPA_PM_DBG("Client %d removed from exception list\n", hdl);
559
560 return 0;
561}
562
563/**
564 * ipa_pm_init() - initialize IPA PM Components
565 * @ipa_pm_init_params: parameters needed to fill exceptions and thresholds
566 *
567 * Returns: 0 on success, negative on failure
568 */
569int ipa_pm_init(struct ipa_pm_init_params *params)
570{
571 int i, j;
572 struct clk_scaling_db *clk_scaling;
573
574 if (params == NULL) {
575 IPA_PM_ERR("Invalid Params\n");
576 return -EINVAL;
577 }
578
579 if (params->threshold_size <= 0
580 || params->threshold_size > IPA_PM_THRESHOLD_MAX) {
581 IPA_PM_ERR("Invalid threshold size\n");
582 return -EINVAL;
583 }
584
585 if (params->exception_size < 0
586 || params->exception_size > IPA_PM_EXCEPTION_MAX) {
587 IPA_PM_ERR("Invalid exception size\n");
588 return -EINVAL;
589 }
590
591 IPA_PM_DBG("IPA PM initialization started\n");
592
593 if (ipa_pm_ctx != NULL) {
594 IPA_PM_ERR("Already initialized\n");
595 return -EPERM;
596 }
597
598
599 ipa_pm_ctx = kzalloc(sizeof(*ipa_pm_ctx), GFP_KERNEL);
600 if (!ipa_pm_ctx) {
601 IPA_PM_ERR(":kzalloc err.\n");
602 return -ENOMEM;
603 }
604
605 ipa_pm_ctx->wq = create_singlethread_workqueue("ipa_pm_activate");
606 if (!ipa_pm_ctx->wq) {
607 IPA_PM_ERR("create workqueue failed\n");
608 kfree(ipa_pm_ctx);
609 return -ENOMEM;
610 }
611
612 mutex_init(&ipa_pm_ctx->client_mutex);
613
614 /* Populate and init locks in clk_scaling_db */
615 clk_scaling = &ipa_pm_ctx->clk_scaling;
616 spin_lock_init(&clk_scaling->lock);
617 clk_scaling->threshold_size = params->threshold_size;
618 clk_scaling->exception_size = params->exception_size;
619 INIT_WORK(&clk_scaling->work, clock_scaling_func);
620
621 for (i = 0; i < params->threshold_size; i++)
622 clk_scaling->default_threshold[i] =
623 params->default_threshold[i];
624
625 /* Populate exception list*/
626 for (i = 0; i < params->exception_size; i++) {
627 strlcpy(clk_scaling->exception_list[i].clients,
628 params->exceptions[i].usecase, IPA_PM_MAX_EX_CL);
629 IPA_PM_DBG("Usecase: %s\n", params->exceptions[i].usecase);
630
631 /* Parse the commas to count the size of the clients */
632 for (j = 0; j < IPA_PM_MAX_EX_CL &&
633 clk_scaling->exception_list[i].clients[j]; j++) {
634 if (clk_scaling->exception_list[i].clients[j] == ',')
635 clk_scaling->exception_list[i].pending++;
636 }
637
638 clk_scaling->exception_list[i].pending++;
639 IPA_PM_DBG("Pending: %d\n", clk_scaling->
640 exception_list[i].pending);
641
642 /* populate the threshold */
643 for (j = 0; j < params->threshold_size; j++) {
644 clk_scaling->exception_list[i].threshold[j]
645 = params->exceptions[i].threshold[j];
646 }
647
648 }
649 IPA_PM_DBG("initialization success");
650
651 return 0;
652}
653
654int ipa_pm_destroy(void)
655{
656 IPA_PM_DBG("IPA PM destroy started\n");
657
658 if (ipa_pm_ctx == NULL) {
659 IPA_PM_ERR("Already destroyed\n");
660 return -EPERM;
661 }
662
663 destroy_workqueue(ipa_pm_ctx->wq);
664
665 kfree(ipa_pm_ctx);
666 ipa_pm_ctx = NULL;
667
668 return 0;
669}
670
671/**
672 * ipa_rm_delete_register() - register an IPA PM client with the PM
673 * @register_params: params for a client like throughput, callback, etc.
674 * @hdl: int pointer that will be used as an index to access the client
675 *
676 * Returns: 0 on success, negative on failure
677 *
678 * Side effects: *hdl is replaced with the client index or -EEXIST if
679 * client is already registered
680 */
681int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl)
682{
683 struct ipa_pm_client *client;
684
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800685 if (ipa_pm_ctx == NULL) {
686 IPA_PM_ERR("PM_ctx is null\n");
687 return -EINVAL;
688 }
689
Michael Adisumartace75fc72017-10-04 11:42:11 -0700690 if (params == NULL || hdl == NULL || params->name == NULL) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700691 IPA_PM_ERR("Invalid Params\n");
692 return -EINVAL;
693 }
694
695 IPA_PM_DBG("IPA PM registering client\n");
696
697 mutex_lock(&ipa_pm_ctx->client_mutex);
698
699 *hdl = find_next_open_array_element(params->name);
700
701 if (*hdl > IPA_CLIENT_MAX) {
702 mutex_unlock(&ipa_pm_ctx->client_mutex);
703 IPA_PM_ERR("client is already registered or array is full\n");
704 return *hdl;
705 }
706
707 ipa_pm_ctx->clients[*hdl] = kzalloc(sizeof
708 (struct ipa_pm_client), GFP_KERNEL);
709 if (!ipa_pm_ctx->clients[*hdl]) {
710 mutex_unlock(&ipa_pm_ctx->client_mutex);
711 IPA_PM_ERR(":kzalloc err.\n");
712 return -ENOMEM;
713 }
714 mutex_unlock(&ipa_pm_ctx->client_mutex);
715
716 client = ipa_pm_ctx->clients[*hdl];
717
718 spin_lock_init(&client->state_lock);
719
720 INIT_DELAYED_WORK(&client->deactivate_work,
721 delayed_deferred_deactivate_work_func);
722
723 INIT_WORK(&client->activate_work, activate_work_func);
724
725 /* populate fields */
726 strlcpy(client->name, params->name, IPA_PM_MAX_EX_CL);
727 client->callback = params->callback;
728 client->callback_params = params->user_data;
729 client->group = params->group;
730 client->hdl = *hdl;
731 client->skip_clk_vote = params->skip_clk_vote;
732
733 /* add client to exception list */
734 if (add_client_to_exception_list(*hdl)) {
735 ipa_pm_deregister(*hdl);
736 IPA_PM_ERR("Fail to add client to exception_list\n");
737 return -EPERM;
738 }
739
740 IPA_PM_DBG("IPA PM client registered with handle %d\n", *hdl);
741 return 0;
742}
743
744/**
745 * ipa_pm_deregister() - deregister IPA client from the PM
746 * @hdl: index of the client in the array
747 *
748 * Returns: 0 on success, negative on failure
749 */
750int ipa_pm_deregister(u32 hdl)
751{
752 struct ipa_pm_client *client;
753 int i;
754 unsigned long flags;
755
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800756 if (ipa_pm_ctx == NULL) {
757 IPA_PM_ERR("PM_ctx is null\n");
758 return -EINVAL;
759 }
760
Michael Adisumartac06df412017-09-19 10:10:35 -0700761 if (hdl >= IPA_PM_MAX_CLIENTS) {
762 IPA_PM_ERR("Invalid Param\n");
763 return -EINVAL;
764 }
765
766 if (ipa_pm_ctx->clients[hdl] == NULL) {
767 IPA_PM_ERR("Client is Null\n");
768 return -EINVAL;
769 }
770
771 IPA_PM_DBG("IPA PM deregistering client\n");
772
773 client = ipa_pm_ctx->clients[hdl];
774 spin_lock_irqsave(&client->state_lock, flags);
775 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
776 spin_unlock_irqrestore(&client->state_lock, flags);
777 wait_for_completion(&client->complete);
778 spin_lock_irqsave(&client->state_lock, flags);
779 }
780
781 if (IPA_PM_STATE_ACTIVE(client->state)) {
782 IPA_PM_DBG("Activated clients cannot be deregistered");
783 spin_unlock_irqrestore(&client->state_lock, flags);
784 return -EPERM;
785 }
786 spin_unlock_irqrestore(&client->state_lock, flags);
787
788 mutex_lock(&ipa_pm_ctx->client_mutex);
789
790 /* nullify pointers in pipe array */
791 for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
792 if (ipa_pm_ctx->clients_by_pipe[i] == ipa_pm_ctx->clients[hdl])
793 ipa_pm_ctx->clients_by_pipe[i] = NULL;
794 }
795 kfree(client);
796 ipa_pm_ctx->clients[hdl] = NULL;
797
798 remove_client_from_exception_list(hdl);
799 IPA_PM_DBG("IPA PM client %d deregistered\n", hdl);
800 mutex_unlock(&ipa_pm_ctx->client_mutex);
801
802 return 0;
803}
804
805/**
806 * ipa_pm_associate_ipa_cons_to_client() - add mapping to pipe with ipa cllent
807 * @hdl: index of the client to be mapped
808 * @consumer: the pipe/consumer name to be pipped to the client
809 *
810 * Returns: 0 on success, negative on failure
811 *
812 * Side effects: multiple pipes are allowed to be mapped to a single client
813 */
814int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer)
815{
816 int idx;
817
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800818 if (ipa_pm_ctx == NULL) {
819 IPA_PM_ERR("PM_ctx is null\n");
820 return -EINVAL;
821 }
822
Michael Adisumartac06df412017-09-19 10:10:35 -0700823 if (hdl >= IPA_PM_MAX_CLIENTS || consumer < 0 ||
824 consumer >= IPA_CLIENT_MAX) {
825 IPA_PM_ERR("invalid params\n");
826 return -EINVAL;
827 }
828
829 mutex_lock(&ipa_pm_ctx->client_mutex);
830 idx = ipa_get_ep_mapping(consumer);
831
832 IPA_PM_DBG("Mapping pipe %d to client %d\n", idx, hdl);
833
834 if (idx < 0) {
835 mutex_unlock(&ipa_pm_ctx->client_mutex);
836 IPA_PM_DBG("Pipe is not used\n");
837 return 0;
838 }
839
840 if (ipa_pm_ctx->clients[hdl] == NULL) {
841 mutex_unlock(&ipa_pm_ctx->client_mutex);
842 IPA_PM_ERR("Client is NULL\n");
843 return -EPERM;
844 }
845
846 if (ipa_pm_ctx->clients_by_pipe[idx] != NULL) {
847 mutex_unlock(&ipa_pm_ctx->client_mutex);
848 IPA_PM_ERR("Pipe is already mapped\n");
849 return -EPERM;
850 }
851 ipa_pm_ctx->clients_by_pipe[idx] = ipa_pm_ctx->clients[hdl];
852 mutex_unlock(&ipa_pm_ctx->client_mutex);
853
854 IPA_PM_DBG("Pipe %d is mapped to client %d\n", idx, hdl);
855
856 return 0;
857}
858
859static int ipa_pm_activate_helper(struct ipa_pm_client *client, bool sync)
860{
861 struct ipa_active_client_logging_info log_info;
862 int result = 0;
863 unsigned long flags;
864
865 spin_lock_irqsave(&client->state_lock, flags);
866 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
867
868 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
869 if (sync) {
870 spin_unlock_irqrestore(&client->state_lock, flags);
871 wait_for_completion(&client->complete);
872 spin_lock_irqsave(&client->state_lock, flags);
873 } else {
874 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
875 spin_unlock_irqrestore(&client->state_lock, flags);
876 return -EINPROGRESS;
877 }
878 }
879
880 switch (client->state) {
881 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
882 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
883 client->state = IPA_PM_ACTIVATED_TIMER_SET;
884 case IPA_PM_ACTIVATED:
885 case IPA_PM_ACTIVATED_TIMER_SET:
886 spin_unlock_irqrestore(&client->state_lock, flags);
887 return 0;
888 case IPA_PM_DEACTIVATED:
889 break;
890 default:
891 IPA_PM_ERR("Invalid State\n");
892 spin_unlock_irqrestore(&client->state_lock, flags);
893 return -EPERM;
894 }
895 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
896
897 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, client->name);
898 if (!client->skip_clk_vote) {
899 if (sync) {
900 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
901 spin_unlock_irqrestore(&client->state_lock, flags);
902 IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
903 spin_lock_irqsave(&client->state_lock, flags);
904 } else
905 result = ipa3_inc_client_enable_clks_no_block
906 (&log_info);
907 }
908
909 /* we got the clocks */
910 if (result == 0) {
911 client->state = IPA_PM_ACTIVATED;
912 spin_unlock_irqrestore(&client->state_lock, flags);
913 activate_client(client->hdl);
914 if (sync)
915 do_clk_scaling();
916 else
917 queue_work(ipa_pm_ctx->wq,
918 &ipa_pm_ctx->clk_scaling.work);
919 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
920 return 0;
921 }
922
923 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
924 init_completion(&client->complete);
925 queue_work(ipa_pm_ctx->wq, &client->activate_work);
926 spin_unlock_irqrestore(&client->state_lock, flags);
927 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
928 return -EINPROGRESS;
929}
930
931/**
932 * ipa_pm_activate(): activate ipa client to vote for clock(). Can be called
933 * from atomic context and returns -EINPROGRESS if cannot be done synchronously
934 * @hdl: index of the client in the array
935 *
936 * Returns: 0 on success, -EINPROGRESS if operation cannot be done synchronously
937 * and other negatives on failure
938 */
939int ipa_pm_activate(u32 hdl)
940{
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800941 if (ipa_pm_ctx == NULL) {
942 IPA_PM_ERR("PM_ctx is null\n");
943 return -EINVAL;
944 }
945
Michael Adisumartac06df412017-09-19 10:10:35 -0700946 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
947 IPA_PM_ERR("Invalid Param\n");
948 return -EINVAL;
949 }
950
951 return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], false);
952}
953
954/**
955 * ipa_pm_activate(): activate ipa client to vote for clock synchronously.
956 * Cannot be called from an atomic contex.
957 * @hdl: index of the client in the array
958 *
959 * Returns: 0 on success, negative on failure
960 */
961int ipa_pm_activate_sync(u32 hdl)
962{
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800963 if (ipa_pm_ctx == NULL) {
964 IPA_PM_ERR("PM_ctx is null\n");
965 return -EINVAL;
966 }
967
Michael Adisumartac06df412017-09-19 10:10:35 -0700968 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
969 IPA_PM_ERR("Invalid Param\n");
970 return -EINVAL;
971 }
972
973 return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], true);
974}
975
976/**
977 * ipa_pm_deferred_deactivate(): schedule a timer to deactivate client and
978 * devote clock. Can be called from atomic context (asynchronously)
979 * @hdl: index of the client in the array
980 *
981 * Returns: 0 on success, negative on failure
982 */
983int ipa_pm_deferred_deactivate(u32 hdl)
984{
985 struct ipa_pm_client *client;
986 unsigned long flags;
987
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800988 if (ipa_pm_ctx == NULL) {
989 IPA_PM_ERR("PM_ctx is null\n");
990 return -EINVAL;
991 }
992
Michael Adisumartac06df412017-09-19 10:10:35 -0700993 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
994 IPA_PM_ERR("Invalid Param\n");
995 return -EINVAL;
996 }
997
998 client = ipa_pm_ctx->clients[hdl];
999 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1000
1001 spin_lock_irqsave(&client->state_lock, flags);
1002 switch (client->state) {
1003 case IPA_PM_ACTIVATE_IN_PROGRESS:
1004 client->state = IPA_PM_DEACTIVATE_IN_PROGRESS;
1005 case IPA_PM_DEACTIVATED:
1006 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1007 spin_unlock_irqrestore(&client->state_lock, flags);
1008 return 0;
1009 case IPA_PM_ACTIVATED:
1010 client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
1011 queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
1012 msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
1013 break;
1014 case IPA_PM_ACTIVATED_TIMER_SET:
1015 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
1016 client->state = IPA_PM_ACTIVATED_PENDING_RESCHEDULE;
1017 case IPA_PM_DEACTIVATE_IN_PROGRESS:
1018 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
1019 break;
1020 }
1021 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1022 spin_unlock_irqrestore(&client->state_lock, flags);
1023
1024 return 0;
1025}
1026
1027/**
1028 * ipa_pm_deactivate_all_deferred(): Cancel the deferred deactivation timer and
1029 * immediately devotes for IPA clocks
1030 *
1031 * Returns: 0 on success, negative on failure
1032 */
1033int ipa_pm_deactivate_all_deferred(void)
1034{
1035 int i;
1036 bool run_algorithm = false;
1037 struct ipa_pm_client *client;
1038 unsigned long flags;
1039
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001040 if (ipa_pm_ctx == NULL) {
1041 IPA_PM_ERR("PM_ctx is null\n");
1042 return -EINVAL;
1043 }
1044
Michael Adisumartaf0424822018-01-15 16:15:33 -08001045 for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001046 client = ipa_pm_ctx->clients[i];
1047
1048 if (client == NULL)
1049 continue;
1050
1051 cancel_delayed_work_sync(&client->deactivate_work);
1052
1053 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
1054 wait_for_completion(&client->complete);
1055 continue;
1056 }
1057
1058 spin_lock_irqsave(&client->state_lock, flags);
1059 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
1060
1061 if (client->state == IPA_PM_ACTIVATED_TIMER_SET) {
1062 client->state = IPA_PM_ACTIVATED;
1063 IPA_PM_DBG_STATE(client->hdl, client->name,
1064 client->state);
1065 spin_unlock_irqrestore(&client->state_lock, flags);
Ghanim Fodia7af6332017-11-28 20:32:07 +02001066 } else if (client->state ==
Chris Fries012712b2017-12-12 23:30:04 +02001067 IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||
1068 client->state ==
1069 IPA_PM_ACTIVATED_PENDING_RESCHEDULE) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001070 run_algorithm = true;
1071 client->state = IPA_PM_DEACTIVATED;
1072 IPA_PM_DBG_STATE(client->hdl, client->name,
1073 client->state);
1074 spin_unlock_irqrestore(&client->state_lock, flags);
Michael Adisumartac06df412017-09-19 10:10:35 -07001075 if (!client->skip_clk_vote)
1076 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
1077 deactivate_client(client->hdl);
1078 } else /* if activated or deactivated, we do nothing */
1079 spin_unlock_irqrestore(&client->state_lock, flags);
1080 }
1081
1082 if (run_algorithm)
1083 do_clk_scaling();
1084
1085 return 0;
1086}
1087
1088/**
1089 * ipa_pm_deactivate_sync(): deactivate ipa client and devote clock. Cannot be
1090 * called from atomic context.
1091 * @hdl: index of the client in the array
1092 *
1093 * Returns: 0 on success, negative on failure
1094 */
1095int ipa_pm_deactivate_sync(u32 hdl)
1096{
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001097 struct ipa_pm_client *client;
Michael Adisumartac06df412017-09-19 10:10:35 -07001098 unsigned long flags;
1099
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001100 if (ipa_pm_ctx == NULL) {
1101 IPA_PM_ERR("PM_ctx is null\n");
1102 return -EINVAL;
1103 }
1104
Michael Adisumartac06df412017-09-19 10:10:35 -07001105 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
1106 IPA_PM_ERR("Invalid Param\n");
1107 return -EINVAL;
1108 }
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001109 client = ipa_pm_ctx->clients[hdl];
Michael Adisumartac06df412017-09-19 10:10:35 -07001110
1111 cancel_delayed_work_sync(&client->deactivate_work);
1112
1113 if (IPA_PM_STATE_IN_PROGRESS(client->state))
1114 wait_for_completion(&client->complete);
1115
1116 spin_lock_irqsave(&client->state_lock, flags);
1117 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1118
1119 if (client->state == IPA_PM_DEACTIVATED) {
1120 spin_unlock_irqrestore(&client->state_lock, flags);
1121 return 0;
1122 }
1123
1124 spin_unlock_irqrestore(&client->state_lock, flags);
1125
1126 /* else case (Deactivates all Activated cases)*/
Michael Adisumartac06df412017-09-19 10:10:35 -07001127 if (!client->skip_clk_vote)
1128 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
1129
1130 spin_lock_irqsave(&client->state_lock, flags);
1131 client->state = IPA_PM_DEACTIVATED;
1132 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1133 spin_unlock_irqrestore(&client->state_lock, flags);
1134 deactivate_client(hdl);
1135 do_clk_scaling();
1136
1137 return 0;
1138}
1139
1140/**
1141 * ipa_pm_handle_suspend(): calls the callbacks of suspended clients to wake up
1142 * @pipe_bitmask: the bits represent the indexes of the clients to be woken up
1143 *
1144 * Returns: 0 on success, negative on failure
1145 */
1146int ipa_pm_handle_suspend(u32 pipe_bitmask)
1147{
1148 int i;
1149 struct ipa_pm_client *client;
1150 bool client_notified[IPA_PM_MAX_CLIENTS] = { false };
1151
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001152 if (ipa_pm_ctx == NULL) {
1153 IPA_PM_ERR("PM_ctx is null\n");
1154 return -EINVAL;
1155 }
1156
Michael Adisumartac06df412017-09-19 10:10:35 -07001157 IPA_PM_DBG_LOW("bitmask: %d", pipe_bitmask);
1158
1159 if (pipe_bitmask == 0)
1160 return 0;
1161
1162 mutex_lock(&ipa_pm_ctx->client_mutex);
1163 for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
1164 if (pipe_bitmask & (1 << i)) {
1165 client = ipa_pm_ctx->clients_by_pipe[i];
1166 if (client && client_notified[client->hdl] == false) {
Michael Adisumartace75fc72017-10-04 11:42:11 -07001167 if (client->callback) {
1168 client->callback(client->callback_params
1169 , IPA_PM_REQUEST_WAKEUP);
1170 client_notified[client->hdl] = true;
1171 } else {
1172 IPA_PM_ERR("client has no callback");
1173 WARN_ON(1);
1174 }
Michael Adisumartac06df412017-09-19 10:10:35 -07001175 }
1176 }
1177 }
1178 mutex_unlock(&ipa_pm_ctx->client_mutex);
1179 return 0;
1180}
1181
1182/**
1183 * ipa_pm_set_perf_profile(): Adds/changes the throughput requirement to IPA PM
1184 * to be used for clock scaling
1185 * @hdl: index of the client in the array
1186 * @throughput: the new throughput value to be set for that client
1187 *
1188 * Returns: 0 on success, negative on failure
1189 */
1190int ipa_pm_set_perf_profile(u32 hdl, int throughput)
1191{
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001192 struct ipa_pm_client *client;
Michael Adisumartac06df412017-09-19 10:10:35 -07001193 unsigned long flags;
1194
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001195 if (ipa_pm_ctx == NULL) {
1196 IPA_PM_ERR("PM_ctx is null\n");
1197 return -EINVAL;
1198 }
1199
Michael Adisumartac06df412017-09-19 10:10:35 -07001200 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL
1201 || throughput < 0) {
1202 IPA_PM_ERR("Invalid Params\n");
1203 return -EINVAL;
1204 }
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001205 client = ipa_pm_ctx->clients[hdl];
Michael Adisumartac06df412017-09-19 10:10:35 -07001206
1207 mutex_lock(&ipa_pm_ctx->client_mutex);
1208 if (client->group == IPA_PM_GROUP_DEFAULT)
1209 IPA_PM_DBG_LOW("Old throughput: %d\n", client->throughput);
1210 else
1211 IPA_PM_DBG_LOW("old Group %d throughput: %d\n",
1212 client->group, ipa_pm_ctx->group_tput[client->group]);
1213
1214 if (client->group == IPA_PM_GROUP_DEFAULT)
1215 client->throughput = throughput;
1216 else
1217 ipa_pm_ctx->group_tput[client->group] = throughput;
1218
1219 if (client->group == IPA_PM_GROUP_DEFAULT)
1220 IPA_PM_DBG_LOW("New throughput: %d\n", client->throughput);
1221 else
1222 IPA_PM_DBG_LOW("New Group %d throughput: %d\n",
1223 client->group, ipa_pm_ctx->group_tput[client->group]);
1224 mutex_unlock(&ipa_pm_ctx->client_mutex);
1225
1226 spin_lock_irqsave(&client->state_lock, flags);
Michael Adisumarta3a6f6002017-09-26 16:48:12 -07001227 if (IPA_PM_STATE_ACTIVE(client->state) || (client->group !=
1228 IPA_PM_GROUP_DEFAULT)) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001229 spin_unlock_irqrestore(&client->state_lock, flags);
1230 do_clk_scaling();
1231 return 0;
1232 }
1233 spin_unlock_irqrestore(&client->state_lock, flags);
1234
1235 return 0;
1236}
1237
1238/**
1239 * ipa_pm_stat() - print PM stat
1240 * @buf: [in] The user buff used to print
1241 * @size: [in] The size of buf
1242 * Returns: number of bytes used on success, negative on failure
1243 *
1244 * This function is called by ipa_debugfs in order to receive
1245 * a picture of the clients in the PM and the throughput, threshold and cur vote
1246 */
1247int ipa_pm_stat(char *buf, int size)
1248{
1249 struct ipa_pm_client *client;
1250 struct clk_scaling_db *clk = &ipa_pm_ctx->clk_scaling;
1251 int i, j, tput, cnt = 0, result = 0;
1252 unsigned long flags;
1253
1254 if (!buf || size < 0)
1255 return -EINVAL;
1256
1257 mutex_lock(&ipa_pm_ctx->client_mutex);
1258
1259 result = scnprintf(buf + cnt, size - cnt, "\n\nCurrent threshold: [");
1260 cnt += result;
1261
1262 for (i = 0; i < clk->threshold_size; i++) {
1263 result = scnprintf(buf + cnt, size - cnt,
1264 "%d, ", clk->current_threshold[i]);
1265 cnt += result;
1266 }
1267
1268 result = scnprintf(buf + cnt, size - cnt, "\b\b]\n");
1269 cnt += result;
1270
1271 result = scnprintf(buf + cnt, size - cnt,
1272 "Aggregated tput: %d, Cur vote: %d",
1273 ipa_pm_ctx->aggregated_tput, clk->cur_vote);
1274 cnt += result;
1275
1276 result = scnprintf(buf + cnt, size - cnt, "\n\nRegistered Clients:\n");
1277 cnt += result;
1278
1279
Michael Adisumartaf0424822018-01-15 16:15:33 -08001280 for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001281 client = ipa_pm_ctx->clients[i];
1282
1283 if (client == NULL)
1284 continue;
1285
1286 spin_lock_irqsave(&client->state_lock, flags);
1287 if (client->group == IPA_PM_GROUP_DEFAULT)
1288 tput = client->throughput;
1289 else
1290 tput = ipa_pm_ctx->group_tput[client->group];
1291
1292 result = scnprintf(buf + cnt, size - cnt,
1293 "Client[%d]: %s State:%s\nGroup: %s Throughput: %d Pipes: ",
1294 i, client->name, client_state_to_str[client->state],
1295 ipa_pm_group_to_str[client->group], tput);
1296 cnt += result;
1297
1298 for (j = 0; j < IPA3_MAX_NUM_PIPES; j++) {
1299 if (ipa_pm_ctx->clients_by_pipe[j] == client) {
1300 result = scnprintf(buf + cnt, size - cnt,
1301 "%d, ", j);
1302 cnt += result;
1303 }
1304 }
1305
1306 result = scnprintf(buf + cnt, size - cnt, "\b\b\n\n");
1307 cnt += result;
1308 spin_unlock_irqrestore(&client->state_lock, flags);
1309 }
1310 mutex_unlock(&ipa_pm_ctx->client_mutex);
1311
1312 return cnt;
1313}
1314
1315/**
1316 * ipa_pm_exceptions_stat() - print PM exceptions stat
1317 * @buf: [in] The user buff used to print
1318 * @size: [in] The size of buf
1319 * Returns: number of bytes used on success, negative on failure
1320 *
1321 * This function is called by ipa_debugfs in order to receive
1322 * a full picture of the exceptions in the PM
1323 */
1324int ipa_pm_exceptions_stat(char *buf, int size)
1325{
1326 int i, j, cnt = 0, result = 0;
1327 struct ipa_pm_exception_list *exception;
1328
1329 if (!buf || size < 0)
1330 return -EINVAL;
1331
1332 result = scnprintf(buf + cnt, size - cnt, "\n");
1333 cnt += result;
1334
1335 mutex_lock(&ipa_pm_ctx->client_mutex);
1336 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
1337 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
1338 if (exception == NULL) {
1339 result = scnprintf(buf + cnt, size - cnt,
1340 "Exception %d is NULL\n\n", i);
1341 cnt += result;
1342 continue;
1343 }
1344
1345 result = scnprintf(buf + cnt, size - cnt,
1346 "Exception %d: %s\nPending: %d Bitmask: %d Threshold: ["
1347 , i, exception->clients, exception->pending,
1348 exception->bitmask);
1349 cnt += result;
1350 for (j = 0; j < ipa_pm_ctx->clk_scaling.threshold_size; j++) {
1351 result = scnprintf(buf + cnt, size - cnt,
1352 "%d, ", exception->threshold[j]);
1353 cnt += result;
1354 }
1355 result = scnprintf(buf + cnt, size - cnt, "\b\b]\n\n");
1356 cnt += result;
1357 }
1358 mutex_unlock(&ipa_pm_ctx->client_mutex);
1359
1360 return cnt;
1361}