* Re: [PATCH v11 7/9] libata: expose pm qos flags for ata device
From: Tejun Heo @ 2013-01-07 18:43 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-8-git-send-email-aaron.lu@intel.com>
On Sun, Jan 06, 2013 at 10:48:27AM +0800, Aaron Lu wrote:
> Expose pm qos flags to user space so that user has a chance to disable
> pm features like power off, if he/she has a broken platform or devices
> or simply does not like this pm feature.
>
> This flag is exposed to user space only for ata device or atapi device
> that is zero power capable. For normal atapi device, it will never be
> powered off.
>
> Signed-off-by: Aaron Lu <aaron.lu@intel.com>
> ---
> drivers/ata/libata-acpi.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
> index e832bf6..5b67be3 100644
> --- a/drivers/ata/libata-acpi.c
> +++ b/drivers/ata/libata-acpi.c
> @@ -17,6 +17,7 @@
> #include <linux/pci.h>
> #include <linux/slab.h>
> #include <linux/pm_runtime.h>
> +#include <linux/pm_qos.h>
> #include <scsi/scsi_device.h>
> #include "libata.h"
>
> @@ -1022,6 +1023,8 @@ static void ata_acpi_unregister_power_resource(struct ata_device *dev)
> void ata_acpi_bind(struct ata_device *dev)
> {
> ata_acpi_register_power_resource(dev);
> + if (dev->class == ATA_DEV_ATA || zpodd_dev_enabled(dev))
> + dev_pm_qos_expose_flags(&dev->sdev->sdev_gendev, 0);
> }
Why from ata_acpi_bind()?
--
tejun
^ permalink raw reply
* Re: [PATCH v11 6/9] libata: handle power transition of ODD
From: Tejun Heo @ 2013-01-07 18:42 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-7-git-send-email-aaron.lu@intel.com>
On Sun, Jan 06, 2013 at 10:48:26AM +0800, Aaron Lu wrote:
> +bool zpodd_zpready(struct ata_device *dev)
> +{
> + struct zpodd *zpodd = dev->zpodd;
> + return zpodd->zp_ready;
> +}
> +
> +void zpodd_pre_poweroff(struct ata_device *dev)
> +{
> + struct zpodd *zpodd = dev->zpodd;
> +
> + zpodd->powered_off = true;
> + device_set_run_wake(&dev->sdev->sdev_gendev, true);
> + acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
> +}
> +
> +void zpodd_pre_poweron(struct ata_device *dev)
> +{
> + struct zpodd *zpodd = dev->zpodd;
> +
> + if (zpodd->powered_off) {
> + acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false);
> + device_set_run_wake(&dev->sdev->sdev_gendev, false);
> + }
> +}
> +
> +void zpodd_post_resume(struct ata_device *dev)
> +{
> + struct zpodd *zpodd = dev->zpodd;
> +
> + if (!zpodd->powered_off)
> + return;
> +
> + zpodd->powered_off = false;
> +
> + if (zpodd->from_notify) {
> + zpodd->from_notify = false;
> + if (zpodd->drawer)
> + eject_tray(dev);
> + }
> +
> + zpodd->last_ready = 0;
> + zpodd->zp_ready = false;
> +}
I would really appreciate some comments at least on functions visible
outside zpodd.c. Please add proper function comments explaining what
they're doing to achieve what.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v11 5/9] libata: check zero power ready status for ZPODD
From: Tejun Heo @ 2013-01-07 18:36 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-6-git-send-email-aaron.lu@intel.com>
Hello, Aaron.
On Sun, Jan 06, 2013 at 10:48:25AM +0800, Aaron Lu wrote:
> +/* Check zero power ready status */
> +void zpodd_on_suspend(struct ata_device *dev)
> +{
> + struct zpodd *zpodd = dev->zpodd;
> + unsigned long expires;
> +
> + if (!zpready(dev)) {
> + zpodd->zp_ready = false;
> + zpodd->last_ready = 0;
> + return;
> + }
> +
> + if (!zpodd->last_ready) {
> + zpodd->last_ready = jiffies;
> + return;
> + }
> +
> + expires = zpodd->last_ready +
> + msecs_to_jiffies(zpodd_poweroff_delay * 1000);
> + if (time_before(jiffies, expires))
> + return;
> +
> + zpodd->zp_ready = true;
> +}
Using 0 jiffies as special value is generally considered a bad form.
It should be mostly ok here but it's not like avoiding that is
difficult, so let's please not use 0 jiffies as special value. If you
have to, add another variable zp_sample_cnt or whatever.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v11 4/9] libata: move acpi notification code to zpodd
From: Tejun Heo @ 2013-01-07 18:26 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-5-git-send-email-aaron.lu@intel.com>
On Sun, Jan 06, 2013 at 10:48:24AM +0800, Aaron Lu wrote:
> @@ -7,6 +9,9 @@ struct zpodd {
> bool slot:1;
> bool drawer:1;
>
> + /* The following bits are synchronized by PM core */
> + bool from_notify:1; /* resumed as a result of acpi notification */
> +
> struct ata_device *dev;
> };
So, you can't put bitfields which belong to different synchronization
domains next to each other. They may (and here will) be put into the
same word and RMW cycles may race with each other. Please either use
unsigned integer flags per sync domain or just put them in separate
bools. At any rate, please comment on how RWs are supposed to be
synchronized.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v11 3/9] libata: identify and init ZPODD devices
From: Tejun Heo @ 2013-01-07 18:20 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-4-git-send-email-aaron.lu@intel.com>
On Sun, Jan 06, 2013 at 10:48:23AM +0800, Aaron Lu wrote:
> diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
> index ef01ac0..5aa7322 100644
> --- a/drivers/ata/libata-acpi.c
> +++ b/drivers/ata/libata-acpi.c
> @@ -1063,6 +1063,8 @@ void ata_acpi_bind(struct ata_device *dev)
>
> void ata_acpi_unbind(struct ata_device *dev)
> {
> + if (zpodd_dev_enabled(dev))
> + zpodd_exit(dev);
> ata_acpi_remove_pm_notifier(dev);
> ata_acpi_unregister_power_resource(dev);
> }
Wouldn't it make more sense to invoke zpodd_exit() from
ata_scsi_remove_dev() which is approximate counterpart of
dev_configure?
> +struct zpodd {
> + bool slot:1;
> + bool drawer:1;
> +
> + struct ata_device *dev;
> +};
Field names are usually indented. It would be nice to have a comment
explaining synchronization. Bitfields w/ their implicit RMW ops tend
to make people wonder about what the access rules are.
> +static int run_atapi_cmd(struct ata_device *dev, const char *cdb,
> + unsigned short cdb_len, char *buf, unsigned int buf_len)
> +{
> + struct ata_taskfile tf = {0};
No need for 0. { } is enough and more generic.
> +
> + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
> + tf.command = ATA_CMD_PACKET;
> +
> + if (buf) {
> + tf.protocol = ATAPI_PROT_PIO;
> + tf.lbam = buf_len;
> + } else {
> + tf.protocol = ATAPI_PROT_NODATA;
> + }
> +
> + return ata_exec_internal(dev, &tf, cdb,
> + buf ? DMA_FROM_DEVICE : DMA_NONE, buf, buf_len, 0);
> +}
So, the function name is a bit of misnomer given that ATAPI commands
are not limited to PIO or DMA_FROM_DEVICE. Also, this function ends
up being used twice - once w/ read buffer and once w/o. Do we really
want this function? It's not like exec_internal is difficult to use.
> +/*
> + * Per the spec, only slot type and drawer type ODD can be supported
> + *
> + * Return 0 for slot type, 1 for drawer, -ENODEV for other types or on error.
> + */
Maybe bool odd_has_drawer() is better?
> +static int check_loading_mechanism(struct ata_device *dev)
> +{
> + char buf[16];
> + unsigned int ret;
> + struct rm_feature_desc *desc = (void *)(buf + 8);
> +
> + char cdb[] = { GPCMD_GET_CONFIGURATION,
> + 2, /* only 1 feature descriptor requested */
> + 0, 3, /* 3, removable medium feature */
> + 0, 0, 0,/* reserved */
> + 0, sizeof(buf),
> + 0, 0, 0,
> + };
> +
> + ret = run_atapi_cmd(dev, cdb, sizeof(cdb), buf, sizeof(buf));
> + if (ret)
> + return -ENODEV;
> +
> + if (be16_to_cpu(desc->feature_code) != 3)
> + return -ENODEV;
> +
> + if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
> + return 0; /* slot */
> + else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
> + return 1; /* drawer */
> + else
> + return -ENODEV;
> +}
> +
> +static bool odd_can_poweroff(struct ata_device *ata_dev)
> +{
> + acpi_handle handle;
> + acpi_status status;
> + struct acpi_device *acpi_dev;
> +
> + handle = ata_dev_acpi_handle(ata_dev);
> + if (!handle)
> + return false;
> +
> + status = acpi_bus_get_device(handle, &acpi_dev);
> + if (ACPI_FAILURE(status))
> + return false;
> +
> + return acpi_device_can_poweroff(acpi_dev);
> +}
> +
> +void zpodd_init(struct ata_device *dev)
> +{
> + int ret;
> + struct zpodd *zpodd;
> +
> + if (dev->zpodd)
> + return;
> +
> + if (!odd_can_poweroff(dev))
> + return;
> +
> + if ((ret = check_loading_mechanism(dev)) == -ENODEV)
> + return;
> +
> + zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
> + if (!zpodd)
> + return;
> +
> + if (ret)
> + zpodd->drawer = true;
> + else
> + zpodd->slot = true;
> +
> + zpodd->dev = dev;
> + dev->zpodd = zpodd;
> +}
> +
> +void zpodd_exit(struct ata_device *dev)
> +{
> + kfree(dev->zpodd);
> + dev->zpodd = NULL;
> +}
> diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
> index 7148a58..8cb4372 100644
> --- a/drivers/ata/libata.h
> +++ b/drivers/ata/libata.h
> @@ -230,4 +230,18 @@ static inline void ata_sff_exit(void)
> { }
> #endif /* CONFIG_ATA_SFF */
>
> +/* libata-zpodd.c */
> +#ifdef CONFIG_SATA_ZPODD
> +void zpodd_init(struct ata_device *dev);
> +void zpodd_exit(struct ata_device *dev);
> +static inline bool zpodd_dev_enabled(struct ata_device *dev)
> +{
> + return dev->zpodd ? true : false;
return dev->zpodd or return dev->zpodd != NULL?
Other than the above nits, looks okay to me.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v11 2/9] libata: Add CONFIG_SATA_ZPODD
From: Tejun Heo @ 2013-01-07 18:06 UTC (permalink / raw)
To: Aaron Lu
Cc: Jeff Garzik, James Bottomley, Rafael J. Wysocki, Alan Stern,
Aaron Lu, Jeff Wu, linux-ide, linux-pm, linux-scsi, linux-acpi
In-Reply-To: <1357440509-28108-3-git-send-email-aaron.lu@intel.com>
On Sun, Jan 06, 2013 at 10:48:22AM +0800, Aaron Lu wrote:
> Added a new config CONFIG_SATA_ZPODD, which is used to support
> SATA based zero power ODD(ZPODD), and depends on ATA_ACPI.
>
> Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Maybe just fold this into the next patch? It's rather unconventional
to introduce the config option and makefile changes by themselves.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v6 3/4] block: implement runtime pm strategy
From: Alan Stern @ 2013-01-07 17:21 UTC (permalink / raw)
To: Aaron Lu
Cc: Jens Axboe, Rafael J. Wysocki, James Bottomley, linux-pm,
linux-scsi, linux-kernel, Aaron Lu, Shane Huang
In-Reply-To: <1357461697-4219-4-git-send-email-aaron.lu@intel.com>
On Sun, 6 Jan 2013, Aaron Lu wrote:
> From: Lin Ming <ming.m.lin@intel.com>
>
> When a request is added:
> If device is suspended or is suspending and the request is not a
> PM request, resume the device.
>
> When the last request finishes:
> Call pm_runtime_mark_last_busy() and pm_runtime_autosuspend().
>
> When pick a request:
> If device is resuming/suspending, then only PM request is allowed to go.
> Return NULL for other cases.
>
> [aaron.lu@intel.com: PM request does not involve nr_pending counting]
> [aaron.lu@intel.com: No need to check q->dev]
> [aaron.lu@intel.com: Autosuspend when the last request finished]
> Signed-off-by: Lin Ming <ming.m.lin@intel.com>
> Signed-off-by: Aaron Lu <aaron.lu@intel.com>
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -974,6 +974,40 @@ extern int blk_pre_runtime_suspend(struct request_queue *q);
> extern void blk_post_runtime_suspend(struct request_queue *q, int err);
> extern void blk_pre_runtime_resume(struct request_queue *q);
> extern void blk_post_runtime_resume(struct request_queue *q, int err);
> +
> +static inline void blk_pm_put_request(struct request *rq)
> +{
> + if (!(rq->cmd_flags & REQ_PM) && !--rq->q->nr_pending) {
> + pm_runtime_mark_last_busy(rq->q->dev);
> + pm_runtime_autosuspend(rq->q->dev);
> + }
> +}
> +
> +static inline struct request *blk_pm_peek_request(
> + struct request_queue *q, struct request *rq)
> +{
> + if (q->rpm_status == RPM_SUSPENDED ||
> + (q->rpm_status != RPM_ACTIVE && !(rq->cmd_flags & REQ_PM)))
> + return NULL;
> + else
> + return rq;
> +}
> +
> +static inline void blk_pm_requeue_request(struct request *rq)
> +{
> + if (!(rq->cmd_flags & REQ_PM))
> + rq->q->nr_pending--;
> +}
> +
> +static inline void blk_pm_add_request(struct request_queue *q,
> + struct request *rq)
> +{
> + if (!(rq->cmd_flags & REQ_PM) &&
> + q->nr_pending++ == 0 &&
> + (q->rpm_status == RPM_SUSPENDED ||
> + q->rpm_status == RPM_SUSPENDING))
> + pm_request_resume(q->dev);
> +}
These routines also don't belong in include/linux. And they don't need
to be marked inline.
Alan Stern
^ permalink raw reply
* Re: [PATCH v6 2/4] block: add runtime pm helpers
From: Alan Stern @ 2013-01-07 17:15 UTC (permalink / raw)
To: Aaron Lu
Cc: Jens Axboe, Rafael J. Wysocki, James Bottomley, linux-pm,
linux-scsi, linux-kernel, Aaron Lu, Shane Huang
In-Reply-To: <1357461697-4219-3-git-send-email-aaron.lu@intel.com>
On Sun, 6 Jan 2013, Aaron Lu wrote:
> From: Lin Ming <ming.m.lin@intel.com>
>
> Add runtime pm helper functions:
>
> void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
> - Initialization function for drivers to call.
>
> int blk_pre_runtime_suspend(struct request_queue *q)
> - If any requests are in the queue, return -EBUSY.
> Otherwise set q->rpm_status to RPM_SUSPENDING and return 0.
>
> void blk_post_runtime_suspend(struct request_queue *q, int err)
> - If the suspend succeeded then set q->rpm_status to RPM_SUSPENDED.
> Otherwise set it to RPM_ACTIVE.
>
> void blk_pre_runtime_resume(struct request_queue *q)
> - Set q->rpm_status to RPM_RESUMING.
>
> void blk_post_runtime_resume(struct request_queue *q, int err)
> - If the resume succeeded then set q->rpm_status to RPM_ACTIVE
> and call __blk_run_queue.
> Otherwise set q->rpm_status to RPM_SUSPENDED.
>
> [aaron.lu@intel.com: do not touch last busy in these helper functions]
> Signed-off-by: Lin Ming <ming.m.lin@intel.com>
> Signed-off-by: Aaron Lu <aaron.lu@intel.com>
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -19,6 +19,7 @@
> #include <linux/gfp.h>
> #include <linux/bsg.h>
> #include <linux/smp.h>
> +#include <linux/pm_runtime.h>
This doesn't belong here. Clients of the block layer don't need to
know about pm_runtime.h. Move this #include to block/blk-core.c.
Alan Stern
^ permalink raw reply
* Re: [PATCH v6 0/4] block layer runtime pm
From: Alan Stern @ 2013-01-07 17:11 UTC (permalink / raw)
To: Aaron Lu
Cc: Jens Axboe, Rafael J. Wysocki, James Bottomley, linux-pm,
linux-scsi, linux-kernel, Aaron Lu, Shane Huang
In-Reply-To: <1357461697-4219-1-git-send-email-aaron.lu@intel.com>
On Sun, 6 Jan 2013, Aaron Lu wrote:
> In August 2010, Jens and Alan discussed about "Runtime PM and the block
> layer". http://marc.info/?t=128259108400001&r=1&w=2
> And then Alan has given a detailed implementation guide:
> http://marc.info/?l=linux-scsi&m=133727953625963&w=2
>
> To test:
> # ls -l /sys/block/sda
> /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
>
> # echo 10000 > /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/power/autosuspend_delay_ms
> # echo auto > /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/power/control
> Then you'll see sda is suspended after 10secs idle.
>
> [ 1767.680192] sd 2:0:0:0: [sda] Synchronizing SCSI cache
> [ 1767.680317] sd 2:0:0:0: [sda] Stopping disk
>
> And if you do some IO, it will resume immediately.
> [ 1791.052438] sd 2:0:0:0: [sda] Starting disk
>
> For test, I often set the autosuspend time to 1 second. If you are using
> a GUI, the 10 seconds delay may be too long that the disk can not enter
> runtime suspended state.
>
> Note that sd's runtime suspend callback will dump some kernel messages
> and the syslog daemon will write kernel message to /var/log/messages,
> making the disk instantly resume after suspended. So for test, the
> syslog daemon should better be temporarily stopped.
>
> v6:
> Take over from Lin Ming.
>
> - Instead of put the device into autosuspend state in
> blk_post_runtime_suspend, do it when the last request is finished.
> This can also solve the problem illustrated below:
>
> thread A thread B
> |suspend timer expired |
> | ... ... |a new request comes in,
> | ... ... |blk_pm_add_request
> | ... ... |skip request_resume due to
> | ... ... |q->status is still RPM_ACTIVE
> | rpm_suspend | ... ...
> | scsi_runtime_suspend | ... ...
> | blk_pre_runtime_suspend | ... ...
> | return -EBUSY due to nr_pending | ... ...
> | rpm_suspend done | ... ...
> | | blk_pm_put_request, mark last busy
>
> But no more trigger point, and the device will stay at RPM_ACTIVE state.
> Run pm_runtime_autosuspend after the last request is finished solved
> this problem.
This doesn't look like the best solution, because it involves adding a
nontrivial routine (pm_runtime_autosuspend) to a hot path.
How about this instead? When blk_pre_runtime_suspend returns -EBUSY,
have it do a mark-last-busy. Then rpm_suspend will automatically
reschedule the autosuspend for later.
> - Requests which have the REQ_PM flag should not involve nr_pending
> counting, or we may lose the condition to resume the device:
> Suppose queue is active and nr_pending is 0. Then a REQ_PM request
> comes and nr_pending will be increased to 1, but since the request has
> REQ_PM flag, it will not cause resume. Before it is finished, a normal
> request comes in, and since nr_pending is 1 now, it will not trigger
> the resume of the device either. Bug.
>
> - Do not quiesce the device in scsi bus level runtime suspend callback.
> Since the only reason the device is to be runtime suspended is due to
> no more requests pending for it, quiesce it is pointless.
>
> - Remove scsi_autopm_* from sd_check_events as we are request driven.
>
> - Call blk_pm_runtime_init in scsi_sysfs_initialize_dev, so that we do
> not need to check queue's device in blk_pm_add/put_request.
I think you still need to have that check. After all, the block layer
has other users besides the SCSI stack, and those users don't call
blk_pm_runtime_init.
> - Do not mark last busy and initiate an autosuspend for the device in
> blk_pm_runtime_init function.
>
> - Do not mark last busy and initiate an autosuspend for the device in
> block_post_runtime_resume, as when the request that triggered the
> resume finished, the blk_pm_put_request will mark last busy and
> initiate an autosuspend.
If you make the change that I recommended above then this is still
necessary.
Alan Stern
^ permalink raw reply
* Re: [PATCH 1/2] regulator: add regulator_is_dummy function
From: Mark Brown @ 2013-01-07 13:22 UTC (permalink / raw)
To: Dr. Rainer Kaluscha
Cc: Kevin Liu, linux-pm, linux-mmc, Chris Ball, Marek Szyprowski,
Rainer Kaluscha, Philip Rakity, Zhangfei Gao, Haojian Zhuang,
Chao Xie, Kevin Liu
In-Reply-To: <50EABFFE.9070908@web.de>
[-- Attachment #1: Type: text/plain, Size: 751 bytes --]
On Mon, Jan 07, 2013 at 01:30:54PM +0100, Dr. Rainer Kaluscha wrote:
> The problem is that *only* a dummy regulator is available which
> refuses to do any regulation at all.
> So sdhci/mmc should better behave as no regulator was available at all.
> This may happen if e.g. in a precompiled kernel of some linux distro
> regulator support (including dummy) is enabled but the machine
> running that kernel doesn't have a known hardware regulator. This
> results in sdhci/mmc failing to enable the SD card reader though it
> would work well without regulator support in the kernel.
Production systems should not enable the dummy regulators, it's that
simple. They're a crutch to get things booting but they're going to
cause problems in production.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] regulator: add regulator_is_dummy function
From: Mark Brown @ 2013-01-07 13:18 UTC (permalink / raw)
To: Kevin Liu
Cc: Kevin Liu, linux-pm, linux-mmc, Chris Ball, Marek Szyprowski,
Rainer Kaluscha, Rainer Kaluscha, Philip Rakity, Zhangfei Gao,
Haojian Zhuang, Chao Xie
In-Reply-To: <CADz5_gJvtgwA9c88wZcjQArmKiAtB7CLHvRAxkDNUnNpM8Z8Qg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 576 bytes --]
On Mon, Jan 07, 2013 at 06:36:36AM -0500, Kevin Liu wrote:
> 2013/1/7 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > No, we've been through this repeatedly. Whatever problem you're trying
> > to bodge around is going to be a problem with some real physical
> > regulators too.
> Then the only way is MUST define the regulator rather than let dummy
> regulator handle it, right?
To repeat once again, dummy regulators should never be used in
production. They are purely a crutch to help get boot going - it is
expected that things like this and cpufreq might fail.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] regulator: add regulator_is_dummy function
From: Dr. Rainer Kaluscha @ 2013-01-07 12:30 UTC (permalink / raw)
To: Mark Brown
Cc: Kevin Liu, linux-pm, linux-mmc, Chris Ball, Marek Szyprowski,
Rainer Kaluscha, Philip Rakity, Zhangfei Gao, Haojian Zhuang,
Chao Xie, Kevin Liu
In-Reply-To: <20130107112527.GD4544@opensource.wolfsonmicro.com>
Am 07.01.2013 12:25, schrieb Mark Brown:
> On Mon, Jan 07, 2013 at 01:38:50PM +0800, Kevin Liu wrote:
>> Introduce a regulator_is_dummy function to check whether the
>> regulator is dummy.
>
> No, we've been through this repeatedly. Whatever problem you're trying
> to bodge around is going to be a problem with some real physical
> regulators too.
Though I don't know the previous discussion, this seems a different case to me.
The problem is that *only* a dummy regulator is available which refuses to do any regulation at
all.
So sdhci/mmc should better behave as no regulator was available at all.
This may happen if e.g. in a precompiled kernel of some linux distro regulator support
(including dummy) is enabled but the machine running that kernel doesn't have a known hardware
regulator. This results in sdhci/mmc failing to enable the SD card reader though it would work
well without regulator support in the kernel.
Rainer
^ permalink raw reply
* Re: [PATCH 1/2] regulator: add regulator_is_dummy function
From: Kevin Liu @ 2013-01-07 11:36 UTC (permalink / raw)
To: Mark Brown
Cc: Kevin Liu, linux-pm, linux-mmc, Chris Ball, Marek Szyprowski,
Rainer Kaluscha, Rainer Kaluscha, Philip Rakity, Zhangfei Gao,
Haojian Zhuang, Chao Xie
In-Reply-To: <20130107112527.GD4544@opensource.wolfsonmicro.com>
2013/1/7 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Mon, Jan 07, 2013 at 01:38:50PM +0800, Kevin Liu wrote:
>> Introduce a regulator_is_dummy function to check whether the
>> regulator is dummy.
>
> No, we've been through this repeatedly. Whatever problem you're trying
> to bodge around is going to be a problem with some real physical
> regulators too.
Then the only way is MUST define the regulator rather than let dummy
regulator handle it, right?
^ permalink raw reply
* Re: [PATCH 1/2] regulator: add regulator_is_dummy function
From: Mark Brown @ 2013-01-07 11:25 UTC (permalink / raw)
To: Kevin Liu
Cc: linux-pm, linux-mmc, Chris Ball, Marek Szyprowski,
Rainer Kaluscha, Rainer Kaluscha, Philip Rakity, Zhangfei Gao,
Haojian Zhuang, Chao Xie, Kevin Liu
In-Reply-To: <1357537131-8000-1-git-send-email-kliu5@marvell.com>
[-- Attachment #1: Type: text/plain, Size: 298 bytes --]
On Mon, Jan 07, 2013 at 01:38:50PM +0800, Kevin Liu wrote:
> Introduce a regulator_is_dummy function to check whether the
> regulator is dummy.
No, we've been through this repeatedly. Whatever problem you're trying
to bodge around is going to be a problem with some real physical
regulators too.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] thermal: Add support for thermal sensor for Orion SoC
From: Andrew Lunn @ 2013-01-07 10:16 UTC (permalink / raw)
To: Eduardo Valentin
Cc: Andrew Lunn, linux ARM, iwamatsu, linux-pm, Thomas Petazzoni,
jgunthorpe, Sebastian Hesselbarth, Jason Cooper
In-Reply-To: <50EA9E10.7080605@ti.com>
> OK. Please put me on Cc so I will keep the review.
>
> >We differentiate between the different SoCs by DT. Each has its own
> >.dtsi file and we will put the node into only those which have the
> >hardware.
>
> Ok. That I understand, but my question was more into the difference
> between 88F6282 and 88F6283. Do you need to differentiate those two?
Hi Eduardo
No, there is no need to differentiate between these. As far as the
temperature sensor goes, they are identical. I've been testing on a
88F6282 and Nobuhiro Iwamatsu on a 88F6283.
Andrew
^ permalink raw reply
* Re: [PATCH 1/2] thermal: Add support for thermal sensor for Orion SoC
From: Eduardo Valentin @ 2013-01-07 10:06 UTC (permalink / raw)
To: Andrew Lunn
Cc: linux ARM, iwamatsu, linux-pm, Thomas Petazzoni, jgunthorpe,
Sebastian Hesselbarth, Jason Cooper
In-Reply-To: <50E6F6AA.4000905@lunn.ch>
On 04-01-2013 17:35, Andrew Lunn wrote:
> On 04/01/13 10:40, Eduardo Valentin wrote:
>> Hey Andrew,
>>
>> On 14-12-2012 13:03, Andrew Lunn wrote:
>>> From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
>>>
>>> Some Orion SoC has thermal sensor.
>>> This patch adds support for 88F6282 and 88F6283.
>>>
>>> Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
>>> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>>> ---
>>> .../devicetree/bindings/thermal/orion-thermal.txt | 16 +++
>>> drivers/thermal/Kconfig | 7 ++
>>> drivers/thermal/Makefile | 1 +
>>> drivers/thermal/orion_thermal.c | 133 ++++++++++++++++++++
>>> 4 files changed, 157 insertions(+)
>>> create mode 100644
>>> Documentation/devicetree/bindings/thermal/orion-thermal.txt
>>> create mode 100644 drivers/thermal/orion_thermal.c
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/thermal/orion-thermal.txt
>>> b/Documentation/devicetree/bindings/thermal/orion-thermal.txt
>>> new file mode 100644
>>> index 0000000..5ce925d
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/thermal/orion-thermal.txt
>>> @@ -0,0 +1,16 @@
>>> +* Orion Thermal
>>> +
>>> +This initial version is for Kirkwood 88F8262 & 88F6283 SoCs, however
>>> +it is expected the driver will sometime in the future be expanded to
>>> +also support Dove, using a different compatibility string.
>>> +
>>> +Required properties:
>>> +- compatible : "marvell,kirkwood-thermal"
>>> +- reg : Address range of the thermal registers
>>> +
>>> +Example:
>>> +
>>> + thermal@10078 {
>>> + compatible = "marvell,kirkwood";
>>> + reg = <0x10078 0x4>;
>>> + };
>>
>> How do you differentiate if the SoC has the temperature sensor? On your
>> patch description you are very clear saying that this supports only
>> 88F8262 & 88F6283 SoCs.
>
> Hi Eduardo
>
> Thanks for the comments. I will address them in the next version.
>
OK. Please put me on Cc so I will keep the review.
> We differentiate between the different SoCs by DT. Each has its own
> .dtsi file and we will put the node into only those which have the
> hardware.
Ok. That I understand, but my question was more into the difference
between 88F6282 and 88F6283. Do you need to differentiate those two? Is
there feature set which is specific to one which is not present in the
second ? Because the DT entries you have you won't differentiate them,
besides you don't read any revision register to check the chip version.
That's my point.
>
> Thanks
> Andrew
^ permalink raw reply
* Re: [PATCH v6 4/4] sd: change to auto suspend mode
From: Aaron Lu @ 2013-01-07 9:31 UTC (permalink / raw)
To: Oliver Neukum
Cc: Alan Stern, Jens Axboe, Rafael J. Wysocki, James Bottomley,
linux-pm, linux-scsi, linux-kernel, Aaron Lu, Shane Huang
In-Reply-To: <2040976.slu5Ii8g67@linux-5eaq.site>
On 01/07/2013 05:19 PM, Oliver Neukum wrote:
> On Sunday 06 January 2013 16:41:37 Aaron Lu wrote:
>> From: Lin Ming <ming.m.lin@intel.com>
>>
>> Uses block layer runtime pm helper functions in
>> scsi_runtime_suspend/resume.
>> Remove scsi_autopm_* from sd open/release path and check_events path.
>> And remove the quiesce call in runtime suspend path, as we know there is
>> no request to quiesce for the device.
>
> How does this handle ioctl() ?
The ioctl code will allocate a new request and execute it through block
layer API, which involves adding the request to the queue and releasing
it when it is finished.
Thanks,
Aaron
^ permalink raw reply
* Re: [PATCH 6/9] Thermal: Add Documentation to new APIs
From: Wei Ni @ 2013-01-07 9:28 UTC (permalink / raw)
To: R, Durgadoss
Cc: Zhang, Rui, linux-pm@vger.kernel.org,
linux-kernel@vger.kernel.org, eduardo.valentin@ti.com,
hongbo.zhang@linaro.org
In-Reply-To: <4D68720C2E767A4AA6A8796D42C8EB5925668A@BGSMSX101.gar.corp.intel.com>
On 01/07/2013 04:53 PM, R, Durgadoss wrote:
>> -----Original Message-----
>> From: Wei Ni [mailto:wni@nvidia.com]
>> Sent: Monday, January 07, 2013 2:10 PM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
>> eduardo.valentin@ti.com; hongbo.zhang@linaro.org
>> Subject: Re: [PATCH 6/9] Thermal: Add Documentation to new APIs
>>
>> On 01/07/2013 03:13 PM, Durgadoss R wrote:
>>> This patch adds Documentation for the new APIs
>>> introduced in this patch set. The documentation
>>> also has a model sysfs structure for reference.
>>>
>>> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
>>> ---
>>> Documentation/thermal/sysfs-api2.txt | 248
>> ++++++++++++++++++++++++++++++++++
>>> 1 file changed, 248 insertions(+)
>>> create mode 100644 Documentation/thermal/sysfs-api2.txt
>>>
>>> diff --git a/Documentation/thermal/sysfs-api2.txt
>> b/Documentation/thermal/sysfs-api2.txt
>>> new file mode 100644
>>> index 0000000..ffd0402
>>> --- /dev/null
>>> +++ b/Documentation/thermal/sysfs-api2.txt
>>> @@ -0,0 +1,248 @@
>>> +Thermal Framework
>>> +-----------------
>>> +
>>> +Written by Durgadoss R <durgadoss.r@intel.com>
>>> +Copyright (c) 2012 Intel Corporation
>>> +
>>> +Created on: 4 November 2012
>>> +Updated on: 18 December 2012
>>> +
>>> +0. Introduction
>>> +---------------
>>> +The Linux thermal framework provides a set of interfaces for thermal
>>> +sensors and thermal cooling devices (fan, processor...) to register
>>> +with the thermal management solution and to be a part of it.
>>> +
>>> +This document focuses on how to enable new thermal sensors and
>> cooling
>>> +devices to participate in thermal management. This solution is intended
>>> +to be 'light-weight' and platform/architecture independent. Any thermal
>>> +sensor/cooling device should be able to use the infrastructure easily.
>>> +
>>> +The goal of thermal framework is to expose the thermal sensor/zone and
>>> +cooling device attributes in a consistent way. This will help the
>>> +thermal governors to make use of the information to manage platform
>>> +thermals efficiently.
>>> +
>>> +The thermal sensor source file can be generic (can be any sensor driver,
>>> +in any subsystem). This driver will use the sensor APIs and register with
>>> +thermal framework to participate in platform Thermal management. This
>>> +does not (and should not) know about which zone it belongs to, or any
>>> +other information about platform thermals. A sensor driver is a
>> standalone
>>> +piece of code, which can optionally register with thermal framework.
>>> +
>>> +However, for any platform, there should be a platformX_thermal.c file,
>>> +which will know about the platform thermal characteristics (like how many
>>> +sensors, zones, cooling devices, etc.. And how they are related to each
>> other
>>> +i.e the mapping information). Only in this file, the zone level APIs should
>>> +be used, in which case the file will have all information required to attach
>>> +various sensors to a particular zone.
>>> +
>>> +This way, we can have one platform level thermal file, which can support
>>> +multiple platforms (may be)using the same set of sensors (but)binded in
>>> +a different way. This file can get the platform thermal information
>>> +through Firmware, ACPI tables, device tree etc.
>>> +
>>> +Unfortunately, today we don't have many drivers that can be clearly
>>> +differentiated as 'sensor_file.c' and 'platform_thermal_file.c'.
>>> +But very soon we will need/have. The reason I am saying this is because
>>> +we are seeing a lot of chip drivers, starting to use thermal framework,
>>> +and we should keep it really light-weight for them to do so.
>>> +
>>> +An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
>>> +In one platform this sensor can belong to 'ZoneA' and in another the
>>> +same can belong to 'ZoneB'. But, emc1403.c does not really care about
>>> +where does it belong. It just reports temperature.
>>> +
>>> +1. Terminology
>>> +--------------
>>> +This section describes the terminology used in the rest of this
>>> +document as well as the thermal framework code.
>>> +
>>> +thermal_sensor: Hardware that can report temperature of a particular
>>> + spot in the platform, where it is placed. The temperature
>>> + reported by the sensor is the 'real' temperature reported
>>> + by the hardware.
>>> +thermal_zone: A virtual area on the device, that gets heated up. It may
>>> + have one or more thermal sensors attached to it.
>>> +cooling_device: Any component that can help in reducing the
>> temperature of
>>> + a 'hot spot' either by reducing its performance (passive
>>> + cooling) or by other means(Active cooling E.g. Fan)
>>> +
>>> +trip_points: Various temperature levels for each sensor. As of now, we
>>> + have four levels namely active, passive, hot and critical.
>>> + Hot and critical trip point support only one value whereas
>>> + active and passive can have any number of values. These
>>> + temperature values can come from platform data, and are
>>> + exposed through sysfs in a consistent manner. Stand-alone
>>> + thermal sensor drivers are not expected to know these values.
>>> + These values are RO.
>>> +thresholds: These are programmable temperature limits, on reaching
>> which
>>> + the thermal sensor generates an interrupt. The framework is
>>> + notified about this interrupt to take appropriate action.
>>> + There can be as many number of thresholds as that of the
>>> + hardware supports. These values are RW.
>>
>> Hi,
>> When generate interrupt, we could call something like
>> notify_thermal_framework(), is it right? but it just notify the
>> framework, how to notify the platform driver? I think the platform
>> driver will wish to update the limited values when interrupt occur.
>> Will we have a thermal zone fops like ops.notify()?
>> I noticed there have "struct thermal_zone *ops" in the thermal_zone
>> structure, will it be used for callback?
>
> Yes, you are right. I missed adding a .notify() call back to thermal_zone ops.
> I will wait to see if we get more comments on this version of the patches.
> If so, will fix this in v3. Otherwise, will submit a patch, once these
> patches make it to Rui's tree. Hope this works for you :-)
Got it, thanks :)
Wei.
^ permalink raw reply
* Re: [PATCH v6 4/4] sd: change to auto suspend mode
From: Oliver Neukum @ 2013-01-07 9:19 UTC (permalink / raw)
To: Aaron Lu
Cc: Alan Stern, Jens Axboe, Rafael J. Wysocki, James Bottomley,
linux-pm, linux-scsi, linux-kernel, Aaron Lu, Shane Huang
In-Reply-To: <1357461697-4219-5-git-send-email-aaron.lu@intel.com>
On Sunday 06 January 2013 16:41:37 Aaron Lu wrote:
> From: Lin Ming <ming.m.lin@intel.com>
>
> Uses block layer runtime pm helper functions in
> scsi_runtime_suspend/resume.
> Remove scsi_autopm_* from sd open/release path and check_events path.
> And remove the quiesce call in runtime suspend path, as we know there is
> no request to quiesce for the device.
How does this handle ioctl() ?
Regards
Oliver
^ permalink raw reply
* RE: [PATCH 6/9] Thermal: Add Documentation to new APIs
From: R, Durgadoss @ 2013-01-07 8:53 UTC (permalink / raw)
To: Wei Ni
Cc: Zhang, Rui, linux-pm@vger.kernel.org,
linux-kernel@vger.kernel.org, eduardo.valentin@ti.com,
hongbo.zhang@linaro.org
In-Reply-To: <50EA89FA.6010703@nvidia.com>
> -----Original Message-----
> From: Wei Ni [mailto:wni@nvidia.com]
> Sent: Monday, January 07, 2013 2:10 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org
> Subject: Re: [PATCH 6/9] Thermal: Add Documentation to new APIs
>
> On 01/07/2013 03:13 PM, Durgadoss R wrote:
> > This patch adds Documentation for the new APIs
> > introduced in this patch set. The documentation
> > also has a model sysfs structure for reference.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> > Documentation/thermal/sysfs-api2.txt | 248
> ++++++++++++++++++++++++++++++++++
> > 1 file changed, 248 insertions(+)
> > create mode 100644 Documentation/thermal/sysfs-api2.txt
> >
> > diff --git a/Documentation/thermal/sysfs-api2.txt
> b/Documentation/thermal/sysfs-api2.txt
> > new file mode 100644
> > index 0000000..ffd0402
> > --- /dev/null
> > +++ b/Documentation/thermal/sysfs-api2.txt
> > @@ -0,0 +1,248 @@
> > +Thermal Framework
> > +-----------------
> > +
> > +Written by Durgadoss R <durgadoss.r@intel.com>
> > +Copyright (c) 2012 Intel Corporation
> > +
> > +Created on: 4 November 2012
> > +Updated on: 18 December 2012
> > +
> > +0. Introduction
> > +---------------
> > +The Linux thermal framework provides a set of interfaces for thermal
> > +sensors and thermal cooling devices (fan, processor...) to register
> > +with the thermal management solution and to be a part of it.
> > +
> > +This document focuses on how to enable new thermal sensors and
> cooling
> > +devices to participate in thermal management. This solution is intended
> > +to be 'light-weight' and platform/architecture independent. Any thermal
> > +sensor/cooling device should be able to use the infrastructure easily.
> > +
> > +The goal of thermal framework is to expose the thermal sensor/zone and
> > +cooling device attributes in a consistent way. This will help the
> > +thermal governors to make use of the information to manage platform
> > +thermals efficiently.
> > +
> > +The thermal sensor source file can be generic (can be any sensor driver,
> > +in any subsystem). This driver will use the sensor APIs and register with
> > +thermal framework to participate in platform Thermal management. This
> > +does not (and should not) know about which zone it belongs to, or any
> > +other information about platform thermals. A sensor driver is a
> standalone
> > +piece of code, which can optionally register with thermal framework.
> > +
> > +However, for any platform, there should be a platformX_thermal.c file,
> > +which will know about the platform thermal characteristics (like how many
> > +sensors, zones, cooling devices, etc.. And how they are related to each
> other
> > +i.e the mapping information). Only in this file, the zone level APIs should
> > +be used, in which case the file will have all information required to attach
> > +various sensors to a particular zone.
> > +
> > +This way, we can have one platform level thermal file, which can support
> > +multiple platforms (may be)using the same set of sensors (but)binded in
> > +a different way. This file can get the platform thermal information
> > +through Firmware, ACPI tables, device tree etc.
> > +
> > +Unfortunately, today we don't have many drivers that can be clearly
> > +differentiated as 'sensor_file.c' and 'platform_thermal_file.c'.
> > +But very soon we will need/have. The reason I am saying this is because
> > +we are seeing a lot of chip drivers, starting to use thermal framework,
> > +and we should keep it really light-weight for them to do so.
> > +
> > +An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
> > +In one platform this sensor can belong to 'ZoneA' and in another the
> > +same can belong to 'ZoneB'. But, emc1403.c does not really care about
> > +where does it belong. It just reports temperature.
> > +
> > +1. Terminology
> > +--------------
> > +This section describes the terminology used in the rest of this
> > +document as well as the thermal framework code.
> > +
> > +thermal_sensor: Hardware that can report temperature of a particular
> > + spot in the platform, where it is placed. The temperature
> > + reported by the sensor is the 'real' temperature reported
> > + by the hardware.
> > +thermal_zone: A virtual area on the device, that gets heated up. It may
> > + have one or more thermal sensors attached to it.
> > +cooling_device: Any component that can help in reducing the
> temperature of
> > + a 'hot spot' either by reducing its performance (passive
> > + cooling) or by other means(Active cooling E.g. Fan)
> > +
> > +trip_points: Various temperature levels for each sensor. As of now, we
> > + have four levels namely active, passive, hot and critical.
> > + Hot and critical trip point support only one value whereas
> > + active and passive can have any number of values. These
> > + temperature values can come from platform data, and are
> > + exposed through sysfs in a consistent manner. Stand-alone
> > + thermal sensor drivers are not expected to know these values.
> > + These values are RO.
> > +thresholds: These are programmable temperature limits, on reaching
> which
> > + the thermal sensor generates an interrupt. The framework is
> > + notified about this interrupt to take appropriate action.
> > + There can be as many number of thresholds as that of the
> > + hardware supports. These values are RW.
>
> Hi,
> When generate interrupt, we could call something like
> notify_thermal_framework(), is it right? but it just notify the
> framework, how to notify the platform driver? I think the platform
> driver will wish to update the limited values when interrupt occur.
> Will we have a thermal zone fops like ops.notify()?
> I noticed there have "struct thermal_zone *ops" in the thermal_zone
> structure, will it be used for callback?
Yes, you are right. I missed adding a .notify() call back to thermal_zone ops.
I will wait to see if we get more comments on this version of the patches.
If so, will fix this in v3. Otherwise, will submit a patch, once these
patches make it to Rui's tree. Hope this works for you :-)
Thanks,
Durga
^ permalink raw reply
* Re: [PATCH 6/9] Thermal: Add Documentation to new APIs
From: Wei Ni @ 2013-01-07 8:40 UTC (permalink / raw)
To: Durgadoss R
Cc: rui.zhang@intel.com, linux-pm@vger.kernel.org,
linux-kernel@vger.kernel.org, eduardo.valentin@ti.com,
hongbo.zhang@linaro.org
In-Reply-To: <1357542806-20449-7-git-send-email-durgadoss.r@intel.com>
On 01/07/2013 03:13 PM, Durgadoss R wrote:
> This patch adds Documentation for the new APIs
> introduced in this patch set. The documentation
> also has a model sysfs structure for reference.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
> Documentation/thermal/sysfs-api2.txt | 248 ++++++++++++++++++++++++++++++++++
> 1 file changed, 248 insertions(+)
> create mode 100644 Documentation/thermal/sysfs-api2.txt
>
> diff --git a/Documentation/thermal/sysfs-api2.txt b/Documentation/thermal/sysfs-api2.txt
> new file mode 100644
> index 0000000..ffd0402
> --- /dev/null
> +++ b/Documentation/thermal/sysfs-api2.txt
> @@ -0,0 +1,248 @@
> +Thermal Framework
> +-----------------
> +
> +Written by Durgadoss R <durgadoss.r@intel.com>
> +Copyright (c) 2012 Intel Corporation
> +
> +Created on: 4 November 2012
> +Updated on: 18 December 2012
> +
> +0. Introduction
> +---------------
> +The Linux thermal framework provides a set of interfaces for thermal
> +sensors and thermal cooling devices (fan, processor...) to register
> +with the thermal management solution and to be a part of it.
> +
> +This document focuses on how to enable new thermal sensors and cooling
> +devices to participate in thermal management. This solution is intended
> +to be 'light-weight' and platform/architecture independent. Any thermal
> +sensor/cooling device should be able to use the infrastructure easily.
> +
> +The goal of thermal framework is to expose the thermal sensor/zone and
> +cooling device attributes in a consistent way. This will help the
> +thermal governors to make use of the information to manage platform
> +thermals efficiently.
> +
> +The thermal sensor source file can be generic (can be any sensor driver,
> +in any subsystem). This driver will use the sensor APIs and register with
> +thermal framework to participate in platform Thermal management. This
> +does not (and should not) know about which zone it belongs to, or any
> +other information about platform thermals. A sensor driver is a standalone
> +piece of code, which can optionally register with thermal framework.
> +
> +However, for any platform, there should be a platformX_thermal.c file,
> +which will know about the platform thermal characteristics (like how many
> +sensors, zones, cooling devices, etc.. And how they are related to each other
> +i.e the mapping information). Only in this file, the zone level APIs should
> +be used, in which case the file will have all information required to attach
> +various sensors to a particular zone.
> +
> +This way, we can have one platform level thermal file, which can support
> +multiple platforms (may be)using the same set of sensors (but)binded in
> +a different way. This file can get the platform thermal information
> +through Firmware, ACPI tables, device tree etc.
> +
> +Unfortunately, today we don't have many drivers that can be clearly
> +differentiated as 'sensor_file.c' and 'platform_thermal_file.c'.
> +But very soon we will need/have. The reason I am saying this is because
> +we are seeing a lot of chip drivers, starting to use thermal framework,
> +and we should keep it really light-weight for them to do so.
> +
> +An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
> +In one platform this sensor can belong to 'ZoneA' and in another the
> +same can belong to 'ZoneB'. But, emc1403.c does not really care about
> +where does it belong. It just reports temperature.
> +
> +1. Terminology
> +--------------
> +This section describes the terminology used in the rest of this
> +document as well as the thermal framework code.
> +
> +thermal_sensor: Hardware that can report temperature of a particular
> + spot in the platform, where it is placed. The temperature
> + reported by the sensor is the 'real' temperature reported
> + by the hardware.
> +thermal_zone: A virtual area on the device, that gets heated up. It may
> + have one or more thermal sensors attached to it.
> +cooling_device: Any component that can help in reducing the temperature of
> + a 'hot spot' either by reducing its performance (passive
> + cooling) or by other means(Active cooling E.g. Fan)
> +
> +trip_points: Various temperature levels for each sensor. As of now, we
> + have four levels namely active, passive, hot and critical.
> + Hot and critical trip point support only one value whereas
> + active and passive can have any number of values. These
> + temperature values can come from platform data, and are
> + exposed through sysfs in a consistent manner. Stand-alone
> + thermal sensor drivers are not expected to know these values.
> + These values are RO.
> +thresholds: These are programmable temperature limits, on reaching which
> + the thermal sensor generates an interrupt. The framework is
> + notified about this interrupt to take appropriate action.
> + There can be as many number of thresholds as that of the
> + hardware supports. These values are RW.
Hi,
When generate interrupt, we could call something like
notify_thermal_framework(), is it right? but it just notify the
framework, how to notify the platform driver? I think the platform
driver will wish to update the limited values when interrupt occur.
Will we have a thermal zone fops like ops.notify()?
I noticed there have "struct thermal_zone *ops" in the thermal_zone
structure, will it be used for callback?
Thanks.
Wei.
> +
> +thermal_map: This provides the mapping (aka binding) information between
> + various sensors and cooling devices in a particular zone.
> + Typically, this also comes from platform data; Stand-alone
> + sensor drivers or cooling device drivers are not expected
> + to know these mapping information.
> +
> +2. Thermal framework APIs
> +-------------------------
> +2.1: For Thermal Sensors
> +2.1.1 thermal_sensor_register:
> + This function creates a new sensor directory under /sys/class/thermal/
> + as sensor[0-*]. This API is expected to be called by thermal sensor
> + drivers. These drivers may or may not be in thermal subsystem. This
> + function returns a thermal_sensor structure on success and appropriate
> + error on failure.
> +
> + name: Name of the sensor
> + count: Number of programmable thresholds associated with this sensor
> + devdata: Device private data
> + ops: Thermal sensor callbacks
> + .get_temp: obtain the current temperature of the sensor
> + .get_trend: obtain the trend of the sensor
> + .get_threshold: get a particular threshold temperature
> + .set_threshold: set a particular threshold temperature
> + .get_hyst: get hysteresis value associated with a threshold
> + .set_hyst: set hysteresis value associated with a threshold
> +
> +2.1.2 thermal_sensor_unregister:
> + This function deletes the sensor directory under /sys/class/thermal/
> + for the given sensor. Thermal sensor drivers may call this API
> + during the driver's 'exit' routine.
> +
> + ts: Thermal sensor that has to be unregistered
> +
> +2.1.3 enable_sensor_thresholds:
> + This function creates 'threshold[0-*]' attributes under a particular
> + sensorX directory. These values are RW. This function is called by
> + the sensr driver only if the sensor supports interrupt mechanism.
> +
> + ts: Thermal sensor for which thresholds have to be enabled
> + num_thresholds: Number of thresholds supported by the sensor
> +
> +2.2: For Cooling Devices
> +2.2.1 thermal_cooling_device_register:
> + This function adds a new thermal cooling device (fan/processor/...)
> + to /sys/class/thermal/ folder as cooling_device[0-*]. This function
> + is expected to be called by cooling device drivers that may be
> + present in other subsystems also.
> +
> + name: the cooling device name
> + devdata: device private data
> + ops: thermal cooling devices callbacks
> + .get_max_state: get the Maximum throttle state of the cooling device
> + .get_cur_state: get the Current throttle state of the cooling device
> + .set_cur_state: set the Current throttle state of the cooling device
> +
> +2.2.2 thermal_cooling_device_unregister:
> + This function deletes the given cdev entry form /sys/class/thermal;
> + and also cleans all the symlinks referred from various zones.
> +
> + cdev: Cooling device to be unregistered
> +
> +2.3: For Thermal Zones
> +2.3.1 create_thermal_zone:
> + This function adds a new 'zone' under /sys/class/thermal/
> + directory as zone[0-*]. This zone has at least one thermal
> + sensor and at most MAX_SENSORS_PER_ZONE number of sensors
> + attached to it. Similarly, this zone has at least one cdev
> + and at most MAX_CDEVS_PER_ZONE number of cdevs attached to it.
> + Both the MAX_*_PER_ZONE values are configurable, through
> + Kconfig option(during 'menuconfig').
> +
> + name: Name of the thermal zone
> + devdata: Device private data
> +
> +2.3.2 add_sensor_to_zone
> + This function adds a 'sensorX' entry under /sys/class/thermal/
> + zoneY/ directory. This 'sensorX' is a symlink to the actual
> + sensor entry under /sys/class/thermal/. Correspondingly, the
> + method remove_sensor_from_zone deletes the symlink.
> +
> + tz: thermal zone structure
> + ts: thermal sensor structure
> +
> +2.3.3 add_cdev_to_zone
> + This function adds a 'cdevX' entry under /sys/class/thermal/
> + zoneY/ directory. This 'cdevX' is a symlink to the actual
> + cdev entry under /sys/class/thermal/. Correspondingly, the
> + method remove_cdev_from_zone deletes the symlink.
> +
> + tz: thermal zone structure
> + cdev: thermal cooling device structure
> +
> +2.4 For Thermal Trip
> +2.4.1 add_sensor_trip_info
> + This function adds trip point information for the given sensor,
> + (under a given zone) under /sys/class/thermal/zoneX/thermal_trip/
> + This API creates 4 sysfs attributes namely active, passive, hot,
> + and critical. Each of these hold one or more trip point temperature
> + values, as provided from platform data.
> +
> + tz: thermal zone structure
> + ts: thermal sensor to which the trip points are attached
> + trip: trip point structure. Usually obtained from platform data
> +
> +2.5 For Thermal Map
> +2.5.1 add_map_entry
> + This function adds a 'map[0-*]' sysfs attribute under
> + /sys/class/thermal/zoneX/thermal_map/. Each map holds a space
> + separated list of values, that specify the binding relationship
> + between a sensor and a cdev in the given zone. The map structure
> + is typically obtained as platform data. For example, through
> + ACPI tables, SFI tables, Device tree etc.
> +
> + tz: thermal zone to which a 'map' is being added
> + map: thermal_map structure
> +
> +3. Sysfs attributes structure
> +-----------------------------
> +Thermal sysfs attributes will be represented under /sys/class/thermal.
> +
> +3.1: For Thermal Sensors
> + /sys/class/thermal/sensor[0-*]:
> + |---type: Name of the thermal sensor
> + |---temp_input: Current temperature in mC
> + |---threshold[0-*]: Threshold temperature in mC
> + |---threshold[0-*]_hyst:Optional hysteresis value in mC
> +
> +3.2: For Thermal Cooling Devices
> + /sys/class/thermal/cooling_device[0-*]:
> + |---type: Type of the cooling device
> + |---max_state: Maximum throttle state of the cdev
> + |---cur_state: Current throttle state of the cdev
> +
> +3.3: For Thermal Zones
> + /sys/class/thermal/zone[0-*]:
> + |---name: Name of the thermal
> + |---sensorX: Symlink to ../sensorX
> + |---cdevY: Symlink to ../cdevY
> + |---thermal_trip: trip point values for sensors
> + |---thermal_map: mapping info between sensors and cdevs
> +
> +3.4: For Thermal Trip
> + This attribute represents the trip point values for all sensors
> + present in the thermal zone. All values are in mC.
> + /sys/class/thermal/zoneX/thermal_trip/sensorY:
> + |---hot: hot trip point value
> + |---critical: critical trip point value
> + |---passive: list of passive trip point values
> + |---active: list of active trip point values
> +
> +3.5: For Thermal Map
> + Each attribute represents the mapping/binding information between
> + a sensor and a cdev, together with a trip type.
> + /sys/class/thermal/zoneX/thermal_map/:
> + |---mapX: mapping information
> + A typical map entry is like below:
> +
> + trip_type sensor cdev trip_mask weight(s)
> + passive cpu proc 0x03 50 30
> + active cpu fan0 0x03 50 70
> +
> + The trip mask is a bit string; if 'n' th bit is set, then for
> + trip point 'n' this cdev is throttled with the given weight[n].
> --
> 1.7.9.5
>
^ permalink raw reply
* [PATCH 8/9] Thermal: Add ABI Documentation for sysfs interfaces
From: Durgadoss R @ 2013-01-07 7:13 UTC (permalink / raw)
To: rui.zhang, linux-pm
Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R
In-Reply-To: <1357542806-20449-1-git-send-email-durgadoss.r@intel.com>
This patch adds Documentation for ABI's introduced
for thermal subsystem (under /sys/class/thermal/).
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
Documentation/ABI/testing/sysfs-class-thermal | 93 +++++++++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
diff --git a/Documentation/ABI/testing/sysfs-class-thermal b/Documentation/ABI/testing/sysfs-class-thermal
new file mode 100644
index 0000000..d1a450e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-thermal
@@ -0,0 +1,93 @@
+What: /sys/class/thermal/sensorX/temp
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Exposes 'temperature' of a thermal sensor in mC
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/sensorX/name
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Name of the thermal sensor
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/sensorX/thresholdY
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Programmable threshold (in terms of mC). On reaching
+ this, the thermal governors may take action to control
+ temperature.
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/name
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Name of the thermal zone.
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/sensorY
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Symlink to a sensor associated with this zone.
+Users: User space thermal governors or applications
+
+What: /sys/class/thermal/zoneX/cooling_deviceY
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Symlink to a cooling device associated with this zone.
+Users: User space thermal governors or applications
+
+What: /sys/class/thermal/zoneX/sensorY_trip_active
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Space separated list of active trip points for 'sensorY'
+ in 'zoneX' (in mC).
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/sensorY_trip_passive
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Space separated list of passive trip points for 'sensorY'
+ in 'zoneX' (in mC).
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/sensorY_trip_hot
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Hot trip point for 'sensorY' in 'zoneX' (in mC).
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/sensorY_trip_critical
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Critical trip point for 'sensorY' in 'zoneX' (in mC).
+Users: Kernel/User space thermal governors
+
+What: /sys/class/thermal/zoneX/mapY
+Date: January 2013
+KernelVersion: 3.8
+Contact: Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+ Mapping information between a sensor and a cooling device
+ in 'zoneX'. See Documentation/thermal/sysfs-api2.txt for more
+ information on this interface.
+Users: Kernel/User space thermal governors
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/9] Thermal: Add trip point sysfs nodes for sensor
From: Durgadoss R @ 2013-01-07 7:13 UTC (permalink / raw)
To: rui.zhang, linux-pm
Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R
In-Reply-To: <1357542806-20449-1-git-send-email-durgadoss.r@intel.com>
This patch adds a trip point related sysfs nodes
for each sensor under a zone in /sys/class/thermal/zoneX/.
The nodes will be named, sensorX_trip_active,
sensorX_trip_passive, sensorX_trip_hot, sensorX_trip_critical
for active, passive, hot and critical trip points
respectively for sensorX.
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
drivers/thermal/thermal_sys.c | 211 ++++++++++++++++++++++++++++++++++++++++-
include/linux/thermal.h | 38 +++++++-
2 files changed, 246 insertions(+), 3 deletions(-)
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 332bd61..1958bb8 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -450,6 +450,22 @@ static void thermal_zone_device_check(struct work_struct *work)
thermal_zone_device_update(tz);
}
+static int get_sensor_indx_by_kobj(struct thermal_zone *tz, const char *name)
+{
+ int i, indx = -EINVAL;
+
+ mutex_lock(&sensor_list_lock);
+ for (i = 0; i < tz->sensor_indx; i++) {
+ if (!strnicmp(name, kobject_name(&tz->sensors[i]->device.kobj),
+ THERMAL_NAME_LENGTH)) {
+ indx = i;
+ break;
+ }
+ }
+ mutex_unlock(&sensor_list_lock);
+ return indx;
+}
+
static void remove_sensor_from_zone(struct thermal_zone *tz,
struct thermal_sensor *ts)
{
@@ -461,9 +477,16 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
+ /* Remove trip point attributes associated with this sensor */
+ kfree(tz->trip_attr[indx]);
+ tz->trip_attr[indx] = NULL;
+
/* Shift the entries in the tz->sensors array */
- for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
+ for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++) {
tz->sensors[j] = tz->sensors[j + 1];
+ tz->sensor_trip[j] = tz->sensor_trip[j + 1];
+ tz->trip_attr[j] = tz->trip_attr[j + 1];
+ }
tz->sensor_indx--;
}
@@ -877,6 +900,99 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
return sprintf(buf, "%s\n", tz->governor->name);
}
+static ssize_t
+active_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i, indx, ret = 0;
+ char kobj_name[THERMAL_NAME_LENGTH];
+ struct thermal_zone *tz = to_zone(dev);
+
+ if (!sscanf(attr->attr.name, "sensor%d_trip_active", &i))
+ return -EINVAL;
+
+ snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
+ indx = get_sensor_indx_by_kobj(tz, kobj_name);
+ if (indx < 0)
+ return indx;
+
+ if (tz->sensor_trip[indx]->num_active_trips <= 0)
+ return sprintf(buf, "<Not available>\n");
+
+ ret += sprintf(buf, "0x%x", tz->sensor_trip[indx]->active_trip_mask);
+ for (i = 0; i < tz->sensor_trip[indx]->num_active_trips; i++) {
+ ret += sprintf(buf + ret, " %d",
+ tz->sensor_trip[indx]->active_trips[i]);
+ }
+
+ ret += sprintf(buf + ret, "\n");
+ return ret;
+}
+
+static ssize_t
+ptrip_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i, indx, ret = 0;
+ char kobj_name[THERMAL_NAME_LENGTH];
+ struct thermal_zone *tz = to_zone(dev);
+
+ if (!sscanf(attr->attr.name, "sensor%d_trip_passive", &i))
+ return -EINVAL;
+
+ snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
+ indx = get_sensor_indx_by_kobj(tz, kobj_name);
+ if (indx < 0)
+ return indx;
+
+ if (tz->sensor_trip[indx]->num_passive_trips <= 0)
+ return sprintf(buf, "<Not available>\n");
+
+ for (i = 0; i < tz->sensor_trip[indx]->num_passive_trips; i++) {
+ ret += sprintf(buf + ret, "%d ",
+ tz->sensor_trip[indx]->passive_trips[i]);
+ }
+
+ ret += sprintf(buf + ret, "\n");
+ return ret;
+}
+
+static ssize_t
+hot_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int indx;
+ char kobj_name[THERMAL_NAME_LENGTH];
+ struct thermal_zone *tz = to_zone(dev);
+
+ if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
+ return -EINVAL;
+
+ snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
+
+ indx = get_sensor_indx_by_kobj(tz, kobj_name);
+ if (indx < 0)
+ return indx;
+
+ return sprintf(buf, "%d\n", tz->sensor_trip[indx]->hot);
+}
+
+static ssize_t
+critical_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int indx;
+ char kobj_name[THERMAL_NAME_LENGTH];
+ struct thermal_zone *tz = to_zone(dev);
+
+ if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
+ return -EINVAL;
+
+ snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
+
+ indx = get_sensor_indx_by_kobj(tz, kobj_name);
+ if (indx < 0)
+ return indx;
+
+ return sprintf(buf, "%d\n", tz->sensor_trip[indx]->crit);
+}
+
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(temp, 0444, temp_show, NULL);
static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
@@ -887,7 +1003,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
-static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
+/* Thermal zone attributes */
+static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
/* sys I/F for cooling device */
#define to_cooling_device(_dev) \
@@ -1742,6 +1859,38 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
return 0;
}
+static int create_sensor_trip_attrs(struct thermal_zone *tz,
+ struct thermal_trip_attr *attr, int indx)
+{
+ int i, ret;
+ static const char *const names[NUM_TRIP_TYPES] = {
+ "sensor%d_trip_active",
+ "sensor%d_trip_passive",
+ "sensor%d_trip_hot",
+ "sensor%d_trip_critical",
+ };
+ static ssize_t (*const rd_ptr[NUM_TRIP_TYPES]) (struct device *dev,
+ struct device_attribute *devattr, char *buf) = {
+ active_show, ptrip_show, hot_show, critical_show};
+
+ for (i = 0; i < NUM_TRIP_TYPES; i++) {
+ snprintf(attr->attrs[i].name, THERMAL_NAME_LENGTH, names[i],
+ indx);
+ sysfs_attr_init(&attr->attrs[i].attr.attr);
+ attr->attrs[i].attr.attr.name = attr->attrs[i].name;
+ attr->attrs[i].attr.attr.mode = S_IRUGO;
+ attr->attrs[i].attr.show = rd_ptr[i];
+ ret = device_create_file(&tz->device, &attr->attrs[i].attr);
+ if (ret)
+ goto exit;
+ }
+ return 0;
+exit:
+ while (--i >= 0)
+ device_remove_file(&tz->device, &attr->attrs[i].attr);
+ return ret;
+}
+
struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
{
struct thermal_zone *tz;
@@ -1791,6 +1940,7 @@ EXPORT_SYMBOL(create_thermal_zone);
void remove_thermal_zone(struct thermal_zone *tz)
{
struct thermal_zone *pos, *next;
+ int i;
bool found = false;
if (!tz)
@@ -1811,6 +1961,23 @@ void remove_thermal_zone(struct thermal_zone *tz)
device_remove_file(&tz->device, &dev_attr_zone_name);
+ /* Just for ease of usage */
+ i = tz->sensor_indx;
+ while (--i >= 0) {
+ /* Remove /sys/class/thermal/zoneX/sensorY */
+ sysfs_remove_link(&tz->device.kobj,
+ kobject_name(&tz->sensors[i]->device.kobj));
+ kfree(tz->trip_attr[i]);
+ }
+
+ /* Release the cdevs attached to this zone */
+ i = tz->cdev_indx;
+ while (--i >= 0) {
+ /* Remove /sys/class/thermal/zoneX/cooling_deviceY */
+ sysfs_remove_link(&tz->device.kobj,
+ kobject_name(&tz->cdevs[i]->device.kobj));
+ }
+
release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
@@ -1922,6 +2089,46 @@ exit_zone:
}
EXPORT_SYMBOL(add_cdev_to_zone);
+int add_sensor_trip_info(struct thermal_zone *tz, struct thermal_sensor *ts,
+ struct thermal_trip_point *trip)
+{
+ int ret, indx, kobj_indx;
+
+ if (!tz || !ts || !trip)
+ return -EINVAL;
+
+ if (!sscanf(kobject_name(&ts->device.kobj), "sensor%d", &kobj_indx))
+ return -EINVAL;
+
+ mutex_lock(&zone_list_lock);
+
+ indx = GET_INDEX(tz, ts, sensor);
+ if (indx < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ tz->trip_attr[indx] = kzalloc(sizeof(struct thermal_trip_attr),
+ GFP_KERNEL);
+ if (!tz->trip_attr[indx]) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = create_sensor_trip_attrs(tz, tz->trip_attr[indx], kobj_indx);
+ if (ret) {
+ kfree(tz->trip_attr[indx]);
+ goto exit;
+ }
+
+ tz->sensor_trip[indx] = trip;
+
+exit:
+ mutex_unlock(&zone_list_lock);
+ return ret;
+}
+EXPORT_SYMBOL(add_sensor_trip_info);
+
/**
* thermal_sensor_register - register a new thermal sensor
* @name: name of the thermal sensor
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 12cc953..474547d 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -31,7 +31,8 @@
#define THERMAL_TRIPS_NONE -1
#define THERMAL_MAX_TRIPS 12
-#define THERMAL_NAME_LENGTH 20
+#define THERMAL_NAME_LENGTH 22
+#define NUM_TRIP_TYPES 4
/* No upper/lower limit requirement */
#define THERMAL_NO_LIMIT -1UL
@@ -158,6 +159,34 @@ struct thermal_attr {
char name[THERMAL_NAME_LENGTH];
};
+/*
+ * This structure defines the trip points for a sensor.
+ * The actual values for these trip points come from
+ * platform characterization. The thermal governors
+ * (either kernel or user space) may take appropriate
+ * actions when the sensors reach these trip points.
+ * See Documentation/thermal/sysfs-api2.txt for more details.
+ *
+ * As of now, For a particular sensor, we support:
+ * a) 1 hot trip point
+ * b) 1 critical trip point
+ * c) 'n' passive trip points
+ * d) 'm' active trip points
+ */
+struct thermal_trip_point {
+ int hot;
+ int crit;
+ int num_passive_trips;
+ int *passive_trips;
+ int num_active_trips;
+ int *active_trips;
+ int active_trip_mask;
+};
+
+struct thermal_trip_attr {
+ struct thermal_attr attrs[NUM_TRIP_TYPES];
+};
+
struct thermal_sensor {
char name[THERMAL_NAME_LENGTH];
int id;
@@ -215,6 +244,10 @@ struct thermal_zone {
/* cdev level information */
int cdev_indx; /* index into 'cdevs' array */
struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
+
+ /* Thermal sensors trip information */
+ struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
+ struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
};
/* Structure that holds thermal governor information */
@@ -297,6 +330,9 @@ struct thermal_sensor *get_sensor_by_name(const char *);
int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
struct thermal_cooling_device *get_cdev_by_name(const char *);
+int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
+ struct thermal_trip_point *);
+
#ifdef CONFIG_NET
extern int thermal_generate_netlink_event(u32 orig, enum events event);
#else
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/9] Thermal: Add APIs to bind cdev to new zone structure
From: Durgadoss R @ 2013-01-07 7:13 UTC (permalink / raw)
To: rui.zhang, linux-pm
Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R
In-Reply-To: <1357542806-20449-1-git-send-email-durgadoss.r@intel.com>
This patch creates new APIs to add/remove a
cdev to/from a zone. This patch does not change
the old cooling device implementation.
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
drivers/thermal/thermal_sys.c | 80 +++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 9 +++++
2 files changed, 89 insertions(+)
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 513b0fc..332bd61 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -58,6 +58,7 @@ static LIST_HEAD(thermal_governor_list);
static DEFINE_MUTEX(thermal_list_lock);
static DEFINE_MUTEX(sensor_list_lock);
static DEFINE_MUTEX(zone_list_lock);
+static DEFINE_MUTEX(cdev_list_lock);
static DEFINE_MUTEX(thermal_governor_lock);
#define for_each_thermal_sensor(pos) \
@@ -84,6 +85,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
ret; \
})
+#define for_each_cdev(pos) \
+ list_for_each_entry(pos, &thermal_cdev_list, node)
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
@@ -464,6 +468,24 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
tz->sensor_indx--;
}
+static void remove_cdev_from_zone(struct thermal_zone *tz,
+ struct thermal_cooling_device *cdev)
+{
+ int j, indx;
+
+ indx = GET_INDEX(tz, cdev, cdev);
+ if (indx < 0)
+ return;
+
+ sysfs_remove_link(&tz->device.kobj, kobject_name(&cdev->device.kobj));
+
+ /* Shift the entries in the tz->cdevs array */
+ for (j = indx; j < MAX_CDEVS_PER_ZONE - 1; j++)
+ tz->cdevs[j] = tz->cdevs[j + 1];
+
+ tz->cdev_indx--;
+}
+
/* sys I/F for thermal zone */
#define to_thermal_zone(_dev) \
@@ -1460,6 +1482,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
int i;
const struct thermal_zone_params *tzp;
struct thermal_zone_device *tz;
+ struct thermal_zone *tmp_tz;
struct thermal_cooling_device *pos = NULL;
if (!cdev)
@@ -1497,6 +1520,13 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
mutex_unlock(&thermal_list_lock);
+ mutex_lock(&zone_list_lock);
+
+ for_each_thermal_zone(tmp_tz)
+ remove_cdev_from_zone(tmp_tz, cdev);
+
+ mutex_unlock(&zone_list_lock);
+
if (cdev->type[0])
device_remove_file(&cdev->device, &dev_attr_cdev_type);
device_remove_file(&cdev->device, &dev_attr_max_state);
@@ -1792,6 +1822,23 @@ exit:
}
EXPORT_SYMBOL(remove_thermal_zone);
+struct thermal_cooling_device *get_cdev_by_name(const char *name)
+{
+ struct thermal_cooling_device *pos;
+ struct thermal_cooling_device *cdev = NULL;
+
+ mutex_lock(&cdev_list_lock);
+ for_each_cdev(pos) {
+ if (!strnicmp(pos->type, name, THERMAL_NAME_LENGTH)) {
+ cdev = pos;
+ break;
+ }
+ }
+ mutex_unlock(&cdev_list_lock);
+ return cdev;
+}
+EXPORT_SYMBOL(get_cdev_by_name);
+
struct thermal_sensor *get_sensor_by_name(const char *name)
{
struct thermal_sensor *pos;
@@ -1842,6 +1889,39 @@ exit_zone:
}
EXPORT_SYMBOL(add_sensor_to_zone);
+int add_cdev_to_zone(struct thermal_zone *tz,
+ struct thermal_cooling_device *cdev)
+{
+ int ret;
+
+ if (!tz || !cdev)
+ return -EINVAL;
+
+ mutex_lock(&zone_list_lock);
+
+ /* Ensure we are not adding the same cdev again!! */
+ ret = GET_INDEX(tz, cdev, cdev);
+ if (ret >= 0) {
+ ret = -EEXIST;
+ goto exit_zone;
+ }
+
+ mutex_lock(&cdev_list_lock);
+ ret = sysfs_create_link(&tz->device.kobj, &cdev->device.kobj,
+ kobject_name(&cdev->device.kobj));
+ if (ret)
+ goto exit_cdev;
+
+ tz->cdevs[tz->cdev_indx++] = cdev;
+
+exit_cdev:
+ mutex_unlock(&cdev_list_lock);
+exit_zone:
+ mutex_unlock(&zone_list_lock);
+ return ret;
+}
+EXPORT_SYMBOL(add_cdev_to_zone);
+
/**
* thermal_sensor_register - register a new thermal sensor
* @name: name of the thermal sensor
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f5b9540..12cc953 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -51,6 +51,8 @@
#define MAX_SENSORS_PER_ZONE 5
+#define MAX_CDEVS_PER_ZONE 5
+
struct thermal_sensor;
struct thermal_zone_device;
struct thermal_cooling_device;
@@ -209,6 +211,10 @@ struct thermal_zone {
/* Sensor level information */
int sensor_indx; /* index into 'sensors' array */
struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
+
+ /* cdev level information */
+ int cdev_indx; /* index into 'cdevs' array */
+ struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
};
/* Structure that holds thermal governor information */
@@ -288,6 +294,9 @@ void remove_thermal_zone(struct thermal_zone *);
int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
struct thermal_sensor *get_sensor_by_name(const char *);
+int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
+struct thermal_cooling_device *get_cdev_by_name(const char *);
+
#ifdef CONFIG_NET
extern int thermal_generate_netlink_event(u32 orig, enum events event);
#else
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/9] Thermal: Create zone level APIs
From: Durgadoss R @ 2013-01-07 7:13 UTC (permalink / raw)
To: rui.zhang, linux-pm
Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R
In-Reply-To: <1357542806-20449-1-git-send-email-durgadoss.r@intel.com>
This patch adds a new thermal_zone structure to
thermal.h. Also, adds zone level APIs to the thermal
framework.
A thermal zone is a hot spot on the platform, which
can have one or more sensors and cooling devices attached
to it. These sensors can be mapped to a set of cooling
devices, which when throttled, can help to bring down
the temperature of the hot spot.
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
drivers/thermal/thermal_sys.c | 196 +++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 22 +++++
2 files changed, 218 insertions(+)
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index b2becb9..513b0fc 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -44,19 +44,46 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_zone_idr);
static DEFINE_IDR(thermal_cdev_idr);
static DEFINE_IDR(thermal_sensor_idr);
static DEFINE_MUTEX(thermal_idr_lock);
static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_sensor_list);
+static LIST_HEAD(thermal_zone_list);
static LIST_HEAD(thermal_cdev_list);
static LIST_HEAD(thermal_governor_list);
static DEFINE_MUTEX(thermal_list_lock);
static DEFINE_MUTEX(sensor_list_lock);
+static DEFINE_MUTEX(zone_list_lock);
static DEFINE_MUTEX(thermal_governor_lock);
+#define for_each_thermal_sensor(pos) \
+ list_for_each_entry(pos, &thermal_sensor_list, node)
+
+#define for_each_thermal_zone(pos) \
+ list_for_each_entry(pos, &thermal_zone_list, node)
+
+#define GET_INDEX(tz, ptr, type) \
+({ \
+ int i, ret = -EINVAL; \
+ do { \
+ if (!tz || !ptr) \
+ break; \
+ mutex_lock(&type##_list_lock); \
+ for (i = 0; i < tz->type##_indx; i++) { \
+ if (tz->type##s[i] == ptr) { \
+ ret = i; \
+ break; \
+ } \
+ } \
+ mutex_unlock(&type##_list_lock); \
+ } while (0); \
+ ret; \
+})
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
@@ -419,15 +446,44 @@ static void thermal_zone_device_check(struct work_struct *work)
thermal_zone_device_update(tz);
}
+static void remove_sensor_from_zone(struct thermal_zone *tz,
+ struct thermal_sensor *ts)
+{
+ int j, indx;
+
+ indx = GET_INDEX(tz, ts, sensor);
+ if (indx < 0)
+ return;
+
+ sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
+
+ /* Shift the entries in the tz->sensors array */
+ for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
+ tz->sensors[j] = tz->sensors[j + 1];
+
+ tz->sensor_indx--;
+}
+
/* sys I/F for thermal zone */
#define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device)
+#define to_zone(_dev) \
+ container_of(_dev, struct thermal_zone, device)
+
#define to_thermal_sensor(_dev) \
container_of(_dev, struct thermal_sensor, device)
static ssize_t
+zone_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_zone *tz = to_zone(dev);
+
+ return sprintf(buf, "%s\n", tz->name);
+}
+
+static ssize_t
sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_sensor *ts = to_thermal_sensor(dev);
@@ -809,6 +865,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
+static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
+
/* sys I/F for cooling device */
#define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device)
@@ -1654,6 +1712,136 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
return 0;
}
+struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
+{
+ struct thermal_zone *tz;
+ int ret;
+
+ if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
+ return ERR_PTR(-EINVAL);
+
+ tz = kzalloc(sizeof(*tz), GFP_KERNEL);
+ if (!tz)
+ return ERR_PTR(-ENOMEM);
+
+ idr_init(&tz->idr);
+ ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
+ if (ret)
+ goto exit_free;
+
+ strcpy(tz->name, name);
+ tz->devdata = devdata;
+ tz->device.class = &thermal_class;
+
+ dev_set_name(&tz->device, "zone%d", tz->id);
+ ret = device_register(&tz->device);
+ if (ret)
+ goto exit_idr;
+
+ ret = device_create_file(&tz->device, &dev_attr_zone_name);
+ if (ret)
+ goto exit_unregister;
+
+ /* Add this zone to the global list of thermal zones */
+ mutex_lock(&zone_list_lock);
+ list_add_tail(&tz->node, &thermal_zone_list);
+ mutex_unlock(&zone_list_lock);
+ return tz;
+
+exit_unregister:
+ device_unregister(&tz->device);
+exit_idr:
+ release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+exit_free:
+ kfree(tz);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(create_thermal_zone);
+
+void remove_thermal_zone(struct thermal_zone *tz)
+{
+ struct thermal_zone *pos, *next;
+ bool found = false;
+
+ if (!tz)
+ return;
+
+ mutex_lock(&zone_list_lock);
+
+ list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
+ if (pos == tz) {
+ list_del(&tz->node);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ goto exit;
+
+ device_remove_file(&tz->device, &dev_attr_zone_name);
+
+ release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+ idr_destroy(&tz->idr);
+
+ device_unregister(&tz->device);
+ kfree(tz);
+exit:
+ mutex_unlock(&zone_list_lock);
+ return;
+}
+EXPORT_SYMBOL(remove_thermal_zone);
+
+struct thermal_sensor *get_sensor_by_name(const char *name)
+{
+ struct thermal_sensor *pos;
+ struct thermal_sensor *ts = NULL;
+
+ mutex_lock(&sensor_list_lock);
+ for_each_thermal_sensor(pos) {
+ if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
+ ts = pos;
+ break;
+ }
+ }
+ mutex_unlock(&sensor_list_lock);
+ return ts;
+}
+EXPORT_SYMBOL(get_sensor_by_name);
+
+int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+ int ret;
+
+ if (!tz || !ts)
+ return -EINVAL;
+
+ mutex_lock(&zone_list_lock);
+
+ /* Ensure we are not adding the same sensor again!! */
+ ret = GET_INDEX(tz, ts, sensor);
+ if (ret >= 0) {
+ ret = -EEXIST;
+ goto exit_zone;
+ }
+
+ mutex_lock(&sensor_list_lock);
+
+ ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
+ kobject_name(&ts->device.kobj));
+ if (ret)
+ goto exit_sensor;
+
+ tz->sensors[tz->sensor_indx++] = ts;
+
+exit_sensor:
+ mutex_unlock(&sensor_list_lock);
+exit_zone:
+ mutex_unlock(&zone_list_lock);
+ return ret;
+}
+EXPORT_SYMBOL(add_sensor_to_zone);
+
/**
* thermal_sensor_register - register a new thermal sensor
* @name: name of the thermal sensor
@@ -1730,6 +1918,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
void thermal_sensor_unregister(struct thermal_sensor *ts)
{
int i;
+ struct thermal_zone *tz;
struct thermal_sensor *pos, *next;
bool found = false;
@@ -1749,6 +1938,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
if (!found)
return;
+ mutex_lock(&zone_list_lock);
+
+ for_each_thermal_zone(tz)
+ remove_sensor_from_zone(tz, ts);
+
+ mutex_unlock(&zone_list_lock);
+
for (i = 0; i < ts->thresholds; i++) {
device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
if (ts->ops->get_hyst) {
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a49cb38..f5b9540 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -49,6 +49,8 @@
/* Default Thermal Governor: Does Linear Throttling */
#define DEFAULT_THERMAL_GOVERNOR "step_wise"
+#define MAX_SENSORS_PER_ZONE 5
+
struct thermal_sensor;
struct thermal_zone_device;
struct thermal_cooling_device;
@@ -194,6 +196,21 @@ struct thermal_zone_device {
struct delayed_work poll_queue;
};
+struct thermal_zone {
+ char name[THERMAL_NAME_LENGTH];
+ int id;
+ void *devdata;
+ struct thermal_zone *ops;
+ struct thermal_governor *governor;
+ struct idr idr;
+ struct device device;
+ struct list_head node;
+
+ /* Sensor level information */
+ int sensor_indx; /* index into 'sensors' array */
+ struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
+};
+
/* Structure that holds thermal governor information */
struct thermal_governor {
char name[THERMAL_NAME_LENGTH];
@@ -266,6 +283,11 @@ struct thermal_sensor *thermal_sensor_register(const char *, int,
struct thermal_sensor_ops *, void *);
void thermal_sensor_unregister(struct thermal_sensor *);
+struct thermal_zone *create_thermal_zone(const char *, void *);
+void remove_thermal_zone(struct thermal_zone *);
+int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
+struct thermal_sensor *get_sensor_by_name(const char *);
+
#ifdef CONFIG_NET
extern int thermal_generate_netlink_event(u32 orig, enum events event);
#else
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox