All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Rajendra Nayak" <rnayak@ti.com>
To: "'Dasgupta, Romit'" <romit@ti.com>, linux-omap@vger.kernel.org
Subject: RE: [PATCH 01/04] OMAP3 SRF: Generic shared resource f/w
Date: Fri, 17 Oct 2008 11:59:56 +0530	[thread overview]
Message-ID: <02a701c93021$c7615ab0$LocalHost@wipultra1382> (raw)
In-Reply-To: <B85A65D85D7EB246BE421B3FB0FBB59301B03147FF@dbde02.ent.ti.com>


> -----Original Message-----
> From: Dasgupta, Romit [mailto:romit@ti.com] 
> Sent: Friday, October 17, 2008 11:47 AM
> To: Nayak, Rajendra; linux-omap@vger.kernel.org
> Subject: RE: [PATCH 01/04] OMAP3 SRF: Generic shared resource f/w
> 
> Rajendra,
>                    Few bugs in the code
> 1) curr_level of the shared_resource is not updated in 
> update_resource_level

Yes, its not. Its done as part of the platform specific change_level call.

> 2) resource_request invokes spin_lock_irqsave and then if it 
> is a request for a new device it invokes get_user().
> get_user() calls kmalloc with GFP_KERNEL. So it can sleep. 
> Hence you will sleep with spinlocks held!!

Right, so I'll probably have to add a GFP_ATOMIC flag to that.
I am now thinking If I really need spinlocks, think I can do with mutex's instead.
The spinlocks were put in place to take care of the omap-pm hooks from 
clock f/w which no longer seem to be needed.
 
> 
> Trying to review the remaining patches.
> 
> Regards,
> -Romit
> 
> 
> >-----Original Message-----
> >From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> >owner@vger.kernel.org] On Behalf Of Nayak, Rajendra
> >Sent: Thursday, October 16, 2008 7:42 PM
> >To: linux-omap@vger.kernel.org
> >Subject: [PATCH 01/04] OMAP3 SRF: Generic shared resource f/w
> >
> >This patch defines and implements the Generic
> >Shared Resource Framework structures and API's
> >
> >Signed-off-by: Rajendra Nayak <rnayak@ti.com>
> >---
> > arch/arm/plat-omap/include/mach/resource.h |   79 +++++
> > arch/arm/plat-omap/resource.c              |  433 
> +++++++++++++++++++++++++++++
> > 2 files changed, 512 insertions(+)
> >
> >Index: linux-omap-2.6/arch/arm/plat-omap/resource.c
> >================================================================
> >===
> >--- /dev/null  1970-01-01 00:00:00.000000000 +0000
> >+++ linux-omap-2.6/arch/arm/plat-omap/resource.c       2008-10-16
> >18:04:05.000000000 +0530
> >@@ -0,0 +1,433 @@
> >+/*
> >+ * linux/arch/arm/plat-omap/resource.c
> >+ * Shared Resource Framework API implementation
> >+ *
> >+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
> >+ * Rajendra Nayak <rnayak@ti.com>
> >+ *
> >+ * This program is free software; you can redistribute it 
> and/or modify
> >+ * it under the terms of the GNU General Public License version 2 as
> >+ * published by the Free Software Foundation.
> >+ *
> >+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
> >+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
> >+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
> >PURPOSE.
> >+ * History:
> >+ *
> >+ */
> >+
> >+#include <linux/errno.h>
> >+#include <linux/err.h>
> >+#include <mach/resource.h>
> >+#include <linux/slab.h>
> >+
> >+/*
> >+ * This is for statically defining the users pool. This 
> static pool is
> >+ * used early at bootup till kmalloc becomes available.
> >+ */
> >+#define MAX_USERS     10
> >+#define UNUSED                0x0
> >+#define       DYNAMIC_ALLOC   0x1
> >+#define STATIC_ALLOC  0x2
> >+
> >+/* res_list contains all registered struct shared_resource */
> >+static LIST_HEAD(res_list);
> >+
> >+/* res_lock protects res_list add and del ops */
> >+static DEFINE_SPINLOCK(res_lock);
> >+
> >+/* Static Pool of users for a resource used till kmalloc 
> becomes available */
> >+struct  users_list usr_list[MAX_USERS];
> >+
> >+/* Private/Internal functions */
> >+
> >+/**
> >+ * _resource_lookup - loop up a resource by its name, 
> return a pointer
> >+ * @name: The name of the resource to lookup
> >+ *
> >+ * Looks for a registered resource by its name. Returns a pointer to
> >+ * the struct shared_resource if found, else returns NULL.
> >+ * The function is not lock safe.
> >+ */
> >+static struct shared_resource *_resource_lookup(const char *name)
> >+{
> >+      struct shared_resource *res, *tmp_res;
> >+
> >+      if (!name)
> >+              return NULL;
> >+
> >+      res = NULL;
> >+
> >+      list_for_each_entry(tmp_res, &res_list, node) {
> >+              if (!strcmp(name, tmp_res->name)) {
> >+                      res = tmp_res;
> >+                      break;
> >+              }
> >+      }
> >+      return res;
> >+}
> >+
> >+/**
> >+ * resource_lookup - loop up a resource by its name, return 
> a pointer
> >+ * @name: The name of the resource to lookup
> >+ *
> >+ * Looks for a registered resource by its name. Returns a pointer to
> >+ * the struct shared_resource if found, else returns NULL.
> >+ * The function holds spinlocks and takes care of atomicity.
> >+ */
> >+static struct shared_resource *resource_lookup(const char *name)
> >+{
> >+      struct shared_resource *res;
> >+      unsigned long flags;
> >+
> >+      if (!name)
> >+              return NULL;
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      res = _resource_lookup(name);
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+
> >+      return res;
> >+}
> >+
> >+/**
> >+ * update_resource_level - Regenerates and updates the 
> curr_level of the res
> >+ * @resp: Pointer to the resource
> >+ *
> >+ * This function looks at all the users of the given 
> resource and the levels
> >+ * requested by each of them, and recomputes a target level 
> for the resource
> >+ * acceptable to all its current usres. It then calls 
> platform specific
> >+ * change_level to change the level of the resource.
> >+ * Returns 0 on success, else a non-zero value returned by 
> the platform
> >+ * specific change_level function.
> >+ **/
> >+static int update_resource_level(struct shared_resource *resp)
> >+{
> >+      struct users_list *user;
> >+      unsigned long target_level;
> >+      int ret;
> >+
> >+      /* Regenerate the target_value for the resource */
> >+      target_level = RES_DEFAULTLEVEL;
> >+      list_for_each_entry(user, &resp->users_list, node)
> >+              if (user->level > target_level)
> >+                      target_level = user->level;
> >+
> >+      pr_debug("SRF: Changing Level for resource %s to %ld\n",
> >+                              resp->name, target_level);
> >+      ret = resp->ops->change_level(resp, target_level);
> >+      if (ret) {
> >+              printk(KERN_ERR "Unable to Change"
> >+                                      "level for resource 
> %s to %ld\n",
> >+              resp->name, target_level);
> >+      }
> >+      return ret;
> >+}
> >+
> >+/**
> >+ * get_user - gets a new users_list struct from static pool 
> or dynamically
> >+ *
> >+ * This function initally looks for availability in the 
> static pool and
> >+ * tries to dynamcially allocate only once the static pool is empty.
> >+ * We hope that during bootup by the time we hit a case of 
> dynamic allocation
> >+ * slab initialization would have happened.
> >+ * Returns a pointer users_list struct on success. On 
> dynamic allocation failure
> >+ * returns a ERR_PTR(-ENOMEM).
> >+ */
> >+static struct users_list *get_user(void)
> >+{
> >+      int ind = 0;
> >+      struct users_list *user;
> >+
> >+      /* See if something available in the static pool */
> >+      while (ind < MAX_USERS) {
> >+              if (usr_list[ind].usage == UNUSED)
> >+                      break;
> >+              else
> >+                      ind++;
> >+      }
> >+      if (ind < MAX_USERS) {
> >+              /* Pick from the static pool */
> >+              user = &usr_list[ind];
> >+              user->usage = STATIC_ALLOC;
> >+      } else {
> >+              /* By this time we hope slab is initialized */
> >+              if (slab_is_available()) {
> >+                      user = kmalloc(sizeof(struct  
> users_list), GFP_KERNEL);
> >+                      if (!user) {
> >+                              printk(KERN_ERR "SRF:FATAL 
> ERROR: kmalloc"
> >+                                                      "failed\n");
> >+                              return ERR_PTR(-ENOMEM);
> >+                      }
> >+                      user->usage = DYNAMIC_ALLOC;
> >+              } else {
> >+                      /* Dynamic alloc not available yet */
> >+                      printk(KERN_ERR "SRF: FATAL ERROR: users_list"
> >+                              "initial POOL EMPTY before 
> slab init\n");
> >+                      return ERR_PTR(-ENOMEM);
> >+              }
> >+      }
> >+      return user;
> >+}
> >+
> >+/**
> >+ * free_user - frees the dynamic users_list and marks the 
> static one unused
> >+ * @user: The struct users_list to be freed
> >+ *
> >+ * Looks at the usage flag and either frees the users_list if it was
> >+ * dynamically allocated, and if its from the static pool, 
> marks it unused.
> >+ * No return value.
> >+ */
> >+void free_user(struct users_list *user)
> >+{
> >+      if (user->usage == DYNAMIC_ALLOC) {
> >+              kfree(user);
> >+      } else {
> >+              user->usage = UNUSED;
> >+              user->level = RES_DEFAULTLEVEL;
> >+              user->dev = NULL;
> >+      }
> >+}
> >+
> >+/**
> >+ * resource_init - Initializes the Shared resource framework.
> >+ * @resources: List of all the resources modelled
> >+ *
> >+ * Loops through the list of resources and registers all that
> >+ * are available for the current CPU.
> >+ * No return value
> >+ */
> >+void resource_init(struct shared_resource **resources)
> >+{
> >+      struct shared_resource **resp;
> >+      int ind;
> >+
> >+      pr_debug("Initializing Shared Resource Framework\n");
> >+
> >+      if (!cpu_is_omap34xx()) {
> >+              /* This CPU is not supported */
> >+              printk(KERN_WARNING "Shared Resource 
> Framework does not"
> >+                      "support this CPU type.\n");
> >+              WARN_ON(1);
> >+      }
> >+
> >+      /* Init the users_list POOL */
> >+      for (ind = 0; ind < MAX_USERS; ind++) {
> >+              usr_list[ind].usage = UNUSED;
> >+              usr_list[ind].dev = NULL;
> >+              usr_list[ind].level = RES_DEFAULTLEVEL;
> >+      }
> >+
> >+      if (resources)
> >+              for (resp = resources; *resp; resp++)
> >+                      resource_register(*resp);
> >+}
> >+
> >+/**
> >+ * resource_register - registers and initializes a resource
> >+ * @res: struct shared_resource * to register
> >+ *
> >+ * Initializes the given resource and adds it to the resource list
> >+ * for the current CPU.
> >+ * Returns 0 on success, -EINVAL if given a NULL pointer, 
> -EEXIST if the
> >+ * resource is already registered.
> >+ */
> >+int resource_register(struct shared_resource *resp)
> >+{
> >+      unsigned long flags;
> >+
> >+      if (!resp)
> >+              return -EINVAL;
> >+
> >+      if (!omap_chip_is(resp->omap_chip))
> >+              return -EINVAL;
> >+
> >+      /* Verify that the resource is not already registered */
> >+      if (resource_lookup(resp->name))
> >+              return -EEXIST;
> >+
> >+      INIT_LIST_HEAD(&resp->users_list);
> >+
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      /* Add the resource to the resource list */
> >+      list_add(&resp->node, &res_list);
> >+
> >+      /* Call the resource specific init*/
> >+      if (resp->ops->init)
> >+              resp->ops->init(resp);
> >+
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+      pr_debug("resource: registered %s\n", resp->name);
> >+
> >+      return 0;
> >+}
> >+EXPORT_SYMBOL(resource_register);
> >+
> >+/**
> >+ * resource_unregister - unregister a resource
> >+ * @res: struct shared_resource * to unregister
> >+ *
> >+ * Removes a resource from the resource list.
> >+ * Returns 0 on success, -EINVAL if passed a NULL pointer.
> >+ */
> >+int resource_unregister(struct shared_resource *resp)
> >+{
> >+      unsigned long flags;
> >+
> >+      if (!resp)
> >+              return -EINVAL;
> >+
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      /* delete the resource from the resource list */
> >+      list_del(&resp->node);
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+
> >+      pr_debug("resource: unregistered %s\n", resp->name);
> >+
> >+      return 0;
> >+}
> >+EXPORT_SYMBOL(resource_unregister);
> >+
> >+/**
> >+ * resource_request - Request for a required level of a resource
> >+ * @name: The name of the resource requested
> >+ * @dev: Uniquely identifes the caller
> >+ * @level: The requested level for the resource
> >+ *
> >+ * This function recomputes the target level of the 
> resource based on
> >+ * the level requested by the user. The level of the resource is
> >+ * changed to the target level, if it is not the same as 
> the existing level
> >+ * of the resource. Multiple calls to this function by the 
> same device will
> >+ * replace the previous level requested
> >+ * Returns 0 on success, -EINVAL if the resource name 
> passed in invalid.
> >+ * -ENOMEM if no static pool available or dynamic allocations fails.
> >+ * Else returns a non-zero error value returned by one of 
> the failing
> >+ * shared_resource_ops.
> >+ */
> >+int resource_request(const char *name, struct device *dev,
> >+                                      unsigned long level)
> >+{
> >+      struct shared_resource *resp;
> >+      struct  users_list *user;
> >+      int     found = 0, ret = 0;
> >+      unsigned long flags;
> >+
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      resp = _resource_lookup(name);
> >+      if (!resp) {
> >+              printk(KERN_ERR "resource_request: Invalid 
> resource name\n");
> >+              ret = -EINVAL;
> >+              goto res_unlock;
> >+      }
> >+
> >+      /* Call the resource specific validate function */
> >+      if (resp->ops->validate_level) {
> >+              ret = resp->ops->validate_level(resp, level);
> >+              if (ret)
> >+                      goto res_unlock;
> >+      }
> >+
> >+      list_for_each_entry(user, &resp->users_list, node) {
> >+              if (user->dev == dev) {
> >+                      found = 1;
> >+                      break;
> >+              }
> >+      }
> >+
> >+      if (!found) {
> >+              /* First time user */
> >+              user = get_user();
> >+              if (IS_ERR(user)) {
> >+                      ret = -ENOMEM;
> >+                      goto res_unlock;
> >+              }
> >+              user->dev = dev;
> >+              list_add(&user->node, &resp->users_list);
> >+              resp->no_of_users++;
> >+      }
> >+      user->level = level;
> >+
> >+      /* Recompute and set the current level for the resource */
> >+      ret = update_resource_level(resp);
> >+res_unlock:
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+      return ret;
> >+}
> >+EXPORT_SYMBOL(resource_request);
> >+
> >+/**
> >+ * resource_release - Release a previously requested level 
> of a resource
> >+ * @name: The name of the resource to be released
> >+ * @dev: Uniquely identifes the caller
> >+ *
> >+ * This function recomputes the target level of the 
> resource after removing
> >+ * the level requested by the user. The level of the resource is
> >+ * changed to the target level, if it is not the same as 
> the existing level
> >+ * of the resource.
> >+ * Returns 0 on success, -EINVAL if the resource name or 
> dev structure
> >+ * is invalid.
> >+ */
> >+int resource_release(const char *name, struct device *dev)
> >+{
> >+      struct shared_resource *resp;
> >+      struct users_list *user;
> >+      int found = 0, ret = 0;
> >+      unsigned long flags;
> >+
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      resp = _resource_lookup(name);
> >+      if (!resp) {
> >+              printk(KERN_ERR "resource_release: Invalid 
> resource name\n");
> >+              ret = -EINVAL;
> >+              goto res_unlock;
> >+      }
> >+
> >+      list_for_each_entry(user, &resp->users_list, node) {
> >+              if (user->dev == dev) {
> >+                      found = 1;
> >+                      break;
> >+              }
> >+      }
> >+
> >+      if (!found) {
> >+              /* No such user exists */
> >+              ret = -EINVAL;
> >+              goto res_unlock;
> >+      }
> >+
> >+      resp->no_of_users--;
> >+      list_del(&user->node);
> >+      free_user(user);
> >+
> >+      /* Recompute and set the current level for the resource */
> >+      ret = update_resource_level(resp);
> >+res_unlock:
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+      return ret;
> >+}
> >+EXPORT_SYMBOL(resource_release);
> >+
> >+/**
> >+ * resource_get_level - Returns the current level of the resource
> >+ * @name: Name of the resource
> >+ *
> >+ * Returns the current level of the resource if found, else returns
> >+ * -EINVAL if the resource name is invalid.
> >+ */
> >+int resource_get_level(const char *name)
> >+{
> >+      struct shared_resource *resp;
> >+      u32 ret;
> >+      unsigned long flags;
> >+
> >+      spin_lock_irqsave(&res_lock, flags);
> >+      resp = _resource_lookup(name);
> >+      if (!resp) {
> >+              printk(KERN_ERR "resource_release: Invalid 
> resource name\n");
> >+              spin_unlock_irqrestore(&res_lock, flags);
> >+              return -EINVAL;
> >+      }
> >+      ret = resp->curr_level;
> >+      spin_unlock_irqrestore(&res_lock, flags);
> >+      return ret;
> >+}
> >+EXPORT_SYMBOL(resource_get_level);
> >Index: linux-omap-2.6/arch/arm/plat-omap/include/mach/resource.h
> >================================================================
> >===
> >--- /dev/null  1970-01-01 00:00:00.000000000 +0000
> >+++ 
> linux-omap-2.6/arch/arm/plat-omap/include/mach/resource.h  2008-10-16
> >18:01:57.000000000 +0530
> >@@ -0,0 +1,79 @@
> >+/*
> >+ * linux/include/asm-arm/arch-omap/resource.h
> >+ * Structure definitions for Shared resource Framework
> >+ *
> >+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
> >+ * Written by Rajendra Nayak <rnayak@ti.com>
> >+ *
> >+ * This program is free software; you can redistribute it 
> and/or modify
> >+ * it under the terms of the GNU General Public License version 2 as
> >+ * published by the Free Software Foundation.
> >+ *
> >+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
> >+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
> >+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
> >PURPOSE.
> >+ *
> >+ * History:
> >+ *
> >+ */
> >+
> >+#ifndef __ARCH_ARM_OMAP_RESOURCE_H
> >+#define __ARCH_ARM_OMAP_RESOURCE_H
> >+
> >+#include <linux/list.h>
> >+#include <linux/mutex.h>
> >+#include <linux/device.h>
> >+#include <mach/cpu.h>
> >+
> >+#define RES_DEFAULTLEVEL      0x0
> >+
> >+struct shared_resource_ops; /* forward declaration */
> >+
> >+/* Used to model a Shared Multilevel Resource */
> >+struct shared_resource {
> >+      /* Resource name */
> >+      const char *name;
> >+      /* Used to represent the OMAP chip types containing 
> this res */
> >+      const struct omap_chip_id omap_chip;
> >+      /* Total no of users at any point of this resource */
> >+      u8 no_of_users;
> >+      /* Current level of this resource */
> >+      u32 curr_level;
> >+      /* Used to store any resource specific data */
> >+      void  *resource_data;
> >+      /* List of all the current users for this resource */
> >+      struct list_head users_list;
> >+      /* Shared resource operations */
> >+      struct shared_resource_ops *ops;
> >+      struct list_head node;
> >+};
> >+
> >+struct shared_resource_ops {
> >+      /* Init function for the resource */
> >+      void (*init)(struct shared_resource *res);
> >+      /* Function to change the level of the resource */
> >+      int (*change_level)(struct shared_resource *res, u32 
> target_level);
> >+      /* Function to validate the requested level of the resource */
> >+      int (*validate_level)(struct shared_resource *res, 
> u32 target_level);
> >+};
> >+
> >+/* Used to represent a user of a shared resource */
> >+struct users_list {
> >+      /* Device pointer used to uniquely identify the user */
> >+      struct device *dev;
> >+      /* Current level as requested for the resource by the user */
> >+      u32 level;
> >+      struct list_head node;
> >+      u8 usage;
> >+};
> >+
> >+/* Shared resource Framework API's */
> >+void resource_init(struct shared_resource **resources);
> >+int resource_register(struct shared_resource *res);
> >+int resource_unregister(struct shared_resource *res);
> >+int resource_request(const char *name, struct device *dev,
> >+                                               unsigned long level);
> >+int resource_release(const char *name, struct device *dev);
> >+int resource_get_level(const char *name);
> >+
> >+#endif /* __ARCH_ARM_OMAP_RESOURCE_H */
> >
> >--
> >To unsubscribe from this list: send the line "unsubscribe 
> linux-omap" in
> >the body of a message to majordomo@vger.kernel.org
> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


  reply	other threads:[~2008-10-17  6:30 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-16 14:11 [PATCH 01/04] OMAP3 SRF: Generic shared resource f/w Rajendra Nayak
2008-10-16 18:27 ` David Brownell
2008-10-17  5:27   ` Rajendra Nayak
2008-10-17  6:16 ` Dasgupta, Romit
2008-10-17  6:29   ` Rajendra Nayak [this message]
2008-10-17  7:35     ` Dasgupta, Romit
2008-10-17  7:43       ` Rajendra Nayak
2008-10-17 11:01         ` Dasgupta, Romit
2008-10-17 11:31           ` Dasgupta, Romit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='02a701c93021$c7615ab0$LocalHost@wipultra1382' \
    --to=rnayak@ti.com \
    --cc=linux-omap@vger.kernel.org \
    --cc=romit@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.