OMAP3 SRF: Generic shared resource f/w
[linux-ginger.git] / arch / arm / plat-omap / resource.c
blob7f5897a875bb938fed701d31d250d34836a30888
1 /*
2 * linux/arch/arm/plat-omap/resource.c
3 * Shared Resource Framework API implementation
5 * Copyright (C) 2007-2008 Texas Instruments, Inc.
6 * Rajendra Nayak <rnayak@ti.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 * History:
19 #include <linux/errno.h>
20 #include <linux/err.h>
21 #include <linux/slab.h>
23 #include <plat/resource.h>
26 * This is for statically defining the users pool. This static pool is
27 * used early at bootup till kmalloc becomes available.
29 #define MAX_USERS 10
30 #define UNUSED 0x0
31 #define DYNAMIC_ALLOC 0x1
32 #define STATIC_ALLOC 0x2
34 /* res_list contains all registered struct shared_resource */
35 static LIST_HEAD(res_list);
37 /* res_lock protects res_list add and del ops */
38 static DEFINE_SPINLOCK(res_lock);
40 /* Static Pool of users for a resource used till kmalloc becomes available */
41 struct users_list usr_list[MAX_USERS];
43 /* Private/Internal functions */
45 /**
46 * _resource_lookup - loop up a resource by its name, return a pointer
47 * @name: The name of the resource to lookup
49 * Looks for a registered resource by its name. Returns a pointer to
50 * the struct shared_resource if found, else returns NULL.
51 * The function is not lock safe.
53 static struct shared_resource *_resource_lookup(const char *name)
55 struct shared_resource *res, *tmp_res;
57 if (!name)
58 return NULL;
60 res = NULL;
62 list_for_each_entry(tmp_res, &res_list, node) {
63 if (!strcmp(name, tmp_res->name)) {
64 res = tmp_res;
65 break;
68 return res;
71 /**
72 * resource_lookup - loop up a resource by its name, return a pointer
73 * @name: The name of the resource to lookup
75 * Looks for a registered resource by its name. Returns a pointer to
76 * the struct shared_resource if found, else returns NULL.
77 * The function holds spinlocks and takes care of atomicity.
79 static struct shared_resource *resource_lookup(const char *name)
81 struct shared_resource *res;
82 unsigned long flags;
84 if (!name)
85 return NULL;
86 spin_lock_irqsave(&res_lock, flags);
87 res = _resource_lookup(name);
88 spin_unlock_irqrestore(&res_lock, flags);
90 return res;
93 /**
94 * update_resource_level - Regenerates and updates the curr_level of the res
95 * @resp: Pointer to the resource
97 * This function looks at all the users of the given resource and the levels
98 * requested by each of them, and recomputes a target level for the resource
99 * acceptable to all its current usres. It then calls platform specific
100 * change_level to change the level of the resource.
101 * Returns 0 on success, else a non-zero value returned by the platform
102 * specific change_level function.
104 static int update_resource_level(struct shared_resource *resp)
106 struct users_list *user;
107 unsigned long target_level;
108 int ret;
110 /* Regenerate the target_value for the resource */
111 target_level = RES_DEFAULTLEVEL;
112 list_for_each_entry(user, &resp->users_list, node)
113 if (user->level > target_level)
114 target_level = user->level;
116 pr_debug("SRF: Changing Level for resource %s to %ld\n",
117 resp->name, target_level);
118 ret = resp->ops->change_level(resp, target_level);
119 if (ret) {
120 printk(KERN_ERR "Unable to Change"
121 "level for resource %s to %ld\n",
122 resp->name, target_level);
124 return ret;
128 * get_user - gets a new users_list struct from static pool or dynamically
130 * This function initally looks for availability in the static pool and
131 * tries to dynamcially allocate only once the static pool is empty.
132 * We hope that during bootup by the time we hit a case of dynamic allocation
133 * slab initialization would have happened.
134 * Returns a pointer users_list struct on success. On dynamic allocation failure
135 * returns a ERR_PTR(-ENOMEM).
137 static struct users_list *get_user(void)
139 int ind = 0;
140 struct users_list *user;
142 /* See if something available in the static pool */
143 while (ind < MAX_USERS) {
144 if (usr_list[ind].usage == UNUSED)
145 break;
146 else
147 ind++;
149 if (ind < MAX_USERS) {
150 /* Pick from the static pool */
151 user = &usr_list[ind];
152 user->usage = STATIC_ALLOC;
153 } else {
154 /* By this time we hope slab is initialized */
155 if (slab_is_available()) {
156 user = kmalloc(sizeof(struct users_list), GFP_KERNEL);
157 if (!user) {
158 printk(KERN_ERR "SRF:FATAL ERROR: kmalloc"
159 "failed\n");
160 return ERR_PTR(-ENOMEM);
162 user->usage = DYNAMIC_ALLOC;
163 } else {
164 /* Dynamic alloc not available yet */
165 printk(KERN_ERR "SRF: FATAL ERROR: users_list"
166 "initial POOL EMPTY before slab init\n");
167 return ERR_PTR(-ENOMEM);
170 return user;
174 * free_user - frees the dynamic users_list and marks the static one unused
175 * @user: The struct users_list to be freed
177 * Looks at the usage flag and either frees the users_list if it was
178 * dynamically allocated, and if its from the static pool, marks it unused.
179 * No return value.
181 void free_user(struct users_list *user)
183 if (user->usage == DYNAMIC_ALLOC) {
184 kfree(user);
185 } else {
186 user->usage = UNUSED;
187 user->level = RES_DEFAULTLEVEL;
188 user->dev = NULL;
193 * resource_init - Initializes the Shared resource framework.
194 * @resources: List of all the resources modelled
196 * Loops through the list of resources and registers all that
197 * are available for the current CPU.
198 * No return value
200 void resource_init(struct shared_resource **resources)
202 struct shared_resource **resp;
203 int ind;
205 pr_debug("Initializing Shared Resource Framework\n");
207 if (!cpu_is_omap34xx()) {
208 /* This CPU is not supported */
209 printk(KERN_WARNING "Shared Resource Framework does not"
210 "support this CPU type.\n");
211 WARN_ON(1);
214 /* Init the users_list POOL */
215 for (ind = 0; ind < MAX_USERS; ind++) {
216 usr_list[ind].usage = UNUSED;
217 usr_list[ind].dev = NULL;
218 usr_list[ind].level = RES_DEFAULTLEVEL;
221 if (resources)
222 for (resp = resources; *resp; resp++)
223 resource_register(*resp);
227 * resource_register - registers and initializes a resource
228 * @res: struct shared_resource * to register
230 * Initializes the given resource and adds it to the resource list
231 * for the current CPU.
232 * Returns 0 on success, -EINVAL if given a NULL pointer, -EEXIST if the
233 * resource is already registered.
235 int resource_register(struct shared_resource *resp)
237 unsigned long flags;
239 if (!resp)
240 return -EINVAL;
242 if (!omap_chip_is(resp->omap_chip))
243 return -EINVAL;
245 /* Verify that the resource is not already registered */
246 if (resource_lookup(resp->name))
247 return -EEXIST;
249 INIT_LIST_HEAD(&resp->users_list);
251 spin_lock_irqsave(&res_lock, flags);
252 /* Add the resource to the resource list */
253 list_add(&resp->node, &res_list);
255 /* Call the resource specific init*/
256 if (resp->ops->init)
257 resp->ops->init(resp);
259 spin_unlock_irqrestore(&res_lock, flags);
260 pr_debug("resource: registered %s\n", resp->name);
262 return 0;
264 EXPORT_SYMBOL(resource_register);
267 * resource_unregister - unregister a resource
268 * @res: struct shared_resource * to unregister
270 * Removes a resource from the resource list.
271 * Returns 0 on success, -EINVAL if passed a NULL pointer.
273 int resource_unregister(struct shared_resource *resp)
275 unsigned long flags;
277 if (!resp)
278 return -EINVAL;
280 spin_lock_irqsave(&res_lock, flags);
281 /* delete the resource from the resource list */
282 list_del(&resp->node);
283 spin_unlock_irqrestore(&res_lock, flags);
285 pr_debug("resource: unregistered %s\n", resp->name);
287 return 0;
289 EXPORT_SYMBOL(resource_unregister);
292 * resource_request - Request for a required level of a resource
293 * @name: The name of the resource requested
294 * @dev: Uniquely identifes the caller
295 * @level: The requested level for the resource
297 * This function recomputes the target level of the resource based on
298 * the level requested by the user. The level of the resource is
299 * changed to the target level, if it is not the same as the existing level
300 * of the resource. Multiple calls to this function by the same device will
301 * replace the previous level requested
302 * Returns 0 on success, -EINVAL if the resource name passed in invalid.
303 * -ENOMEM if no static pool available or dynamic allocations fails.
304 * Else returns a non-zero error value returned by one of the failing
305 * shared_resource_ops.
307 int resource_request(const char *name, struct device *dev,
308 unsigned long level)
310 struct shared_resource *resp;
311 struct users_list *user;
312 int found = 0, ret = 0;
313 unsigned long flags;
315 spin_lock_irqsave(&res_lock, flags);
316 resp = _resource_lookup(name);
317 if (!resp) {
318 printk(KERN_ERR "resource_request: Invalid resource name\n");
319 ret = -EINVAL;
320 goto res_unlock;
323 /* Call the resource specific validate function */
324 if (resp->ops->validate_level) {
325 ret = resp->ops->validate_level(resp, level);
326 if (ret)
327 goto res_unlock;
330 list_for_each_entry(user, &resp->users_list, node) {
331 if (user->dev == dev) {
332 found = 1;
333 break;
337 if (!found) {
338 /* First time user */
339 user = get_user();
340 if (IS_ERR(user)) {
341 ret = -ENOMEM;
342 goto res_unlock;
344 user->dev = dev;
345 list_add(&user->node, &resp->users_list);
346 resp->no_of_users++;
348 user->level = level;
350 /* Recompute and set the current level for the resource */
351 ret = update_resource_level(resp);
352 res_unlock:
353 spin_unlock_irqrestore(&res_lock, flags);
354 return ret;
356 EXPORT_SYMBOL(resource_request);
359 * resource_release - Release a previously requested level of a resource
360 * @name: The name of the resource to be released
361 * @dev: Uniquely identifes the caller
363 * This function recomputes the target level of the resource after removing
364 * the level requested by the user. The level of the resource is
365 * changed to the target level, if it is not the same as the existing level
366 * of the resource.
367 * Returns 0 on success, -EINVAL if the resource name or dev structure
368 * is invalid.
370 int resource_release(const char *name, struct device *dev)
372 struct shared_resource *resp;
373 struct users_list *user;
374 int found = 0, ret = 0;
375 unsigned long flags;
377 spin_lock_irqsave(&res_lock, flags);
378 resp = _resource_lookup(name);
379 if (!resp) {
380 printk(KERN_ERR "resource_release: Invalid resource name\n");
381 ret = -EINVAL;
382 goto res_unlock;
385 list_for_each_entry(user, &resp->users_list, node) {
386 if (user->dev == dev) {
387 found = 1;
388 break;
392 if (!found) {
393 /* No such user exists */
394 ret = -EINVAL;
395 goto res_unlock;
398 resp->no_of_users--;
399 list_del(&user->node);
400 free_user(user);
402 /* Recompute and set the current level for the resource */
403 ret = update_resource_level(resp);
404 res_unlock:
405 spin_unlock_irqrestore(&res_lock, flags);
406 return ret;
408 EXPORT_SYMBOL(resource_release);
411 * resource_get_level - Returns the current level of the resource
412 * @name: Name of the resource
414 * Returns the current level of the resource if found, else returns
415 * -EINVAL if the resource name is invalid.
417 int resource_get_level(const char *name)
419 struct shared_resource *resp;
420 u32 ret;
421 unsigned long flags;
423 spin_lock_irqsave(&res_lock, flags);
424 resp = _resource_lookup(name);
425 if (!resp) {
426 printk(KERN_ERR "resource_release: Invalid resource name\n");
427 spin_unlock_irqrestore(&res_lock, flags);
428 return -EINVAL;
430 ret = resp->curr_level;
431 spin_unlock_irqrestore(&res_lock, flags);
432 return ret;
434 EXPORT_SYMBOL(resource_get_level);