Re: adding handles to pm_qos?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Oh.
> 
> This will not scale with the aggregation logic very well at all
> if
> pm_qos update requirement gets hit per transaction through a
> driver code
> path, then I think some thought on the scalability is needed and
> perhaps
> a change to the aggregation design for such uses.
> 
> Do you have a patch for the handle implementation I could look
> at?

Here is the patch that I use with the test code.  There are three new
functions:

void *pm_qos_get(int qos, char *name);
int pm_qos_put(void *handle);
int pm_qos_update_requirement_direct(void *handle, s32 new_value);

In the test, I wanted to keep the existing interface intact so I
could compare them at the same time.  For the formal code submission,
a different approach may work better.


--- include/linux/pm_qos_params.h.orig
+++ include/linux/pm_qos_params.h
@@ -16,7 +16,11 @@
 
 int pm_qos_add_requirement(int qos, char *name, s32 value);
 int pm_qos_update_requirement(int qos, char *name, s32 new_value);
-void pm_qos_remove_requirement(int qos, char *name);
+int pm_qos_remove_requirement(int qos, char *name);
+
+void *pm_qos_get(int qos, char *name);
+int pm_qos_put(void *handle);
+int pm_qos_update_requirement_direct(void *handle, s32 new_value);
 
 int pm_qos_requirement(int qos);
 
--- kernel/pm_qos_params.c.orig
+++ kernel/pm_qos_params.c
@@ -55,6 +55,8 @@ struct requirement_list {
 		s32 kbps;
 	};
 	char *name;
+	int pm_qos_class;
+	int handle_count;
 };
 
 static s32 max_compare(s32 v1, s32 v2);
@@ -210,7 +212,9 @@ EXPORT_SYMBOL_GPL(pm_qos_requirement);
 int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
 {
 	struct requirement_list *dep;
+	struct requirement_list *node;
 	unsigned long flags;
+	int retval;
 
 	dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
 	if (dep) {
@@ -219,10 +223,25 @@ int pm_qos_add_requirement(int pm_qos_class,
char *name, s32 value)
 		else
 			dep->value = value;
 		dep->name = kstrdup(name, GFP_KERNEL);
-		if (!dep->name)
+		if (!dep->name) {
+			retval = -ENOMEM;
 			goto cleanup;
+		}
+		dep->pm_qos_class = pm_qos_class;
 
 		spin_lock_irqsave(&pm_qos_lock, flags);
+		/* make sure the new name is unique */
+		list_for_each_entry(node,
+
&pm_qos_array[pm_qos_class]->requirements.list, list) {
+			if (strcmp(node->name, name) == 0) {
+				spin_unlock_irqrestore(&pm_qos_lock,
flags);
+
+				kfree(dep->name);
+				retval = -EINVAL;
+				goto cleanup;
+			}
+		}
+
 		list_add(&dep->list,
 
&pm_qos_array[pm_qos_class]->requirements.list);
 		spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -231,9 +250,11 @@ int pm_qos_add_requirement(int pm_qos_class,
char *name, s32 value)
 		return 0;
 	}
 
+	retval = -ENOMEM;
+
 cleanup:
 	kfree(dep);
-	return -ENOMEM;
+	return retval;
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
 
@@ -282,8 +303,10 @@ EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
  *
  * Will remove named qos request from pm_qos_class list of
parameters and
  * recompute the current target value for the pm_qos_class.
+ *
+ * If there are outstanding handles to the request, -EBUSY is
returned.
  */
-void pm_qos_remove_requirement(int pm_qos_class, char *name)
+int pm_qos_remove_requirement(int pm_qos_class, char *name)
 {
 	unsigned long flags;
 	struct requirement_list *node;
@@ -293,6 +316,11 @@ void pm_qos_remove_requirement(int pm_qos_class,
char *name)
 	list_for_each_entry(node,
 		&pm_qos_array[pm_qos_class]->requirements.list, list)
{
 		if (strcmp(node->name, name) == 0) {
+			if (node->handle_count > 0) {
+				spin_unlock_irqrestore(&pm_qos_lock,
flags);
+				return -EBUSY;
+			}
+
 			kfree(node->name);
 			list_del(&node->list);
 			kfree(node);
@@ -303,9 +331,83 @@ void pm_qos_remove_requirement(int pm_qos_class,
char *name)
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 	if (pending_update)
 		update_target(pm_qos_class);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
 
+/* pm_qos_get - returns an opaque handle to the existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ *
+ * Will increment the reference count as well.
+ *
+ * If the named request isn't in the list then NULL is returned.
+ */
+void *pm_qos_get(int pm_qos_class, char *name)
+{
+	unsigned long flags;
+	struct requirement_list *node;
+	struct requirement_list *handle = NULL;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	list_for_each_entry(node,
+		&pm_qos_array[pm_qos_class]->requirements.list, list)
{
+		if (strcmp(node->name, name) == 0) {
+			node->handle_count++;
+			handle = node;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+	return handle;
+}
+EXPORT_SYMBOL_GPL(pm_qos_get);
+
+/* pm_qos_put - release the handle of the existing qos request
+ * @handle: previously acquired through pm_qos_get
+ *
+ * Will decrement the reference count as well. Caller should no
+ * longer use the handle after this call.
+ */
+int pm_qos_put(void *handle)
+{
+	unsigned long flags;
+	struct requirement_list *node =	(struct requirement_list *)
handle;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	BUG_ON(node->handle_count == 0);
+	node->handle_count--;
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_put);
+
+/* pm_qos_update_requirement_direct - modifies an existing qos
request
+ * @handle: previously acquired through pm_qos_get
+ * @value: defines the qos request
+ *
+ * Updates an existing qos requirement for the pm_qos_class of
parameters along
+ * with updating the target pm_qos_class value.
+ */
+int pm_qos_update_requirement_direct(void *handle, s32 new_value)
+{
+	unsigned long flags;
+	struct requirement_list *node = (struct requirement_list *)
handle;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	if (new_value == PM_QOS_DEFAULT_VALUE)
+		node->value =
pm_qos_array[node->pm_qos_class]->default_value;
+	else
+		node->value = new_value;
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+	update_target(node->pm_qos_class);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_requirement_direct);
+
 /**
  * pm_qos_add_notifier - sets notification entry for changes to
target value
  * @pm_qos_class: identifies which qos target changes should be
notified.


~Ai

_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux