All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jean Pihet <jean.pihet@newoldbits.com>
To: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: markgross@thegnar.org,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Linux PM mailing list <linux-pm@lists.linux-foundation.org>,
	linux-omap@vger.kernel.org, Jean Pihet <j-pihet@ti.com>
Subject: Re: [PATCH 06/15] PM QoS: implement the per-device PM QoS constraints
Date: Sun, 14 Aug 2011 10:50:09 +0200	[thread overview]
Message-ID: <CAORVsuVZjrqY0qhEvCpRRvt5RDcG-YT5SJo6Ejhyr-_fTyk9HQ__13036.3858108923$1313311872$gmane$org@mail.gmail.com> (raw)
In-Reply-To: <201108132308.26265.rjw@sisk.pl>

Rafael,

2011/8/13 Rafael J. Wysocki <rjw@sisk.pl>:
> Hi,
>
> Well, it looks like I should have reviewed this one more carefully.
>
> On Thursday, August 11, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> Implement the per-device PM QoS constraints by creating a device
>> PM QoS API, which calls the PM QoS constraints management core code.
>>
>> The per-device latency constraints data strctures are stored
>> in the device dev_pm_info struct.
>>
>> The device PM code calls the init and destroy of the per-device constraints
>> data struct in order to support the dynamic insertion and removal of the
>> devices in the system.
>>
>> To minimize the data usage by the per-device constraints, the data struct
>> is only allocated at the first call to dev_pm_qos_add_request.
>> The data is later free'd when the device is removed from the system.
>>
>> Signed-off-by: Jean Pihet <j-pihet@ti.com>
>> ---
...
>> +/*#define DEBUG*/
>
> Please remove this.
Ok

>
>> +
>> +#include <linux/pm_qos.h>
>> +#include <linux/sched.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/slab.h>
>> +#include <linux/time.h>
>> +#include <linux/fs.h>
>> +#include <linux/device.h>
>> +#include <linux/string.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>
> Are you sure all of the headers are necessary?
No. I can check that.

>
>> +
>> +
>> +static void dev_pm_qos_constraints_allocate(struct device *dev);
>> +
>> +int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
>> +{
>> +     return req->dev != 0;
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_request_active);
>
> That should be a static inline in a header.
Ok

>
>> +
>> +/**
>> + * dev_pm_qos_add_request - inserts new qos request into the list
>> + * @req: pointer to a preallocated handle
>> + * @dev: target device for the constraint
>> + * @value: defines the qos request
>> + *
>> + * This function inserts a new entry in the device constraints list of
>> + * requested qos performance characteristics. It recomputes the aggregate
>> + * QoS expectations of parameters and initializes the dev_pm_qos_request
>> + * handle.  Caller needs to save this handle for later use in updates and
>> + * removal.
>> + */
>> +void dev_pm_qos_add_request(struct dev_pm_qos_request *req, struct device *dev,
>> +                         s32 value)
>
> I'd use a different ordering of arguments, namely (dev, req, value).
Ok

>
>> +{
>> +     if (!req) /*guard against callers passing in null */
>> +             return;
>
> Why not to check for !dev too?
Ok that makes sense

>
>> +
>> +     if (dev_pm_qos_request_active(req)) {
>> +             WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already "
>> +                     "added request\n");
>> +             return;
>> +     }
>> +     req->dev = dev;
>> +
>> +     /* Allocate the constraints struct on the first call to add_request */
>> +     if (req->dev->power.constraints_state == DEV_PM_QOS_DEVICE_PRESENT)
>> +             dev_pm_qos_constraints_allocate(dev);
>
> Why not to do
>
> +       if (!req->dev->power.constraints)
> +               dev_pm_qos_constraints_allocate(dev);

Cf. my comments at the end of this message for the data structs
alloc/free and the locking.

>
>> +
>> +     /* Silently return if the device has been removed */
>> +     if (req->dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
>> +             return;
>> +
>
> Hmm.  What will happen if two callers run dev_pm_qos_add_request()
> concurrently for the same device?
update_target is using the power.lock to protect the constraints lists changes.

>
>> +     pm_qos_update_target(dev->power.constraints,
>> +                          &req->node, PM_QOS_ADD_REQ, value);
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
>> +
>> +/**
>> + * dev_pm_qos_update_request - modifies an existing qos request
>> + * @req : handle to list element holding a dev_pm_qos request to use
>> + * @value: defines the qos request
>> + *
>> + * Updates an existing dev PM qos request along with updating the
>> + * target value.
>> + *
>> + * Attempts are made to make this code callable on hot code paths.
>> + */
>> +void dev_pm_qos_update_request(struct dev_pm_qos_request *req,
>> +                        s32 new_value)
>> +{
>> +     if (!req) /*guard against callers passing in null */
>> +             return;
>> +
>> +     if (!dev_pm_qos_request_active(req)) {
>> +             WARN(1, KERN_ERR "dev_pm_qos_update_request() called for "
>> +                     "unknown object\n");
>> +             return;
>> +     }
>> +
>> +     /* Silently return if the device has been removed */
>> +     if (req->dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
>> +             return;
>> +
>> +     if (new_value != req->node.prio)
>> +             pm_qos_update_target(
>> +                     req->dev->power.constraints,
>> +                     &req->node, PM_QOS_UPDATE_REQ, new_value);
>
> I'm not sure what prevents dev_pm_qos_constraints_destroy() from removing
> the list from under us while we're executing this?
Cf. my comments at the end of this message for the data structs
alloc/free and the locking.

>
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
>> +
>> +/**
>> + * dev_pm_qos_remove_request - modifies an existing qos request
>> + * @req: handle to request list element
>> + *
>> + * Will remove pm qos request from the list of constraints and
>> + * recompute the current target value. Call this on slow code paths.
>> + */
>> +void dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
>> +{
>> +     if (!req) /*guard against callers passing in null */
>> +             return;
>> +
>> +     if (!dev_pm_qos_request_active(req)) {
>> +             WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for "
>> +                     "unknown object\n");
>> +             return;
>> +     }
>> +
>> +     /* Silently return if the device has been removed */
>> +     if (req->dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
>> +             return;
>> +
>> +     pm_qos_update_target(req->dev->power.constraints,
>> +                          &req->node, PM_QOS_REMOVE_REQ,
>> +                          PM_QOS_DEFAULT_VALUE);
>
> Same here.
>
>> +     memset(req, 0, sizeof(*req));
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
>> +
>> +/**
>> + * dev_pm_qos_add_notifier - sets notification entry for changes to target value
>> + * of per-device PM QoS constraints
>> + *
>> + * @dev: target device for the constraint
>> + * @notifier: notifier block managed by caller.
>> + *
>> + * Will register the notifier into a notification chain that gets called
>> + * upon changes to the target value for the device.
>> + */
>> +int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
>> +{
>> +     int retval = 0;
>> +
>> +     /* Silently return if the device has been removed */
>> +     if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
>> +             return retval;
>> +
>> +     retval = blocking_notifier_chain_register(
>> +                     dev->power.constraints->notifiers,
>> +                     notifier);
>
> That may be racing with dev_pm_qos_constraints_destroy() too.
>
>> +
>> +     return retval;
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
>> +
>> +/**
>> + * dev_pm_qos_remove_notifier - deletes notification for changes to target value
>> + * of per-device PM QoS constraints
>> + *
>> + * @dev: target device for the constraint
>> + * @notifier: notifier block to be removed.
>> + *
>> + * Will remove the notifier from the notification chain that gets called
>> + * upon changes to the target value.
>> + */
>> +int dev_pm_qos_remove_notifier(struct device *dev,
>> +                            struct notifier_block *notifier)
>> +{
>> +     int retval = 0;
>> +
>> +     /* Silently return if the device has been removed */
>> +     if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
>> +             return retval;
>> +
>> +     retval = blocking_notifier_chain_unregister(
>> +                     dev->power.constraints->notifiers,
>> +                     notifier);
>
> Same here.
>
>> +
>> +     return retval;
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
>> +
>> +/* Called at the first call to add_request, for constraint data allocation */
>> +static void dev_pm_qos_constraints_allocate(struct device *dev)
>> +{
>> +     struct pm_qos_constraints *c;
>> +     struct blocking_notifier_head *n;
>> +
>> +     c = kzalloc(sizeof(*c), GFP_KERNEL);
>> +     if (!c)
>> +             return;
>> +
>> +     n = kzalloc(sizeof(*n), GFP_KERNEL);
>> +     if (!n) {
>> +             kfree(c);
>> +             return;
>> +     }
>> +     BLOCKING_INIT_NOTIFIER_HEAD(n);
>> +
>> +     dev->power.constraints = c;
>> +     plist_head_init(&dev->power.constraints->list, &dev->power.lock);
>> +     dev->power.constraints->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.constraints->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.constraints->type = PM_QOS_MIN;
>> +     dev->power.constraints->notifiers = n;
>> +     dev->power.constraints_state = DEV_PM_QOS_ALLOCATED;
>> +}
>> +
>> +/* Called from the device PM subsystem at device insertion */
>> +void dev_pm_qos_constraints_init(struct device *dev)
>> +{
>> +     dev->power.constraints_state = DEV_PM_QOS_DEVICE_PRESENT;
>
> Hmm.  Is it insufficient to check if "constraints" is not NULL?
>
>> +}
>> +
>> +/* Called from the device PM subsystem at device removal */
>> +void dev_pm_qos_constraints_destroy(struct device *dev)
>> +{
>> +     struct dev_pm_qos_request *req, *tmp;
>> +     enum dev_pm_qos_state constraints_state = dev->power.constraints_state;
>> +
>> +     dev->power.constraints_state = DEV_PM_QOS_NO_DEVICE;
>
> I'm not sure what the purpose of this is.  I'd simply check if "constraints"
> is not NULL and I'd flush the list if not.
>
> Moreover, that has to go under a lock so that it doesn't race with
> the other functions above.  I think you can reuse power.lock for that.
>

Your remarks are inline with the concerns I had about the adata
structs alloc/free and the locking.

1) data structs alloc/free
As described in the changelog:
>> To minimize the data usage by the per-device constraints, the data struct
>> is only allocated at the first call to dev_pm_qos_add_request.
>> The data is later free'd when the device is removed from the system.
A basic state machine is needed in order to allocate the data at the
first call to add_request and free it when the device is removed.
Another option is to allocate the data when the device is added to the
system and free it when the device is removed. That would make the
code simpler but it is using a lot of memory for unneeded data.

2) Race conditions
I will add a lock to isolate the API callers from
dev_pm_qos_constraints_destroy().
The power.lock is already used by update_target so another lock is
needed to protect the data allocation/free.

I will rework this tomorrow and re-submit asap when it is ready.
Is that OK?

>
> Thanks,
> Rafael
>

Thanks,
Jean

  parent reply	other threads:[~2011-08-14  8:50 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-11 15:06 [PATCH v4 00/15] PM QoS: add a per-device latency constraints class jean.pihet
2011-08-11 15:06 ` [PATCH 01/15] PM QoS: move and rename the implementation files jean.pihet
2011-08-13  2:47   ` mark gross
2011-08-13  2:47   ` mark gross
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 02/15] PM QoS: minor clean-ups jean.pihet
2011-08-13  2:48   ` mark gross
2011-08-13  2:48   ` mark gross
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 03/15] PM QoS: code re-organization jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-13  2:50   ` mark gross
2011-08-13  2:50   ` mark gross
2011-08-11 15:06 ` [PATCH 04/15] PM QoS: re-organize data structs jean.pihet
2011-08-13  2:56   ` mark gross
2011-08-13 20:58     ` Rafael J. Wysocki
2011-08-14  8:29       ` Jean Pihet
2011-08-14  8:29       ` Jean Pihet
2011-08-14 13:34         ` Rafael J. Wysocki
2011-08-14 13:34         ` Rafael J. Wysocki
2011-08-13 20:58     ` Rafael J. Wysocki
2011-08-13  2:56   ` mark gross
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 05/15] PM QoS: generalize and export the constraints management code jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-13  3:09   ` mark gross
2011-08-13 20:34     ` Rafael J. Wysocki
2011-08-14  8:25       ` Jean Pihet
2011-08-14 13:37         ` Rafael J. Wysocki
2011-08-16  4:08           ` mark gross
2011-08-16  4:08           ` mark gross
2011-08-16  6:44             ` Jean Pihet
2011-08-16 17:45               ` mark gross
2011-08-16 18:01                 ` Rafael J. Wysocki
2011-08-16 18:01                 ` Rafael J. Wysocki
2011-08-16 17:45               ` mark gross
2011-08-16  6:44             ` Jean Pihet
2011-08-14 13:37         ` Rafael J. Wysocki
2011-08-14  8:25       ` Jean Pihet
2011-08-13 20:34     ` Rafael J. Wysocki
2011-08-13  3:09   ` mark gross
2011-08-11 15:06 ` [PATCH 06/15] PM QoS: implement the per-device PM QoS constraints jean.pihet
2011-08-13  3:16   ` mark gross
2011-08-13  3:16   ` mark gross
2011-08-13 21:08   ` Rafael J. Wysocki
2011-08-14  8:50     ` Jean Pihet
2011-08-14 13:51       ` Rafael J. Wysocki
2011-08-14 13:51       ` Rafael J. Wysocki
2011-08-14  8:50     ` Jean Pihet [this message]
2011-08-13 21:08   ` Rafael J. Wysocki
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 07/15] PM QoS: add a global notification mechanism for the device constraints jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-14 21:50   ` Rafael J. Wysocki
2011-08-16  9:58     ` Jean Pihet
2011-08-16  9:58     ` Jean Pihet
2011-08-14 21:50   ` Rafael J. Wysocki
2011-08-11 15:06 ` [PATCH 08/15] OMAP: convert I2C driver to PM QoS for latency constraints jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 09/15] OMAP: PM: create a PM layer plugin for per-device constraints jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 10/15] OMAP2+: powerdomain: control power domains next state jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 11/15] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 12/15] OMAP4: " jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 13/15] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 14/15] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-11 15:06 ` [PATCH 15/15] OMAP2+: cpuidle only influences the MPU state jean.pihet
2011-08-11 15:06 ` jean.pihet
2011-08-12  8:02 ` [PATCH v4 00/15] PM QoS: add a per-device latency constraints class Rafael J. Wysocki
2011-08-12 11:56   ` Jean Pihet
2011-08-12 21:56     ` Rafael J. Wysocki
2011-08-12 21:56     ` Rafael J. Wysocki
2011-08-14  8:51       ` Jean Pihet
2011-08-14  8:51       ` Jean Pihet
2011-08-14 13:53         ` Rafael J. Wysocki
2011-08-14 13:53         ` Rafael J. Wysocki
2011-08-12 11:56   ` Jean Pihet
2011-08-12  8:02 ` Rafael J. Wysocki
2011-08-16 13:43 [PATCH v5 00/15] PM QoS: add a per-device latency constraints framework jean.pihet
2011-08-16 13:43 ` [PATCH 06/15] PM QoS: implement the per-device PM QoS constraints jean.pihet
2011-08-16 13:43 ` jean.pihet
2011-08-16 21:40   ` Rafael J. Wysocki
2011-08-16 21:40   ` Rafael J. Wysocki

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='CAORVsuVZjrqY0qhEvCpRRvt5RDcG-YT5SJo6Ejhyr-_fTyk9HQ__13036.3858108923$1313311872$gmane$org@mail.gmail.com' \
    --to=jean.pihet@newoldbits.com \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=j-pihet@ti.com \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=markgross@thegnar.org \
    --cc=rjw@sisk.pl \
    /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.