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_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
)
242 if (!omap_chip_is(resp
->omap_chip
))
245 /* Verify that the resource is not already registered */
246 if (resource_lookup(resp
->name
))
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*/
257 resp
->ops
->init(resp
);
259 spin_unlock_irqrestore(&res_lock
, flags
);
260 pr_debug("resource: registered %s\n", resp
->name
);
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
)
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
);
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
,
310 struct shared_resource
*resp
;
311 struct users_list
*user
;
312 int found
= 0, ret
= 0;
315 spin_lock_irqsave(&res_lock
, flags
);
316 resp
= _resource_lookup(name
);
318 printk(KERN_ERR
"resource_request: Invalid resource name\n");
323 /* Call the resource specific validate function */
324 if (resp
->ops
->validate_level
) {
325 ret
= resp
->ops
->validate_level(resp
, level
);
330 list_for_each_entry(user
, &resp
->users_list
, node
) {
331 if (user
->dev
== dev
) {
338 /* First time user */
345 list_add(&user
->node
, &resp
->users_list
);
350 /* Recompute and set the current level for the resource */
351 ret
= update_resource_level(resp
);
353 spin_unlock_irqrestore(&res_lock
, flags
);
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
367 * Returns 0 on success, -EINVAL if the resource name or dev structure
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;
377 spin_lock_irqsave(&res_lock
, flags
);
378 resp
= _resource_lookup(name
);
380 printk(KERN_ERR
"resource_release: Invalid resource name\n");
385 list_for_each_entry(user
, &resp
->users_list
, node
) {
386 if (user
->dev
== dev
) {
393 /* No such user exists */
399 list_del(&user
->node
);
402 /* Recompute and set the current level for the resource */
403 ret
= update_resource_level(resp
);
405 spin_unlock_irqrestore(&res_lock
, flags
);
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
;
423 spin_lock_irqsave(&res_lock
, flags
);
424 resp
= _resource_lookup(name
);
426 printk(KERN_ERR
"resource_release: Invalid resource name\n");
427 spin_unlock_irqrestore(&res_lock
, flags
);
430 ret
= resp
->curr_level
;
431 spin_unlock_irqrestore(&res_lock
, flags
);
434 EXPORT_SYMBOL(resource_get_level
);