blob: 90d0630d0f68b7971d5946b0514dfbd505ac5d30 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Naveen Ramarajb9da05782012-05-07 09:07: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/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,
Naveen Ramarajcc4ec152012-05-14 09:55:29 -070057 PRIO_OTHER_OS = 0x1,
Naveen Ramarajb9da05782012-05-07 09:07:35 -070058 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
Naveen Ramarajcc4ec152012-05-14 09:55:29 -070078static struct list_head rdm_queue;
79static struct mutex rdm_mutex;
80static struct workqueue_struct *ocmem_rdm_wq;
81static struct workqueue_struct *ocmem_eviction_wq;
82
83static struct ocmem_eviction_data *evictions[OCMEM_CLIENT_MAX];
84
85struct ocmem_rdm_work {
86 int id;
87 struct ocmem_map_list *list;
88 struct ocmem_handle *handle;
89 int direction;
90 struct work_struct work;
91};
92
Naveen Ramarajb9da05782012-05-07 09:07:35 -070093/* OCMEM Operational modes */
94enum ocmem_client_modes {
95 OCMEM_PERFORMANCE = 1,
96 OCMEM_PASSIVE,
97 OCMEM_LOW_POWER,
98 OCMEM_MODE_MAX = OCMEM_LOW_POWER
99};
100
101/* OCMEM Addressing modes */
102enum ocmem_interconnects {
103 OCMEM_BLOCKED = 0,
104 OCMEM_PORT = 1,
105 OCMEM_OCMEMNOC = 2,
106 OCMEM_SYSNOC = 3,
107};
108
109/**
110 * Primary OCMEM Arbitration Table
111 **/
112struct ocmem_table {
113 int client_id;
114 int priority;
115 int mode;
116 int hw_interconnect;
117} ocmem_client_table[OCMEM_CLIENT_MAX] = {
118 {OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
Naveen Ramaraje9f11f32012-08-13 22:46:50 -0700119 {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700120 {OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
121 {OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
122 {OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
123 {OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
124 {OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700125 {OCMEM_OTHER_OS, PRIO_OTHER_OS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700126};
127
128static struct rb_root sched_tree;
129static struct mutex sched_mutex;
130
131/* A region represents a continuous interval in OCMEM address space */
132struct ocmem_region {
133 /* Chain in Interval Tree */
134 struct rb_node region_rb;
135 /* Hash map of requests */
136 struct idr region_idr;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700137 /* Chain in eviction list */
138 struct list_head eviction_list;
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700139 unsigned long r_start;
140 unsigned long r_end;
141 unsigned long r_sz;
142 /* Highest priority of all requests served by this region */
143 int max_prio;
144};
145
146/* Is OCMEM tightly coupled to the client ?*/
147static inline int is_tcm(int id)
148{
149 if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
150 ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
151 return 1;
152 else
153 return 0;
154}
155
156static inline int is_blocked(int id)
157{
158 return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
159}
160
Naveen Ramarajb9938772012-08-20 14:41:13 -0700161inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
162{
163 if (handle)
164 return &handle->buffer;
165 else
166 return NULL;
167}
168
169inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
170{
171 if (buffer)
172 return container_of(buffer, struct ocmem_handle, buffer);
173 else
174 return NULL;
175}
176
177inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
178{
179 if (handle)
180 return handle->req;
181 else
182 return NULL;
183}
184
185inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
186{
187 if (req && req->buffer)
188 return container_of(req->buffer, struct ocmem_handle, buffer);
189 else
190 return NULL;
191}
192
193/* Simple wrappers which will have debug features added later */
194inline int ocmem_read(void *at)
195{
196 return readl_relaxed(at);
197}
198
199inline int ocmem_write(unsigned long val, void *at)
200{
201 writel_relaxed(val, at);
202 return 0;
203}
204
205inline int get_mode(int id)
206{
207 if (!check_id(id))
208 return MODE_NOT_SET;
209 else
210 return ocmem_client_table[id].mode == OCMEM_PERFORMANCE ?
211 WIDE_MODE : THIN_MODE;
212}
213
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700214/* Returns the address that can be used by a device core to access OCMEM */
215static unsigned long device_address(int id, unsigned long addr)
216{
217 int hw_interconnect = ocmem_client_table[id].hw_interconnect;
218 unsigned long ret_addr = 0x0;
219
220 switch (hw_interconnect) {
221 case OCMEM_PORT:
222 ret_addr = phys_to_offset(addr);
223 break;
224 case OCMEM_OCMEMNOC:
225 case OCMEM_SYSNOC:
226 ret_addr = addr;
227 break;
228 case OCMEM_BLOCKED:
229 ret_addr = 0x0;
230 break;
231 }
232 return ret_addr;
233}
234
235/* Returns the address as viewed by the core */
236static unsigned long core_address(int id, unsigned long addr)
237{
238 int hw_interconnect = ocmem_client_table[id].hw_interconnect;
239 unsigned long ret_addr = 0x0;
240
241 switch (hw_interconnect) {
242 case OCMEM_PORT:
243 ret_addr = offset_to_phys(addr);
244 break;
245 case OCMEM_OCMEMNOC:
246 case OCMEM_SYSNOC:
247 ret_addr = addr;
248 break;
249 case OCMEM_BLOCKED:
250 ret_addr = 0x0;
251 break;
252 }
253 return ret_addr;
254}
255
256static int insert_region(struct ocmem_region *region)
257{
258
259 struct rb_root *root = &sched_tree;
260 struct rb_node **p = &root->rb_node;
261 struct rb_node *parent = NULL;
262 struct ocmem_region *tmp = NULL;
263 unsigned long addr = region->r_start;
264
265 while (*p) {
266 parent = *p;
267 tmp = rb_entry(parent, struct ocmem_region, region_rb);
268
269 if (tmp->r_end > addr) {
270 if (tmp->r_start <= addr)
271 break;
272 p = &(*p)->rb_left;
273 } else if (tmp->r_end <= addr)
274 p = &(*p)->rb_right;
275 }
276 rb_link_node(&region->region_rb, parent, p);
277 rb_insert_color(&region->region_rb, root);
278 return 0;
279}
280
281static int remove_region(struct ocmem_region *region)
282{
283 struct rb_root *root = &sched_tree;
284 rb_erase(&region->region_rb, root);
285 return 0;
286}
287
288static struct ocmem_req *ocmem_create_req(void)
289{
290 struct ocmem_req *p = NULL;
291
292 p = kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
293 if (!p)
294 return NULL;
295
296 INIT_LIST_HEAD(&p->zone_list);
297 INIT_LIST_HEAD(&p->sched_list);
298 init_rwsem(&p->rw_sem);
299 SET_STATE(p, R_FREE);
300 return p;
301}
302
303static int ocmem_destroy_req(struct ocmem_req *req)
304{
305 kfree(req);
306 return 0;
307}
308
309static struct ocmem_region *create_region(void)
310{
311 struct ocmem_region *p = NULL;
312
313 p = kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
314 if (!p)
315 return NULL;
316 idr_init(&p->region_idr);
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700317 INIT_LIST_HEAD(&p->eviction_list);
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700318 p->r_start = p->r_end = p->r_sz = 0x0;
319 p->max_prio = NO_PRIO;
320 return p;
321}
322
323static int destroy_region(struct ocmem_region *region)
324{
325 kfree(region);
326 return 0;
327}
328
329static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
330{
331 int ret, id;
332
333 while (1) {
334 if (idr_pre_get(&region->region_idr, GFP_KERNEL) == 0)
335 return -ENOMEM;
336
337 ret = idr_get_new_above(&region->region_idr, req, 1, &id);
338
339 if (ret != -EAGAIN)
340 break;
341 }
342
343 if (!ret) {
344 req->req_id = id;
345 pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
346 req, id, region);
347 return 0;
348 }
349 return -EINVAL;
350}
351
352static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
353{
354 idr_remove(&region->region_idr, req->req_id);
355 return 0;
356}
357
358static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
359{
360 region->r_start = req->req_start;
361 region->r_end = req->req_end;
362 region->r_sz = req->req_end - req->req_start + 1;
363 return 0;
364}
365
366static int region_req_count(int id, void *ptr, void *data)
367{
368 int *count = data;
369 *count = *count + 1;
370 return 0;
371}
372
373static int req_count(struct ocmem_region *region)
374{
375 int count = 0;
376 idr_for_each(&region->region_idr, region_req_count, &count);
377 return count;
378}
379
380static int compute_max_prio(int id, void *ptr, void *data)
381{
382 int *max = data;
383 struct ocmem_req *req = ptr;
384
385 if (req->prio > *max)
386 *max = req->prio;
387 return 0;
388}
389
390static int update_region_prio(struct ocmem_region *region)
391{
392 int max_prio;
393 if (req_count(region) != 0) {
394 idr_for_each(&region->region_idr, compute_max_prio, &max_prio);
395 region->max_prio = max_prio;
396 } else {
397 region->max_prio = NO_PRIO;
398 }
399 pr_debug("ocmem: Updating prio of region %p as %d\n",
400 region, max_prio);
401
402 return 0;
403}
404
405static struct ocmem_region *find_region(unsigned long addr)
406{
407 struct ocmem_region *region = NULL;
408 struct rb_node *rb_node = NULL;
409
410 rb_node = sched_tree.rb_node;
411
412 while (rb_node) {
413 struct ocmem_region *tmp_region = NULL;
414 tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
415
416 if (tmp_region->r_end > addr) {
417 region = tmp_region;
418 if (tmp_region->r_start <= addr)
419 break;
420 rb_node = rb_node->rb_left;
421 } else {
422 rb_node = rb_node->rb_right;
423 }
424 }
425 return region;
426}
427
428static struct ocmem_region *find_region_intersection(unsigned long start,
429 unsigned long end)
430{
431
432 struct ocmem_region *region = NULL;
433 region = find_region(start);
434 if (region && end <= region->r_start)
435 region = NULL;
436 return region;
437}
438
439static struct ocmem_region *find_region_match(unsigned long start,
440 unsigned long end)
441{
442
443 struct ocmem_region *region = NULL;
444 region = find_region(start);
445 if (region && start == region->r_start && end == region->r_end)
446 return region;
447 return NULL;
448}
449
450static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
451{
452 struct ocmem_req *req = NULL;
453
454 if (!region)
455 return NULL;
456
457 req = idr_find(&region->region_idr, owner);
458
459 return req;
460}
461
462/* Must be called with req->sem held */
463static inline int is_mapped(struct ocmem_req *req)
464{
465 return TEST_STATE(req, R_MAPPED);
466}
467
468/* Must be called with sched_mutex held */
469static int __sched_unmap(struct ocmem_req *req)
470{
471 struct ocmem_req *matched_req = NULL;
472 struct ocmem_region *matched_region = NULL;
473
474 matched_region = find_region_match(req->req_start, req->req_end);
475 matched_req = find_req_match(req->req_id, matched_region);
476
477 if (!matched_region || !matched_req) {
478 pr_err("Could not find backing region for req");
479 goto invalid_op_error;
480 }
481
482 if (matched_req != req) {
483 pr_err("Request does not match backing req");
484 goto invalid_op_error;
485 }
486
487 if (!is_mapped(req)) {
488 pr_err("Request is not currently mapped");
489 goto invalid_op_error;
490 }
491
492 /* Update the request state */
493 CLEAR_STATE(req, R_MAPPED);
494 SET_STATE(req, R_MUST_MAP);
495
496 return OP_COMPLETE;
497
498invalid_op_error:
499 return OP_FAIL;
500}
501
502/* Must be called with sched_mutex held */
503static int __sched_map(struct ocmem_req *req)
504{
505 struct ocmem_req *matched_req = NULL;
506 struct ocmem_region *matched_region = NULL;
507
508 matched_region = find_region_match(req->req_start, req->req_end);
509 matched_req = find_req_match(req->req_id, matched_region);
510
511 if (!matched_region || !matched_req) {
512 pr_err("Could not find backing region for req");
513 goto invalid_op_error;
514 }
515
516 if (matched_req != req) {
517 pr_err("Request does not match backing req");
518 goto invalid_op_error;
519 }
520
521 /* Update the request state */
522 CLEAR_STATE(req, R_MUST_MAP);
523 SET_STATE(req, R_MAPPED);
524
525 return OP_COMPLETE;
526
527invalid_op_error:
528 return OP_FAIL;
529}
530
531static int do_map(struct ocmem_req *req)
532{
533 int rc = 0;
534
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700535 down_write(&req->rw_sem);
536
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700537 mutex_lock(&sched_mutex);
538 rc = __sched_map(req);
539 mutex_unlock(&sched_mutex);
540
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700541 up_write(&req->rw_sem);
542
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700543 if (rc == OP_FAIL)
544 return -EINVAL;
545
546 return 0;
547}
548
549static int do_unmap(struct ocmem_req *req)
550{
551 int rc = 0;
552
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700553 down_write(&req->rw_sem);
554
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700555 mutex_lock(&sched_mutex);
556 rc = __sched_unmap(req);
557 mutex_unlock(&sched_mutex);
558
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700559 up_write(&req->rw_sem);
560
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700561 if (rc == OP_FAIL)
562 return -EINVAL;
563
564 return 0;
565}
566
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700567static int process_map(struct ocmem_req *req, unsigned long start,
568 unsigned long end)
569{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700570 int rc = 0;
571
572 rc = ocmem_enable_core_clock();
573
574 if (rc < 0)
575 goto core_clock_fail;
576
577 rc = ocmem_enable_iface_clock();
578
579 if (rc < 0)
Naveen Ramarajb9938772012-08-20 14:41:13 -0700580 goto iface_clock_fail;
581
582 rc = ocmem_enable_br_clock();
583
584 if (rc < 0)
585 goto br_clock_fail;
586
587 rc = do_map(req);
588
589 if (rc < 0) {
590 pr_err("ocmem: Failed to map request %p for %d\n",
591 req, req->owner);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700592 goto process_map_fail;
593
Naveen Ramarajb9938772012-08-20 14:41:13 -0700594 }
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700595
Naveen Ramarajb9938772012-08-20 14:41:13 -0700596 if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
597 get_mode(req->owner))) {
598 pr_err("ocmem: Failed to secure request %p for %d\n", req,
599 req->owner);
600 rc = -EINVAL;
601 goto lock_failed;
602 }
603
604 return 0;
605lock_failed:
606 do_unmap(req);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700607process_map_fail:
608 ocmem_disable_core_clock();
609core_clock_fail:
610 pr_err("ocmem: Failed to map ocmem request\n");
611 return rc;
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700612}
613
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700614static int process_unmap(struct ocmem_req *req, unsigned long start,
615 unsigned long end)
616{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700617 int rc = 0;
618
Naveen Ramarajb9938772012-08-20 14:41:13 -0700619 if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
620 req->req_sz)) {
621 pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
622 req->owner);
623 rc = -EINVAL;
624 goto unlock_failed;
625 }
626
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700627 rc = do_unmap(req);
628
629 if (rc < 0)
630 goto process_unmap_fail;
631
632 ocmem_disable_iface_clock();
633 ocmem_disable_core_clock();
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700634 return 0;
635
Naveen Ramarajb9938772012-08-20 14:41:13 -0700636unlock_failed:
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700637process_unmap_fail:
638 pr_err("ocmem: Failed to unmap ocmem request\n");
639 return rc;
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700640}
641
642static int __sched_grow(struct ocmem_req *req, bool can_block)
643{
644 unsigned long min = req->req_min;
645 unsigned long max = req->req_max;
646 unsigned long step = req->req_step;
647 int owner = req->owner;
648 unsigned long curr_sz = 0;
649 unsigned long growth_sz = 0;
650 unsigned long curr_start = 0;
651 enum client_prio prio = req->prio;
652 unsigned long alloc_addr = 0x0;
653 bool retry;
654 struct ocmem_region *spanned_r = NULL;
655 struct ocmem_region *overlap_r = NULL;
656
657 struct ocmem_req *matched_req = NULL;
658 struct ocmem_region *matched_region = NULL;
659
660 struct ocmem_zone *zone = get_zone(owner);
661 struct ocmem_region *region = NULL;
662
663 matched_region = find_region_match(req->req_start, req->req_end);
664 matched_req = find_req_match(req->req_id, matched_region);
665
666 if (!matched_region || !matched_req) {
667 pr_err("Could not find backing region for req");
668 goto invalid_op_error;
669 }
670
671 if (matched_req != req) {
672 pr_err("Request does not match backing req");
673 goto invalid_op_error;
674 }
675
676 curr_sz = matched_req->req_sz;
677 curr_start = matched_req->req_start;
678 growth_sz = matched_req->req_max - matched_req->req_sz;
679
680 pr_debug("Attempting to grow req %p from %lx to %lx\n",
681 req, matched_req->req_sz, matched_req->req_max);
682
683 retry = false;
684
685 pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
686
687retry_next_step:
688
689 spanned_r = NULL;
690 overlap_r = NULL;
691
692 spanned_r = find_region(zone->z_head);
693 overlap_r = find_region_intersection(zone->z_head,
694 zone->z_head + growth_sz);
695
696 if (overlap_r == NULL) {
697 /* no conflicting regions, schedule this region */
698 zone->z_ops->free(zone, curr_start, curr_sz);
699 alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
700
701 if (alloc_addr < 0) {
702 pr_err("ocmem: zone allocation operation failed\n");
703 goto internal_error;
704 }
705
706 curr_sz += growth_sz;
707 /* Detach the region from the interval tree */
708 /* This is to guarantee that any change in size
709 * causes the tree to be rebalanced if required */
710
711 detach_req(matched_region, req);
712 if (req_count(matched_region) == 0) {
713 remove_region(matched_region);
714 region = matched_region;
715 } else {
716 region = create_region();
717 if (!region) {
718 pr_err("ocmem: Unable to create region\n");
719 goto region_error;
720 }
721 }
722
723 /* update the request */
724 req->req_start = alloc_addr;
725 /* increment the size to reflect new length */
726 req->req_sz = curr_sz;
727 req->req_end = alloc_addr + req->req_sz - 1;
728
729 /* update request state */
730 CLEAR_STATE(req, R_MUST_GROW);
731 SET_STATE(req, R_ALLOCATED);
732 SET_STATE(req, R_MUST_MAP);
733 req->op = SCHED_MAP;
734
735 /* update the region with new req */
736 attach_req(region, req);
737 populate_region(region, req);
738 update_region_prio(region);
739
740 /* update the tree with new region */
741 if (insert_region(region)) {
742 pr_err("ocmem: Failed to insert the region\n");
743 goto region_error;
744 }
745
746 if (retry) {
747 SET_STATE(req, R_MUST_GROW);
748 SET_STATE(req, R_PENDING);
749 req->op = SCHED_GROW;
750 return OP_PARTIAL;
751 }
752 } else if (spanned_r != NULL && overlap_r != NULL) {
753 /* resolve conflicting regions based on priority */
754 if (overlap_r->max_prio < prio) {
755 /* Growth cannot be triggered unless a previous
756 * client of lower priority was evicted */
757 pr_err("ocmem: Invalid growth scheduled\n");
758 /* This is serious enough to fail */
759 BUG();
760 return OP_FAIL;
761 } else if (overlap_r->max_prio > prio) {
762 if (min == max) {
763 /* Cannot grow at this time, try later */
764 SET_STATE(req, R_PENDING);
765 SET_STATE(req, R_MUST_GROW);
766 return OP_RESCHED;
767 } else {
768 /* Try to grow in steps */
769 growth_sz -= step;
770 /* We are OOM at this point so need to retry */
771 if (growth_sz <= curr_sz) {
772 SET_STATE(req, R_PENDING);
773 SET_STATE(req, R_MUST_GROW);
774 return OP_RESCHED;
775 }
776 retry = true;
777 pr_debug("ocmem: Attempting with reduced size %lx\n",
778 growth_sz);
779 goto retry_next_step;
780 }
781 } else {
782 pr_err("ocmem: grow: New Region %p Existing %p\n",
783 matched_region, overlap_r);
784 pr_err("ocmem: Undetermined behavior\n");
785 /* This is serious enough to fail */
786 BUG();
787 }
788 } else if (spanned_r == NULL && overlap_r != NULL) {
789 goto err_not_supported;
790 }
791
792 return OP_COMPLETE;
793
794err_not_supported:
795 pr_err("ocmem: Scheduled unsupported operation\n");
796 return OP_FAIL;
797region_error:
798 zone->z_ops->free(zone, alloc_addr, curr_sz);
799 detach_req(region, req);
800 update_region_prio(region);
801 /* req is going to be destroyed by the caller anyways */
802internal_error:
803 destroy_region(region);
804invalid_op_error:
805 return OP_FAIL;
806}
807
808/* Must be called with sched_mutex held */
809static int __sched_free(struct ocmem_req *req)
810{
811 int owner = req->owner;
812 int ret = 0;
813
814 struct ocmem_req *matched_req = NULL;
815 struct ocmem_region *matched_region = NULL;
816
817 struct ocmem_zone *zone = get_zone(owner);
818
819 BUG_ON(!zone);
820
821 matched_region = find_region_match(req->req_start, req->req_end);
822 matched_req = find_req_match(req->req_id, matched_region);
823
824 if (!matched_region || !matched_req)
825 goto invalid_op_error;
826 if (matched_req != req)
827 goto invalid_op_error;
828
829 ret = zone->z_ops->free(zone,
830 matched_req->req_start, matched_req->req_sz);
831
832 if (ret < 0)
833 goto err_op_fail;
834
835 detach_req(matched_region, matched_req);
836 update_region_prio(matched_region);
837 if (req_count(matched_region) == 0) {
838 remove_region(matched_region);
839 destroy_region(matched_region);
840 }
841
842 /* Update the request */
843 req->req_start = 0x0;
844 req->req_sz = 0x0;
845 req->req_end = 0x0;
846 SET_STATE(req, R_FREE);
847 return OP_COMPLETE;
848invalid_op_error:
849 pr_err("ocmem: free: Failed to find matching region\n");
850err_op_fail:
851 pr_err("ocmem: free: Failed\n");
852 return OP_FAIL;
853}
854
855/* Must be called with sched_mutex held */
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700856static int __sched_shrink(struct ocmem_req *req, unsigned long new_sz)
857{
858 int owner = req->owner;
859 int ret = 0;
860
861 struct ocmem_req *matched_req = NULL;
862 struct ocmem_region *matched_region = NULL;
863 struct ocmem_region *region = NULL;
864 unsigned long alloc_addr = 0x0;
865
866 struct ocmem_zone *zone = get_zone(owner);
867
868 BUG_ON(!zone);
869
870 /* The shrink should not be called for zero size */
871 BUG_ON(new_sz == 0);
872
873 matched_region = find_region_match(req->req_start, req->req_end);
874 matched_req = find_req_match(req->req_id, matched_region);
875
876 if (!matched_region || !matched_req)
877 goto invalid_op_error;
878 if (matched_req != req)
879 goto invalid_op_error;
880
881
882 ret = zone->z_ops->free(zone,
883 matched_req->req_start, matched_req->req_sz);
884
885 if (ret < 0) {
886 pr_err("Zone Allocation operation failed\n");
887 goto internal_error;
888 }
889
890 alloc_addr = zone->z_ops->allocate(zone, new_sz);
891
892 if (alloc_addr < 0) {
893 pr_err("Zone Allocation operation failed\n");
894 goto internal_error;
895 }
896
897 /* Detach the region from the interval tree */
898 /* This is to guarantee that the change in size
899 * causes the tree to be rebalanced if required */
900
901 detach_req(matched_region, req);
902 if (req_count(matched_region) == 0) {
903 remove_region(matched_region);
904 region = matched_region;
905 } else {
906 region = create_region();
907 if (!region) {
908 pr_err("ocmem: Unable to create region\n");
909 goto internal_error;
910 }
911 }
912 /* update the request */
913 req->req_start = alloc_addr;
914 req->req_sz = new_sz;
915 req->req_end = alloc_addr + req->req_sz;
916
917 if (req_count(region) == 0) {
918 remove_region(matched_region);
919 destroy_region(matched_region);
920 }
921
922 /* update request state */
923 SET_STATE(req, R_MUST_GROW);
924 SET_STATE(req, R_MUST_MAP);
925 req->op = SCHED_MAP;
926
927 /* attach the request to the region */
928 attach_req(region, req);
929 populate_region(region, req);
930 update_region_prio(region);
931
932 /* update the tree with new region */
933 if (insert_region(region)) {
934 pr_err("ocmem: Failed to insert the region\n");
935 zone->z_ops->free(zone, alloc_addr, new_sz);
936 detach_req(region, req);
937 update_region_prio(region);
938 /* req will be destroyed by the caller */
939 goto region_error;
940 }
941 return OP_COMPLETE;
942
943region_error:
944 destroy_region(region);
945internal_error:
946 pr_err("ocmem: shrink: Failed\n");
947 return OP_FAIL;
948invalid_op_error:
949 pr_err("ocmem: shrink: Failed to find matching region\n");
950 return OP_FAIL;
951}
952
953/* Must be called with sched_mutex held */
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700954static int __sched_allocate(struct ocmem_req *req, bool can_block,
955 bool can_wait)
956{
957 unsigned long min = req->req_min;
958 unsigned long max = req->req_max;
959 unsigned long step = req->req_step;
960 int owner = req->owner;
961 unsigned long sz = max;
962 enum client_prio prio = req->prio;
963 unsigned long alloc_addr = 0x0;
964 bool retry;
965
966 struct ocmem_region *spanned_r = NULL;
967 struct ocmem_region *overlap_r = NULL;
968
969 struct ocmem_zone *zone = get_zone(owner);
970 struct ocmem_region *region = NULL;
971
972 BUG_ON(!zone);
973
974 if (min > (zone->z_end - zone->z_start)) {
975 pr_err("ocmem: requested minimum size exceeds quota\n");
976 goto invalid_op_error;
977 }
978
979 if (max > (zone->z_end - zone->z_start)) {
980 pr_err("ocmem: requested maximum size exceeds quota\n");
981 goto invalid_op_error;
982 }
983
984 if (min > zone->z_free) {
985 pr_err("ocmem: out of memory for zone %d\n", owner);
986 goto invalid_op_error;
987 }
988
989 region = create_region();
990
991 if (!region) {
992 pr_err("ocmem: Unable to create region\n");
993 goto invalid_op_error;
994 }
995
996 retry = false;
997
998 pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
999
1000retry_next_step:
1001
1002 spanned_r = NULL;
1003 overlap_r = NULL;
1004
1005 spanned_r = find_region(zone->z_head);
1006 overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
1007
1008 if (overlap_r == NULL) {
1009 /* no conflicting regions, schedule this region */
1010 alloc_addr = zone->z_ops->allocate(zone, sz);
1011
1012 if (alloc_addr < 0) {
1013 pr_err("Zone Allocation operation failed\n");
1014 goto internal_error;
1015 }
1016
1017 /* update the request */
1018 req->req_start = alloc_addr;
1019 req->req_end = alloc_addr + sz - 1;
1020 req->req_sz = sz;
1021 req->zone = zone;
1022
1023 /* update request state */
1024 CLEAR_STATE(req, R_FREE);
1025 SET_STATE(req, R_ALLOCATED);
1026 SET_STATE(req, R_MUST_MAP);
1027 req->op = SCHED_NOP;
1028
1029 /* attach the request to the region */
1030 attach_req(region, req);
1031 populate_region(region, req);
1032 update_region_prio(region);
1033
1034 /* update the tree with new region */
1035 if (insert_region(region)) {
1036 pr_err("ocmem: Failed to insert the region\n");
1037 zone->z_ops->free(zone, alloc_addr, sz);
1038 detach_req(region, req);
1039 update_region_prio(region);
1040 /* req will be destroyed by the caller */
1041 goto internal_error;
1042 }
1043
1044 if (retry) {
1045 SET_STATE(req, R_MUST_GROW);
1046 SET_STATE(req, R_PENDING);
1047 req->op = SCHED_GROW;
1048 return OP_PARTIAL;
1049 }
1050 } else if (spanned_r != NULL && overlap_r != NULL) {
1051 /* resolve conflicting regions based on priority */
1052 if (overlap_r->max_prio < prio) {
1053 if (min == max) {
1054 pr_err("ocmem: Requires eviction support\n");
1055 goto err_not_supported;
1056 } else {
1057 /* Try to allocate atleast >= 'min' immediately */
1058 sz -= step;
1059 if (sz < min)
1060 goto err_out_of_mem;
1061 retry = true;
1062 pr_debug("ocmem: Attempting with reduced size %lx\n",
1063 sz);
1064 goto retry_next_step;
1065 }
1066 } else if (overlap_r->max_prio > prio) {
1067 if (can_block == true) {
1068 SET_STATE(req, R_PENDING);
1069 SET_STATE(req, R_MUST_GROW);
1070 return OP_RESCHED;
1071 } else {
1072 if (min == max) {
1073 pr_err("Cannot allocate %lx synchronously\n",
1074 sz);
1075 goto err_out_of_mem;
1076 } else {
1077 sz -= step;
1078 if (sz < min)
1079 goto err_out_of_mem;
1080 retry = true;
1081 pr_debug("ocmem: Attempting reduced size %lx\n",
1082 sz);
1083 goto retry_next_step;
1084 }
1085 }
1086 } else {
1087 pr_err("ocmem: Undetermined behavior\n");
1088 pr_err("ocmem: New Region %p Existing %p\n", region,
1089 overlap_r);
1090 /* This is serious enough to fail */
1091 BUG();
1092 }
1093 } else if (spanned_r == NULL && overlap_r != NULL)
1094 goto err_not_supported;
1095
1096 return OP_COMPLETE;
1097
1098err_not_supported:
1099 pr_err("ocmem: Scheduled unsupported operation\n");
1100 return OP_FAIL;
1101
1102err_out_of_mem:
1103 pr_err("ocmem: Out of memory during allocation\n");
1104internal_error:
1105 destroy_region(region);
1106invalid_op_error:
1107 return OP_FAIL;
1108}
1109
1110static int sched_enqueue(struct ocmem_req *priv)
1111{
1112 struct ocmem_req *next = NULL;
1113 mutex_lock(&sched_queue_mutex);
1114 list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
1115 pr_debug("enqueued req %p\n", priv);
1116 list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
1117 pr_debug("pending requests for client %p\n", next);
1118 }
1119 mutex_unlock(&sched_queue_mutex);
1120 return 0;
1121}
1122
1123static struct ocmem_req *ocmem_fetch_req(void)
1124{
1125 int i;
1126 struct ocmem_req *req = NULL;
1127 struct ocmem_req *next = NULL;
1128
1129 mutex_lock(&sched_queue_mutex);
1130 for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
1131 if (list_empty(&sched_queue[i]))
1132 continue;
1133 list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
1134 {
1135 if (req) {
1136 pr_debug("ocmem: Fetched pending request %p\n",
1137 req);
1138 list_del(&req->sched_list);
1139 break;
1140 }
1141 }
1142 }
1143 mutex_unlock(&sched_queue_mutex);
1144 return req;
1145}
1146
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001147
1148unsigned long process_quota(int id)
1149{
1150 struct ocmem_zone *zone = NULL;
1151
1152 if (is_blocked(id))
1153 return 0;
1154
1155 zone = get_zone(id);
1156
1157 if (zone && zone->z_pool)
1158 return zone->z_end - zone->z_start;
1159 else
1160 return 0;
1161}
1162
1163static int do_grow(struct ocmem_req *req)
1164{
1165 struct ocmem_buf *buffer = NULL;
1166 bool can_block = true;
1167 int rc = 0;
1168
1169 down_write(&req->rw_sem);
1170 buffer = req->buffer;
1171
1172 /* Take the scheduler mutex */
1173 mutex_lock(&sched_mutex);
1174 rc = __sched_grow(req, can_block);
1175 mutex_unlock(&sched_mutex);
1176
1177 if (rc == OP_FAIL)
1178 goto err_op_fail;
1179
1180 if (rc == OP_RESCHED) {
1181 pr_debug("ocmem: Enqueue this allocation");
1182 sched_enqueue(req);
1183 }
1184
1185 else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
1186 buffer->addr = device_address(req->owner, req->req_start);
1187 buffer->len = req->req_sz;
1188 }
1189
1190 up_write(&req->rw_sem);
1191 return 0;
1192err_op_fail:
1193 up_write(&req->rw_sem);
1194 return -EINVAL;
1195}
1196
1197static int process_grow(struct ocmem_req *req)
1198{
1199 int rc = 0;
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001200 unsigned long offset = 0;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001201
1202 /* Attempt to grow the region */
1203 rc = do_grow(req);
1204
1205 if (rc < 0)
1206 return -EINVAL;
1207
1208 /* Map the newly grown region */
1209 if (is_tcm(req->owner)) {
1210 rc = process_map(req, req->req_start, req->req_end);
1211 if (rc < 0)
1212 return -EINVAL;
1213 }
1214
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001215 offset = phys_to_offset(req->req_start);
1216
1217 rc = ocmem_memory_on(req->owner, offset, req->req_sz);
1218
1219 if (rc < 0) {
1220 pr_err("Failed to switch ON memory macros\n");
1221 goto power_ctl_error;
1222 }
1223
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001224 /* Notify the client about the buffer growth */
1225 rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
1226 if (rc < 0) {
1227 pr_err("No notifier callback to cater for req %p event: %d\n",
1228 req, OCMEM_ALLOC_GROW);
1229 BUG();
1230 }
1231 return 0;
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001232power_ctl_error:
1233 return -EINVAL;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001234}
1235
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001236static int do_shrink(struct ocmem_req *req, unsigned long shrink_size)
1237{
1238
1239 int rc = 0;
1240 struct ocmem_buf *buffer = NULL;
1241
1242 down_write(&req->rw_sem);
1243 buffer = req->buffer;
1244
1245 /* Take the scheduler mutex */
1246 mutex_lock(&sched_mutex);
1247 rc = __sched_shrink(req, shrink_size);
1248 mutex_unlock(&sched_mutex);
1249
1250 if (rc == OP_FAIL)
1251 goto err_op_fail;
1252
1253 else if (rc == OP_COMPLETE) {
1254 buffer->addr = device_address(req->owner, req->req_start);
1255 buffer->len = req->req_sz;
1256 }
1257
1258 up_write(&req->rw_sem);
1259 return 0;
1260err_op_fail:
1261 up_write(&req->rw_sem);
1262 return -EINVAL;
1263}
1264
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001265static void ocmem_sched_wk_func(struct work_struct *work);
1266DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
1267
1268static int ocmem_schedule_pending(void)
1269{
1270 schedule_delayed_work(&ocmem_sched_thread,
1271 msecs_to_jiffies(SCHED_DELAY));
1272 return 0;
1273}
1274
1275static int do_free(struct ocmem_req *req)
1276{
1277 int rc = 0;
1278 struct ocmem_buf *buffer = req->buffer;
1279
1280 down_write(&req->rw_sem);
1281
1282 if (is_mapped(req)) {
1283 pr_err("ocmem: Buffer needs to be unmapped before free\n");
1284 goto err_free_fail;
1285 }
1286
1287 /* Grab the sched mutex */
1288 mutex_lock(&sched_mutex);
1289 rc = __sched_free(req);
1290 mutex_unlock(&sched_mutex);
1291
1292 switch (rc) {
1293
1294 case OP_COMPLETE:
1295 buffer->addr = 0x0;
1296 buffer->len = 0x0;
1297 break;
1298 case OP_FAIL:
1299 default:
1300 goto err_free_fail;
1301 break;
1302 }
1303
1304 up_write(&req->rw_sem);
1305 return 0;
1306err_free_fail:
1307 up_write(&req->rw_sem);
1308 pr_err("ocmem: freeing req %p failed\n", req);
1309 return -EINVAL;
1310}
1311
1312int process_free(int id, struct ocmem_handle *handle)
1313{
1314 struct ocmem_req *req = NULL;
1315 struct ocmem_buf *buffer = NULL;
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001316 unsigned long offset = 0;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001317 int rc = 0;
1318
1319 if (is_blocked(id)) {
1320 pr_err("Client %d cannot request free\n", id);
1321 return -EINVAL;
1322 }
1323
1324 req = handle_to_req(handle);
1325 buffer = handle_to_buffer(handle);
1326
1327 if (!req)
1328 return -EINVAL;
1329
1330 if (req->req_start != core_address(id, buffer->addr)) {
1331 pr_err("Invalid buffer handle passed for free\n");
1332 return -EINVAL;
1333 }
1334
1335 if (is_tcm(req->owner)) {
1336 rc = process_unmap(req, req->req_start, req->req_end);
1337 if (rc < 0)
1338 return -EINVAL;
1339 }
1340
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001341 if (req->req_sz != 0) {
1342
1343 offset = phys_to_offset(req->req_start);
1344
1345 rc = ocmem_memory_off(req->owner, offset, req->req_sz);
1346
1347 if (rc < 0) {
1348 pr_err("Failed to switch OFF memory macros\n");
1349 return -EINVAL;
1350 }
1351
1352 }
1353
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001354 rc = do_free(req);
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001355 if (rc < 0)
1356 return -EINVAL;
1357
1358 ocmem_destroy_req(req);
1359 handle->req = NULL;
1360
1361 ocmem_schedule_pending();
1362 return 0;
1363}
1364
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001365static void ocmem_rdm_worker(struct work_struct *work)
1366{
1367 int offset = 0;
1368 int rc = 0;
1369 int event;
1370 struct ocmem_rdm_work *work_data = container_of(work,
1371 struct ocmem_rdm_work, work);
1372 int id = work_data->id;
1373 struct ocmem_map_list *list = work_data->list;
1374 int direction = work_data->direction;
1375 struct ocmem_handle *handle = work_data->handle;
1376 struct ocmem_req *req = handle_to_req(handle);
1377 struct ocmem_buf *buffer = handle_to_buffer(handle);
1378
1379 down_write(&req->rw_sem);
1380 offset = phys_to_offset(req->req_start);
1381 rc = ocmem_rdm_transfer(id, list, offset, direction);
1382 if (work_data->direction == TO_OCMEM)
1383 event = (rc == 0) ? OCMEM_MAP_DONE : OCMEM_MAP_FAIL;
1384 else
1385 event = (rc == 0) ? OCMEM_UNMAP_DONE : OCMEM_UNMAP_FAIL;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001386 up_write(&req->rw_sem);
1387 kfree(work_data);
1388 dispatch_notification(id, event, buffer);
1389}
1390
1391int queue_transfer(struct ocmem_req *req, struct ocmem_handle *handle,
1392 struct ocmem_map_list *list, int direction)
1393{
1394 struct ocmem_rdm_work *work_data = NULL;
1395
1396 down_write(&req->rw_sem);
1397
1398 work_data = kzalloc(sizeof(struct ocmem_rdm_work), GFP_ATOMIC);
1399 if (!work_data)
1400 BUG();
1401
1402 work_data->handle = handle;
1403 work_data->list = list;
1404 work_data->id = req->owner;
1405 work_data->direction = direction;
1406 INIT_WORK(&work_data->work, ocmem_rdm_worker);
1407 up_write(&req->rw_sem);
1408 queue_work(ocmem_rdm_wq, &work_data->work);
1409 return 0;
1410}
1411
1412int process_xfer_out(int id, struct ocmem_handle *handle,
1413 struct ocmem_map_list *list)
1414{
1415 struct ocmem_req *req = NULL;
1416 int rc = 0;
1417
1418 req = handle_to_req(handle);
1419
1420 if (!req)
1421 return -EINVAL;
1422
1423 if (!is_mapped(req)) {
1424 pr_err("Buffer is not already mapped\n");
1425 goto transfer_out_error;
1426 }
1427
1428 rc = process_unmap(req, req->req_start, req->req_end);
1429 if (rc < 0) {
1430 pr_err("Unmapping the buffer failed\n");
1431 goto transfer_out_error;
1432 }
1433
1434 rc = queue_transfer(req, handle, list, TO_DDR);
1435
1436 if (rc < 0) {
1437 pr_err("Failed to queue rdm transfer to DDR\n");
1438 goto transfer_out_error;
1439 }
1440
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001441
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001442 return 0;
1443
1444transfer_out_error:
1445 return -EINVAL;
1446}
1447
1448int process_xfer_in(int id, struct ocmem_handle *handle,
1449 struct ocmem_map_list *list)
1450{
1451 struct ocmem_req *req = NULL;
1452 int rc = 0;
1453
1454 req = handle_to_req(handle);
1455
1456 if (!req)
1457 return -EINVAL;
1458
1459 if (is_mapped(req)) {
1460 pr_err("Buffer is already mapped\n");
1461 goto transfer_in_error;
1462 }
1463
1464 rc = process_map(req, req->req_start, req->req_end);
1465 if (rc < 0) {
1466 pr_err("Mapping the buffer failed\n");
1467 goto transfer_in_error;
1468 }
1469
1470 rc = queue_transfer(req, handle, list, TO_OCMEM);
1471
1472 if (rc < 0) {
1473 pr_err("Failed to queue rdm transfer to OCMEM\n");
1474 goto transfer_in_error;
1475 }
1476
1477 return 0;
1478transfer_in_error:
1479 return -EINVAL;
1480}
1481
1482int process_shrink(int id, struct ocmem_handle *handle, unsigned long size)
1483{
1484 struct ocmem_req *req = NULL;
1485 struct ocmem_buf *buffer = NULL;
1486 struct ocmem_eviction_data *edata = NULL;
1487 int rc = 0;
1488
1489 if (is_blocked(id)) {
1490 pr_err("Client %d cannot request free\n", id);
1491 return -EINVAL;
1492 }
1493
1494 req = handle_to_req(handle);
1495 buffer = handle_to_buffer(handle);
1496
1497 if (!req)
1498 return -EINVAL;
1499
1500 if (req->req_start != core_address(id, buffer->addr)) {
1501 pr_err("Invalid buffer handle passed for shrink\n");
1502 return -EINVAL;
1503 }
1504
1505 edata = req->edata;
1506
1507 if (is_tcm(req->owner))
1508 do_unmap(req);
1509
1510 if (size == 0) {
1511 pr_info("req %p being shrunk to zero\n", req);
1512 rc = do_free(req);
1513 if (rc < 0)
1514 return -EINVAL;
1515 } else {
1516 rc = do_shrink(req, size);
1517 if (rc < 0)
1518 return -EINVAL;
1519 }
1520
1521 edata->pending--;
1522 if (edata->pending == 0) {
1523 pr_debug("All regions evicted");
1524 complete(&edata->completion);
1525 }
1526
1527 return 0;
1528}
1529
1530int process_xfer(int id, struct ocmem_handle *handle,
1531 struct ocmem_map_list *list, int direction)
1532{
1533 int rc = 0;
1534
1535 if (is_tcm(id)) {
1536 WARN(1, "Mapping operation is invalid for client\n");
1537 return -EINVAL;
1538 }
1539
1540 if (direction == TO_DDR)
1541 rc = process_xfer_out(id, handle, list);
1542 else if (direction == TO_OCMEM)
1543 rc = process_xfer_in(id, handle, list);
1544 return rc;
1545}
1546
1547int ocmem_eviction_thread(struct work_struct *work)
1548{
1549 return 0;
1550}
1551
1552int process_evict(int id)
1553{
1554 struct ocmem_eviction_data *edata = NULL;
1555 int prio = ocmem_client_table[id].priority;
1556 struct rb_node *rb_node = NULL;
1557 struct ocmem_req *req = NULL;
1558 struct ocmem_buf buffer;
1559 int j = 0;
1560
1561 edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
1562
1563 INIT_LIST_HEAD(&edata->victim_list);
1564 INIT_LIST_HEAD(&edata->req_list);
1565 edata->prio = prio;
1566 edata->pending = 0;
1567 edata->passive = 1;
1568 evictions[id] = edata;
1569
1570 mutex_lock(&sched_mutex);
1571
1572 for (rb_node = rb_first(&sched_tree); rb_node;
1573 rb_node = rb_next(rb_node)) {
1574 struct ocmem_region *tmp_region = NULL;
1575 tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
1576 if (tmp_region->max_prio < prio) {
1577 for (j = id - 1; j > NO_PRIO; j--) {
1578 req = find_req_match(j, tmp_region);
1579 if (req) {
1580 pr_info("adding %p to eviction list\n",
1581 tmp_region);
1582 list_add_tail(
1583 &tmp_region->eviction_list,
1584 &edata->victim_list);
1585 list_add_tail(
1586 &req->eviction_list,
1587 &edata->req_list);
1588 edata->pending++;
1589 req->edata = edata;
1590 buffer.addr = req->req_start;
1591 buffer.len = 0x0;
1592 dispatch_notification(req->owner,
1593 OCMEM_ALLOC_SHRINK, &buffer);
1594 }
1595 }
1596 } else {
1597 pr_info("skipping %p from eviction\n", tmp_region);
1598 }
1599 }
1600 mutex_unlock(&sched_mutex);
1601 pr_debug("Waiting for all regions to be shrunk\n");
1602 if (edata->pending > 0) {
1603 init_completion(&edata->completion);
1604 wait_for_completion(&edata->completion);
1605 }
1606 return 0;
1607}
1608
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001609static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
1610{
1611 int rc = 0;
1612 struct ocmem_buf *buffer = req->buffer;
1613
1614 down_write(&req->rw_sem);
1615
1616 /* Take the scheduler mutex */
1617 mutex_lock(&sched_mutex);
1618 rc = __sched_allocate(req, can_block, can_wait);
1619 mutex_unlock(&sched_mutex);
1620
1621 if (rc == OP_FAIL)
1622 goto err_allocate_fail;
1623
1624 if (rc == OP_RESCHED) {
1625 buffer->addr = 0x0;
1626 buffer->len = 0x0;
1627 pr_debug("ocmem: Enqueuing req %p\n", req);
1628 sched_enqueue(req);
1629 } else if (rc == OP_PARTIAL) {
1630 buffer->addr = device_address(req->owner, req->req_start);
1631 buffer->len = req->req_sz;
1632 pr_debug("ocmem: Enqueuing req %p\n", req);
1633 sched_enqueue(req);
1634 } else if (rc == OP_COMPLETE) {
1635 buffer->addr = device_address(req->owner, req->req_start);
1636 buffer->len = req->req_sz;
1637 }
1638
1639 up_write(&req->rw_sem);
1640 return 0;
1641err_allocate_fail:
1642 up_write(&req->rw_sem);
1643 return -EINVAL;
1644}
1645
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001646int process_restore(int id)
1647{
1648 struct ocmem_req *req = NULL;
1649 struct ocmem_req *next = NULL;
1650 struct ocmem_eviction_data *edata = evictions[id];
1651
1652 if (!edata)
1653 return 0;
1654
1655 list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
1656 {
1657 if (req) {
1658 pr_debug("ocmem: Fetched evicted request %p\n",
1659 req);
1660 list_del(&req->sched_list);
1661 req->op = SCHED_ALLOCATE;
1662 sched_enqueue(req);
1663 }
1664 }
1665 kfree(edata);
1666 evictions[id] = NULL;
1667 pr_debug("Restore all evicted regions\n");
1668 ocmem_schedule_pending();
1669 return 0;
1670}
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001671
1672int process_allocate(int id, struct ocmem_handle *handle,
1673 unsigned long min, unsigned long max,
1674 unsigned long step, bool can_block, bool can_wait)
1675{
1676
1677 struct ocmem_req *req = NULL;
1678 struct ocmem_buf *buffer = NULL;
1679 int rc = 0;
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001680 unsigned long offset = 0;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001681
1682 /* sanity checks */
1683 if (is_blocked(id)) {
1684 pr_err("Client %d cannot request allocation\n", id);
1685 return -EINVAL;
1686 }
1687
1688 if (handle->req != NULL) {
1689 pr_err("Invalid handle passed in\n");
1690 return -EINVAL;
1691 }
1692
1693 buffer = handle_to_buffer(handle);
1694 BUG_ON(buffer == NULL);
1695
1696 /* prepare a request structure to represent this transaction */
1697 req = ocmem_create_req();
1698 if (!req)
1699 return -ENOMEM;
1700
1701 req->owner = id;
1702 req->req_min = min;
1703 req->req_max = max;
1704 req->req_step = step;
1705 req->prio = ocmem_client_table[id].priority;
1706 req->op = SCHED_ALLOCATE;
1707 req->buffer = buffer;
1708
1709 rc = do_allocate(req, can_block, can_wait);
1710
1711 if (rc < 0)
1712 goto do_allocate_error;
1713
1714 handle->req = req;
1715
1716 if (is_tcm(id)) {
1717 rc = process_map(req, req->req_start, req->req_end);
1718 if (rc < 0)
1719 goto map_error;
1720 }
1721
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001722 if (req->req_sz != 0) {
1723
1724 offset = phys_to_offset(req->req_start);
1725
1726 rc = ocmem_memory_on(req->owner, offset, req->req_sz);
1727
1728 if (rc < 0) {
1729 pr_err("Failed to switch ON memory macros\n");
1730 goto power_ctl_error;
1731 }
1732 }
1733
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001734 return 0;
1735
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001736power_ctl_error:
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001737map_error:
1738 handle->req = NULL;
1739 do_free(req);
1740do_allocate_error:
1741 ocmem_destroy_req(req);
1742 return -EINVAL;
1743}
1744
1745int process_delayed_allocate(struct ocmem_req *req)
1746{
1747
1748 struct ocmem_handle *handle = NULL;
1749 int rc = 0;
1750 int id = req->owner;
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001751 unsigned long offset = 0;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001752
1753 handle = req_to_handle(req);
1754 BUG_ON(handle == NULL);
1755
1756 rc = do_allocate(req, true, false);
1757
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001758
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001759 if (rc < 0)
1760 goto do_allocate_error;
1761
1762 if (is_tcm(id)) {
1763 rc = process_map(req, req->req_start, req->req_end);
1764 if (rc < 0)
1765 goto map_error;
1766 }
1767
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001768 if (req->req_sz != 0) {
1769
1770 offset = phys_to_offset(req->req_start);
1771
1772 rc = ocmem_memory_on(req->owner, offset, req->req_sz);
1773
1774 if (rc < 0) {
1775 pr_err("Failed to switch ON memory macros\n");
1776 goto power_ctl_error;
1777 }
1778 }
1779
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001780 /* Notify the client about the buffer growth */
1781 rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
1782 if (rc < 0) {
1783 pr_err("No notifier callback to cater for req %p event: %d\n",
1784 req, OCMEM_ALLOC_GROW);
1785 BUG();
1786 }
1787 return 0;
1788
Naveen Ramaraj99b07562012-05-28 20:57:09 -07001789power_ctl_error:
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001790map_error:
1791 handle->req = NULL;
1792 do_free(req);
1793do_allocate_error:
1794 ocmem_destroy_req(req);
1795 return -EINVAL;
1796}
1797
1798static void ocmem_sched_wk_func(struct work_struct *work)
1799{
1800
1801 struct ocmem_buf *buffer = NULL;
1802 struct ocmem_handle *handle = NULL;
1803 struct ocmem_req *req = ocmem_fetch_req();
1804
1805 if (!req) {
1806 pr_debug("No Pending Requests found\n");
1807 return;
1808 }
1809
1810 pr_debug("ocmem: sched_wk pending req %p\n", req);
1811 handle = req_to_handle(req);
1812 buffer = handle_to_buffer(handle);
1813 BUG_ON(req->op == SCHED_NOP);
1814
1815 switch (req->op) {
1816 case SCHED_GROW:
1817 process_grow(req);
1818 break;
1819 case SCHED_ALLOCATE:
1820 process_delayed_allocate(req);
1821 break;
1822 default:
1823 pr_err("ocmem: Unknown operation encountered\n");
1824 break;
1825 }
1826 return;
1827}
1828
1829int ocmem_sched_init(void)
1830{
1831 int i = 0;
1832 sched_tree = RB_ROOT;
1833 mutex_init(&sched_mutex);
1834 mutex_init(&sched_queue_mutex);
1835 for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
1836 INIT_LIST_HEAD(&sched_queue[i]);
1837
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001838 mutex_init(&rdm_mutex);
1839 INIT_LIST_HEAD(&rdm_queue);
1840 ocmem_rdm_wq = alloc_workqueue("ocmem_rdm_wq", 0, 0);
1841 if (!ocmem_rdm_wq)
1842 return -ENOMEM;
1843 ocmem_eviction_wq = alloc_workqueue("ocmem_eviction_wq", 0, 0);
1844 if (!ocmem_eviction_wq)
1845 return -ENOMEM;
Naveen Ramarajb9da05782012-05-07 09:07:35 -07001846 return 0;
1847}