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.
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.
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 */
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
;
62 list_for_each_entry(tmp_res
, &res_list
, node
) {
63 if (!strcmp(name
, tmp_res
->name
)) {
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
;
86 spin_lock_irqsave(&res_lock
, flags
);
87 res
= _resource_lookup(name
);
88 spin_unlock_irqrestore(&res_lock
, flags
);
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
;
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
);
120 printk(KERN_ERR
"Unable to Change"
121 "level for resource %s to %ld\n",
122 resp
->name
, target_level
);
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)
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
)
149 if (ind
< MAX_USERS
) {
150 /* Pick from the static pool */
151 user
= &usr_list
[ind
];
152 user
->usage
= STATIC_ALLOC
;
154 /* By this time we hope slab is initialized */
155 if (slab_is_available()) {
156 user
= kmalloc(sizeof(struct users_list
), GFP_KERNEL
);
158 printk(KERN_ERR
"SRF:FATAL ERROR: kmalloc"
160 return ERR_PTR(-ENOMEM
);
162 user
->usage
= DYNAMIC_ALLOC
;
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
);
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.
181 void free_user(struct users_list
*user
)
183 if (user
->usage
== DYNAMIC_ALLOC
) {
186 user
->usage
= UNUSED
;
187 user
->level
= RES_DEFAULTLEVEL
;
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.
200 void resource_init(struct shared_resource
**resources
)
202 struct shared_resource
**resp
;
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");
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
;
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
;
239 list_for_each_entry(resp
, &res_list
, node
) {
240 ret
= update_resource_level(resp
);
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
)
263 if (!omap_chip_is(resp
->omap_chip
))
266 /* Verify that the resource is not already registered */
267 if (resource_lookup(resp
->name
))
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*/
278 resp
->ops
->init(resp
);
280 spin_unlock_irqrestore(&res_lock
, flags
);
281 pr_debug("resource: registered %s\n", resp
->name
);
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
)
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
);
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
,
331 struct shared_resource
*resp
;
332 struct users_list
*user
;
333 int found
= 0, ret
= 0;
336 spin_lock_irqsave(&res_lock
, flags
);
337 resp
= _resource_lookup(name
);
339 printk(KERN_ERR
"resource_request: Invalid resource name\n");
344 /* Call the resource specific validate function */
345 if (resp
->ops
->validate_level
) {
346 ret
= resp
->ops
->validate_level(resp
, level
);
351 list_for_each_entry(user
, &resp
->users_list
, node
) {
352 if (user
->dev
== dev
) {
359 /* First time user */
366 list_add(&user
->node
, &resp
->users_list
);
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.
380 ret
= update_resource_level(resp
);
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
394 * Returns 0 on success, -EINVAL if the resource name or dev structure
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;
404 spin_lock_irqsave(&res_lock
, flags
);
405 resp
= _resource_lookup(name
);
407 printk(KERN_ERR
"resource_release: Invalid resource name\n");
412 list_for_each_entry(user
, &resp
->users_list
, node
) {
413 if (user
->dev
== dev
) {
420 /* No such user exists */
426 list_del(&user
->node
);
429 /* Recompute and set the current level for the resource */
430 ret
= update_resource_level(resp
);
432 spin_unlock_irqrestore(&res_lock
, flags
);
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
;
450 spin_lock_irqsave(&res_lock
, flags
);
451 resp
= _resource_lookup(name
);
453 printk(KERN_ERR
"resource_release: Invalid resource name\n");
454 spin_unlock_irqrestore(&res_lock
, flags
);
457 ret
= resp
->curr_level
;
458 spin_unlock_irqrestore(&res_lock
, flags
);
461 EXPORT_SYMBOL(resource_get_level
);