OMAP: SRF: Fixes to shared resource framework (Ver.3)
[linux-ginger.git] / arch / arm / plat-omap / resource.c
blobde75446e306f380da801e76e4d5157590f1f08a6
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_refresh - Refresh the states of all current resources
229 * If a condition in power domains has changed that requires refreshing
230 * power domain states, this function can be used to restore correct
231 * states according to shared resources.
232 * Returns 0 on success, non-zero, if some resource cannot be refreshed.
234 int resource_refresh(void)
236 struct shared_resource *resp = NULL;
237 int ret = 0;
239 list_for_each_entry(resp, &res_list, node) {
240 ret = update_resource_level(resp);
241 if (ret)
242 break;
244 return ret;
248 * resource_register - registers and initializes a resource
249 * @res: struct shared_resource * to register
251 * Initializes the given resource and adds it to the resource list
252 * for the current CPU.
253 * Returns 0 on success, -EINVAL if given a NULL pointer, -EEXIST if the
254 * resource is already registered.
256 int resource_register(struct shared_resource *resp)
258 unsigned long flags;
260 if (!resp)
261 return -EINVAL;
263 if (!omap_chip_is(resp->omap_chip))
264 return -EINVAL;
266 /* Verify that the resource is not already registered */
267 if (resource_lookup(resp->name))
268 return -EEXIST;
270 INIT_LIST_HEAD(&resp->users_list);
272 spin_lock_irqsave(&res_lock, flags);
273 /* Add the resource to the resource list */
274 list_add(&resp->node, &res_list);
276 /* Call the resource specific init*/
277 if (resp->ops->init)
278 resp->ops->init(resp);
280 spin_unlock_irqrestore(&res_lock, flags);
281 pr_debug("resource: registered %s\n", resp->name);
283 return 0;
285 EXPORT_SYMBOL(resource_register);
288 * resource_unregister - unregister a resource
289 * @res: struct shared_resource * to unregister
291 * Removes a resource from the resource list.
292 * Returns 0 on success, -EINVAL if passed a NULL pointer.
294 int resource_unregister(struct shared_resource *resp)
296 unsigned long flags;
298 if (!resp)
299 return -EINVAL;
301 spin_lock_irqsave(&res_lock, flags);
302 /* delete the resource from the resource list */
303 list_del(&resp->node);
304 spin_unlock_irqrestore(&res_lock, flags);
306 pr_debug("resource: unregistered %s\n", resp->name);
308 return 0;
310 EXPORT_SYMBOL(resource_unregister);
313 * resource_request - Request for a required level of a resource
314 * @name: The name of the resource requested
315 * @dev: Uniquely identifes the caller
316 * @level: The requested level for the resource
318 * This function recomputes the target level of the resource based on
319 * the level requested by the user. The level of the resource is
320 * changed to the target level, if it is not the same as the existing level
321 * of the resource. Multiple calls to this function by the same device will
322 * replace the previous level requested
323 * Returns 0 on success, -EINVAL if the resource name passed in invalid.
324 * -ENOMEM if no static pool available or dynamic allocations fails.
325 * Else returns a non-zero error value returned by one of the failing
326 * shared_resource_ops.
328 int resource_request(const char *name, struct device *dev,
329 unsigned long level)
331 struct shared_resource *resp;
332 struct users_list *user;
333 int found = 0, ret = 0;
334 unsigned long flags;
336 spin_lock_irqsave(&res_lock, flags);
337 resp = _resource_lookup(name);
338 if (!resp) {
339 printk(KERN_ERR "resource_request: Invalid resource name\n");
340 ret = -EINVAL;
341 goto res_unlock;
344 /* Call the resource specific validate function */
345 if (resp->ops->validate_level) {
346 ret = resp->ops->validate_level(resp, level);
347 if (ret)
348 goto res_unlock;
351 list_for_each_entry(user, &resp->users_list, node) {
352 if (user->dev == dev) {
353 found = 1;
354 break;
358 if (!found) {
359 /* First time user */
360 user = get_user();
361 if (IS_ERR(user)) {
362 ret = -ENOMEM;
363 goto res_unlock;
365 user->dev = dev;
366 list_add(&user->node, &resp->users_list);
367 resp->no_of_users++;
369 user->level = level;
371 res_unlock:
372 spin_unlock_irqrestore(&res_lock, flags);
374 * Recompute and set the current level for the resource.
375 * NOTE: update_resource level moved out of spin_lock, as it may call
376 * pm_qos_add_requirement, which does a kzmalloc. This won't be allowed
377 * in iterrupt context. The spin_lock still protects add/remove users.
379 if (!ret)
380 ret = update_resource_level(resp);
381 return ret;
383 EXPORT_SYMBOL(resource_request);
386 * resource_release - Release a previously requested level of a resource
387 * @name: The name of the resource to be released
388 * @dev: Uniquely identifes the caller
390 * This function recomputes the target level of the resource after removing
391 * the level requested by the user. The level of the resource is
392 * changed to the target level, if it is not the same as the existing level
393 * of the resource.
394 * Returns 0 on success, -EINVAL if the resource name or dev structure
395 * is invalid.
397 int resource_release(const char *name, struct device *dev)
399 struct shared_resource *resp;
400 struct users_list *user;
401 int found = 0, ret = 0;
402 unsigned long flags;
404 spin_lock_irqsave(&res_lock, flags);
405 resp = _resource_lookup(name);
406 if (!resp) {
407 printk(KERN_ERR "resource_release: Invalid resource name\n");
408 ret = -EINVAL;
409 goto res_unlock;
412 list_for_each_entry(user, &resp->users_list, node) {
413 if (user->dev == dev) {
414 found = 1;
415 break;
419 if (!found) {
420 /* No such user exists */
421 ret = -EINVAL;
422 goto res_unlock;
425 resp->no_of_users--;
426 list_del(&user->node);
427 free_user(user);
429 /* Recompute and set the current level for the resource */
430 ret = update_resource_level(resp);
431 res_unlock:
432 spin_unlock_irqrestore(&res_lock, flags);
433 return ret;
435 EXPORT_SYMBOL(resource_release);
438 * resource_get_level - Returns the current level of the resource
439 * @name: Name of the resource
441 * Returns the current level of the resource if found, else returns
442 * -EINVAL if the resource name is invalid.
444 int resource_get_level(const char *name)
446 struct shared_resource *resp;
447 u32 ret;
448 unsigned long flags;
450 spin_lock_irqsave(&res_lock, flags);
451 resp = _resource_lookup(name);
452 if (!resp) {
453 printk(KERN_ERR "resource_release: Invalid resource name\n");
454 spin_unlock_irqrestore(&res_lock, flags);
455 return -EINVAL;
457 ret = resp->curr_level;
458 spin_unlock_irqrestore(&res_lock, flags);
459 return ret;
461 EXPORT_SYMBOL(resource_get_level);