blob: 10a267c4824e003ff5cf725467f8f22674d27796 [file] [log] [blame]
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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/kernel.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/mm.h>
17#include <linux/rbtree.h>
18#include <linux/idr.h>
19#include <linux/genalloc.h>
20#include <linux/of.h>
21#include <linux/io.h>
22#include <linux/platform_device.h>
23#include <linux/debugfs.h>
24#include <linux/seq_file.h>
25#include <mach/ocmem_priv.h>
26
27enum request_states {
28 R_FREE = 0x0, /* request is not allocated */
29 R_PENDING, /* request has a pending operation */
30 R_ALLOCATED, /* request has been allocated */
31 R_MUST_GROW, /* request must grow as a part of pending operation */
32 R_MUST_SHRINK, /* request must shrink as a part of pending operation */
33 R_MUST_MAP, /* request must be mapped before being used */
34 R_MUST_UNMAP, /* request must be unmapped when not being used */
35 R_MAPPED, /* request is mapped and actively used by client */
36 R_UNMAPPED, /* request is not mapped, so it's not in active use */
37 R_EVICTED, /* request is evicted and must be restored */
38};
39
40#define SET_STATE(x, val) (set_bit((val), &(x)->state))
41#define CLEAR_STATE(x, val) (clear_bit((val), &(x)->state))
42#define TEST_STATE(x, val) (test_bit((val), &(x)->state))
43
44enum op_res {
45 OP_COMPLETE = 0x0,
46 OP_RESCHED,
47 OP_PARTIAL,
48 OP_FAIL = ~0x0,
49};
50
51/* Represents various client priorities */
52/* Note: More than one client can share a priority level */
53enum client_prio {
54 MIN_PRIO = 0x0,
55 NO_PRIO = MIN_PRIO,
56 PRIO_SENSORS = 0x1,
57 PRIO_BLAST = 0x1,
58 PRIO_LP_AUDIO = 0x1,
59 PRIO_HP_AUDIO = 0x2,
60 PRIO_VOICE = 0x3,
61 PRIO_GFX_GROWTH = 0x4,
62 PRIO_VIDEO = 0x5,
63 PRIO_GFX = 0x6,
64 PRIO_OCMEM = 0x7,
65 MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
66};
67
68static struct list_head sched_queue[MAX_OCMEM_PRIO];
69static struct mutex sched_queue_mutex;
70
71/* The duration in msecs before a pending operation is scheduled
72 * This allows an idle window between use case boundaries where various
73 * hardware state changes can occur. The value will be tweaked on actual
74 * hardware.
75*/
76#define SCHED_DELAY 10
77
78/* OCMEM Operational modes */
79enum ocmem_client_modes {
80 OCMEM_PERFORMANCE = 1,
81 OCMEM_PASSIVE,
82 OCMEM_LOW_POWER,
83 OCMEM_MODE_MAX = OCMEM_LOW_POWER
84};
85
86/* OCMEM Addressing modes */
87enum ocmem_interconnects {
88 OCMEM_BLOCKED = 0,
89 OCMEM_PORT = 1,
90 OCMEM_OCMEMNOC = 2,
91 OCMEM_SYSNOC = 3,
92};
93
94/**
95 * Primary OCMEM Arbitration Table
96 **/
97struct ocmem_table {
98 int client_id;
99 int priority;
100 int mode;
101 int hw_interconnect;
102} ocmem_client_table[OCMEM_CLIENT_MAX] = {
103 {OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
104 {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
105 {OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
106 {OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
107 {OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
108 {OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
109 {OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
110 {OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
111};
112
113static struct rb_root sched_tree;
114static struct mutex sched_mutex;
115
116/* A region represents a continuous interval in OCMEM address space */
117struct ocmem_region {
118 /* Chain in Interval Tree */
119 struct rb_node region_rb;
120 /* Hash map of requests */
121 struct idr region_idr;
122 unsigned long r_start;
123 unsigned long r_end;
124 unsigned long r_sz;
125 /* Highest priority of all requests served by this region */
126 int max_prio;
127};
128
129/* Is OCMEM tightly coupled to the client ?*/
130static inline int is_tcm(int id)
131{
132 if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
133 ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
134 return 1;
135 else
136 return 0;
137}
138
139static inline int is_blocked(int id)
140{
141 return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
142}
143
144/* Returns the address that can be used by a device core to access OCMEM */
145static unsigned long device_address(int id, unsigned long addr)
146{
147 int hw_interconnect = ocmem_client_table[id].hw_interconnect;
148 unsigned long ret_addr = 0x0;
149
150 switch (hw_interconnect) {
151 case OCMEM_PORT:
152 ret_addr = phys_to_offset(addr);
153 break;
154 case OCMEM_OCMEMNOC:
155 case OCMEM_SYSNOC:
156 ret_addr = addr;
157 break;
158 case OCMEM_BLOCKED:
159 ret_addr = 0x0;
160 break;
161 }
162 return ret_addr;
163}
164
165/* Returns the address as viewed by the core */
166static unsigned long core_address(int id, unsigned long addr)
167{
168 int hw_interconnect = ocmem_client_table[id].hw_interconnect;
169 unsigned long ret_addr = 0x0;
170
171 switch (hw_interconnect) {
172 case OCMEM_PORT:
173 ret_addr = offset_to_phys(addr);
174 break;
175 case OCMEM_OCMEMNOC:
176 case OCMEM_SYSNOC:
177 ret_addr = addr;
178 break;
179 case OCMEM_BLOCKED:
180 ret_addr = 0x0;
181 break;
182 }
183 return ret_addr;
184}
185
186static int insert_region(struct ocmem_region *region)
187{
188
189 struct rb_root *root = &sched_tree;
190 struct rb_node **p = &root->rb_node;
191 struct rb_node *parent = NULL;
192 struct ocmem_region *tmp = NULL;
193 unsigned long addr = region->r_start;
194
195 while (*p) {
196 parent = *p;
197 tmp = rb_entry(parent, struct ocmem_region, region_rb);
198
199 if (tmp->r_end > addr) {
200 if (tmp->r_start <= addr)
201 break;
202 p = &(*p)->rb_left;
203 } else if (tmp->r_end <= addr)
204 p = &(*p)->rb_right;
205 }
206 rb_link_node(&region->region_rb, parent, p);
207 rb_insert_color(&region->region_rb, root);
208 return 0;
209}
210
211static int remove_region(struct ocmem_region *region)
212{
213 struct rb_root *root = &sched_tree;
214 rb_erase(&region->region_rb, root);
215 return 0;
216}
217
218static struct ocmem_req *ocmem_create_req(void)
219{
220 struct ocmem_req *p = NULL;
221
222 p = kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
223 if (!p)
224 return NULL;
225
226 INIT_LIST_HEAD(&p->zone_list);
227 INIT_LIST_HEAD(&p->sched_list);
228 init_rwsem(&p->rw_sem);
229 SET_STATE(p, R_FREE);
230 return p;
231}
232
233static int ocmem_destroy_req(struct ocmem_req *req)
234{
235 kfree(req);
236 return 0;
237}
238
239static struct ocmem_region *create_region(void)
240{
241 struct ocmem_region *p = NULL;
242
243 p = kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
244 if (!p)
245 return NULL;
246 idr_init(&p->region_idr);
247 p->r_start = p->r_end = p->r_sz = 0x0;
248 p->max_prio = NO_PRIO;
249 return p;
250}
251
252static int destroy_region(struct ocmem_region *region)
253{
254 kfree(region);
255 return 0;
256}
257
258static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
259{
260 int ret, id;
261
262 while (1) {
263 if (idr_pre_get(&region->region_idr, GFP_KERNEL) == 0)
264 return -ENOMEM;
265
266 ret = idr_get_new_above(&region->region_idr, req, 1, &id);
267
268 if (ret != -EAGAIN)
269 break;
270 }
271
272 if (!ret) {
273 req->req_id = id;
274 pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
275 req, id, region);
276 return 0;
277 }
278 return -EINVAL;
279}
280
281static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
282{
283 idr_remove(&region->region_idr, req->req_id);
284 return 0;
285}
286
287static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
288{
289 region->r_start = req->req_start;
290 region->r_end = req->req_end;
291 region->r_sz = req->req_end - req->req_start + 1;
292 return 0;
293}
294
295static int region_req_count(int id, void *ptr, void *data)
296{
297 int *count = data;
298 *count = *count + 1;
299 return 0;
300}
301
302static int req_count(struct ocmem_region *region)
303{
304 int count = 0;
305 idr_for_each(&region->region_idr, region_req_count, &count);
306 return count;
307}
308
309static int compute_max_prio(int id, void *ptr, void *data)
310{
311 int *max = data;
312 struct ocmem_req *req = ptr;
313
314 if (req->prio > *max)
315 *max = req->prio;
316 return 0;
317}
318
319static int update_region_prio(struct ocmem_region *region)
320{
321 int max_prio;
322 if (req_count(region) != 0) {
323 idr_for_each(&region->region_idr, compute_max_prio, &max_prio);
324 region->max_prio = max_prio;
325 } else {
326 region->max_prio = NO_PRIO;
327 }
328 pr_debug("ocmem: Updating prio of region %p as %d\n",
329 region, max_prio);
330
331 return 0;
332}
333
334static struct ocmem_region *find_region(unsigned long addr)
335{
336 struct ocmem_region *region = NULL;
337 struct rb_node *rb_node = NULL;
338
339 rb_node = sched_tree.rb_node;
340
341 while (rb_node) {
342 struct ocmem_region *tmp_region = NULL;
343 tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
344
345 if (tmp_region->r_end > addr) {
346 region = tmp_region;
347 if (tmp_region->r_start <= addr)
348 break;
349 rb_node = rb_node->rb_left;
350 } else {
351 rb_node = rb_node->rb_right;
352 }
353 }
354 return region;
355}
356
357static struct ocmem_region *find_region_intersection(unsigned long start,
358 unsigned long end)
359{
360
361 struct ocmem_region *region = NULL;
362 region = find_region(start);
363 if (region && end <= region->r_start)
364 region = NULL;
365 return region;
366}
367
368static struct ocmem_region *find_region_match(unsigned long start,
369 unsigned long end)
370{
371
372 struct ocmem_region *region = NULL;
373 region = find_region(start);
374 if (region && start == region->r_start && end == region->r_end)
375 return region;
376 return NULL;
377}
378
379static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
380{
381 struct ocmem_req *req = NULL;
382
383 if (!region)
384 return NULL;
385
386 req = idr_find(&region->region_idr, owner);
387
388 return req;
389}
390
391/* Must be called with req->sem held */
392static inline int is_mapped(struct ocmem_req *req)
393{
394 return TEST_STATE(req, R_MAPPED);
395}
396
397/* Must be called with sched_mutex held */
398static int __sched_unmap(struct ocmem_req *req)
399{
400 struct ocmem_req *matched_req = NULL;
401 struct ocmem_region *matched_region = NULL;
402
403 matched_region = find_region_match(req->req_start, req->req_end);
404 matched_req = find_req_match(req->req_id, matched_region);
405
406 if (!matched_region || !matched_req) {
407 pr_err("Could not find backing region for req");
408 goto invalid_op_error;
409 }
410
411 if (matched_req != req) {
412 pr_err("Request does not match backing req");
413 goto invalid_op_error;
414 }
415
416 if (!is_mapped(req)) {
417 pr_err("Request is not currently mapped");
418 goto invalid_op_error;
419 }
420
421 /* Update the request state */
422 CLEAR_STATE(req, R_MAPPED);
423 SET_STATE(req, R_MUST_MAP);
424
425 return OP_COMPLETE;
426
427invalid_op_error:
428 return OP_FAIL;
429}
430
431/* Must be called with sched_mutex held */
432static int __sched_map(struct ocmem_req *req)
433{
434 struct ocmem_req *matched_req = NULL;
435 struct ocmem_region *matched_region = NULL;
436
437 matched_region = find_region_match(req->req_start, req->req_end);
438 matched_req = find_req_match(req->req_id, matched_region);
439
440 if (!matched_region || !matched_req) {
441 pr_err("Could not find backing region for req");
442 goto invalid_op_error;
443 }
444
445 if (matched_req != req) {
446 pr_err("Request does not match backing req");
447 goto invalid_op_error;
448 }
449
450 /* Update the request state */
451 CLEAR_STATE(req, R_MUST_MAP);
452 SET_STATE(req, R_MAPPED);
453
454 return OP_COMPLETE;
455
456invalid_op_error:
457 return OP_FAIL;
458}
459
460static int do_map(struct ocmem_req *req)
461{
462 int rc = 0;
463
464 mutex_lock(&sched_mutex);
465 rc = __sched_map(req);
466 mutex_unlock(&sched_mutex);
467
468 if (rc == OP_FAIL)
469 return -EINVAL;
470
471 return 0;
472}
473
474static int do_unmap(struct ocmem_req *req)
475{
476 int rc = 0;
477
478 mutex_lock(&sched_mutex);
479 rc = __sched_unmap(req);
480 mutex_unlock(&sched_mutex);
481
482 if (rc == OP_FAIL)
483 return -EINVAL;
484
485 return 0;
486}
487
488/* process map is a wrapper where power control will be added later */
489static int process_map(struct ocmem_req *req, unsigned long start,
490 unsigned long end)
491{
492 return do_map(req);
493}
494
495/* process unmap is a wrapper where power control will be added later */
496static int process_unmap(struct ocmem_req *req, unsigned long start,
497 unsigned long end)
498{
499 return do_unmap(req);
500}
501
502static int __sched_grow(struct ocmem_req *req, bool can_block)
503{
504 unsigned long min = req->req_min;
505 unsigned long max = req->req_max;
506 unsigned long step = req->req_step;
507 int owner = req->owner;
508 unsigned long curr_sz = 0;
509 unsigned long growth_sz = 0;
510 unsigned long curr_start = 0;
511 enum client_prio prio = req->prio;
512 unsigned long alloc_addr = 0x0;
513 bool retry;
514 struct ocmem_region *spanned_r = NULL;
515 struct ocmem_region *overlap_r = NULL;
516
517 struct ocmem_req *matched_req = NULL;
518 struct ocmem_region *matched_region = NULL;
519
520 struct ocmem_zone *zone = get_zone(owner);
521 struct ocmem_region *region = NULL;
522
523 matched_region = find_region_match(req->req_start, req->req_end);
524 matched_req = find_req_match(req->req_id, matched_region);
525
526 if (!matched_region || !matched_req) {
527 pr_err("Could not find backing region for req");
528 goto invalid_op_error;
529 }
530
531 if (matched_req != req) {
532 pr_err("Request does not match backing req");
533 goto invalid_op_error;
534 }
535
536 curr_sz = matched_req->req_sz;
537 curr_start = matched_req->req_start;
538 growth_sz = matched_req->req_max - matched_req->req_sz;
539
540 pr_debug("Attempting to grow req %p from %lx to %lx\n",
541 req, matched_req->req_sz, matched_req->req_max);
542
543 retry = false;
544
545 pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
546
547retry_next_step:
548
549 spanned_r = NULL;
550 overlap_r = NULL;
551
552 spanned_r = find_region(zone->z_head);
553 overlap_r = find_region_intersection(zone->z_head,
554 zone->z_head + growth_sz);
555
556 if (overlap_r == NULL) {
557 /* no conflicting regions, schedule this region */
558 zone->z_ops->free(zone, curr_start, curr_sz);
559 alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
560
561 if (alloc_addr < 0) {
562 pr_err("ocmem: zone allocation operation failed\n");
563 goto internal_error;
564 }
565
566 curr_sz += growth_sz;
567 /* Detach the region from the interval tree */
568 /* This is to guarantee that any change in size
569 * causes the tree to be rebalanced if required */
570
571 detach_req(matched_region, req);
572 if (req_count(matched_region) == 0) {
573 remove_region(matched_region);
574 region = matched_region;
575 } else {
576 region = create_region();
577 if (!region) {
578 pr_err("ocmem: Unable to create region\n");
579 goto region_error;
580 }
581 }
582
583 /* update the request */
584 req->req_start = alloc_addr;
585 /* increment the size to reflect new length */
586 req->req_sz = curr_sz;
587 req->req_end = alloc_addr + req->req_sz - 1;
588
589 /* update request state */
590 CLEAR_STATE(req, R_MUST_GROW);
591 SET_STATE(req, R_ALLOCATED);
592 SET_STATE(req, R_MUST_MAP);
593 req->op = SCHED_MAP;
594
595 /* update the region with new req */
596 attach_req(region, req);
597 populate_region(region, req);
598 update_region_prio(region);
599
600 /* update the tree with new region */
601 if (insert_region(region)) {
602 pr_err("ocmem: Failed to insert the region\n");
603 goto region_error;
604 }
605
606 if (retry) {
607 SET_STATE(req, R_MUST_GROW);
608 SET_STATE(req, R_PENDING);
609 req->op = SCHED_GROW;
610 return OP_PARTIAL;
611 }
612 } else if (spanned_r != NULL && overlap_r != NULL) {
613 /* resolve conflicting regions based on priority */
614 if (overlap_r->max_prio < prio) {
615 /* Growth cannot be triggered unless a previous
616 * client of lower priority was evicted */
617 pr_err("ocmem: Invalid growth scheduled\n");
618 /* This is serious enough to fail */
619 BUG();
620 return OP_FAIL;
621 } else if (overlap_r->max_prio > prio) {
622 if (min == max) {
623 /* Cannot grow at this time, try later */
624 SET_STATE(req, R_PENDING);
625 SET_STATE(req, R_MUST_GROW);
626 return OP_RESCHED;
627 } else {
628 /* Try to grow in steps */
629 growth_sz -= step;
630 /* We are OOM at this point so need to retry */
631 if (growth_sz <= curr_sz) {
632 SET_STATE(req, R_PENDING);
633 SET_STATE(req, R_MUST_GROW);
634 return OP_RESCHED;
635 }
636 retry = true;
637 pr_debug("ocmem: Attempting with reduced size %lx\n",
638 growth_sz);
639 goto retry_next_step;
640 }
641 } else {
642 pr_err("ocmem: grow: New Region %p Existing %p\n",
643 matched_region, overlap_r);
644 pr_err("ocmem: Undetermined behavior\n");
645 /* This is serious enough to fail */
646 BUG();
647 }
648 } else if (spanned_r == NULL && overlap_r != NULL) {
649 goto err_not_supported;
650 }
651
652 return OP_COMPLETE;
653
654err_not_supported:
655 pr_err("ocmem: Scheduled unsupported operation\n");
656 return OP_FAIL;
657region_error:
658 zone->z_ops->free(zone, alloc_addr, curr_sz);
659 detach_req(region, req);
660 update_region_prio(region);
661 /* req is going to be destroyed by the caller anyways */
662internal_error:
663 destroy_region(region);
664invalid_op_error:
665 return OP_FAIL;
666}
667
668/* Must be called with sched_mutex held */
669static int __sched_free(struct ocmem_req *req)
670{
671 int owner = req->owner;
672 int ret = 0;
673
674 struct ocmem_req *matched_req = NULL;
675 struct ocmem_region *matched_region = NULL;
676
677 struct ocmem_zone *zone = get_zone(owner);
678
679 BUG_ON(!zone);
680
681 matched_region = find_region_match(req->req_start, req->req_end);
682 matched_req = find_req_match(req->req_id, matched_region);
683
684 if (!matched_region || !matched_req)
685 goto invalid_op_error;
686 if (matched_req != req)
687 goto invalid_op_error;
688
689 ret = zone->z_ops->free(zone,
690 matched_req->req_start, matched_req->req_sz);
691
692 if (ret < 0)
693 goto err_op_fail;
694
695 detach_req(matched_region, matched_req);
696 update_region_prio(matched_region);
697 if (req_count(matched_region) == 0) {
698 remove_region(matched_region);
699 destroy_region(matched_region);
700 }
701
702 /* Update the request */
703 req->req_start = 0x0;
704 req->req_sz = 0x0;
705 req->req_end = 0x0;
706 SET_STATE(req, R_FREE);
707 return OP_COMPLETE;
708invalid_op_error:
709 pr_err("ocmem: free: Failed to find matching region\n");
710err_op_fail:
711 pr_err("ocmem: free: Failed\n");
712 return OP_FAIL;
713}
714
715/* Must be called with sched_mutex held */
716static int __sched_allocate(struct ocmem_req *req, bool can_block,
717 bool can_wait)
718{
719 unsigned long min = req->req_min;
720 unsigned long max = req->req_max;
721 unsigned long step = req->req_step;
722 int owner = req->owner;
723 unsigned long sz = max;
724 enum client_prio prio = req->prio;
725 unsigned long alloc_addr = 0x0;
726 bool retry;
727
728 struct ocmem_region *spanned_r = NULL;
729 struct ocmem_region *overlap_r = NULL;
730
731 struct ocmem_zone *zone = get_zone(owner);
732 struct ocmem_region *region = NULL;
733
734 BUG_ON(!zone);
735
736 if (min > (zone->z_end - zone->z_start)) {
737 pr_err("ocmem: requested minimum size exceeds quota\n");
738 goto invalid_op_error;
739 }
740
741 if (max > (zone->z_end - zone->z_start)) {
742 pr_err("ocmem: requested maximum size exceeds quota\n");
743 goto invalid_op_error;
744 }
745
746 if (min > zone->z_free) {
747 pr_err("ocmem: out of memory for zone %d\n", owner);
748 goto invalid_op_error;
749 }
750
751 region = create_region();
752
753 if (!region) {
754 pr_err("ocmem: Unable to create region\n");
755 goto invalid_op_error;
756 }
757
758 retry = false;
759
760 pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
761
762retry_next_step:
763
764 spanned_r = NULL;
765 overlap_r = NULL;
766
767 spanned_r = find_region(zone->z_head);
768 overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
769
770 if (overlap_r == NULL) {
771 /* no conflicting regions, schedule this region */
772 alloc_addr = zone->z_ops->allocate(zone, sz);
773
774 if (alloc_addr < 0) {
775 pr_err("Zone Allocation operation failed\n");
776 goto internal_error;
777 }
778
779 /* update the request */
780 req->req_start = alloc_addr;
781 req->req_end = alloc_addr + sz - 1;
782 req->req_sz = sz;
783 req->zone = zone;
784
785 /* update request state */
786 CLEAR_STATE(req, R_FREE);
787 SET_STATE(req, R_ALLOCATED);
788 SET_STATE(req, R_MUST_MAP);
789 req->op = SCHED_NOP;
790
791 /* attach the request to the region */
792 attach_req(region, req);
793 populate_region(region, req);
794 update_region_prio(region);
795
796 /* update the tree with new region */
797 if (insert_region(region)) {
798 pr_err("ocmem: Failed to insert the region\n");
799 zone->z_ops->free(zone, alloc_addr, sz);
800 detach_req(region, req);
801 update_region_prio(region);
802 /* req will be destroyed by the caller */
803 goto internal_error;
804 }
805
806 if (retry) {
807 SET_STATE(req, R_MUST_GROW);
808 SET_STATE(req, R_PENDING);
809 req->op = SCHED_GROW;
810 return OP_PARTIAL;
811 }
812 } else if (spanned_r != NULL && overlap_r != NULL) {
813 /* resolve conflicting regions based on priority */
814 if (overlap_r->max_prio < prio) {
815 if (min == max) {
816 pr_err("ocmem: Requires eviction support\n");
817 goto err_not_supported;
818 } else {
819 /* Try to allocate atleast >= 'min' immediately */
820 sz -= step;
821 if (sz < min)
822 goto err_out_of_mem;
823 retry = true;
824 pr_debug("ocmem: Attempting with reduced size %lx\n",
825 sz);
826 goto retry_next_step;
827 }
828 } else if (overlap_r->max_prio > prio) {
829 if (can_block == true) {
830 SET_STATE(req, R_PENDING);
831 SET_STATE(req, R_MUST_GROW);
832 return OP_RESCHED;
833 } else {
834 if (min == max) {
835 pr_err("Cannot allocate %lx synchronously\n",
836 sz);
837 goto err_out_of_mem;
838 } else {
839 sz -= step;
840 if (sz < min)
841 goto err_out_of_mem;
842 retry = true;
843 pr_debug("ocmem: Attempting reduced size %lx\n",
844 sz);
845 goto retry_next_step;
846 }
847 }
848 } else {
849 pr_err("ocmem: Undetermined behavior\n");
850 pr_err("ocmem: New Region %p Existing %p\n", region,
851 overlap_r);
852 /* This is serious enough to fail */
853 BUG();
854 }
855 } else if (spanned_r == NULL && overlap_r != NULL)
856 goto err_not_supported;
857
858 return OP_COMPLETE;
859
860err_not_supported:
861 pr_err("ocmem: Scheduled unsupported operation\n");
862 return OP_FAIL;
863
864err_out_of_mem:
865 pr_err("ocmem: Out of memory during allocation\n");
866internal_error:
867 destroy_region(region);
868invalid_op_error:
869 return OP_FAIL;
870}
871
872static int sched_enqueue(struct ocmem_req *priv)
873{
874 struct ocmem_req *next = NULL;
875 mutex_lock(&sched_queue_mutex);
876 list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
877 pr_debug("enqueued req %p\n", priv);
878 list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
879 pr_debug("pending requests for client %p\n", next);
880 }
881 mutex_unlock(&sched_queue_mutex);
882 return 0;
883}
884
885static struct ocmem_req *ocmem_fetch_req(void)
886{
887 int i;
888 struct ocmem_req *req = NULL;
889 struct ocmem_req *next = NULL;
890
891 mutex_lock(&sched_queue_mutex);
892 for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
893 if (list_empty(&sched_queue[i]))
894 continue;
895 list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
896 {
897 if (req) {
898 pr_debug("ocmem: Fetched pending request %p\n",
899 req);
900 list_del(&req->sched_list);
901 break;
902 }
903 }
904 }
905 mutex_unlock(&sched_queue_mutex);
906 return req;
907}
908
909int process_xfer(int id, struct ocmem_handle *handle,
910 struct ocmem_map_list *list, int direction)
911{
912
913 return 0;
914}
915
916unsigned long process_quota(int id)
917{
918 struct ocmem_zone *zone = NULL;
919
920 if (is_blocked(id))
921 return 0;
922
923 zone = get_zone(id);
924
925 if (zone && zone->z_pool)
926 return zone->z_end - zone->z_start;
927 else
928 return 0;
929}
930
931static int do_grow(struct ocmem_req *req)
932{
933 struct ocmem_buf *buffer = NULL;
934 bool can_block = true;
935 int rc = 0;
936
937 down_write(&req->rw_sem);
938 buffer = req->buffer;
939
940 /* Take the scheduler mutex */
941 mutex_lock(&sched_mutex);
942 rc = __sched_grow(req, can_block);
943 mutex_unlock(&sched_mutex);
944
945 if (rc == OP_FAIL)
946 goto err_op_fail;
947
948 if (rc == OP_RESCHED) {
949 pr_debug("ocmem: Enqueue this allocation");
950 sched_enqueue(req);
951 }
952
953 else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
954 buffer->addr = device_address(req->owner, req->req_start);
955 buffer->len = req->req_sz;
956 }
957
958 up_write(&req->rw_sem);
959 return 0;
960err_op_fail:
961 up_write(&req->rw_sem);
962 return -EINVAL;
963}
964
965static int process_grow(struct ocmem_req *req)
966{
967 int rc = 0;
968
969 /* Attempt to grow the region */
970 rc = do_grow(req);
971
972 if (rc < 0)
973 return -EINVAL;
974
975 /* Map the newly grown region */
976 if (is_tcm(req->owner)) {
977 rc = process_map(req, req->req_start, req->req_end);
978 if (rc < 0)
979 return -EINVAL;
980 }
981
982 /* Notify the client about the buffer growth */
983 rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
984 if (rc < 0) {
985 pr_err("No notifier callback to cater for req %p event: %d\n",
986 req, OCMEM_ALLOC_GROW);
987 BUG();
988 }
989 return 0;
990}
991
992static void ocmem_sched_wk_func(struct work_struct *work);
993DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
994
995static int ocmem_schedule_pending(void)
996{
997 schedule_delayed_work(&ocmem_sched_thread,
998 msecs_to_jiffies(SCHED_DELAY));
999 return 0;
1000}
1001
1002static int do_free(struct ocmem_req *req)
1003{
1004 int rc = 0;
1005 struct ocmem_buf *buffer = req->buffer;
1006
1007 down_write(&req->rw_sem);
1008
1009 if (is_mapped(req)) {
1010 pr_err("ocmem: Buffer needs to be unmapped before free\n");
1011 goto err_free_fail;
1012 }
1013
1014 /* Grab the sched mutex */
1015 mutex_lock(&sched_mutex);
1016 rc = __sched_free(req);
1017 mutex_unlock(&sched_mutex);
1018
1019 switch (rc) {
1020
1021 case OP_COMPLETE:
1022 buffer->addr = 0x0;
1023 buffer->len = 0x0;
1024 break;
1025 case OP_FAIL:
1026 default:
1027 goto err_free_fail;
1028 break;
1029 }
1030
1031 up_write(&req->rw_sem);
1032 return 0;
1033err_free_fail:
1034 up_write(&req->rw_sem);
1035 pr_err("ocmem: freeing req %p failed\n", req);
1036 return -EINVAL;
1037}
1038
1039int process_free(int id, struct ocmem_handle *handle)
1040{
1041 struct ocmem_req *req = NULL;
1042 struct ocmem_buf *buffer = NULL;
1043 int rc = 0;
1044
1045 if (is_blocked(id)) {
1046 pr_err("Client %d cannot request free\n", id);
1047 return -EINVAL;
1048 }
1049
1050 req = handle_to_req(handle);
1051 buffer = handle_to_buffer(handle);
1052
1053 if (!req)
1054 return -EINVAL;
1055
1056 if (req->req_start != core_address(id, buffer->addr)) {
1057 pr_err("Invalid buffer handle passed for free\n");
1058 return -EINVAL;
1059 }
1060
1061 if (is_tcm(req->owner)) {
1062 rc = process_unmap(req, req->req_start, req->req_end);
1063 if (rc < 0)
1064 return -EINVAL;
1065 }
1066
1067 rc = do_free(req);
1068
1069 if (rc < 0)
1070 return -EINVAL;
1071
1072 ocmem_destroy_req(req);
1073 handle->req = NULL;
1074
1075 ocmem_schedule_pending();
1076 return 0;
1077}
1078
1079static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
1080{
1081 int rc = 0;
1082 struct ocmem_buf *buffer = req->buffer;
1083
1084 down_write(&req->rw_sem);
1085
1086 /* Take the scheduler mutex */
1087 mutex_lock(&sched_mutex);
1088 rc = __sched_allocate(req, can_block, can_wait);
1089 mutex_unlock(&sched_mutex);
1090
1091 if (rc == OP_FAIL)
1092 goto err_allocate_fail;
1093
1094 if (rc == OP_RESCHED) {
1095 buffer->addr = 0x0;
1096 buffer->len = 0x0;
1097 pr_debug("ocmem: Enqueuing req %p\n", req);
1098 sched_enqueue(req);
1099 } else if (rc == OP_PARTIAL) {
1100 buffer->addr = device_address(req->owner, req->req_start);
1101 buffer->len = req->req_sz;
1102 pr_debug("ocmem: Enqueuing req %p\n", req);
1103 sched_enqueue(req);
1104 } else if (rc == OP_COMPLETE) {
1105 buffer->addr = device_address(req->owner, req->req_start);
1106 buffer->len = req->req_sz;
1107 }
1108
1109 up_write(&req->rw_sem);
1110 return 0;
1111err_allocate_fail:
1112 up_write(&req->rw_sem);
1113 return -EINVAL;
1114}
1115
1116
1117int process_allocate(int id, struct ocmem_handle *handle,
1118 unsigned long min, unsigned long max,
1119 unsigned long step, bool can_block, bool can_wait)
1120{
1121
1122 struct ocmem_req *req = NULL;
1123 struct ocmem_buf *buffer = NULL;
1124 int rc = 0;
1125
1126 /* sanity checks */
1127 if (is_blocked(id)) {
1128 pr_err("Client %d cannot request allocation\n", id);
1129 return -EINVAL;
1130 }
1131
1132 if (handle->req != NULL) {
1133 pr_err("Invalid handle passed in\n");
1134 return -EINVAL;
1135 }
1136
1137 buffer = handle_to_buffer(handle);
1138 BUG_ON(buffer == NULL);
1139
1140 /* prepare a request structure to represent this transaction */
1141 req = ocmem_create_req();
1142 if (!req)
1143 return -ENOMEM;
1144
1145 req->owner = id;
1146 req->req_min = min;
1147 req->req_max = max;
1148 req->req_step = step;
1149 req->prio = ocmem_client_table[id].priority;
1150 req->op = SCHED_ALLOCATE;
1151 req->buffer = buffer;
1152
1153 rc = do_allocate(req, can_block, can_wait);
1154
1155 if (rc < 0)
1156 goto do_allocate_error;
1157
1158 handle->req = req;
1159
1160 if (is_tcm(id)) {
1161 rc = process_map(req, req->req_start, req->req_end);
1162 if (rc < 0)
1163 goto map_error;
1164 }
1165
1166 return 0;
1167
1168map_error:
1169 handle->req = NULL;
1170 do_free(req);
1171do_allocate_error:
1172 ocmem_destroy_req(req);
1173 return -EINVAL;
1174}
1175
1176int process_delayed_allocate(struct ocmem_req *req)
1177{
1178
1179 struct ocmem_handle *handle = NULL;
1180 int rc = 0;
1181 int id = req->owner;
1182
1183 handle = req_to_handle(req);
1184 BUG_ON(handle == NULL);
1185
1186 rc = do_allocate(req, true, false);
1187
1188 if (rc < 0)
1189 goto do_allocate_error;
1190
1191 if (is_tcm(id)) {
1192 rc = process_map(req, req->req_start, req->req_end);
1193 if (rc < 0)
1194 goto map_error;
1195 }
1196
1197 /* Notify the client about the buffer growth */
1198 rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
1199 if (rc < 0) {
1200 pr_err("No notifier callback to cater for req %p event: %d\n",
1201 req, OCMEM_ALLOC_GROW);
1202 BUG();
1203 }
1204 return 0;
1205
1206map_error:
1207 handle->req = NULL;
1208 do_free(req);
1209do_allocate_error:
1210 ocmem_destroy_req(req);
1211 return -EINVAL;
1212}
1213
1214static void ocmem_sched_wk_func(struct work_struct *work)
1215{
1216
1217 struct ocmem_buf *buffer = NULL;
1218 struct ocmem_handle *handle = NULL;
1219 struct ocmem_req *req = ocmem_fetch_req();
1220
1221 if (!req) {
1222 pr_debug("No Pending Requests found\n");
1223 return;
1224 }
1225
1226 pr_debug("ocmem: sched_wk pending req %p\n", req);
1227 handle = req_to_handle(req);
1228 buffer = handle_to_buffer(handle);
1229 BUG_ON(req->op == SCHED_NOP);
1230
1231 switch (req->op) {
1232 case SCHED_GROW:
1233 process_grow(req);
1234 break;
1235 case SCHED_ALLOCATE:
1236 process_delayed_allocate(req);
1237 break;
1238 default:
1239 pr_err("ocmem: Unknown operation encountered\n");
1240 break;
1241 }
1242 return;
1243}
1244
1245int ocmem_sched_init(void)
1246{
1247 int i = 0;
1248 sched_tree = RB_ROOT;
1249 mutex_init(&sched_mutex);
1250 mutex_init(&sched_queue_mutex);
1251 for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
1252 INIT_LIST_HEAD(&sched_queue[i]);
1253
1254 return 0;
1255}