blob: 93f7e48fca49f9a11c166e3a9d68dd08cc1a140c [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) {
417 ipa_set_tag_process_before_gating(true);
418 if (!client->skip_clk_vote)
419 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
420
421 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
422 return;
423 }
424
425 activate_client(client->hdl);
426
427 mutex_lock(&ipa_pm_ctx->client_mutex);
Michael Adisumartace75fc72017-10-04 11:42:11 -0700428 if (client->callback) {
429 client->callback(client->callback_params,
430 IPA_PM_CLIENT_ACTIVATED);
431 } else {
432 IPA_PM_ERR("client has no callback");
433 WARN_ON(1);
434 }
Michael Adisumartac06df412017-09-19 10:10:35 -0700435 mutex_unlock(&ipa_pm_ctx->client_mutex);
436
437 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
438 do_clk_scaling();
439}
440
441/**
442 * delayed_deferred_deactivate_work_func - deferred deactivate on a work queue
443 */
444static void delayed_deferred_deactivate_work_func(struct work_struct *work)
445{
446 struct delayed_work *dwork;
447 struct ipa_pm_client *client;
448 unsigned long flags;
449
450 dwork = container_of(work, struct delayed_work, work);
451 client = container_of(dwork, struct ipa_pm_client, deactivate_work);
452
453 spin_lock_irqsave(&client->state_lock, flags);
454 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
455 switch (client->state) {
456 case IPA_PM_ACTIVATED_TIMER_SET:
457 client->state = IPA_PM_ACTIVATED;
458 goto bail;
459 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
460 queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
461 msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
462 client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
463 goto bail;
464 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
465 client->state = IPA_PM_DEACTIVATED;
466 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
467 spin_unlock_irqrestore(&client->state_lock, flags);
468 ipa_set_tag_process_before_gating(true);
469 if (!client->skip_clk_vote)
470 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
471
472 deactivate_client(client->hdl);
473 do_clk_scaling();
474 return;
475 default:
476 IPA_PM_ERR("unexpected state %d\n", client->state);
477 WARN_ON(1);
478 goto bail;
479 }
480
481bail:
482 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
483 spin_unlock_irqrestore(&client->state_lock, flags);
484}
485
486static int find_next_open_array_element(const char *name)
487{
488 int i, n;
489
490 n = -ENOBUFS;
491
Michael Adisumartaf0424822018-01-15 16:15:33 -0800492 /* 0 is not a valid handle */
493 for (i = IPA_PM_MAX_CLIENTS - 1; i >= 1; i--) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700494 if (ipa_pm_ctx->clients[i] == NULL) {
495 n = i;
496 continue;
497 }
498
499 if (strlen(name) == strlen(ipa_pm_ctx->clients[i]->name))
500 if (!strcmp(name, ipa_pm_ctx->clients[i]->name))
501 return -EEXIST;
502 }
503 return n;
504}
505
506/**
507 * add_client_to_exception_list() - add client to the exception list and
508 * update pending if necessary
509 * @hdl: index of the IPA client
510 *
511 * Returns: 0 if success, negative otherwise
512 */
513static int add_client_to_exception_list(u32 hdl)
514{
515 int i;
516 struct ipa_pm_exception_list *exception;
517
518 mutex_lock(&ipa_pm_ctx->client_mutex);
519 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
520 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
521 if (strnstr(exception->clients, ipa_pm_ctx->clients[hdl]->name,
522 strlen(exception->clients))) {
523 exception->pending--;
524
525 if (exception->pending < 0) {
526 WARN_ON(1);
527 exception->pending = 0;
528 mutex_unlock(&ipa_pm_ctx->client_mutex);
529 return -EPERM;
530 }
531 exception->bitmask |= (1 << hdl);
532 }
533 }
534 IPA_PM_DBG("%s added to exception list\n",
535 ipa_pm_ctx->clients[hdl]->name);
536 mutex_unlock(&ipa_pm_ctx->client_mutex);
537
538 return 0;
539}
540
541/**
542 * remove_client_to_exception_list() - remove client from the exception list and
543 * update pending if necessary
544 * @hdl: index of the IPA client
545 *
546 * Returns: 0 if success, negative otherwise
547 */
548static int remove_client_from_exception_list(u32 hdl)
549{
550 int i;
551 struct ipa_pm_exception_list *exception;
552
553 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
554 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
555 if (exception->bitmask & (1 << hdl)) {
556 exception->pending++;
557 exception->bitmask &= ~(1 << hdl);
558 }
559 }
560 IPA_PM_DBG("Client %d removed from exception list\n", hdl);
561
562 return 0;
563}
564
565/**
566 * ipa_pm_init() - initialize IPA PM Components
567 * @ipa_pm_init_params: parameters needed to fill exceptions and thresholds
568 *
569 * Returns: 0 on success, negative on failure
570 */
571int ipa_pm_init(struct ipa_pm_init_params *params)
572{
573 int i, j;
574 struct clk_scaling_db *clk_scaling;
575
576 if (params == NULL) {
577 IPA_PM_ERR("Invalid Params\n");
578 return -EINVAL;
579 }
580
581 if (params->threshold_size <= 0
582 || params->threshold_size > IPA_PM_THRESHOLD_MAX) {
583 IPA_PM_ERR("Invalid threshold size\n");
584 return -EINVAL;
585 }
586
587 if (params->exception_size < 0
588 || params->exception_size > IPA_PM_EXCEPTION_MAX) {
589 IPA_PM_ERR("Invalid exception size\n");
590 return -EINVAL;
591 }
592
593 IPA_PM_DBG("IPA PM initialization started\n");
594
595 if (ipa_pm_ctx != NULL) {
596 IPA_PM_ERR("Already initialized\n");
597 return -EPERM;
598 }
599
600
601 ipa_pm_ctx = kzalloc(sizeof(*ipa_pm_ctx), GFP_KERNEL);
602 if (!ipa_pm_ctx) {
603 IPA_PM_ERR(":kzalloc err.\n");
604 return -ENOMEM;
605 }
606
607 ipa_pm_ctx->wq = create_singlethread_workqueue("ipa_pm_activate");
608 if (!ipa_pm_ctx->wq) {
609 IPA_PM_ERR("create workqueue failed\n");
610 kfree(ipa_pm_ctx);
611 return -ENOMEM;
612 }
613
614 mutex_init(&ipa_pm_ctx->client_mutex);
615
616 /* Populate and init locks in clk_scaling_db */
617 clk_scaling = &ipa_pm_ctx->clk_scaling;
618 spin_lock_init(&clk_scaling->lock);
619 clk_scaling->threshold_size = params->threshold_size;
620 clk_scaling->exception_size = params->exception_size;
621 INIT_WORK(&clk_scaling->work, clock_scaling_func);
622
623 for (i = 0; i < params->threshold_size; i++)
624 clk_scaling->default_threshold[i] =
625 params->default_threshold[i];
626
627 /* Populate exception list*/
628 for (i = 0; i < params->exception_size; i++) {
629 strlcpy(clk_scaling->exception_list[i].clients,
630 params->exceptions[i].usecase, IPA_PM_MAX_EX_CL);
631 IPA_PM_DBG("Usecase: %s\n", params->exceptions[i].usecase);
632
633 /* Parse the commas to count the size of the clients */
634 for (j = 0; j < IPA_PM_MAX_EX_CL &&
635 clk_scaling->exception_list[i].clients[j]; j++) {
636 if (clk_scaling->exception_list[i].clients[j] == ',')
637 clk_scaling->exception_list[i].pending++;
638 }
639
640 clk_scaling->exception_list[i].pending++;
641 IPA_PM_DBG("Pending: %d\n", clk_scaling->
642 exception_list[i].pending);
643
644 /* populate the threshold */
645 for (j = 0; j < params->threshold_size; j++) {
646 clk_scaling->exception_list[i].threshold[j]
647 = params->exceptions[i].threshold[j];
648 }
649
650 }
651 IPA_PM_DBG("initialization success");
652
653 return 0;
654}
655
656int ipa_pm_destroy(void)
657{
658 IPA_PM_DBG("IPA PM destroy started\n");
659
660 if (ipa_pm_ctx == NULL) {
661 IPA_PM_ERR("Already destroyed\n");
662 return -EPERM;
663 }
664
665 destroy_workqueue(ipa_pm_ctx->wq);
666
667 kfree(ipa_pm_ctx);
668 ipa_pm_ctx = NULL;
669
670 return 0;
671}
672
673/**
674 * ipa_rm_delete_register() - register an IPA PM client with the PM
675 * @register_params: params for a client like throughput, callback, etc.
676 * @hdl: int pointer that will be used as an index to access the client
677 *
678 * Returns: 0 on success, negative on failure
679 *
680 * Side effects: *hdl is replaced with the client index or -EEXIST if
681 * client is already registered
682 */
683int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl)
684{
685 struct ipa_pm_client *client;
686
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800687 if (ipa_pm_ctx == NULL) {
688 IPA_PM_ERR("PM_ctx is null\n");
689 return -EINVAL;
690 }
691
Michael Adisumartace75fc72017-10-04 11:42:11 -0700692 if (params == NULL || hdl == NULL || params->name == NULL) {
Michael Adisumartac06df412017-09-19 10:10:35 -0700693 IPA_PM_ERR("Invalid Params\n");
694 return -EINVAL;
695 }
696
697 IPA_PM_DBG("IPA PM registering client\n");
698
699 mutex_lock(&ipa_pm_ctx->client_mutex);
700
701 *hdl = find_next_open_array_element(params->name);
702
703 if (*hdl > IPA_CLIENT_MAX) {
704 mutex_unlock(&ipa_pm_ctx->client_mutex);
705 IPA_PM_ERR("client is already registered or array is full\n");
706 return *hdl;
707 }
708
709 ipa_pm_ctx->clients[*hdl] = kzalloc(sizeof
710 (struct ipa_pm_client), GFP_KERNEL);
711 if (!ipa_pm_ctx->clients[*hdl]) {
712 mutex_unlock(&ipa_pm_ctx->client_mutex);
713 IPA_PM_ERR(":kzalloc err.\n");
714 return -ENOMEM;
715 }
716 mutex_unlock(&ipa_pm_ctx->client_mutex);
717
718 client = ipa_pm_ctx->clients[*hdl];
719
720 spin_lock_init(&client->state_lock);
721
722 INIT_DELAYED_WORK(&client->deactivate_work,
723 delayed_deferred_deactivate_work_func);
724
725 INIT_WORK(&client->activate_work, activate_work_func);
726
727 /* populate fields */
728 strlcpy(client->name, params->name, IPA_PM_MAX_EX_CL);
729 client->callback = params->callback;
730 client->callback_params = params->user_data;
731 client->group = params->group;
732 client->hdl = *hdl;
733 client->skip_clk_vote = params->skip_clk_vote;
734
735 /* add client to exception list */
736 if (add_client_to_exception_list(*hdl)) {
737 ipa_pm_deregister(*hdl);
738 IPA_PM_ERR("Fail to add client to exception_list\n");
739 return -EPERM;
740 }
741
742 IPA_PM_DBG("IPA PM client registered with handle %d\n", *hdl);
743 return 0;
744}
745
746/**
747 * ipa_pm_deregister() - deregister IPA client from the PM
748 * @hdl: index of the client in the array
749 *
750 * Returns: 0 on success, negative on failure
751 */
752int ipa_pm_deregister(u32 hdl)
753{
754 struct ipa_pm_client *client;
755 int i;
756 unsigned long flags;
757
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800758 if (ipa_pm_ctx == NULL) {
759 IPA_PM_ERR("PM_ctx is null\n");
760 return -EINVAL;
761 }
762
Michael Adisumartac06df412017-09-19 10:10:35 -0700763 if (hdl >= IPA_PM_MAX_CLIENTS) {
764 IPA_PM_ERR("Invalid Param\n");
765 return -EINVAL;
766 }
767
768 if (ipa_pm_ctx->clients[hdl] == NULL) {
769 IPA_PM_ERR("Client is Null\n");
770 return -EINVAL;
771 }
772
773 IPA_PM_DBG("IPA PM deregistering client\n");
774
775 client = ipa_pm_ctx->clients[hdl];
776 spin_lock_irqsave(&client->state_lock, flags);
777 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
778 spin_unlock_irqrestore(&client->state_lock, flags);
779 wait_for_completion(&client->complete);
780 spin_lock_irqsave(&client->state_lock, flags);
781 }
782
783 if (IPA_PM_STATE_ACTIVE(client->state)) {
784 IPA_PM_DBG("Activated clients cannot be deregistered");
785 spin_unlock_irqrestore(&client->state_lock, flags);
786 return -EPERM;
787 }
788 spin_unlock_irqrestore(&client->state_lock, flags);
789
790 mutex_lock(&ipa_pm_ctx->client_mutex);
791
792 /* nullify pointers in pipe array */
793 for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
794 if (ipa_pm_ctx->clients_by_pipe[i] == ipa_pm_ctx->clients[hdl])
795 ipa_pm_ctx->clients_by_pipe[i] = NULL;
796 }
797 kfree(client);
798 ipa_pm_ctx->clients[hdl] = NULL;
799
800 remove_client_from_exception_list(hdl);
801 IPA_PM_DBG("IPA PM client %d deregistered\n", hdl);
802 mutex_unlock(&ipa_pm_ctx->client_mutex);
803
804 return 0;
805}
806
807/**
808 * ipa_pm_associate_ipa_cons_to_client() - add mapping to pipe with ipa cllent
809 * @hdl: index of the client to be mapped
810 * @consumer: the pipe/consumer name to be pipped to the client
811 *
812 * Returns: 0 on success, negative on failure
813 *
814 * Side effects: multiple pipes are allowed to be mapped to a single client
815 */
816int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer)
817{
818 int idx;
819
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800820 if (ipa_pm_ctx == NULL) {
821 IPA_PM_ERR("PM_ctx is null\n");
822 return -EINVAL;
823 }
824
Michael Adisumartac06df412017-09-19 10:10:35 -0700825 if (hdl >= IPA_PM_MAX_CLIENTS || consumer < 0 ||
826 consumer >= IPA_CLIENT_MAX) {
827 IPA_PM_ERR("invalid params\n");
828 return -EINVAL;
829 }
830
831 mutex_lock(&ipa_pm_ctx->client_mutex);
832 idx = ipa_get_ep_mapping(consumer);
833
834 IPA_PM_DBG("Mapping pipe %d to client %d\n", idx, hdl);
835
836 if (idx < 0) {
837 mutex_unlock(&ipa_pm_ctx->client_mutex);
838 IPA_PM_DBG("Pipe is not used\n");
839 return 0;
840 }
841
842 if (ipa_pm_ctx->clients[hdl] == NULL) {
843 mutex_unlock(&ipa_pm_ctx->client_mutex);
844 IPA_PM_ERR("Client is NULL\n");
845 return -EPERM;
846 }
847
848 if (ipa_pm_ctx->clients_by_pipe[idx] != NULL) {
849 mutex_unlock(&ipa_pm_ctx->client_mutex);
850 IPA_PM_ERR("Pipe is already mapped\n");
851 return -EPERM;
852 }
853 ipa_pm_ctx->clients_by_pipe[idx] = ipa_pm_ctx->clients[hdl];
854 mutex_unlock(&ipa_pm_ctx->client_mutex);
855
856 IPA_PM_DBG("Pipe %d is mapped to client %d\n", idx, hdl);
857
858 return 0;
859}
860
861static int ipa_pm_activate_helper(struct ipa_pm_client *client, bool sync)
862{
863 struct ipa_active_client_logging_info log_info;
864 int result = 0;
865 unsigned long flags;
866
867 spin_lock_irqsave(&client->state_lock, flags);
868 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
869
870 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
871 if (sync) {
872 spin_unlock_irqrestore(&client->state_lock, flags);
873 wait_for_completion(&client->complete);
874 spin_lock_irqsave(&client->state_lock, flags);
875 } else {
876 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
877 spin_unlock_irqrestore(&client->state_lock, flags);
878 return -EINPROGRESS;
879 }
880 }
881
882 switch (client->state) {
883 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
884 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
885 client->state = IPA_PM_ACTIVATED_TIMER_SET;
886 case IPA_PM_ACTIVATED:
887 case IPA_PM_ACTIVATED_TIMER_SET:
888 spin_unlock_irqrestore(&client->state_lock, flags);
889 return 0;
890 case IPA_PM_DEACTIVATED:
891 break;
892 default:
893 IPA_PM_ERR("Invalid State\n");
894 spin_unlock_irqrestore(&client->state_lock, flags);
895 return -EPERM;
896 }
897 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
898
899 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, client->name);
900 if (!client->skip_clk_vote) {
901 if (sync) {
902 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
903 spin_unlock_irqrestore(&client->state_lock, flags);
904 IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
905 spin_lock_irqsave(&client->state_lock, flags);
906 } else
907 result = ipa3_inc_client_enable_clks_no_block
908 (&log_info);
909 }
910
911 /* we got the clocks */
912 if (result == 0) {
913 client->state = IPA_PM_ACTIVATED;
914 spin_unlock_irqrestore(&client->state_lock, flags);
915 activate_client(client->hdl);
916 if (sync)
917 do_clk_scaling();
918 else
919 queue_work(ipa_pm_ctx->wq,
920 &ipa_pm_ctx->clk_scaling.work);
921 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
922 return 0;
923 }
924
925 client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
926 init_completion(&client->complete);
927 queue_work(ipa_pm_ctx->wq, &client->activate_work);
928 spin_unlock_irqrestore(&client->state_lock, flags);
929 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
930 return -EINPROGRESS;
931}
932
933/**
934 * ipa_pm_activate(): activate ipa client to vote for clock(). Can be called
935 * from atomic context and returns -EINPROGRESS if cannot be done synchronously
936 * @hdl: index of the client in the array
937 *
938 * Returns: 0 on success, -EINPROGRESS if operation cannot be done synchronously
939 * and other negatives on failure
940 */
941int ipa_pm_activate(u32 hdl)
942{
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800943 if (ipa_pm_ctx == NULL) {
944 IPA_PM_ERR("PM_ctx is null\n");
945 return -EINVAL;
946 }
947
Michael Adisumartac06df412017-09-19 10:10:35 -0700948 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
949 IPA_PM_ERR("Invalid Param\n");
950 return -EINVAL;
951 }
952
953 return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], false);
954}
955
956/**
957 * ipa_pm_activate(): activate ipa client to vote for clock synchronously.
958 * Cannot be called from an atomic contex.
959 * @hdl: index of the client in the array
960 *
961 * Returns: 0 on success, negative on failure
962 */
963int ipa_pm_activate_sync(u32 hdl)
964{
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800965 if (ipa_pm_ctx == NULL) {
966 IPA_PM_ERR("PM_ctx is null\n");
967 return -EINVAL;
968 }
969
Michael Adisumartac06df412017-09-19 10:10:35 -0700970 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
971 IPA_PM_ERR("Invalid Param\n");
972 return -EINVAL;
973 }
974
975 return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], true);
976}
977
978/**
979 * ipa_pm_deferred_deactivate(): schedule a timer to deactivate client and
980 * devote clock. Can be called from atomic context (asynchronously)
981 * @hdl: index of the client in the array
982 *
983 * Returns: 0 on success, negative on failure
984 */
985int ipa_pm_deferred_deactivate(u32 hdl)
986{
987 struct ipa_pm_client *client;
988 unsigned long flags;
989
Michael Adisumarta45653fe2017-12-13 20:32:44 -0800990 if (ipa_pm_ctx == NULL) {
991 IPA_PM_ERR("PM_ctx is null\n");
992 return -EINVAL;
993 }
994
Michael Adisumartac06df412017-09-19 10:10:35 -0700995 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
996 IPA_PM_ERR("Invalid Param\n");
997 return -EINVAL;
998 }
999
1000 client = ipa_pm_ctx->clients[hdl];
1001 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1002
1003 spin_lock_irqsave(&client->state_lock, flags);
1004 switch (client->state) {
1005 case IPA_PM_ACTIVATE_IN_PROGRESS:
1006 client->state = IPA_PM_DEACTIVATE_IN_PROGRESS;
1007 case IPA_PM_DEACTIVATED:
1008 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1009 spin_unlock_irqrestore(&client->state_lock, flags);
1010 return 0;
1011 case IPA_PM_ACTIVATED:
1012 client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
1013 queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
1014 msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
1015 break;
1016 case IPA_PM_ACTIVATED_TIMER_SET:
1017 case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
1018 client->state = IPA_PM_ACTIVATED_PENDING_RESCHEDULE;
1019 case IPA_PM_DEACTIVATE_IN_PROGRESS:
1020 case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
1021 break;
1022 }
1023 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1024 spin_unlock_irqrestore(&client->state_lock, flags);
1025
1026 return 0;
1027}
1028
1029/**
1030 * ipa_pm_deactivate_all_deferred(): Cancel the deferred deactivation timer and
1031 * immediately devotes for IPA clocks
1032 *
1033 * Returns: 0 on success, negative on failure
1034 */
1035int ipa_pm_deactivate_all_deferred(void)
1036{
1037 int i;
1038 bool run_algorithm = false;
1039 struct ipa_pm_client *client;
1040 unsigned long flags;
1041
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001042 if (ipa_pm_ctx == NULL) {
1043 IPA_PM_ERR("PM_ctx is null\n");
1044 return -EINVAL;
1045 }
1046
Michael Adisumartaf0424822018-01-15 16:15:33 -08001047 for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001048 client = ipa_pm_ctx->clients[i];
1049
1050 if (client == NULL)
1051 continue;
1052
1053 cancel_delayed_work_sync(&client->deactivate_work);
1054
1055 if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
1056 wait_for_completion(&client->complete);
1057 continue;
1058 }
1059
1060 spin_lock_irqsave(&client->state_lock, flags);
1061 IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
1062
1063 if (client->state == IPA_PM_ACTIVATED_TIMER_SET) {
1064 client->state = IPA_PM_ACTIVATED;
1065 IPA_PM_DBG_STATE(client->hdl, client->name,
1066 client->state);
1067 spin_unlock_irqrestore(&client->state_lock, flags);
Ghanim Fodia7af6332017-11-28 20:32:07 +02001068 } else if (client->state ==
Chris Fries012712b2017-12-12 23:30:04 +02001069 IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||
1070 client->state ==
1071 IPA_PM_ACTIVATED_PENDING_RESCHEDULE) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001072 run_algorithm = true;
1073 client->state = IPA_PM_DEACTIVATED;
1074 IPA_PM_DBG_STATE(client->hdl, client->name,
1075 client->state);
1076 spin_unlock_irqrestore(&client->state_lock, flags);
1077 ipa_set_tag_process_before_gating(true);
1078 if (!client->skip_clk_vote)
1079 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
1080 deactivate_client(client->hdl);
1081 } else /* if activated or deactivated, we do nothing */
1082 spin_unlock_irqrestore(&client->state_lock, flags);
1083 }
1084
1085 if (run_algorithm)
1086 do_clk_scaling();
1087
1088 return 0;
1089}
1090
1091/**
1092 * ipa_pm_deactivate_sync(): deactivate ipa client and devote clock. Cannot be
1093 * called from atomic context.
1094 * @hdl: index of the client in the array
1095 *
1096 * Returns: 0 on success, negative on failure
1097 */
1098int ipa_pm_deactivate_sync(u32 hdl)
1099{
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001100 struct ipa_pm_client *client;
Michael Adisumartac06df412017-09-19 10:10:35 -07001101 unsigned long flags;
1102
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001103 if (ipa_pm_ctx == NULL) {
1104 IPA_PM_ERR("PM_ctx is null\n");
1105 return -EINVAL;
1106 }
1107
Michael Adisumartac06df412017-09-19 10:10:35 -07001108 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
1109 IPA_PM_ERR("Invalid Param\n");
1110 return -EINVAL;
1111 }
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001112 client = ipa_pm_ctx->clients[hdl];
Michael Adisumartac06df412017-09-19 10:10:35 -07001113
1114 cancel_delayed_work_sync(&client->deactivate_work);
1115
1116 if (IPA_PM_STATE_IN_PROGRESS(client->state))
1117 wait_for_completion(&client->complete);
1118
1119 spin_lock_irqsave(&client->state_lock, flags);
1120 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1121
1122 if (client->state == IPA_PM_DEACTIVATED) {
1123 spin_unlock_irqrestore(&client->state_lock, flags);
1124 return 0;
1125 }
1126
1127 spin_unlock_irqrestore(&client->state_lock, flags);
1128
1129 /* else case (Deactivates all Activated cases)*/
1130 ipa_set_tag_process_before_gating(true);
1131 if (!client->skip_clk_vote)
1132 IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
1133
1134 spin_lock_irqsave(&client->state_lock, flags);
1135 client->state = IPA_PM_DEACTIVATED;
1136 IPA_PM_DBG_STATE(hdl, client->name, client->state);
1137 spin_unlock_irqrestore(&client->state_lock, flags);
1138 deactivate_client(hdl);
1139 do_clk_scaling();
1140
1141 return 0;
1142}
1143
1144/**
1145 * ipa_pm_handle_suspend(): calls the callbacks of suspended clients to wake up
1146 * @pipe_bitmask: the bits represent the indexes of the clients to be woken up
1147 *
1148 * Returns: 0 on success, negative on failure
1149 */
1150int ipa_pm_handle_suspend(u32 pipe_bitmask)
1151{
1152 int i;
1153 struct ipa_pm_client *client;
1154 bool client_notified[IPA_PM_MAX_CLIENTS] = { false };
1155
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001156 if (ipa_pm_ctx == NULL) {
1157 IPA_PM_ERR("PM_ctx is null\n");
1158 return -EINVAL;
1159 }
1160
Michael Adisumartac06df412017-09-19 10:10:35 -07001161 IPA_PM_DBG_LOW("bitmask: %d", pipe_bitmask);
1162
1163 if (pipe_bitmask == 0)
1164 return 0;
1165
1166 mutex_lock(&ipa_pm_ctx->client_mutex);
1167 for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
1168 if (pipe_bitmask & (1 << i)) {
1169 client = ipa_pm_ctx->clients_by_pipe[i];
1170 if (client && client_notified[client->hdl] == false) {
Michael Adisumartace75fc72017-10-04 11:42:11 -07001171 if (client->callback) {
1172 client->callback(client->callback_params
1173 , IPA_PM_REQUEST_WAKEUP);
1174 client_notified[client->hdl] = true;
1175 } else {
1176 IPA_PM_ERR("client has no callback");
1177 WARN_ON(1);
1178 }
Michael Adisumartac06df412017-09-19 10:10:35 -07001179 }
1180 }
1181 }
1182 mutex_unlock(&ipa_pm_ctx->client_mutex);
1183 return 0;
1184}
1185
1186/**
1187 * ipa_pm_set_perf_profile(): Adds/changes the throughput requirement to IPA PM
1188 * to be used for clock scaling
1189 * @hdl: index of the client in the array
1190 * @throughput: the new throughput value to be set for that client
1191 *
1192 * Returns: 0 on success, negative on failure
1193 */
1194int ipa_pm_set_perf_profile(u32 hdl, int throughput)
1195{
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001196 struct ipa_pm_client *client;
Michael Adisumartac06df412017-09-19 10:10:35 -07001197 unsigned long flags;
1198
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001199 if (ipa_pm_ctx == NULL) {
1200 IPA_PM_ERR("PM_ctx is null\n");
1201 return -EINVAL;
1202 }
1203
Michael Adisumartac06df412017-09-19 10:10:35 -07001204 if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL
1205 || throughput < 0) {
1206 IPA_PM_ERR("Invalid Params\n");
1207 return -EINVAL;
1208 }
Michael Adisumarta45653fe2017-12-13 20:32:44 -08001209 client = ipa_pm_ctx->clients[hdl];
Michael Adisumartac06df412017-09-19 10:10:35 -07001210
1211 mutex_lock(&ipa_pm_ctx->client_mutex);
1212 if (client->group == IPA_PM_GROUP_DEFAULT)
1213 IPA_PM_DBG_LOW("Old throughput: %d\n", client->throughput);
1214 else
1215 IPA_PM_DBG_LOW("old Group %d throughput: %d\n",
1216 client->group, ipa_pm_ctx->group_tput[client->group]);
1217
1218 if (client->group == IPA_PM_GROUP_DEFAULT)
1219 client->throughput = throughput;
1220 else
1221 ipa_pm_ctx->group_tput[client->group] = throughput;
1222
1223 if (client->group == IPA_PM_GROUP_DEFAULT)
1224 IPA_PM_DBG_LOW("New throughput: %d\n", client->throughput);
1225 else
1226 IPA_PM_DBG_LOW("New Group %d throughput: %d\n",
1227 client->group, ipa_pm_ctx->group_tput[client->group]);
1228 mutex_unlock(&ipa_pm_ctx->client_mutex);
1229
1230 spin_lock_irqsave(&client->state_lock, flags);
Michael Adisumarta3a6f6002017-09-26 16:48:12 -07001231 if (IPA_PM_STATE_ACTIVE(client->state) || (client->group !=
1232 IPA_PM_GROUP_DEFAULT)) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001233 spin_unlock_irqrestore(&client->state_lock, flags);
1234 do_clk_scaling();
1235 return 0;
1236 }
1237 spin_unlock_irqrestore(&client->state_lock, flags);
1238
1239 return 0;
1240}
1241
1242/**
1243 * ipa_pm_stat() - print PM stat
1244 * @buf: [in] The user buff used to print
1245 * @size: [in] The size of buf
1246 * Returns: number of bytes used on success, negative on failure
1247 *
1248 * This function is called by ipa_debugfs in order to receive
1249 * a picture of the clients in the PM and the throughput, threshold and cur vote
1250 */
1251int ipa_pm_stat(char *buf, int size)
1252{
1253 struct ipa_pm_client *client;
1254 struct clk_scaling_db *clk = &ipa_pm_ctx->clk_scaling;
1255 int i, j, tput, cnt = 0, result = 0;
1256 unsigned long flags;
1257
1258 if (!buf || size < 0)
1259 return -EINVAL;
1260
1261 mutex_lock(&ipa_pm_ctx->client_mutex);
1262
1263 result = scnprintf(buf + cnt, size - cnt, "\n\nCurrent threshold: [");
1264 cnt += result;
1265
1266 for (i = 0; i < clk->threshold_size; i++) {
1267 result = scnprintf(buf + cnt, size - cnt,
1268 "%d, ", clk->current_threshold[i]);
1269 cnt += result;
1270 }
1271
1272 result = scnprintf(buf + cnt, size - cnt, "\b\b]\n");
1273 cnt += result;
1274
1275 result = scnprintf(buf + cnt, size - cnt,
1276 "Aggregated tput: %d, Cur vote: %d",
1277 ipa_pm_ctx->aggregated_tput, clk->cur_vote);
1278 cnt += result;
1279
1280 result = scnprintf(buf + cnt, size - cnt, "\n\nRegistered Clients:\n");
1281 cnt += result;
1282
1283
Michael Adisumartaf0424822018-01-15 16:15:33 -08001284 for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
Michael Adisumartac06df412017-09-19 10:10:35 -07001285 client = ipa_pm_ctx->clients[i];
1286
1287 if (client == NULL)
1288 continue;
1289
1290 spin_lock_irqsave(&client->state_lock, flags);
1291 if (client->group == IPA_PM_GROUP_DEFAULT)
1292 tput = client->throughput;
1293 else
1294 tput = ipa_pm_ctx->group_tput[client->group];
1295
1296 result = scnprintf(buf + cnt, size - cnt,
1297 "Client[%d]: %s State:%s\nGroup: %s Throughput: %d Pipes: ",
1298 i, client->name, client_state_to_str[client->state],
1299 ipa_pm_group_to_str[client->group], tput);
1300 cnt += result;
1301
1302 for (j = 0; j < IPA3_MAX_NUM_PIPES; j++) {
1303 if (ipa_pm_ctx->clients_by_pipe[j] == client) {
1304 result = scnprintf(buf + cnt, size - cnt,
1305 "%d, ", j);
1306 cnt += result;
1307 }
1308 }
1309
1310 result = scnprintf(buf + cnt, size - cnt, "\b\b\n\n");
1311 cnt += result;
1312 spin_unlock_irqrestore(&client->state_lock, flags);
1313 }
1314 mutex_unlock(&ipa_pm_ctx->client_mutex);
1315
1316 return cnt;
1317}
1318
1319/**
1320 * ipa_pm_exceptions_stat() - print PM exceptions stat
1321 * @buf: [in] The user buff used to print
1322 * @size: [in] The size of buf
1323 * Returns: number of bytes used on success, negative on failure
1324 *
1325 * This function is called by ipa_debugfs in order to receive
1326 * a full picture of the exceptions in the PM
1327 */
1328int ipa_pm_exceptions_stat(char *buf, int size)
1329{
1330 int i, j, cnt = 0, result = 0;
1331 struct ipa_pm_exception_list *exception;
1332
1333 if (!buf || size < 0)
1334 return -EINVAL;
1335
1336 result = scnprintf(buf + cnt, size - cnt, "\n");
1337 cnt += result;
1338
1339 mutex_lock(&ipa_pm_ctx->client_mutex);
1340 for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
1341 exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
1342 if (exception == NULL) {
1343 result = scnprintf(buf + cnt, size - cnt,
1344 "Exception %d is NULL\n\n", i);
1345 cnt += result;
1346 continue;
1347 }
1348
1349 result = scnprintf(buf + cnt, size - cnt,
1350 "Exception %d: %s\nPending: %d Bitmask: %d Threshold: ["
1351 , i, exception->clients, exception->pending,
1352 exception->bitmask);
1353 cnt += result;
1354 for (j = 0; j < ipa_pm_ctx->clk_scaling.threshold_size; j++) {
1355 result = scnprintf(buf + cnt, size - cnt,
1356 "%d, ", exception->threshold[j]);
1357 cnt += result;
1358 }
1359 result = scnprintf(buf + cnt, size - cnt, "\b\b]\n\n");
1360 cnt += result;
1361 }
1362 mutex_unlock(&ipa_pm_ctx->client_mutex);
1363
1364 return cnt;
1365}