Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH 07/13] intel_rapl: cleanup some functions
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

Previously, there are three functions:
rapl_register_psys(), which registers platform rapl domain.
rapl_register_powercap(), which registers powercap control type.
rapl_unregsiter_powercap(), which unregisters platform rapl domain and
powercap control type.

This is confusing as the function name does not describe what it does
clearly.

With this patch, the three functions are removed, and two new functions
rapl_register_platform_domain()/rapl_unregister_platform_domain() are
introduced instead, and they do exactly what their function name describes.

Plus, as part of the common code, hardcoded MSR accesses in these functions
are converted to follow the abstracted register access.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 62 +++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 7dc9965..fbf91dd5 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -1051,16 +1051,6 @@ static void rapl_update_domain_data(struct rapl_package *rp)
 
 }
 
-static void rapl_unregister_powercap(void)
-{
-	if (&rapl_msr_priv.platform_rapl_domain) {
-		powercap_unregister_zone(rapl_msr_priv.control_type,
-					 &rapl_msr_priv.platform_rapl_domain->power_zone);
-		kfree(rapl_msr_priv.platform_rapl_domain);
-	}
-	powercap_unregister_control_type(rapl_msr_priv.control_type);
-}
-
 static int rapl_package_register_powercap(struct rapl_package *rp)
 {
 	struct rapl_domain *rd;
@@ -1130,16 +1120,23 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
 	return ret;
 }
 
-static int __init rapl_register_psys(void)
+static int __init rapl_add_platform_domain(struct rapl_priv *priv)
 {
 	struct rapl_domain *rd;
 	struct powercap_zone *power_zone;
-	u64 val;
+	struct reg_action ra;
+	int ret;
 
-	if (rdmsrl_safe_on_cpu(0, rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS], &val) || !val)
+	ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
+	ra.mask = ~0;
+	ret = priv->read_raw(0, &ra);
+	if (ret || !ra.value)
 		return -ENODEV;
 
-	if (rdmsrl_safe_on_cpu(0, rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT], &val) || !val)
+	ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+	ra.mask = ~0;
+	ret = priv->read_raw(0, &ra);
+	if (ret || !ra.value)
 		return -ENODEV;
 
 	rd = kzalloc(sizeof(*rd), GFP_KERNEL);
@@ -1148,15 +1145,15 @@ static int __init rapl_register_psys(void)
 
 	rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
 	rd->id = RAPL_DOMAIN_PLATFORM;
-	rd->regs[RAPL_DOMAIN_REG_LIMIT] = rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
-	rd->regs[RAPL_DOMAIN_REG_STATUS] = rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
+	rd->regs[RAPL_DOMAIN_REG_LIMIT] = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+	rd->regs[RAPL_DOMAIN_REG_STATUS] = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
 	rd->rpl[0].prim_id = PL1_ENABLE;
 	rd->rpl[0].name = pl1_name;
 	rd->rpl[1].prim_id = PL2_ENABLE;
 	rd->rpl[1].name = pl2_name;
-	rd->rp = rapl_find_package_domain(0, &rapl_msr_priv);
+	rd->rp = rapl_find_package_domain(0, priv);
 
-	power_zone = powercap_register_zone(&rd->power_zone, rapl_msr_priv.control_type,
+	power_zone = powercap_register_zone(&rd->power_zone, priv->control_type,
 					    "psys", NULL,
 					    &zone_ops[RAPL_DOMAIN_PLATFORM],
 					    2, &constraint_ops);
@@ -1166,19 +1163,18 @@ static int __init rapl_register_psys(void)
 		return PTR_ERR(power_zone);
 	}
 
-	rapl_msr_priv.platform_rapl_domain = rd;
+	priv->platform_rapl_domain = rd;
 
 	return 0;
 }
 
-static int __init rapl_register_powercap(void)
+static void rapl_remove_platform_domain(struct rapl_priv *priv)
 {
-	rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
-	if (IS_ERR(rapl_msr_priv.control_type)) {
-		pr_debug("failed to register powercap control_type.\n");
-		return PTR_ERR(rapl_msr_priv.control_type);
+	if (priv->platform_rapl_domain) {
+		powercap_unregister_zone(priv->control_type,
+			&priv->platform_rapl_domain->power_zone);
+		kfree(priv->platform_rapl_domain);
 	}
-	return 0;
 }
 
 static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
@@ -1526,9 +1522,12 @@ static int __init rapl_init(void)
 
 	rapl_msr_priv.read_raw = rapl_msr_read_raw;
 	rapl_msr_priv.write_raw = rapl_msr_write_raw;
-	ret = rapl_register_powercap();
-	if (ret)
-		return ret;
+
+	rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
+	if (IS_ERR(rapl_msr_priv.control_type)) {
+		pr_debug("failed to register powercap control_type.\n");
+		return PTR_ERR(rapl_msr_priv.control_type);
+	}
 
 	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
 				rapl_cpu_online, rapl_cpu_down_prep);
@@ -1537,7 +1536,7 @@ static int __init rapl_init(void)
 	rapl_msr_priv.pcap_rapl_online = ret;
 
 	/* Don't bail out if PSys is not supported */
-	rapl_register_psys();
+	rapl_add_platform_domain(&rapl_msr_priv);
 
 	ret = register_pm_notifier(&rapl_pm_notifier);
 	if (ret)
@@ -1549,7 +1548,7 @@ static int __init rapl_init(void)
 	cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
 
 err_unreg:
-	rapl_unregister_powercap();
+	powercap_unregister_control_type(rapl_msr_priv.control_type);
 	return ret;
 }
 
@@ -1557,7 +1556,8 @@ static void __exit rapl_exit(void)
 {
 	unregister_pm_notifier(&rapl_pm_notifier);
 	cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
-	rapl_unregister_powercap();
+	rapl_remove_platform_domain(&rapl_msr_priv);
+	powercap_unregister_control_type(rapl_msr_priv.control_type);
 }
 
 module_init(rapl_init);
-- 
2.7.4


^ permalink raw reply related

* [PATCH 06/13] intel_rapl: abstract register access operations
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

MSR and MMIO RAPL interfaces have different ways to access the registers,
thus in order to abstract the regsiter access operations, two callbacks,
.read_raw()/.write_raw() are introduced, and they should be implemented by
MSR RAPL and MMIO RAPL interface driver respectly.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 111 ++++++++++++++++++++++--------------------
 include/linux/intel_rapl.h    |   9 ++++
 2 files changed, 67 insertions(+), 53 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 70990ff..7dc9965 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -92,13 +92,6 @@ static struct rapl_priv rapl_msr_priv = {
 /* per domain data, some are optional */
 #define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
 
-struct msrl_action {
-	u32 msr_no;
-	u64 clear_mask;
-	u64 set_mask;
-	int err;
-};
-
 #define	DOMAIN_STATE_INACTIVE           BIT(0)
 #define	DOMAIN_STATE_POWER_LIMIT_SET    BIT(1)
 #define DOMAIN_STATE_BIOS_LOCKED        BIT(2)
@@ -691,16 +684,16 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 			enum rapl_primitives prim,
 			bool xlate, u64 *data)
 {
-	u64 value, final;
-	u32 msr;
+	u64 value;
 	struct rapl_primitive_info *rp = &rpi[prim];
+	struct reg_action ra;
 	int cpu;
 
 	if (!rp->name || rp->flag & RAPL_PRIMITIVE_DUMMY)
 		return -EINVAL;
 
-	msr = rd->regs[rp->id];
-	if (!msr)
+	ra.reg = rd->regs[rp->id];
+	if (!ra.reg)
 		return -EINVAL;
 
 	cpu = rd->rp->lead_cpu;
@@ -716,47 +709,23 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 		return 0;
 	}
 
-	if (rdmsrl_safe_on_cpu(cpu, msr, &value)) {
-		pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
+	ra.mask = rp->mask;
+
+	if (rd->rp->priv->read_raw(cpu, &ra)) {
+		pr_debug("failed to read reg 0x%x on cpu %d\n", ra.reg, cpu);
 		return -EIO;
 	}
 
-	final = value & rp->mask;
-	final = final >> rp->shift;
+	value = ra.value >> rp->shift;
+
 	if (xlate)
-		*data = rapl_unit_xlate(rd, rp->unit, final, 0);
+		*data = rapl_unit_xlate(rd, rp->unit, value, 0);
 	else
-		*data = final;
+		*data = value;
 
 	return 0;
 }
 
-
-static int msrl_update_safe(u32 msr_no, u64 clear_mask, u64 set_mask)
-{
-	int err;
-	u64 val;
-
-	err = rdmsrl_safe(msr_no, &val);
-	if (err)
-		goto out;
-
-	val &= ~clear_mask;
-	val |= set_mask;
-
-	err = wrmsrl_safe(msr_no, val);
-
-out:
-	return err;
-}
-
-static void msrl_update_func(void *info)
-{
-	struct msrl_action *ma = info;
-
-	ma->err = msrl_update_safe(ma->msr_no, ma->clear_mask, ma->set_mask);
-}
-
 /* Similar use of primitive info in the read counterpart */
 static int rapl_write_data_raw(struct rapl_domain *rd,
 			enum rapl_primitives prim,
@@ -765,7 +734,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
 	struct rapl_primitive_info *rp = &rpi[prim];
 	int cpu;
 	u64 bits;
-	struct msrl_action ma;
+	struct reg_action ra;
 	int ret;
 
 	cpu = rd->rp->lead_cpu;
@@ -773,17 +742,13 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
 	bits <<= rp->shift;
 	bits &= rp->mask;
 
-	memset(&ma, 0, sizeof(ma));
+	memset(&ra, 0, sizeof(ra));
 
-	ma.msr_no = rd->regs[rp->id];
-	ma.clear_mask = rp->mask;
-	ma.set_mask = bits;
+	ra.reg = rd->regs[rp->id];
+	ra.mask = rp->mask;
+	ra.value = bits;
 
-	ret = smp_call_function_single(cpu, msrl_update_func, &ma, 1);
-	if (ret)
-		WARN_ON_ONCE(ret);
-	else
-		ret = ma.err;
+	ret = rd->rp->priv->write_raw(cpu, &ra);
 
 	return ret;
 }
@@ -1506,6 +1471,44 @@ static struct notifier_block rapl_pm_notifier = {
 	.notifier_call = rapl_pm_callback,
 };
 
+static int rapl_msr_read_raw(int cpu, struct reg_action *ra)
+{
+	if (rdmsrl_safe_on_cpu(cpu, ra->reg, &ra->value)) {
+		pr_debug("failed to read msr 0x%x on cpu %d\n", ra->reg, cpu);
+		return -EIO;
+	}
+	ra->value &= ra->mask;
+	return 0;
+}
+
+static void rapl_msr_update_func(void *info)
+{
+	struct reg_action *ra = info;
+	u64 val;
+
+	ra->err = rdmsrl_safe(ra->reg, &val);
+	if (ra->err)
+		return;
+
+	val &= ~ra->mask;
+	val |= ra->value;
+
+	ra->err = wrmsrl_safe(ra->reg, val);
+}
+
+
+static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
+{
+	int ret;
+
+	ret = smp_call_function_single(cpu, rapl_msr_update_func, ra, 1);
+	if (ret)
+		WARN_ON_ONCE(ret);
+	else
+		ret = ra->err;
+	return ret;
+}
+
 static int __init rapl_init(void)
 {
 	const struct x86_cpu_id *id;
@@ -1521,6 +1524,8 @@ static int __init rapl_init(void)
 
 	rapl_defaults = (struct rapl_defaults *)id->driver_data;
 
+	rapl_msr_priv.read_raw = rapl_msr_read_raw;
+	rapl_msr_priv.write_raw = rapl_msr_write_raw;
 	ret = rapl_register_powercap();
 	if (ret)
 		return ret;
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
index 0277579..1a0df65 100644
--- a/include/linux/intel_rapl.h
+++ b/include/linux/intel_rapl.h
@@ -88,12 +88,21 @@ struct rapl_domain {
 	struct rapl_package *rp;
 };
 
+struct reg_action {
+	u32 reg;
+	u64 mask;
+	u64 value;
+	int err;
+};
+
 struct rapl_priv {
 	struct powercap_control_type *control_type;
 	struct rapl_domain *platform_rapl_domain;
 	enum cpuhp_state pcap_rapl_online;
 	u32 reg_unit;
 	u32 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+	int (*read_raw)(int cpu, struct reg_action *ra);
+	int (*write_raw)(int cpu, struct reg_action *ra);
 };
 
 /* maximum rapl package domain name: package-%d-die-%d */
-- 
2.7.4


^ permalink raw reply related

* [PATCH 05/13] intel_rapl: abstract register address
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

MSR and MMIO RAPL interface have different sets of registers, thus the
RAPL register address should be obtained from interface specific
structure, i.e. struct rapl_private, instead.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 73 +++++++++++++++++++------------------------
 include/linux/intel_rapl.h    |  2 ++
 2 files changed, 35 insertions(+), 40 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index a804370..70990ff 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -75,7 +75,19 @@ enum unit_type {
 	TIME_UNIT,
 };
 
-static struct rapl_priv rapl_msr_priv;
+static struct rapl_priv rapl_msr_priv = {
+	.reg_unit = MSR_RAPL_POWER_UNIT,
+	.regs[RAPL_DOMAIN_PACKAGE] = {
+		MSR_PKG_POWER_LIMIT, MSR_PKG_ENERGY_STATUS, MSR_PKG_PERF_STATUS, 0, MSR_PKG_POWER_INFO },
+	.regs[RAPL_DOMAIN_PP0] = {
+		MSR_PP0_POWER_LIMIT, MSR_PP0_ENERGY_STATUS, 0, MSR_PP0_POLICY, 0 },
+	.regs[RAPL_DOMAIN_PP1] = {
+		MSR_PP1_POWER_LIMIT, MSR_PP1_ENERGY_STATUS, 0, MSR_PP1_POLICY, 0 },
+	.regs[RAPL_DOMAIN_DRAM] = {
+		MSR_DRAM_POWER_LIMIT, MSR_DRAM_ENERGY_STATUS, MSR_DRAM_PERF_STATUS, 0, MSR_DRAM_POWER_INFO },
+	.regs[RAPL_DOMAIN_PLATFORM] = {
+		MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0},
+};
 
 /* per domain data, some are optional */
 #define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
@@ -540,15 +552,17 @@ static void rapl_init_domains(struct rapl_package *rp)
 
 	for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
 		unsigned int mask = rp->domain_map & (1 << i);
+
+		rd->regs[RAPL_DOMAIN_REG_LIMIT] = rp->priv->regs[i][RAPL_DOMAIN_REG_LIMIT];
+		rd->regs[RAPL_DOMAIN_REG_STATUS] = rp->priv->regs[i][RAPL_DOMAIN_REG_STATUS];
+		rd->regs[RAPL_DOMAIN_REG_PERF] = rp->priv->regs[i][RAPL_DOMAIN_REG_PERF];
+		rd->regs[RAPL_DOMAIN_REG_POLICY] = rp->priv->regs[i][RAPL_DOMAIN_REG_POLICY];
+		rd->regs[RAPL_DOMAIN_REG_INFO] = rp->priv->regs[i][RAPL_DOMAIN_REG_INFO];
+
 		switch (mask) {
 		case BIT(RAPL_DOMAIN_PACKAGE):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PACKAGE];
 			rd->id = RAPL_DOMAIN_PACKAGE;
-			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PKG_POWER_LIMIT;
-			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PKG_ENERGY_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_PERF] = MSR_PKG_PERF_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_POLICY] = 0;
-			rd->regs[RAPL_DOMAIN_REG_INFO] = MSR_PKG_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->rpl[1].prim_id = PL2_ENABLE;
@@ -557,33 +571,18 @@ static void rapl_init_domains(struct rapl_package *rp)
 		case BIT(RAPL_DOMAIN_PP0):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP0];
 			rd->id = RAPL_DOMAIN_PP0;
-			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PP0_POWER_LIMIT;
-			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PP0_ENERGY_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_PERF] = 0;
-			rd->regs[RAPL_DOMAIN_REG_POLICY] = MSR_PP0_POLICY;
-			rd->regs[RAPL_DOMAIN_REG_INFO] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_PP1):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP1];
 			rd->id = RAPL_DOMAIN_PP1;
-			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PP1_POWER_LIMIT;
-			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PP1_ENERGY_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_PERF] = 0;
-			rd->regs[RAPL_DOMAIN_REG_POLICY] = MSR_PP1_POLICY;
-			rd->regs[RAPL_DOMAIN_REG_INFO] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_DRAM):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_DRAM];
 			rd->id = RAPL_DOMAIN_DRAM;
-			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_DRAM_POWER_LIMIT;
-			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_DRAM_ENERGY_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_PERF] = MSR_DRAM_PERF_STATUS;
-			rd->regs[RAPL_DOMAIN_REG_POLICY] = 0;
-			rd->regs[RAPL_DOMAIN_REG_INFO] = MSR_DRAM_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->domain_energy_unit =
@@ -805,9 +804,9 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
 	u64 msr_val;
 	u32 value;
 
-	if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
+	if (rdmsrl_safe_on_cpu(cpu, rp->priv->reg_unit, &msr_val)) {
 		pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
-			MSR_RAPL_POWER_UNIT, cpu);
+			rp->priv->reg_unit, cpu);
 		return -ENODEV;
 	}
 
@@ -831,9 +830,9 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
 	u64 msr_val;
 	u32 value;
 
-	if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
+	if (rdmsrl_safe_on_cpu(cpu, rp->priv->reg_unit, &msr_val)) {
 		pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
-			MSR_RAPL_POWER_UNIT, cpu);
+			rp->priv->reg_unit, cpu);
 		return -ENODEV;
 	}
 	value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
@@ -1172,10 +1171,10 @@ static int __init rapl_register_psys(void)
 	struct powercap_zone *power_zone;
 	u64 val;
 
-	if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_ENERGY_STATUS, &val) || !val)
+	if (rdmsrl_safe_on_cpu(0, rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS], &val) || !val)
 		return -ENODEV;
 
-	if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_POWER_LIMIT, &val) || !val)
+	if (rdmsrl_safe_on_cpu(0, rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT], &val) || !val)
 		return -ENODEV;
 
 	rd = kzalloc(sizeof(*rd), GFP_KERNEL);
@@ -1184,8 +1183,8 @@ static int __init rapl_register_psys(void)
 
 	rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
 	rd->id = RAPL_DOMAIN_PLATFORM;
-	rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PLATFORM_POWER_LIMIT;
-	rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PLATFORM_ENERGY_STATUS;
+	rd->regs[RAPL_DOMAIN_REG_LIMIT] = rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+	rd->regs[RAPL_DOMAIN_REG_STATUS] = rapl_msr_priv.regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
 	rd->rpl[0].prim_id = PL1_ENABLE;
 	rd->rpl[0].name = pl1_name;
 	rd->rpl[1].prim_id = PL2_ENABLE;
@@ -1217,23 +1216,17 @@ static int __init rapl_register_powercap(void)
 	return 0;
 }
 
-static int rapl_check_domain(int cpu, int domain)
+static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
 {
-	unsigned msr;
+	u32 reg;
 	u64 val = 0;
 
 	switch (domain) {
 	case RAPL_DOMAIN_PACKAGE:
-		msr = MSR_PKG_ENERGY_STATUS;
-		break;
 	case RAPL_DOMAIN_PP0:
-		msr = MSR_PP0_ENERGY_STATUS;
-		break;
 	case RAPL_DOMAIN_PP1:
-		msr = MSR_PP1_ENERGY_STATUS;
-		break;
 	case RAPL_DOMAIN_DRAM:
-		msr = MSR_DRAM_ENERGY_STATUS;
+		reg = rp->priv->regs[domain][RAPL_DOMAIN_REG_STATUS];
 		break;
 	case RAPL_DOMAIN_PLATFORM:
 		/* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */
@@ -1245,7 +1238,7 @@ static int rapl_check_domain(int cpu, int domain)
 	/* make sure domain counters are available and contains non-zero
 	 * values, otherwise skip it.
 	 */
-	if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val)
+	if (rdmsrl_safe_on_cpu(cpu, reg, &val) || !val)
 		return -ENODEV;
 
 	return 0;
@@ -1292,7 +1285,7 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
 
 	for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
 		/* use physical package id to read counters */
-		if (!rapl_check_domain(cpu, i)) {
+		if (!rapl_check_domain(cpu, i, rp)) {
 			rp->domain_map |= 1 << i;
 			pr_info("Found RAPL domain %s\n", rapl_domain_names[i]);
 		}
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
index d6a8547..0277579 100644
--- a/include/linux/intel_rapl.h
+++ b/include/linux/intel_rapl.h
@@ -92,6 +92,8 @@ struct rapl_priv {
 	struct powercap_control_type *control_type;
 	struct rapl_domain *platform_rapl_domain;
 	enum cpuhp_state pcap_rapl_online;
+	u32 reg_unit;
+	u32 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
 };
 
 /* maximum rapl package domain name: package-%d-die-%d */
-- 
2.7.4


^ permalink raw reply related

* [PATCH 04/13] intel_rapl: introduce struct rapl_private
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

Introduce a new structure, rapl_private, to save the private data
for different RAPL Interface.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 58 +++++++++++++++++++++----------------------
 include/linux/intel_rapl.h    |  7 ++++++
 2 files changed, 35 insertions(+), 30 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index adb35ec..a804370 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -75,6 +75,8 @@ enum unit_type {
 	TIME_UNIT,
 };
 
+static struct rapl_priv rapl_msr_priv;
+
 /* per domain data, some are optional */
 #define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
 
@@ -155,17 +157,14 @@ static const char * const rapl_domain_names[] = {
 	"psys",
 };
 
-static struct powercap_control_type *control_type; /* PowerCap Controller */
-static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */
-
 /* caller to ensure CPU hotplug lock is held */
-static struct rapl_package *rapl_find_package_domain(int cpu)
+static struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_priv *priv)
 {
 	int id = topology_logical_die_id(cpu);
 	struct rapl_package *rp;
 
 	list_for_each_entry(rp, &rapl_packages, plist) {
-		if (rp->id == id)
+		if (rp->id == id && rp->priv->control_type == priv->control_type)
 			return rp;
 	}
 
@@ -1090,12 +1089,12 @@ static void rapl_update_domain_data(struct rapl_package *rp)
 
 static void rapl_unregister_powercap(void)
 {
-	if (platform_rapl_domain) {
-		powercap_unregister_zone(control_type,
-					 &platform_rapl_domain->power_zone);
-		kfree(platform_rapl_domain);
+	if (&rapl_msr_priv.platform_rapl_domain) {
+		powercap_unregister_zone(rapl_msr_priv.control_type,
+					 &rapl_msr_priv.platform_rapl_domain->power_zone);
+		kfree(rapl_msr_priv.platform_rapl_domain);
 	}
-	powercap_unregister_control_type(control_type);
+	powercap_unregister_control_type(rapl_msr_priv.control_type);
 }
 
 static int rapl_package_register_powercap(struct rapl_package *rp)
@@ -1113,7 +1112,7 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
 			nr_pl = find_nr_power_limit(rd);
 			pr_debug("register package domain %s\n", rp->name);
 			power_zone = powercap_register_zone(&rd->power_zone,
-							control_type,
+							rp->priv->control_type,
 							rp->name, NULL,
 							&zone_ops[rd->id],
 							nr_pl,
@@ -1140,7 +1139,7 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
 		/* number of power limits per domain varies */
 		nr_pl = find_nr_power_limit(rd);
 		power_zone = powercap_register_zone(&rd->power_zone,
-						control_type, rd->name,
+						rp->priv->control_type, rd->name,
 						rp->power_zone,
 						&zone_ops[rd->id], nr_pl,
 						&constraint_ops);
@@ -1161,7 +1160,7 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
 	 */
 	while (--rd >= rp->domains) {
 		pr_debug("unregister %s domain %s\n", rp->name, rd->name);
-		powercap_unregister_zone(control_type, &rd->power_zone);
+		powercap_unregister_zone(rp->priv->control_type, &rd->power_zone);
 	}
 
 	return ret;
@@ -1191,9 +1190,9 @@ static int __init rapl_register_psys(void)
 	rd->rpl[0].name = pl1_name;
 	rd->rpl[1].prim_id = PL2_ENABLE;
 	rd->rpl[1].name = pl2_name;
-	rd->rp = rapl_find_package_domain(0);
+	rd->rp = rapl_find_package_domain(0, &rapl_msr_priv);
 
-	power_zone = powercap_register_zone(&rd->power_zone, control_type,
+	power_zone = powercap_register_zone(&rd->power_zone, rapl_msr_priv.control_type,
 					    "psys", NULL,
 					    &zone_ops[RAPL_DOMAIN_PLATFORM],
 					    2, &constraint_ops);
@@ -1203,17 +1202,17 @@ static int __init rapl_register_psys(void)
 		return PTR_ERR(power_zone);
 	}
 
-	platform_rapl_domain = rd;
+	rapl_msr_priv.platform_rapl_domain = rd;
 
 	return 0;
 }
 
 static int __init rapl_register_powercap(void)
 {
-	control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
-	if (IS_ERR(control_type)) {
+	rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
+	if (IS_ERR(rapl_msr_priv.control_type)) {
 		pr_debug("failed to register powercap control_type.\n");
-		return PTR_ERR(control_type);
+		return PTR_ERR(rapl_msr_priv.control_type);
 	}
 	return 0;
 }
@@ -1338,16 +1337,16 @@ static void rapl_remove_package(struct rapl_package *rp)
 		}
 		pr_debug("remove package, undo power limit on %s: %s\n",
 			 rp->name, rd->name);
-		powercap_unregister_zone(control_type, &rd->power_zone);
+		powercap_unregister_zone(rp->priv->control_type, &rd->power_zone);
 	}
 	/* do parent zone last */
-	powercap_unregister_zone(control_type, &rd_package->power_zone);
+	powercap_unregister_zone(rp->priv->control_type, &rd_package->power_zone);
 	list_del(&rp->plist);
 	kfree(rp);
 }
 
 /* called from CPU hotplug notifier, hotplug lock held */
-static struct rapl_package *rapl_add_package(int cpu)
+static struct rapl_package *rapl_add_package(int cpu, struct rapl_priv *priv)
 {
 	int id = topology_logical_die_id(cpu);
 	struct rapl_package *rp;
@@ -1361,6 +1360,7 @@ static struct rapl_package *rapl_add_package(int cpu)
 	/* add the new package to the list */
 	rp->id = id;
 	rp->lead_cpu = cpu;
+	rp->priv = priv;
 
 	if (topology_max_die_per_package() > 1)
 		snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH,
@@ -1399,9 +1399,9 @@ static int rapl_cpu_online(unsigned int cpu)
 {
 	struct rapl_package *rp;
 
-	rp = rapl_find_package_domain(cpu);
+	rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
 	if (!rp) {
-		rp = rapl_add_package(cpu);
+		rp = rapl_add_package(cpu, &rapl_msr_priv);
 		if (IS_ERR(rp))
 			return PTR_ERR(rp);
 	}
@@ -1414,7 +1414,7 @@ static int rapl_cpu_down_prep(unsigned int cpu)
 	struct rapl_package *rp;
 	int lead_cpu;
 
-	rp = rapl_find_package_domain(cpu);
+	rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
 	if (!rp)
 		return 0;
 
@@ -1427,8 +1427,6 @@ static int rapl_cpu_down_prep(unsigned int cpu)
 	return 0;
 }
 
-static enum cpuhp_state pcap_rapl_online;
-
 static void power_limit_state_save(void)
 {
 	struct rapl_package *rp;
@@ -1538,7 +1536,7 @@ static int __init rapl_init(void)
 				rapl_cpu_online, rapl_cpu_down_prep);
 	if (ret < 0)
 		goto err_unreg;
-	pcap_rapl_online = ret;
+	rapl_msr_priv.pcap_rapl_online = ret;
 
 	/* Don't bail out if PSys is not supported */
 	rapl_register_psys();
@@ -1550,7 +1548,7 @@ static int __init rapl_init(void)
 	return 0;
 
 err_unreg_all:
-	cpuhp_remove_state(pcap_rapl_online);
+	cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
 
 err_unreg:
 	rapl_unregister_powercap();
@@ -1560,7 +1558,7 @@ static int __init rapl_init(void)
 static void __exit rapl_exit(void)
 {
 	unregister_pm_notifier(&rapl_pm_notifier);
-	cpuhp_remove_state(pcap_rapl_online);
+	cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
 	rapl_unregister_powercap();
 }
 
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
index 9471603..d6a8547 100644
--- a/include/linux/intel_rapl.h
+++ b/include/linux/intel_rapl.h
@@ -88,6 +88,12 @@ struct rapl_domain {
 	struct rapl_package *rp;
 };
 
+struct rapl_priv {
+	struct powercap_control_type *control_type;
+	struct rapl_domain *platform_rapl_domain;
+	enum cpuhp_state pcap_rapl_online;
+};
+
 /* maximum rapl package domain name: package-%d-die-%d */
 #define PACKAGE_DOMAIN_NAME_LENGTH 30
 
@@ -108,6 +114,7 @@ struct rapl_package {
 	/* Track active cpus */
 	struct cpumask cpumask;
 	char name[PACKAGE_DOMAIN_NAME_LENGTH];
+	struct rapl_priv *priv;
 };
 
 #endif /* __INTEL_RAPL_H__ */
-- 
2.7.4


^ permalink raw reply related

* [PATCH 03/13] intel_rapl: introduce intel_rapl.h
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

Create a new header file for the common definitions that might be used
by different RAPL Interface.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 MAINTAINERS                   |   1 +
 drivers/powercap/intel_rapl.c | 101 +------------------------------------
 include/linux/intel_rapl.h    | 113 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 99 deletions(-)
 create mode 100644 include/linux/intel_rapl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 57f496c..b51f2b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12601,6 +12601,7 @@ F:	drivers/base/power/
 F:	include/linux/pm.h
 F:	include/linux/pm_*
 F:	include/linux/powercap.h
+F:	include/linux/intel_rapl.h
 F:	drivers/powercap/
 F:	kernel/configs/nopm.config
 
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 9be9f20..adb35ec 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -18,8 +18,9 @@
 #include <linux/cpu.h>
 #include <linux/powercap.h>
 #include <linux/suspend.h>
-#include <asm/iosf_mbi.h>
+#include <linux/intel_rapl.h>
 
+#include <asm/iosf_mbi.h>
 #include <asm/processor.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
@@ -74,59 +75,9 @@ enum unit_type {
 	TIME_UNIT,
 };
 
-enum rapl_domain_type {
-	RAPL_DOMAIN_PACKAGE, /* entire package/socket */
-	RAPL_DOMAIN_PP0, /* core power plane */
-	RAPL_DOMAIN_PP1, /* graphics uncore */
-	RAPL_DOMAIN_DRAM,/* DRAM control_type */
-	RAPL_DOMAIN_PLATFORM, /* PSys control_type */
-	RAPL_DOMAIN_MAX,
-};
-
-enum rapl_domain_reg_id {
-	RAPL_DOMAIN_REG_LIMIT,
-	RAPL_DOMAIN_REG_STATUS,
-	RAPL_DOMAIN_REG_PERF,
-	RAPL_DOMAIN_REG_POLICY,
-	RAPL_DOMAIN_REG_INFO,
-	RAPL_DOMAIN_REG_MAX,
-};
-
 /* per domain data, some are optional */
-enum rapl_primitives {
-	ENERGY_COUNTER,
-	POWER_LIMIT1,
-	POWER_LIMIT2,
-	FW_LOCK,
-
-	PL1_ENABLE,  /* power limit 1, aka long term */
-	PL1_CLAMP,   /* allow frequency to go below OS request */
-	PL2_ENABLE,  /* power limit 2, aka short term, instantaneous */
-	PL2_CLAMP,
-
-	TIME_WINDOW1, /* long term */
-	TIME_WINDOW2, /* short term */
-	THERMAL_SPEC_POWER,
-	MAX_POWER,
-
-	MIN_POWER,
-	MAX_TIME_WINDOW,
-	THROTTLED_TIME,
-	PRIORITY_LEVEL,
-
-	/* below are not raw primitive data */
-	AVERAGE_POWER,
-	NR_RAPL_PRIMITIVES,
-};
-
 #define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
 
-/* Can be expanded to include events, etc.*/
-struct rapl_domain_data {
-	u64 primitives[NR_RAPL_PRIMITIVES];
-	unsigned long timestamp;
-};
-
 struct msrl_action {
 	u32 msr_no;
 	u64 clear_mask;
@@ -138,60 +89,12 @@ struct msrl_action {
 #define	DOMAIN_STATE_POWER_LIMIT_SET    BIT(1)
 #define DOMAIN_STATE_BIOS_LOCKED        BIT(2)
 
-#define NR_POWER_LIMITS (2)
-struct rapl_power_limit {
-	struct powercap_zone_constraint *constraint;
-	int prim_id; /* primitive ID used to enable */
-	struct rapl_domain *domain;
-	const char *name;
-	u64 last_power_limit;
-};
-
 static const char pl1_name[] = "long_term";
 static const char pl2_name[] = "short_term";
 
-struct rapl_package;
-struct rapl_domain {
-	const char *name;
-	enum rapl_domain_type id;
-	int regs[RAPL_DOMAIN_REG_MAX];
-	struct powercap_zone power_zone;
-	struct rapl_domain_data rdd;
-	struct rapl_power_limit rpl[NR_POWER_LIMITS];
-	u64 attr_map; /* track capabilities */
-	unsigned int state;
-	unsigned int domain_energy_unit;
-	struct rapl_package *rp;
-};
 #define power_zone_to_rapl_domain(_zone) \
 	container_of(_zone, struct rapl_domain, power_zone)
 
-/* maximum rapl package domain name: package-%d-die-%d */
-#define PACKAGE_DOMAIN_NAME_LENGTH 30
-
-
-/* Each rapl package contains multiple domains, these are the common
- * data across RAPL domains within a package.
- */
-struct rapl_package {
-	unsigned int id; /* logical die id, equals physical 1-die systems */
-	unsigned int nr_domains;
-	unsigned long domain_map; /* bit map of active domains */
-	unsigned int power_unit;
-	unsigned int energy_unit;
-	unsigned int time_unit;
-	struct rapl_domain *domains; /* array of domains, sized at runtime */
-	struct powercap_zone *power_zone; /* keep track of parent zone */
-	unsigned long power_limit_irq; /* keep track of package power limit
-					* notify interrupt enable status.
-					*/
-	struct list_head plist;
-	int lead_cpu; /* one active cpu per package for access */
-	/* Track active cpus */
-	struct cpumask cpumask;
-	char name[PACKAGE_DOMAIN_NAME_LENGTH];
-};
-
 struct rapl_defaults {
 	u8 floor_freq_reg_addr;
 	int (*check_unit)(struct rapl_package *rp, int cpu);
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
new file mode 100644
index 0000000..9471603
--- /dev/null
+++ b/include/linux/intel_rapl.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Data types and headers for RAPL support
+ *
+ *  Copyright (C) 2019  Intel Corporation.
+ *
+ *  Author: Zhang Rui <rui.zhang@intel.com>
+ */
+
+#ifndef __INTEL_RAPL_H__
+#define __INTEL_RAPL_H__
+
+#include <linux/types.h>
+#include <linux/powercap.h>
+
+enum rapl_domain_type {
+	RAPL_DOMAIN_PACKAGE,	/* entire package/socket */
+	RAPL_DOMAIN_PP0,	/* core power plane */
+	RAPL_DOMAIN_PP1,	/* graphics uncore */
+	RAPL_DOMAIN_DRAM,	/* DRAM control_type */
+	RAPL_DOMAIN_PLATFORM,	/* PSys control_type */
+	RAPL_DOMAIN_MAX,
+};
+
+enum rapl_domain_reg_id {
+	RAPL_DOMAIN_REG_LIMIT,
+	RAPL_DOMAIN_REG_STATUS,
+	RAPL_DOMAIN_REG_PERF,
+	RAPL_DOMAIN_REG_POLICY,
+	RAPL_DOMAIN_REG_INFO,
+	RAPL_DOMAIN_REG_MAX,
+};
+
+struct rapl_package;
+
+enum rapl_primitives {
+	ENERGY_COUNTER,
+	POWER_LIMIT1,
+	POWER_LIMIT2,
+	FW_LOCK,
+
+	PL1_ENABLE,		/* power limit 1, aka long term */
+	PL1_CLAMP,		/* allow frequency to go below OS request */
+	PL2_ENABLE,		/* power limit 2, aka short term, instantaneous */
+	PL2_CLAMP,
+
+	TIME_WINDOW1,		/* long term */
+	TIME_WINDOW2,		/* short term */
+	THERMAL_SPEC_POWER,
+	MAX_POWER,
+
+	MIN_POWER,
+	MAX_TIME_WINDOW,
+	THROTTLED_TIME,
+	PRIORITY_LEVEL,
+
+	/* below are not raw primitive data */
+	AVERAGE_POWER,
+	NR_RAPL_PRIMITIVES,
+};
+
+struct rapl_domain_data {
+	u64 primitives[NR_RAPL_PRIMITIVES];
+	unsigned long timestamp;
+};
+
+#define NR_POWER_LIMITS (2)
+struct rapl_power_limit {
+	struct powercap_zone_constraint *constraint;
+	int prim_id;		/* primitive ID used to enable */
+	struct rapl_domain *domain;
+	const char *name;
+	u64 last_power_limit;
+};
+
+struct rapl_package;
+
+struct rapl_domain {
+	const char *name;
+	enum rapl_domain_type id;
+	int regs[RAPL_DOMAIN_REG_MAX];
+	struct powercap_zone power_zone;
+	struct rapl_domain_data rdd;
+	struct rapl_power_limit rpl[NR_POWER_LIMITS];
+	u64 attr_map;		/* track capabilities */
+	unsigned int state;
+	unsigned int domain_energy_unit;
+	struct rapl_package *rp;
+};
+
+/* maximum rapl package domain name: package-%d-die-%d */
+#define PACKAGE_DOMAIN_NAME_LENGTH 30
+
+struct rapl_package {
+	unsigned int id;	/* logical die id, equals physical 1-die systems */
+	unsigned int nr_domains;
+	unsigned long domain_map;	/* bit map of active domains */
+	unsigned int power_unit;
+	unsigned int energy_unit;
+	unsigned int time_unit;
+	struct rapl_domain *domains;	/* array of domains, sized at runtime */
+	struct powercap_zone *power_zone;	/* keep track of parent zone */
+	unsigned long power_limit_irq;	/* keep track of package power limit
+					 * notify interrupt enable status.
+					 */
+	struct list_head plist;
+	int lead_cpu;		/* one active cpu per package for access */
+	/* Track active cpus */
+	struct cpumask cpumask;
+	char name[PACKAGE_DOMAIN_NAME_LENGTH];
+};
+
+#endif /* __INTEL_RAPL_H__ */
-- 
2.7.4


^ permalink raw reply related

* [PATCH 02/13] intel_rapl: remove hardcoded register index
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

enum rapl_domain_reg_id is defined for the RAPL registers for each RAPL
domain, thus use it whenever possible.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 44 +++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 45d5f22..9be9f20 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -642,11 +642,11 @@ static void rapl_init_domains(struct rapl_package *rp)
 		case BIT(RAPL_DOMAIN_PACKAGE):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PACKAGE];
 			rd->id = RAPL_DOMAIN_PACKAGE;
-			rd->regs[0] = MSR_PKG_POWER_LIMIT;
-			rd->regs[1] = MSR_PKG_ENERGY_STATUS;
-			rd->regs[2] = MSR_PKG_PERF_STATUS;
-			rd->regs[3] = 0;
-			rd->regs[4] = MSR_PKG_POWER_INFO;
+			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PKG_POWER_LIMIT;
+			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PKG_ENERGY_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_PERF] = MSR_PKG_PERF_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_POLICY] = 0;
+			rd->regs[RAPL_DOMAIN_REG_INFO] = MSR_PKG_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->rpl[1].prim_id = PL2_ENABLE;
@@ -655,33 +655,33 @@ static void rapl_init_domains(struct rapl_package *rp)
 		case BIT(RAPL_DOMAIN_PP0):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP0];
 			rd->id = RAPL_DOMAIN_PP0;
-			rd->regs[0] = MSR_PP0_POWER_LIMIT;
-			rd->regs[1] = MSR_PP0_ENERGY_STATUS;
-			rd->regs[2] = 0;
-			rd->regs[3] = MSR_PP0_POLICY;
-			rd->regs[4] = 0;
+			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PP0_POWER_LIMIT;
+			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PP0_ENERGY_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_PERF] = 0;
+			rd->regs[RAPL_DOMAIN_REG_POLICY] = MSR_PP0_POLICY;
+			rd->regs[RAPL_DOMAIN_REG_INFO] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_PP1):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP1];
 			rd->id = RAPL_DOMAIN_PP1;
-			rd->regs[0] = MSR_PP1_POWER_LIMIT;
-			rd->regs[1] = MSR_PP1_ENERGY_STATUS;
-			rd->regs[2] = 0;
-			rd->regs[3] = MSR_PP1_POLICY;
-			rd->regs[4] = 0;
+			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PP1_POWER_LIMIT;
+			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PP1_ENERGY_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_PERF] = 0;
+			rd->regs[RAPL_DOMAIN_REG_POLICY] = MSR_PP1_POLICY;
+			rd->regs[RAPL_DOMAIN_REG_INFO] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_DRAM):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_DRAM];
 			rd->id = RAPL_DOMAIN_DRAM;
-			rd->regs[0] = MSR_DRAM_POWER_LIMIT;
-			rd->regs[1] = MSR_DRAM_ENERGY_STATUS;
-			rd->regs[2] = MSR_DRAM_PERF_STATUS;
-			rd->regs[3] = 0;
-			rd->regs[4] = MSR_DRAM_POWER_INFO;
+			rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_DRAM_POWER_LIMIT;
+			rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_DRAM_ENERGY_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_PERF] = MSR_DRAM_PERF_STATUS;
+			rd->regs[RAPL_DOMAIN_REG_POLICY] = 0;
+			rd->regs[RAPL_DOMAIN_REG_INFO] = MSR_DRAM_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->domain_energy_unit =
@@ -1282,8 +1282,8 @@ static int __init rapl_register_psys(void)
 
 	rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
 	rd->id = RAPL_DOMAIN_PLATFORM;
-	rd->regs[0] = MSR_PLATFORM_POWER_LIMIT;
-	rd->regs[1] = MSR_PLATFORM_ENERGY_STATUS;
+	rd->regs[RAPL_DOMAIN_REG_LIMIT] = MSR_PLATFORM_POWER_LIMIT;
+	rd->regs[RAPL_DOMAIN_REG_STATUS] = MSR_PLATFORM_ENERGY_STATUS;
 	rd->rpl[0].prim_id = PL1_ENABLE;
 	rd->rpl[0].name = pl1_name;
 	rd->rpl[1].prim_id = PL2_ENABLE;
-- 
2.7.4


^ permalink raw reply related

* [PATCH 01/13] intel_rapl: use reg instead of msr
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang
In-Reply-To: <1561475808-24839-1-git-send-email-rui.zhang@intel.com>

To support both MSR and MMIO Interface, use 'reg' to discribe RAPL
registers instead of 'msr'.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/powercap/intel_rapl.c | 98 +++++++++++++++++++++----------------------
 1 file changed, 49 insertions(+), 49 deletions(-)

diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 8692f6b..45d5f22 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -83,13 +83,13 @@ enum rapl_domain_type {
 	RAPL_DOMAIN_MAX,
 };
 
-enum rapl_domain_msr_id {
-	RAPL_DOMAIN_MSR_LIMIT,
-	RAPL_DOMAIN_MSR_STATUS,
-	RAPL_DOMAIN_MSR_PERF,
-	RAPL_DOMAIN_MSR_POLICY,
-	RAPL_DOMAIN_MSR_INFO,
-	RAPL_DOMAIN_MSR_MAX,
+enum rapl_domain_reg_id {
+	RAPL_DOMAIN_REG_LIMIT,
+	RAPL_DOMAIN_REG_STATUS,
+	RAPL_DOMAIN_REG_PERF,
+	RAPL_DOMAIN_REG_POLICY,
+	RAPL_DOMAIN_REG_INFO,
+	RAPL_DOMAIN_REG_MAX,
 };
 
 /* per domain data, some are optional */
@@ -154,7 +154,7 @@ struct rapl_package;
 struct rapl_domain {
 	const char *name;
 	enum rapl_domain_type id;
-	int msrs[RAPL_DOMAIN_MSR_MAX];
+	int regs[RAPL_DOMAIN_REG_MAX];
 	struct powercap_zone power_zone;
 	struct rapl_domain_data rdd;
 	struct rapl_power_limit rpl[NR_POWER_LIMITS];
@@ -216,7 +216,7 @@ struct rapl_primitive_info {
 	const char *name;
 	u64 mask;
 	int shift;
-	enum rapl_domain_msr_id id;
+	enum rapl_domain_reg_id id;
 	enum unit_type unit;
 	u32 flag;
 };
@@ -642,11 +642,11 @@ static void rapl_init_domains(struct rapl_package *rp)
 		case BIT(RAPL_DOMAIN_PACKAGE):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PACKAGE];
 			rd->id = RAPL_DOMAIN_PACKAGE;
-			rd->msrs[0] = MSR_PKG_POWER_LIMIT;
-			rd->msrs[1] = MSR_PKG_ENERGY_STATUS;
-			rd->msrs[2] = MSR_PKG_PERF_STATUS;
-			rd->msrs[3] = 0;
-			rd->msrs[4] = MSR_PKG_POWER_INFO;
+			rd->regs[0] = MSR_PKG_POWER_LIMIT;
+			rd->regs[1] = MSR_PKG_ENERGY_STATUS;
+			rd->regs[2] = MSR_PKG_PERF_STATUS;
+			rd->regs[3] = 0;
+			rd->regs[4] = MSR_PKG_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->rpl[1].prim_id = PL2_ENABLE;
@@ -655,33 +655,33 @@ static void rapl_init_domains(struct rapl_package *rp)
 		case BIT(RAPL_DOMAIN_PP0):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP0];
 			rd->id = RAPL_DOMAIN_PP0;
-			rd->msrs[0] = MSR_PP0_POWER_LIMIT;
-			rd->msrs[1] = MSR_PP0_ENERGY_STATUS;
-			rd->msrs[2] = 0;
-			rd->msrs[3] = MSR_PP0_POLICY;
-			rd->msrs[4] = 0;
+			rd->regs[0] = MSR_PP0_POWER_LIMIT;
+			rd->regs[1] = MSR_PP0_ENERGY_STATUS;
+			rd->regs[2] = 0;
+			rd->regs[3] = MSR_PP0_POLICY;
+			rd->regs[4] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_PP1):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_PP1];
 			rd->id = RAPL_DOMAIN_PP1;
-			rd->msrs[0] = MSR_PP1_POWER_LIMIT;
-			rd->msrs[1] = MSR_PP1_ENERGY_STATUS;
-			rd->msrs[2] = 0;
-			rd->msrs[3] = MSR_PP1_POLICY;
-			rd->msrs[4] = 0;
+			rd->regs[0] = MSR_PP1_POWER_LIMIT;
+			rd->regs[1] = MSR_PP1_ENERGY_STATUS;
+			rd->regs[2] = 0;
+			rd->regs[3] = MSR_PP1_POLICY;
+			rd->regs[4] = 0;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			break;
 		case BIT(RAPL_DOMAIN_DRAM):
 			rd->name = rapl_domain_names[RAPL_DOMAIN_DRAM];
 			rd->id = RAPL_DOMAIN_DRAM;
-			rd->msrs[0] = MSR_DRAM_POWER_LIMIT;
-			rd->msrs[1] = MSR_DRAM_ENERGY_STATUS;
-			rd->msrs[2] = MSR_DRAM_PERF_STATUS;
-			rd->msrs[3] = 0;
-			rd->msrs[4] = MSR_DRAM_POWER_INFO;
+			rd->regs[0] = MSR_DRAM_POWER_LIMIT;
+			rd->regs[1] = MSR_DRAM_ENERGY_STATUS;
+			rd->regs[2] = MSR_DRAM_PERF_STATUS;
+			rd->regs[3] = 0;
+			rd->regs[4] = MSR_DRAM_POWER_INFO;
 			rd->rpl[0].prim_id = PL1_ENABLE;
 			rd->rpl[0].name = pl1_name;
 			rd->domain_energy_unit =
@@ -736,37 +736,37 @@ static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
 static struct rapl_primitive_info rpi[] = {
 	/* name, mask, shift, msr index, unit divisor */
 	PRIMITIVE_INFO_INIT(ENERGY_COUNTER, ENERGY_STATUS_MASK, 0,
-				RAPL_DOMAIN_MSR_STATUS, ENERGY_UNIT, 0),
+				RAPL_DOMAIN_REG_STATUS, ENERGY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(POWER_LIMIT1, POWER_LIMIT1_MASK, 0,
-				RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
 	PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
-				RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
 	PRIMITIVE_INFO_INIT(FW_LOCK, POWER_PP_LOCK, 31,
-				RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
-				RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16,
-				RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(PL2_ENABLE, POWER_LIMIT2_ENABLE, 47,
-				RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
-				RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
 	PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
-				RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
 	PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
-				RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
+				RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
 	PRIMITIVE_INFO_INIT(THERMAL_SPEC_POWER, POWER_INFO_THERMAL_SPEC_MASK,
-				0, RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+				0, RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
 	PRIMITIVE_INFO_INIT(MAX_POWER, POWER_INFO_MAX_MASK, 32,
-				RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+				RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
 	PRIMITIVE_INFO_INIT(MIN_POWER, POWER_INFO_MIN_MASK, 16,
-				RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+				RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
 	PRIMITIVE_INFO_INIT(MAX_TIME_WINDOW, POWER_INFO_MAX_TIME_WIN_MASK, 48,
-				RAPL_DOMAIN_MSR_INFO, TIME_UNIT, 0),
+				RAPL_DOMAIN_REG_INFO, TIME_UNIT, 0),
 	PRIMITIVE_INFO_INIT(THROTTLED_TIME, PERF_STATUS_THROTTLE_TIME_MASK, 0,
-				RAPL_DOMAIN_MSR_PERF, TIME_UNIT, 0),
+				RAPL_DOMAIN_REG_PERF, TIME_UNIT, 0),
 	PRIMITIVE_INFO_INIT(PRIORITY_LEVEL, PP_POLICY_MASK, 0,
-				RAPL_DOMAIN_MSR_POLICY, ARBITRARY_UNIT, 0),
+				RAPL_DOMAIN_REG_POLICY, ARBITRARY_UNIT, 0),
 	/* non-hardware */
 	PRIMITIVE_INFO_INIT(AVERAGE_POWER, 0, 0, 0, POWER_UNIT,
 				RAPL_PRIMITIVE_DERIVED),
@@ -798,7 +798,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 	if (!rp->name || rp->flag & RAPL_PRIMITIVE_DUMMY)
 		return -EINVAL;
 
-	msr = rd->msrs[rp->id];
+	msr = rd->regs[rp->id];
 	if (!msr)
 		return -EINVAL;
 
@@ -874,7 +874,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
 
 	memset(&ma, 0, sizeof(ma));
 
-	ma.msr_no = rd->msrs[rp->id];
+	ma.msr_no = rd->regs[rp->id];
 	ma.clear_mask = rp->mask;
 	ma.set_mask = bits;
 
@@ -1282,8 +1282,8 @@ static int __init rapl_register_psys(void)
 
 	rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
 	rd->id = RAPL_DOMAIN_PLATFORM;
-	rd->msrs[0] = MSR_PLATFORM_POWER_LIMIT;
-	rd->msrs[1] = MSR_PLATFORM_ENERGY_STATUS;
+	rd->regs[0] = MSR_PLATFORM_POWER_LIMIT;
+	rd->regs[1] = MSR_PLATFORM_ENERGY_STATUS;
 	rd->rpl[0].prim_id = PL1_ENABLE;
 	rd->rpl[0].name = pl1_name;
 	rd->rpl[1].prim_id = PL2_ENABLE;
-- 
2.7.4


^ permalink raw reply related

* [PATCH 00/13] intel_rapl: RAPL abstraction and MMIO RAPL support
From: Zhang Rui @ 2019-06-25 15:16 UTC (permalink / raw)
  To: rjw; +Cc: linux-pm, srinivas.pandruvada, rui.zhang

Besideis MSR interface, RAPL can also be controlled via the MMIO interface,
by accessing the MCHBar registers exposed by the processor thermal device.

Currently, we only have RAPL MSR interface in Linux kernel, this brings
problems on some platforms that BIOS performs a low power limits via the
MMIO interface by default. This results in poor system performance,
and there is no way for us to change the MMIO MSR setting in Linux.

To fix this, RAPL MMIO interface support is introduced in this patch set.

Patch 1/13 to patch 11/13 abstract the RAPL code, and move all the shared
code into a separate file, intel_rapl_common.c, so that it can be used
by both MSR and MMIO interfaces.
Patch 12/13 introduced RAPL support via MMIO registers, exposed by the
processor thermal devices.
Patch 13/13 fixes a module autoloading issue found later.

The patch series has been tested on Dell XPS 9360, a SKL platform.

Note that this patch series are based on the -tip tree, which contains the
latest RAPL changes for multi-die support.

thanks,
rui

^ permalink raw reply

* Re: [PATCH v4 3/3] nvme: notify thermal framework when temperature threshold events occur
From: Akinobu Mita @ 2019-06-25 15:14 UTC (permalink / raw)
  To: Zhang Rui
  Cc: linux-nvme, linux-pm, Eduardo Valentin, Daniel Lezcano,
	Keith Busch, Jens Axboe, Christoph Hellwig, Sagi Grimberg,
	Minwoo Im, Kenneth Heitke, Chaitanya Kulkarni
In-Reply-To: <1561473887.19713.6.camel@intel.com>

2019年6月25日(火) 23:44 Zhang Rui <rui.zhang@intel.com>:
>
> On 五, 2019-06-14 at 00:20 +0900, Akinobu Mita wrote:
> > The NVMe controller supports the temperature threshold feature
> > (Feature
> > Identifier 04h) that enables to configure the asynchronous event
> > request
> > command to complete when the temperature is crossed its corresponding
> > temperature threshold.
> >
> > This enables the reporting of asynchronous events from the controller
> > when
> > the temperature reached or exceeded a temperature threshold.
> > In the case of the temperature threshold conditions, this notifies
> > the
> > thermal framework.
> >
> > The main purpose of this is to turn on a fan when overheated without
> > polling the device for the smart log that could prevent the lower
> > power
> > state transitions.
> >
> > Cc: Zhang Rui <rui.zhang@intel.com>
> > Cc: Eduardo Valentin <edubezval@gmail.com>
> > Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> > Cc: Keith Busch <kbusch@kernel.org>
> > Cc: Jens Axboe <axboe@fb.com>
> > Cc: Christoph Hellwig <hch@lst.de>
> > Cc: Sagi Grimberg <sagi@grimberg.me>
> > Cc: Minwoo Im <minwoo.im.dev@gmail.com>
> > Cc: Kenneth Heitke <kenneth.heitke@intel.com>
> > Cc: Chaitanya Kulkarni <Chaitanya.Kulkarni@wdc.com>
> > Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> > ---
> > * v4
> > - support DT thermal zone device.
> > - use bitmap to iterate over implemented sensors
> >
> >  drivers/nvme/host/core.c    | 14 ++++++++++++++
> >  drivers/nvme/host/nvme.h    |  5 +++++
> >  drivers/nvme/host/thermal.c | 12 ++++++++++++
> >  include/linux/nvme.h        |  7 +++++++
> >  4 files changed, 38 insertions(+)
> >
> > diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> > index 4be339b..44dadbb 100644
> > --- a/drivers/nvme/host/core.c
> > +++ b/drivers/nvme/host/core.c
> > @@ -1186,6 +1186,9 @@ static void nvme_enable_aen(struct nvme_ctrl
> > *ctrl)
> >       u32 result, supported_aens = ctrl->oaes &
> > NVME_AEN_SUPPORTED;
> >       int status;
> >
> > +     if (IS_ENABLED(CONFIG_THERMAL))
> > +             supported_aens |= NVME_SMART_CRIT_TEMPERATURE;
> > +
> >       if (!supported_aens)
> >               return;
> >
> > @@ -3561,6 +3564,16 @@ void nvme_remove_namespaces(struct nvme_ctrl
> > *ctrl)
> >  }
> >  EXPORT_SYMBOL_GPL(nvme_remove_namespaces);
> >
> > +static void nvme_handle_aen_smart(struct nvme_ctrl *ctrl, u32
> > result)
> > +{
> > +     u32 aer_type = result & NVME_AER_TYPE_MASK;
> > +     u32 aer_info = (result >> NVME_AER_INFO_SHIFT) &
> > NVME_AER_INFO_MASK;
> > +
> > +     if (aer_type == NVME_AER_SMART &&
> > +         aer_info == NVME_AER_SMART_TEMP_THRESH)
> > +             nvme_thermal_notify_framework(ctrl);
> > +}
> > +
> >  static void nvme_aen_uevent(struct nvme_ctrl *ctrl)
> >  {
> >       char *envp[2] = { NULL, NULL };
> > @@ -3582,6 +3595,7 @@ static void nvme_async_event_work(struct
> > work_struct *work)
> >       struct nvme_ctrl *ctrl =
> >               container_of(work, struct nvme_ctrl,
> > async_event_work);
> >
> > +     nvme_handle_aen_smart(ctrl, ctrl->aen_result);
> >       nvme_aen_uevent(ctrl);
> >       ctrl->ops->submit_async_event(ctrl);
> >  }
> > diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> > index a9c63ea..40325b6 100644
> > --- a/drivers/nvme/host/nvme.h
> > +++ b/drivers/nvme/host/nvme.h
> > @@ -605,6 +605,7 @@ static inline struct nvme_ns
> > *nvme_get_ns_from_dev(struct device *dev)
> >
> >  int nvme_thermal_zones_register(struct nvme_ctrl *ctrl);
> >  void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl);
> > +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl);
> >
> >  #else
> >
> > @@ -617,6 +618,10 @@ static inline void
> > nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl)
> >  {
> >  }
> >
> > +static inline void nvme_thermal_notify_framework(struct nvme_ctrl
> > *ctrl)
> > +{
> > +}
> > +
> >  #endif /* CONFIG_THERMAL */
> >
> >  #endif /* _NVME_H */
> > diff --git a/drivers/nvme/host/thermal.c
> > b/drivers/nvme/host/thermal.c
> > index 18d0e4c..b5e835d 100644
> > --- a/drivers/nvme/host/thermal.c
> > +++ b/drivers/nvme/host/thermal.c
> > @@ -309,3 +309,15 @@ void nvme_thermal_zones_unregister(struct
> > nvme_ctrl *ctrl)
> >               __clear_bit(i, ctrl->tz_enabled);
> >       }
> >  }
> > +
> > +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl)
> > +{
> > +     int i;
> > +
> > +     for_each_set_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz))
> > {
> > +             if (ctrl->tz[i].dev)
> > +                     thermal_notify_framework(ctrl->tz[i].dev,
> > 0);
>
> I'd prefer to use thermal_zone_device_update() here to notify the
> thermal framework.
> thermal_notify_framework() will be removed sometime later.

You are right.

I got my ROCKPro64 board and just started testing with pwm-fan cooling
device.  And then I also noticed that using thermal_notify_framework()
is insufficient when polling-delay is zero (i.e. interrupt driven thermal
zone).

^ permalink raw reply

* Re: [PATCH v4 2/3] nvme: add thermal zone devices
From: Zhang Rui @ 2019-06-25 15:03 UTC (permalink / raw)
  To: Akinobu Mita, linux-nvme, linux-pm
  Cc: Eduardo Valentin, Daniel Lezcano, Keith Busch, Jens Axboe,
	Christoph Hellwig, Sagi Grimberg, Minwoo Im, Kenneth Heitke,
	Chaitanya Kulkarni
In-Reply-To: <1560439238-4054-3-git-send-email-akinobu.mita@gmail.com>

On 五, 2019-06-14 at 00:20 +0900, Akinobu Mita wrote:
> The NVMe controller reports up to nine temperature values in the
> SMART /
> Health log page (the composite temperature and temperature sensor 1
> through
> temperature sensor 8).
> 
> This provides these temperatures via thermal zone devices.
> 
> Once the controller is identified, the thermal zone devices are
> created for
> all implemented temperature sensors including the composite
> temperature.
> 
> /sys/class/thermal/thermal_zone[0-*]:
>     |---type: 'nvme<instance>-temp<sensor>'
>     |---temp: Temperature
>     |---trip_point_0_temp: Over temperature threshold
> 
> The thermal_zone[0-*] contains a 'device' symlink to the
> corresponding nvme
> device.
> 
> On the other hand, the following symlinks to the thermal zone devices
> are
> created in the nvme device sysfs directory.
> 
> - temp0: Composite temperature
> - temp1: Temperature sensor 1
> ...
> - temp8: Temperature sensor 8
> 
> In addition to the standard thermal zone device, this also adds
> support for
> registering the DT thermal zone device.
> 
I don't see standard thermal zone device and DT thermal zone device are
registered at the same time very often, especially if they represent
the same sensor.

Eduardo, any comments?

thanks,
rui

> Cc: Zhang Rui <rui.zhang@intel.com>
> Cc: Eduardo Valentin <edubezval@gmail.com>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Keith Busch <kbusch@kernel.org>
> Cc: Jens Axboe <axboe@fb.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Sagi Grimberg <sagi@grimberg.me>
> Cc: Minwoo Im <minwoo.im.dev@gmail.com>
> Cc: Kenneth Heitke <kenneth.heitke@intel.com>
> Cc: Chaitanya Kulkarni <Chaitanya.Kulkarni@wdc.com>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> ---
> * v4
> - add thermal.c to hold thermal zone related code
> - add 'use_thermal_zone' module parameter
> - add CONFIG_THERMAL_WRITABLE_TRIPS dependency
> - add comment about the return value of nvme_thermal_zones_register()
> - support DT thermal zone device.
> - use bitmap to iterate over implemented sensors
> 
>  drivers/nvme/host/Kconfig   |   1 +
>  drivers/nvme/host/Makefile  |   1 +
>  drivers/nvme/host/core.c    |   5 +
>  drivers/nvme/host/nvme.h    |  35 +++++
>  drivers/nvme/host/thermal.c | 311
> ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/nvme.h        |   5 +
>  6 files changed, 358 insertions(+)
>  create mode 100644 drivers/nvme/host/thermal.c
> 
> diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
> index ec43ac9..90429f8 100644
> --- a/drivers/nvme/host/Kconfig
> +++ b/drivers/nvme/host/Kconfig
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  config NVME_CORE
>  	tristate
> +	select THERMAL_WRITABLE_TRIPS if THERMAL
>  
>  config BLK_DEV_NVME
>  	tristate "NVM Express block device"
> diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile
> index 8a4b671..6018668 100644
> --- a/drivers/nvme/host/Makefile
> +++ b/drivers/nvme/host/Makefile
> @@ -14,6 +14,7 @@ nvme-core-$(CONFIG_TRACING)		+=
> trace.o
>  nvme-core-$(CONFIG_NVME_MULTIPATH)	+= multipath.o
>  nvme-core-$(CONFIG_NVM)			+= lightnvm.o
>  nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS)	+=
> fault_inject.o
> +nvme-core-$(CONFIG_THERMAL)		+= thermal.o
>  
>  nvme-y					+= pci.o
>  
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 7e3c786..4be339b 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2696,6 +2696,10 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
>  	if (ret < 0)
>  		return ret;
>  
> +	ret = nvme_thermal_zones_register(ctrl);
> +	if (ret)
> +		return ret;
> +
>  	ctrl->identified = true;
>  
>  	return 0;
> @@ -3699,6 +3703,7 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl)
>  {
>  	nvme_mpath_stop(ctrl);
>  	nvme_stop_keep_alive(ctrl);
> +	nvme_thermal_zones_unregister(ctrl);
>  	flush_work(&ctrl->async_event_work);
>  	cancel_work_sync(&ctrl->fw_act_work);
>  }
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 038b893..a9c63ea 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -15,6 +15,7 @@
>  #include <linux/sed-opal.h>
>  #include <linux/fault-inject.h>
>  #include <linux/rcupdate.h>
> +#include <linux/thermal.h>
>  
>  extern unsigned int nvme_io_timeout;
>  #define NVME_IO_TIMEOUT	(nvme_io_timeout * HZ)
> @@ -146,6 +147,13 @@ enum nvme_ctrl_state {
>  	NVME_CTRL_DEAD,
>  };
>  
> +struct nvme_tz {
> +	struct thermal_zone_params params;
> +	struct thermal_zone_device *dev;
> +	struct thermal_zone_device *of_dev;
> +	unsigned int sensor;
> +};
> +
>  struct nvme_ctrl {
>  	bool comp_seen;
>  	enum nvme_ctrl_state state;
> @@ -247,6 +255,15 @@ struct nvme_ctrl {
>  
>  	struct page *discard_page;
>  	unsigned long discard_page_busy;
> +
> +#ifdef CONFIG_THERMAL
> +	/*
> +	 * tz[0]: composite temperature
> +	 * tz[1-8]: temperature sensor 1 through 8
> +	 */
> +	struct nvme_tz tz[9];
> +	DECLARE_BITMAP(tz_enabled, 9);
> +#endif
>  };
>  
>  enum nvme_iopolicy {
> @@ -584,4 +601,22 @@ static inline struct nvme_ns
> *nvme_get_ns_from_dev(struct device *dev)
>  	return dev_to_disk(dev)->private_data;
>  }
>  
> +#ifdef CONFIG_THERMAL
> +
> +int nvme_thermal_zones_register(struct nvme_ctrl *ctrl);
> +void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl);
> +
> +#else
> +
> +static inline int nvme_thermal_zones_register(struct nvme_ctrl
> *ctrl)
> +{
> +	return 0;
> +}
> +
> +static inline void nvme_thermal_zones_unregister(struct nvme_ctrl
> *ctrl)
> +{
> +}
> +
> +#endif /* CONFIG_THERMAL */
> +
>  #endif /* _NVME_H */
> diff --git a/drivers/nvme/host/thermal.c
> b/drivers/nvme/host/thermal.c
> new file mode 100644
> index 0000000..18d0e4c
> --- /dev/null
> +++ b/drivers/nvme/host/thermal.c
> @@ -0,0 +1,311 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/moduleparam.h>
> +#include <asm/unaligned.h>
> +
> +#include "nvme.h"
> +
> +static bool use_thermal_zone = true;
> +module_param(use_thermal_zone, bool, 0444);
> +MODULE_PARM_DESC(use_thermal_zone,
> +	"Export nvme temperature via generic thermal interface");
> +
> +static int nvme_get_temp(struct nvme_ctrl *ctrl, unsigned int
> sensor, int *temp)
> +{
> +	struct nvme_smart_log *log;
> +	int ret;
> +
> +	BUILD_BUG_ON(ARRAY_SIZE(log->temp_sensor) + 1 !=
> ARRAY_SIZE(ctrl->tz));
> +
> +	if (WARN_ON_ONCE(sensor > ARRAY_SIZE(log->temp_sensor)))
> +		return -EINVAL;
> +
> +	log = kzalloc(sizeof(*log), GFP_KERNEL);
> +	if (!log)
> +		return -ENOMEM;
> +
> +	ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
> log,
> +			   sizeof(*log), 0);
> +	if (ret) {
> +		ret = ret > 0 ? -EINVAL : ret;
> +		goto free_log;
> +	}
> +
> +	if (sensor)
> +		*temp = le16_to_cpu(log->temp_sensor[sensor - 1]);
> +	else
> +		*temp = get_unaligned_le16(log->temperature);
> +
> +free_log:
> +	kfree(log);
> +
> +	return ret;
> +}
> +
> +#define KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS((t) *
> 10)
> +#define MILLICELSIUS_TO_KELVIN(t) ((MILLICELSIUS_TO_DECI_KELVIN(t) +
> 5) / 10)
> +
> +static int nvme_tz_of_get_temp(void *data, int *temp)
> +{
> +	struct nvme_tz *tz = data;
> +	unsigned int sensor = tz->sensor;
> +	struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl,
> tz[sensor]);
> +	int ret;
> +
> +	ret = nvme_get_temp(ctrl, sensor, temp);
> +	if (!ret)
> +		*temp = KELVIN_TO_MILLICELSIUS(*temp);
> +
> +	return ret;
> +}
> +
> +static int nvme_tz_get_temp(struct thermal_zone_device *tzdev, int
> *temp)
> +{
> +	return nvme_tz_of_get_temp(tzdev->devdata, temp);
> +}
> +
> +static int nvme_tz_get_trip_type(struct thermal_zone_device *tzdev,
> +				 int trip, enum thermal_trip_type
> *type)
> +{
> +	*type = THERMAL_TRIP_ACTIVE;
> +
> +	return 0;
> +}
> +
> +static int nvme_get_over_temp_thresh(struct nvme_ctrl *ctrl,
> +				     unsigned int sensor, int *temp)
> +{
> +	unsigned int threshold = sensor <<
> NVME_TEMP_THRESH_SELECT_SHIFT;
> +	int status;
> +	int ret;
> +
> +	if (WARN_ON_ONCE(sensor >= ARRAY_SIZE(ctrl->tz)))
> +		return -EINVAL;
> +
> +	ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH,
> threshold, NULL, 0,
> +				&status);
> +	if (!ret)
> +		*temp = status & NVME_TEMP_THRESH_MASK;
> +
> +	return ret > 0 ? -EINVAL : ret;
> +}
> +
> +static int nvme_set_over_temp_thresh(struct nvme_ctrl *ctrl,
> +				     unsigned int sensor, int temp)
> +{
> +	unsigned int threshold = sensor <<
> NVME_TEMP_THRESH_SELECT_SHIFT;
> +	int ret;
> +
> +	if (WARN_ON_ONCE(sensor >= ARRAY_SIZE(ctrl->tz)))
> +		return -EINVAL;
> +
> +	if (temp > NVME_TEMP_THRESH_MASK)
> +		return -EINVAL;
> +
> +	threshold |= temp & NVME_TEMP_THRESH_MASK;
> +
> +	ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH,
> threshold, NULL, 0,
> +				NULL);
> +
> +	return ret > 0 ? -EINVAL : ret;
> +}
> +
> +static int nvme_tz_get_trip_temp(struct thermal_zone_device *tzdev,
> +				 int trip, int *temp)
> +{
> +	struct nvme_tz *tz = tzdev->devdata;
> +	unsigned int sensor = tz->sensor;
> +	struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl,
> tz[sensor]);
> +	int ret;
> +
> +	ret = nvme_get_over_temp_thresh(ctrl, sensor, temp);
> +	if (!ret)
> +		*temp = KELVIN_TO_MILLICELSIUS(*temp);
> +
> +	return ret;
> +}
> +
> +static int nvme_tz_of_set_trip_temp(void *data, int trip, int temp)
> +{
> +	struct nvme_tz *tz = data;
> +	unsigned int sensor = tz->sensor;
> +	struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl,
> tz[sensor]);
> +
> +	temp = MILLICELSIUS_TO_KELVIN(temp);
> +
> +	return nvme_set_over_temp_thresh(ctrl, sensor, temp);
> +}
> +
> +static int nvme_tz_set_trip_temp(struct thermal_zone_device *tzdev,
> +				 int trip, int temp)
> +{
> +	return nvme_tz_of_set_trip_temp(tzdev->devdata, trip, temp);
> +}
> +
> +static struct thermal_zone_device_ops nvme_tz_ops = {
> +	.get_temp = nvme_tz_get_temp,
> +	.get_trip_type = nvme_tz_get_trip_type,
> +	.get_trip_temp = nvme_tz_get_trip_temp,
> +	.set_trip_temp = nvme_tz_set_trip_temp,
> +};
> +
> +static struct thermal_zone_of_device_ops nvme_tz_of_ops = {
> +	.get_temp = nvme_tz_of_get_temp,
> +	.set_trip_temp = nvme_tz_of_set_trip_temp,
> +};
> +
> +static const struct thermal_zone_params nvme_tz_params = {
> +	.governor_name = "user_space",
> +	.no_hwmon = true,
> +};
> +
> +static int nvme_thermal_zone_register(struct nvme_ctrl *ctrl,
> +				      unsigned int sensor)
> +{
> +	struct thermal_zone_device *tzdev;
> +	struct nvme_tz *tz = &ctrl->tz[sensor];
> +	char name[THERMAL_NAME_LENGTH];
> +	int ret;
> +
> +	tz->params = nvme_tz_params;
> +	tz->sensor = sensor;
> +	snprintf(name, sizeof(name), "nvme%d_temp%u", ctrl-
> >instance, sensor);
> +
> +	tzdev = thermal_zone_device_register(name, 1, 1, tz,
> &nvme_tz_ops,
> +					     &tz->params, 0, 0);
> +	if (IS_ERR(tzdev)) {
> +		dev_err(ctrl->device,
> +			"Failed to register thermal zone device:
> %ld\n",
> +			PTR_ERR(tzdev));
> +		return PTR_ERR(tzdev);
> +	}
> +
> +	tz->dev = tzdev;
> +
> +	snprintf(name, sizeof(name), "temp%d", sensor);
> +	ret = sysfs_create_link(&ctrl->ctrl_device.kobj, &tz->dev-
> >device.kobj,
> +				name);
> +	if (ret)
> +		goto device_unregister;
> +
> +	ret = sysfs_create_link(&tz->dev->device.kobj,
> +				&ctrl->ctrl_device.kobj, "device");
> +	if (ret)
> +		goto remove_sensor_link;
> +
> +	tzdev = thermal_zone_of_sensor_register(ctrl->dev, sensor,
> tz,
> +						&nvme_tz_of_ops);
> +	if (!IS_ERR(tzdev)) {
> +		tz->of_dev = tzdev;
> +	} else if (PTR_ERR(tzdev) != -ENODEV) {
> +		ret = PTR_ERR(tzdev);
> +		dev_err(ctrl->device,
> +			"Failed to register thermal zone of sensor:
> %d\n", ret);
> +		goto remove_device_link;
> +	}
> +
> +	return 0;
> +
> +remove_device_link:
> +	sysfs_remove_link(&tz->dev->device.kobj, "device");
> +remove_sensor_link:
> +	sysfs_remove_link(&ctrl->ctrl_device.kobj, name);
> +device_unregister:
> +	thermal_zone_device_unregister(tz->dev);
> +	tz->dev = NULL;
> +
> +	return ret;
> +}
> +
> +/**
> + * nvme_thermal_zones_register() - register nvme thermal zone
> devices
> + * @ctrl: controller instance
> + *
> + * This function creates up to nine thermal zone devices for all
> implemented
> + * temperature sensors including the composite temperature.
> + * Each thermal zone device provides a single trip point temperature
> that is
> + * associated with an over temperature threshold.
> + * A negative value is returned when the device doesn't respond to
> the host
> + * and won't be able to continue initialization.
> + */
> +int nvme_thermal_zones_register(struct nvme_ctrl *ctrl)
> +{
> +	struct nvme_smart_log *log;
> +	int ret = 0;
> +	int err;
> +	int i;
> +
> +	if (!use_thermal_zone)
> +		return 0;
> +
> +	log = kzalloc(sizeof(*log), GFP_KERNEL);
> +	if (!log)
> +		return 0;
> +
> +	err = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
> log,
> +			   sizeof(*log), 0);
> +	if (err) {
> +		dev_err(ctrl->device, "Failed to get SMART log:
> %d\n", err);
> +		/* If the device provided a response, then it's non-
> fatal */
> +		ret = (err > 0) ? 0 : err;
> +		goto out;
> +	}
> +
> +	for_each_clear_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl-
> >tz)) {
> +		int temp;
> +
> +		if (i)
> +			temp = le16_to_cpu(log->temp_sensor[i - 1]);
> +		else
> +			temp = get_unaligned_le16(log->temperature);
> +
> +		/*
> +		 * All implemented temperature sensors report a non-
> zero value
> +		 * in temperature sensor fields in the smart log
> page.
> +		 */
> +		if (!temp)
> +			continue;
> +
> +		err = nvme_thermal_zone_register(ctrl, i);
> +		if (err)
> +			goto out;
> +
> +		__set_bit(i, ctrl->tz_enabled);
> +	}
> +out:
> +	if (err)
> +		nvme_thermal_zones_unregister(ctrl);
> +
> +	kfree(log);
> +
> +	return ret;
> +}
> +
> +/**
> + * nvme_thermal_zones_unregister() - unregister nvme thermal zone
> devices
> + * @ctrl: controller instance
> + *
> + * This function removes the registered thermal zone devices and
> symlinks.
> + */
> +void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl)
> +{
> +	int i;
> +
> +	for_each_set_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz))
> {
> +		struct nvme_tz *tz = &ctrl->tz[i];
> +		char name[20];
> +
> +		thermal_zone_of_sensor_unregister(ctrl->dev, tz-
> >of_dev);
> +		tz->of_dev = NULL;
> +
> +		sysfs_remove_link(&tz->dev->device.kobj, "device");
> +
> +		snprintf(name, sizeof(name), "temp%d", i);
> +		sysfs_remove_link(&ctrl->ctrl_device.kobj, name);
> +
> +		thermal_zone_device_unregister(tz->dev);
> +		tz->dev = NULL;
> +
> +		__clear_bit(i, ctrl->tz_enabled);
> +	}
> +}
> diff --git a/include/linux/nvme.h b/include/linux/nvme.h
> index 8028ada..f29728b 100644
> --- a/include/linux/nvme.h
> +++ b/include/linux/nvme.h
> @@ -749,6 +749,11 @@ struct nvme_write_zeroes_cmd {
>  
>  /* Features */
>  
> +enum {
> +	NVME_TEMP_THRESH_MASK		= 0xffff,
> +	NVME_TEMP_THRESH_SELECT_SHIFT	= 16,
> +};
> +
>  struct nvme_feat_auto_pst {
>  	__le64 entries[32];
>  };

^ permalink raw reply

* Re: [PATCH v4 1/5] dt-bindings: interconnect: Add Qualcomm QCS404 DT bindings
From: Georgi Djakov @ 2019-06-25 15:00 UTC (permalink / raw)
  To: robh+dt, devicetree
  Cc: bjorn.andersson, agross, vkoul, evgreen, daidavid1, linux-pm,
	linux-kernel, linux-arm-msm
In-Reply-To: <20190613151323.10850-2-georgi.djakov@linaro.org>

Hi Rob,

On 6/13/19 18:13, Georgi Djakov wrote:
> The Qualcomm QCS404 platform has several buses that could be controlled
> and tuned according to the bandwidth demand.
> 
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
> ---
> 
> v4:
> - Add the DT header into this patch.
> - Pick Bjorn's r-b.
> 
> v3:
> - Add a reg property and move the interconnect nodes under the "soc" node.
> 
> v2:
> - No changes.
> 
>  .../bindings/interconnect/qcom,qcs404.txt     | 46 ++++++++++
>  .../dt-bindings/interconnect/qcom,qcs404.h    | 88 +++++++++++++++++++
>  2 files changed, 134 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt
>  create mode 100644 include/dt-bindings/interconnect/qcom,qcs404.h
> 
> diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt
> new file mode 100644
> index 000000000000..14a827268dda
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt
> @@ -0,0 +1,46 @@
> +Qualcomm QCS404 Network-On-Chip interconnect driver binding
> +-----------------------------------------------------------
> +
> +Required properties :
> +- compatible : shall contain only one of the following:
> +			"qcom,qcs404-bimc"
> +			"qcom,qcs404-pcnoc"
> +			"qcom,qcs404-snoc"
> +- #interconnect-cells : should contain 1
> +
> +Optional properties :
> +reg : specifies the physical base address and size of registers
> +clocks : list of phandles and specifiers to all interconnect bus clocks
> +clock-names : clock names should include both "bus_clk" and "bus_a_clk"
> +
> +Example:
> +
> +soc {
> +	...
> +	bimc: interconnect@400000 {
> +		reg = <0x00400000 0x80000>;
> +		compatible = "qcom,qcs404-bimc";
> +		#interconnect-cells = <1>;
> +		clock-names = "bus_clk", "bus_a_clk";
> +		clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
> +			<&rpmcc RPM_SMD_BIMC_A_CLK>;
> +	};
> +
> +	pnoc: interconnect@500000 {
> +		reg = <0x00500000 0x15080>;
> +		compatible = "qcom,qcs404-pcnoc";
> +		#interconnect-cells = <1>;
> +		clock-names = "bus_clk", "bus_a_clk";
> +		clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
> +			<&rpmcc RPM_SMD_PNOC_A_CLK>;
> +	};
> +
> +	snoc: interconnect@580000 {
> +		reg = <0x00580000 0x23080>;
> +		compatible = "qcom,qcs404-snoc";
> +		#interconnect-cells = <1>;
> +		clock-names = "bus_clk", "bus_a_clk";
> +		clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
> +			<&rpmcc RPM_SMD_SNOC_A_CLK>;
> +	};
> +};

Does this look ok from DT perspective?

Thanks,
Georgi

> diff --git a/include/dt-bindings/interconnect/qcom,qcs404.h b/include/dt-bindings/interconnect/qcom,qcs404.h
> new file mode 100644
> index 000000000000..960f6e39c5f2
> --- /dev/null
> +++ b/include/dt-bindings/interconnect/qcom,qcs404.h
> @@ -0,0 +1,88 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Qualcomm interconnect IDs
> + *
> + * Copyright (c) 2019, Linaro Ltd.
> + * Author: Georgi Djakov <georgi.djakov@linaro.org>
> + */
> +
> +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_QCS404_H
> +#define __DT_BINDINGS_INTERCONNECT_QCOM_QCS404_H
> +
> +#define MASTER_AMPSS_M0			0
> +#define MASTER_OXILI			1
> +#define MASTER_MDP_PORT0		2
> +#define MASTER_SNOC_BIMC_1		3
> +#define MASTER_TCU_0			4
> +#define SLAVE_EBI_CH0			5
> +#define SLAVE_BIMC_SNOC			6
> +
> +#define MASTER_SPDM			0
> +#define MASTER_BLSP_1			1
> +#define MASTER_BLSP_2			2
> +#define MASTER_XI_USB_HS1		3
> +#define MASTER_CRYPT0			4
> +#define MASTER_SDCC_1			5
> +#define MASTER_SDCC_2			6
> +#define MASTER_SNOC_PCNOC		7
> +#define MASTER_QPIC			8
> +#define PCNOC_INT_0			9
> +#define PCNOC_INT_2			10
> +#define PCNOC_INT_3			11
> +#define PCNOC_S_0			12
> +#define PCNOC_S_1			13
> +#define PCNOC_S_2			14
> +#define PCNOC_S_3			15
> +#define PCNOC_S_4			16
> +#define PCNOC_S_6			17
> +#define PCNOC_S_7			18
> +#define PCNOC_S_8			19
> +#define PCNOC_S_9			20
> +#define PCNOC_S_10			21
> +#define PCNOC_S_11			22
> +#define SLAVE_SPDM			23
> +#define SLAVE_PDM			24
> +#define SLAVE_PRNG			25
> +#define SLAVE_TCSR			26
> +#define SLAVE_SNOC_CFG			27
> +#define SLAVE_MESSAGE_RAM		28
> +#define SLAVE_DISP_SS_CFG		29
> +#define SLAVE_GPU_CFG			30
> +#define SLAVE_BLSP_1			31
> +#define SLAVE_BLSP_2			32
> +#define SLAVE_TLMM_NORTH		33
> +#define SLAVE_PCIE			34
> +#define SLAVE_ETHERNET			35
> +#define SLAVE_TLMM_EAST			36
> +#define SLAVE_TCU			37
> +#define SLAVE_PMIC_ARB			38
> +#define SLAVE_SDCC_1			39
> +#define SLAVE_SDCC_2			40
> +#define SLAVE_TLMM_SOUTH		41
> +#define SLAVE_USB_HS			42
> +#define SLAVE_USB3			43
> +#define SLAVE_CRYPTO_0_CFG		44
> +#define SLAVE_PCNOC_SNOC		45
> +
> +#define MASTER_QDSS_BAM			0
> +#define MASTER_BIMC_SNOC		1
> +#define MASTER_PCNOC_SNOC		2
> +#define MASTER_QDSS_ETR			3
> +#define MASTER_EMAC			4
> +#define MASTER_PCIE			5
> +#define MASTER_USB3			6
> +#define QDSS_INT			7
> +#define SNOC_INT_0			8
> +#define SNOC_INT_1			9
> +#define SNOC_INT_2			10
> +#define SLAVE_KPSS_AHB			11
> +#define SLAVE_WCSS			12
> +#define SLAVE_SNOC_BIMC_1		13
> +#define SLAVE_IMEM			14
> +#define SLAVE_SNOC_PCNOC		15
> +#define SLAVE_QDSS_STM			16
> +#define SLAVE_CATS_0			17
> +#define SLAVE_CATS_1			18
> +#define SLAVE_LPASS			19
> +
> +#endif
> 

^ permalink raw reply

* Re: [PATCH v4 3/3] nvme: notify thermal framework when temperature threshold events occur
From: Zhang Rui @ 2019-06-25 14:44 UTC (permalink / raw)
  To: Akinobu Mita, linux-nvme, linux-pm
  Cc: Eduardo Valentin, Daniel Lezcano, Keith Busch, Jens Axboe,
	Christoph Hellwig, Sagi Grimberg, Minwoo Im, Kenneth Heitke,
	Chaitanya Kulkarni
In-Reply-To: <1560439238-4054-4-git-send-email-akinobu.mita@gmail.com>

On 五, 2019-06-14 at 00:20 +0900, Akinobu Mita wrote:
> The NVMe controller supports the temperature threshold feature
> (Feature
> Identifier 04h) that enables to configure the asynchronous event
> request
> command to complete when the temperature is crossed its corresponding
> temperature threshold.
> 
> This enables the reporting of asynchronous events from the controller
> when
> the temperature reached or exceeded a temperature threshold.
> In the case of the temperature threshold conditions, this notifies
> the
> thermal framework.
> 
> The main purpose of this is to turn on a fan when overheated without
> polling the device for the smart log that could prevent the lower
> power
> state transitions.
> 
> Cc: Zhang Rui <rui.zhang@intel.com>
> Cc: Eduardo Valentin <edubezval@gmail.com>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Keith Busch <kbusch@kernel.org>
> Cc: Jens Axboe <axboe@fb.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Sagi Grimberg <sagi@grimberg.me>
> Cc: Minwoo Im <minwoo.im.dev@gmail.com>
> Cc: Kenneth Heitke <kenneth.heitke@intel.com>
> Cc: Chaitanya Kulkarni <Chaitanya.Kulkarni@wdc.com>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> ---
> * v4
> - support DT thermal zone device.
> - use bitmap to iterate over implemented sensors
> 
>  drivers/nvme/host/core.c    | 14 ++++++++++++++
>  drivers/nvme/host/nvme.h    |  5 +++++
>  drivers/nvme/host/thermal.c | 12 ++++++++++++
>  include/linux/nvme.h        |  7 +++++++
>  4 files changed, 38 insertions(+)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 4be339b..44dadbb 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -1186,6 +1186,9 @@ static void nvme_enable_aen(struct nvme_ctrl
> *ctrl)
>  	u32 result, supported_aens = ctrl->oaes &
> NVME_AEN_SUPPORTED;
>  	int status;
>  
> +	if (IS_ENABLED(CONFIG_THERMAL))
> +		supported_aens |= NVME_SMART_CRIT_TEMPERATURE;
> +
>  	if (!supported_aens)
>  		return;
>  
> @@ -3561,6 +3564,16 @@ void nvme_remove_namespaces(struct nvme_ctrl
> *ctrl)
>  }
>  EXPORT_SYMBOL_GPL(nvme_remove_namespaces);
>  
> +static void nvme_handle_aen_smart(struct nvme_ctrl *ctrl, u32
> result)
> +{
> +	u32 aer_type = result & NVME_AER_TYPE_MASK;
> +	u32 aer_info = (result >> NVME_AER_INFO_SHIFT) &
> NVME_AER_INFO_MASK;
> +
> +	if (aer_type == NVME_AER_SMART &&
> +	    aer_info == NVME_AER_SMART_TEMP_THRESH)
> +		nvme_thermal_notify_framework(ctrl);
> +}
> +
>  static void nvme_aen_uevent(struct nvme_ctrl *ctrl)
>  {
>  	char *envp[2] = { NULL, NULL };
> @@ -3582,6 +3595,7 @@ static void nvme_async_event_work(struct
> work_struct *work)
>  	struct nvme_ctrl *ctrl =
>  		container_of(work, struct nvme_ctrl,
> async_event_work);
>  
> +	nvme_handle_aen_smart(ctrl, ctrl->aen_result);
>  	nvme_aen_uevent(ctrl);
>  	ctrl->ops->submit_async_event(ctrl);
>  }
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index a9c63ea..40325b6 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -605,6 +605,7 @@ static inline struct nvme_ns
> *nvme_get_ns_from_dev(struct device *dev)
>  
>  int nvme_thermal_zones_register(struct nvme_ctrl *ctrl);
>  void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl);
> +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl);
>  
>  #else
>  
> @@ -617,6 +618,10 @@ static inline void
> nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl)
>  {
>  }
>  
> +static inline void nvme_thermal_notify_framework(struct nvme_ctrl
> *ctrl)
> +{
> +}
> +
>  #endif /* CONFIG_THERMAL */
>  
>  #endif /* _NVME_H */
> diff --git a/drivers/nvme/host/thermal.c
> b/drivers/nvme/host/thermal.c
> index 18d0e4c..b5e835d 100644
> --- a/drivers/nvme/host/thermal.c
> +++ b/drivers/nvme/host/thermal.c
> @@ -309,3 +309,15 @@ void nvme_thermal_zones_unregister(struct
> nvme_ctrl *ctrl)
>  		__clear_bit(i, ctrl->tz_enabled);
>  	}
>  }
> +
> +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl)
> +{
> +	int i;
> +
> +	for_each_set_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz))
> {
> +		if (ctrl->tz[i].dev)
> +			thermal_notify_framework(ctrl->tz[i].dev,
> 0);

I'd prefer to use thermal_zone_device_update() here to notify the
thermal framework.
thermal_notify_framework() will be removed sometime later.

thanks,
rui

> +		if (ctrl->tz[i].of_dev)
> +			thermal_notify_framework(ctrl->tz[i].of_dev, 
> 0);
> +	}
> +}
> diff --git a/include/linux/nvme.h b/include/linux/nvme.h
> index f29728b..069b962 100644
> --- a/include/linux/nvme.h
> +++ b/include/linux/nvme.h
> @@ -476,6 +476,7 @@ enum {
>  };
>  
>  enum {
> +	NVME_AER_TYPE_MASK		= 0x7,
>  	NVME_AER_ERROR			= 0,
>  	NVME_AER_SMART			= 1,
>  	NVME_AER_NOTICE			= 2,
> @@ -484,6 +485,12 @@ enum {
>  };
>  
>  enum {
> +	NVME_AER_INFO_SHIFT		= 8,
> +	NVME_AER_INFO_MASK		= 0xff,
> +	NVME_AER_SMART_TEMP_THRESH	= 0x01,
> +};
> +
> +enum {
>  	NVME_AER_NOTICE_NS_CHANGED	= 0x00,
>  	NVME_AER_NOTICE_FW_ACT_STARTING = 0x01,
>  	NVME_AER_NOTICE_ANA		= 0x03,

^ permalink raw reply

* Re: [PATCH v1 04/22] docs: thermal: convert to ReST
From: Zhang Rui @ 2019-06-25 14:21 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Doc Mailing List, Mauro Carvalho Chehab, linux-kernel,
	Jonathan Corbet, Amit Daniel Kachhap, Viresh Kumar, Javi Merino,
	Kukjin Kim, Krzysztof Kozlowski, Eduardo Valentin, Daniel Lezcano,
	linux-pm, linux-arm-kernel, linux-samsung-soc, Arjan van de Ven
In-Reply-To: <20190625105334.19ae5d12@coco.lan>

On 二, 2019-06-25 at 10:53 -0300, Mauro Carvalho Chehab wrote:
> Em Tue, 25 Jun 2019 21:40:11 +0800
> Zhang Rui <rui.zhang@intel.com> escreveu:
> 
> > 
> > On 二, 2019-06-18 at 18:05 -0300, Mauro Carvalho Chehab wrote:
> > > 
> > > Rename the thermal documentation files to ReST, add an
> > > index for them and adjust in order to produce a nice html
> > > output via the Sphinx build system.
> > > 
> > > At its new index.rst, let's add a :orphan: while this is not
> > > linked
> > > to
> > > the main index.rst file, in order to avoid build warnings.
> > > 
> > > Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> > >   
> > Acked-by: Zhang Rui <rui.zhang@intel.com>
> > 
> > should I apply this patch or you have a separate tree for all these
> > changes?
> Feel free to apply it directly to your tree. The patches on this
> series are pretty much independent.
> 
okay, queued for 5.3-rc1.

thanks,
rui
> > 
> > 
> > thanks,
> > rui
> > > 
> > > ---
> > >  ...pu-cooling-api.txt => cpu-cooling-api.rst} |  39 +-
> > >  .../{exynos_thermal => exynos_thermal.rst}    |  47 +-
> > >  ...emulation => exynos_thermal_emulation.rst} |  66 +--
> > >  Documentation/thermal/index.rst               |  18 +
> > >  ...el_powerclamp.txt => intel_powerclamp.rst} | 177 +++----
> > >  .../{nouveau_thermal => nouveau_thermal.rst}  |  54 +-
> > >  ...ower_allocator.txt => power_allocator.rst} | 140 ++---
> > >  .../thermal/{sysfs-api.txt => sysfs-api.rst}  | 490
> > > ++++++++++++--
> > > ----
> > >  ...hermal => x86_pkg_temperature_thermal.rst} |  28 +-
> > >  MAINTAINERS                                   |   2 +-
> > >  include/linux/thermal.h                       |   4 +-
> > >  11 files changed, 665 insertions(+), 400 deletions(-)
> > >  rename Documentation/thermal/{cpu-cooling-api.txt => cpu-
> > > cooling-
> > > api.rst} (82%)
> > >  rename Documentation/thermal/{exynos_thermal =>
> > > exynos_thermal.rst}
> > > (67%)
> > >  rename Documentation/thermal/{exynos_thermal_emulation =>
> > > exynos_thermal_emulation.rst} (36%)
> > >  create mode 100644 Documentation/thermal/index.rst
> > >  rename Documentation/thermal/{intel_powerclamp.txt =>
> > > intel_powerclamp.rst} (76%)
> > >  rename Documentation/thermal/{nouveau_thermal =>
> > > nouveau_thermal.rst} (64%)
> > >  rename Documentation/thermal/{power_allocator.txt =>
> > > power_allocator.rst} (74%)
> > >  rename Documentation/thermal/{sysfs-api.txt => sysfs-api.rst}
> > > (66%)
> > >  rename Documentation/thermal/{x86_pkg_temperature_thermal =>
> > > x86_pkg_temperature_thermal.rst} (80%)
> > > 
> > > diff --git a/Documentation/thermal/cpu-cooling-api.txt
> > > b/Documentation/thermal/cpu-cooling-api.rst
> > > similarity index 82%
> > > rename from Documentation/thermal/cpu-cooling-api.txt
> > > rename to Documentation/thermal/cpu-cooling-api.rst
> > > index 7df567eaea1a..645d914c45a6 100644
> > > --- a/Documentation/thermal/cpu-cooling-api.txt
> > > +++ b/Documentation/thermal/cpu-cooling-api.rst
> > > @@ -1,5 +1,6 @@
> > > +=======================
> > >  CPU cooling APIs How To
> > > -===================================
> > > +=======================
> > >  
> > >  Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > >  
> > > @@ -8,40 +9,54 @@ Updated: 6 Jan 2015
> > >  Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.sams
> > > ung.
> > > com)
> > >  
> > >  0. Introduction
> > > +===============
> > >  
> > >  The generic cpu cooling(freq clipping) provides
> > > registration/unregistration APIs
> > >  to the caller. The binding of the cooling devices to the trip
> > > point
> > > is left for
> > >  the user. The registration APIs returns the cooling device
> > > pointer.
> > >  
> > >  1. cpu cooling APIs
> > > +===================
> > >  
> > >  1.1 cpufreq registration/unregistration APIs
> > > -1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
> > > -	struct cpumask *clip_cpus)
> > > +--------------------------------------------
> > > +
> > > +    ::
> > > +
> > > +	struct thermal_cooling_device
> > > +	*cpufreq_cooling_register(struct cpumask *clip_cpus)
> > >  
> > >      This interface function registers the cpufreq cooling device
> > > with the name
> > >      "thermal-cpufreq-%x". This api can support multiple
> > > instances of
> > > cpufreq
> > >      cooling devices.
> > >  
> > > -   clip_cpus: cpumask of cpus where the frequency constraints
> > > will
> > > happen.
> > > +   clip_cpus:
> > > +	cpumask of cpus where the frequency constraints will
> > > happen.
> > >  
> > > -1.1.2 struct thermal_cooling_device
> > > *of_cpufreq_cooling_register(
> > > -					struct cpufreq_policy
> > > *policy)
> > > +    ::
> > > +
> > > +	struct thermal_cooling_device
> > > +	*of_cpufreq_cooling_register(struct cpufreq_policy
> > > *policy)
> > >  
> > >      This interface function registers the cpufreq cooling device
> > > with
> > >      the name "thermal-cpufreq-%x" linking it with a device tree
> > > node, in
> > >      order to bind it via the thermal DT code. This api can
> > > support
> > > multiple
> > >      instances of cpufreq cooling devices.
> > >  
> > > -    policy: CPUFreq policy.
> > > +    policy:
> > > +	CPUFreq policy.
> > >  
> > > -1.1.3 void cpufreq_cooling_unregister(struct
> > > thermal_cooling_device
> > > *cdev)
> > > +
> > > +    ::
> > > +
> > > +	void cpufreq_cooling_unregister(struct
> > > thermal_cooling_device *cdev)
> > >  
> > >      This interface function unregisters the "thermal-cpufreq-%x"
> > > cooling device.
> > >  
> > >      cdev: Cooling device pointer which has to be unregistered.
> > >  
> > >  2. Power models
> > > +===============
> > >  
> > >  The power API registration functions provide a simple power
> > > model
> > > for
> > >  CPUs.  The current power is calculated as dynamic power (static
> > > power isn't
> > > @@ -65,9 +80,9 @@ For a given processor implementation the
> > > primary
> > > factors are:
> > >    variation.  In pathological cases this variation can be
> > > significant,
> > >    but typically it is of a much lesser impact than the factors
> > > above.
> > >  
> > > -A high level dynamic power consumption model may then be
> > > represented
> > > as:
> > > +A high level dynamic power consumption model may then be
> > > represented
> > > as::
> > >  
> > > -Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
> > > +	Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
> > >  
> > >  f(run) here represents the described execution behaviour and its
> > >  result has a units of Watts/Hz/Volt^2 (this often expressed in
> > > @@ -80,9 +95,9 @@ factors.  Therefore, in initial implementation
> > > that
> > > contribution is
> > >  represented as a constant coefficient.  This is a simplification
> > >  consistent with the relative contribution to overall power
> > > variation.
> > >  
> > > -In this simplified representation our model becomes:
> > > +In this simplified representation our model becomes::
> > >  
> > > -Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
> > > +	Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
> > >  
> > >  Where `capacitance` is a constant that represents an indicative
> > >  running time dynamic power coefficient in fundamental units of
> > > diff --git a/Documentation/thermal/exynos_thermal
> > > b/Documentation/thermal/exynos_thermal.rst
> > > similarity index 67%
> > > rename from Documentation/thermal/exynos_thermal
> > > rename to Documentation/thermal/exynos_thermal.rst
> > > index 9010c4416967..5bd556566c70 100644
> > > --- a/Documentation/thermal/exynos_thermal
> > > +++ b/Documentation/thermal/exynos_thermal.rst
> > > @@ -1,8 +1,11 @@
> > > +========================
> > >  Kernel driver exynos_tmu
> > > -=================
> > > +========================
> > >  
> > >  Supported chips:
> > > +
> > >  * ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
> > > +
> > >    Datasheet: Not publicly available
> > >  
> > >  Authors: Donggeun Kim <dg77.kim@samsung.com>
> > > @@ -19,32 +22,39 @@ Temperature can be taken from the temperature
> > > code.
> > >  There are three equations converting from temperature to
> > > temperature
> > > code.
> > >  
> > >  The three equations are:
> > > -  1. Two point trimming
> > > +  1. Two point trimming::
> > > +
> > >  	Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
> > >  
> > > -  2. One point trimming
> > > +  2. One point trimming::
> > > +
> > >  	Tc = T + TI1 - 25
> > >  
> > > -  3. No trimming
> > > +  3. No trimming::
> > > +
> > >  	Tc = T + 50
> > >  
> > > -  Tc: Temperature code, T: Temperature,
> > > -  TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO
> > > register)
> > > +  Tc:
> > > +       Temperature code, T: Temperature,
> > > +  TI1:
> > > +       Trimming info for 25 degree Celsius (stored at TRIMINFO
> > > register)
> > >         Temperature code measured at 25 degree Celsius which is
> > > unchanged
> > > -  TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO
> > > register)
> > > +  TI2:
> > > +       Trimming info for 85 degree Celsius (stored at TRIMINFO
> > > register)
> > >         Temperature code measured at 85 degree Celsius which is
> > > unchanged
> > >  
> > >  TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
> > >  when temperature exceeds pre-defined levels.
> > >  The maximum number of configurable threshold is five.
> > > -The threshold levels are defined as follows:
> > > +The threshold levels are defined as follows::
> > > +
> > >    Level_0: current temperature > trigger_level_0 + threshold
> > >    Level_1: current temperature > trigger_level_1 + threshold
> > >    Level_2: current temperature > trigger_level_2 + threshold
> > >    Level_3: current temperature > trigger_level_3 + threshold
> > >  
> > > -  The threshold and each trigger_level are set
> > > -  through the corresponding registers.
> > > +The threshold and each trigger_level are set
> > > +through the corresponding registers.
> > >  
> > >  When an interrupt occurs, this driver notify kernel thermal
> > > framework
> > >  with the function exynos_report_trigger.
> > > @@ -54,24 +64,27 @@ it can be used to synchronize the cooling
> > > action.
> > >  TMU driver description:
> > >  -----------------------
> > >  
> > > -The exynos thermal driver is structured as,
> > > +The exynos thermal driver is structured as::
> > >  
> > >  					Kernel Core thermal
> > > framework
> > >  				(thermal_core.c, step_wise.c,
> > > cpu_cooling.c)
> > >  								
> > > ^
> > >  								
> > > |
> > >  								
> > > |
> > > -TMU configuration data -------> TMU Driver  <------> Exynos Core
> > > thermal wrapper
> > > -(exynos_tmu_data.c)	      (exynos_tmu.c)	   (exyno
> > > s_th
> > > ermal_common.c)
> > > -(exynos_tmu_data.h)	      (exynos_tmu.h)	   (exyno
> > > s_th
> > > ermal_common.h)
> > > +  TMU configuration data -----> TMU Driver  <----> Exynos Core
> > > thermal wrapper
> > > +  (exynos_tmu_data.c)	      (exynos_tmu.c)	   (exy
> > > nos_
> > > thermal_common.c)
> > > +  (exynos_tmu_data.h)	      (exynos_tmu.h)	   (exy
> > > nos_
> > > thermal_common.h)
> > >  
> > > -a) TMU configuration data: This consist of TMU register
> > > offsets/bitfields
> > > +a) TMU configuration data:
> > > +		This consist of TMU register offsets/bitfields
> > >  		described through structure
> > > exynos_tmu_registers.
> > > Also several
> > >  		other platform data (struct
> > > exynos_tmu_platform_data) members
> > >  		are used to configure the TMU.
> > > -b) TMU driver: This component initialises the TMU controller and
> > > sets different
> > > +b) TMU driver:
> > > +		This component initialises the TMU controller
> > > and
> > > sets different
> > >  		thresholds. It invokes core thermal
> > > implementation
> > > with the call
> > >  		exynos_report_trigger.
> > > -c) Exynos Core thermal wrapper: This provides 3 wrapper function
> > > to
> > > use the
> > > +c) Exynos Core thermal wrapper:
> > > +		This provides 3 wrapper function to use the
> > >  		Kernel core thermal framework. They are
> > > exynos_unregister_thermal,
> > >  		exynos_register_thermal and
> > > exynos_report_trigger.
> > > diff --git a/Documentation/thermal/exynos_thermal_emulation
> > > b/Documentation/thermal/exynos_thermal_emulation.rst
> > > similarity index 36%
> > > rename from Documentation/thermal/exynos_thermal_emulation
> > > rename to Documentation/thermal/exynos_thermal_emulation.rst
> > > index b15efec6ca28..c21d10838bc5 100644
> > > --- a/Documentation/thermal/exynos_thermal_emulation
> > > +++ b/Documentation/thermal/exynos_thermal_emulation.rst
> > > @@ -1,5 +1,6 @@
> > > -EXYNOS EMULATION MODE
> > > -========================
> > > +=====================
> > > +Exynos Emulation Mode
> > > +=====================
> > >  
> > >  Copyright (C) 2012 Samsung Electronics
> > >  
> > > @@ -8,46 +9,53 @@ Written by Jonghwa Lee <jonghwa3.lee@samsung.co
> > > m>
> > >  Description
> > >  -----------
> > >  
> > > -Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for
> > > thermal management unit.
> > > -Thermal emulation mode supports software debug for TMU's
> > > operation.
> > > User can set temperature
> > > -manually with software code and TMU will read current
> > > temperature
> > > from user value not from
> > > -sensor's value.
> > > +Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for
> > > thermal
> > > +management unit. Thermal emulation mode supports software debug
> > > for
> > > +TMU's operation. User can set temperature manually with software
> > > code
> > > +and TMU will read current temperature from user value not from
> > > sensor's
> > > +value.
> > >  
> > > -Enabling CONFIG_THERMAL_EMULATION option will make this support
> > > available.
> > > -When it's enabled, sysfs node will be created as
> > > +Enabling CONFIG_THERMAL_EMULATION option will make this support
> > > +available. When it's enabled, sysfs node will be created as
> > >  /sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
> > >  
> > > -The sysfs node, 'emul_node', will contain value 0 for the
> > > initial
> > > state. When you input any
> > > -temperature you want to update to sysfs node, it automatically
> > > enable emulation mode and
> > > -current temperature will be changed into it.
> > > -(Exynos also supports user changeable delay time which would be
> > > used
> > > to delay of
> > > - changing temperature. However, this node only uses same delay
> > > of
> > > real sensing time, 938us.)
> > > +The sysfs node, 'emul_node', will contain value 0 for the
> > > initial
> > > state.
> > > +When you input any temperature you want to update to sysfs node,
> > > it
> > > +automatically enable emulation mode and current temperature will
> > > be
> > > +changed into it.
> > >  
> > > -Exynos emulation mode requires synchronous of value changing and
> > > enabling. It means when you
> > > -want to update the any value of delay or next temperature, then
> > > you
> > > have to enable emulation
> > > -mode at the same time. (Or you have to keep the mode enabling.)
> > > If
> > > you don't, it fails to
> > > -change the value to updated one and just use last succeessful
> > > value
> > > repeatedly. That's why
> > > -this node gives users the right to change termerpature only.
> > > Just
> > > one interface makes it more
> > > -simply to use.
> > > +(Exynos also supports user changeable delay time which would be
> > > used
> > > to
> > > +delay of changing temperature. However, this node only uses same
> > > delay
> > > +of real sensing time, 938us.)
> > > +
> > > +Exynos emulation mode requires synchronous of value changing and
> > > +enabling. It means when you want to update the any value of
> > > delay or
> > > +next temperature, then you have to enable emulation mode at the
> > > same
> > > +time. (Or you have to keep the mode enabling.) If you don't, it
> > > fails to
> > > +change the value to updated one and just use last succeessful
> > > value
> > > +repeatedly. That's why this node gives users the right to change
> > > +termerpature only. Just one interface makes it more simply to
> > > use.
> > >  
> > >  Disabling emulation mode only requires writing value 0 to sysfs
> > > node.
> > >  
> > > +::
> > >  
> > > -TEMP	120 |
> > > +
> > > +  TEMP	120 |
> > >  	    |
> > >  	100 |
> > >  	    |
> > >  	 80 |
> > > -	    |		     	 	 +-----------
> > > -	 60 |      		     	 |	    |
> > > -	    |	           +-------------|          |
> > > +	    |				 +-----------
> > > +	 60 |      			 |	    |
> > > +	    |		   +-------------|          |
> > >  	 40 |              |         	 |          |
> > > -	    |		   |	     	 |        
> > >   |
> > > -	 20 |		   |	     	 |        
> > >   +-
> > > ---------
> > > -	    |	 	   |	     	 |       
> > >    |
> > >           |
> > > +	    |		   |		 |          |
> > > +	 20 |		   |		 |          +
> > > ----
> > > ------
> > > +	    |		   |		 |          |  
> > >     
> > >     |
> > >  	  0
> > > > 
> > > > ______________|_____________|__________|__________|_________
> > > -		   A	    	 A	    A	 
> > >   	
> > >        A     TIME
> > > +		   A		 A	    A		
> > >  
> > >       A     TIME
> > >  		   |<----->|	 |<----->|  |<----->|	
> > >    
> > >     |
> > >  		   | 938us |  	 |	 |  |       |   
> > >     
> > >    |
> > > -emulation    :  0  50	   |  	 70      |  20      |
> > >     
> > >       0
> > > -current temp :   sensor   50		 70         20	
> > >   
> > >     sensor
> > > +  emulation   : 0  50	   |  	 70      |  20      |
> > >     
> > >       0
> > > +  current temp:   sensor   50		 70         20	
> > >  
> > >      sensor
> > > diff --git a/Documentation/thermal/index.rst
> > > b/Documentation/thermal/index.rst
> > > new file mode 100644
> > > index 000000000000..8c1c00146cad
> > > --- /dev/null
> > > +++ b/Documentation/thermal/index.rst
> > > @@ -0,0 +1,18 @@
> > > +:orphan:
> > > +
> > > +=======
> > > +Thermal
> > > +=======
> > > +
> > > +.. toctree::
> > > +   :maxdepth: 1
> > > +
> > > +   cpu-cooling-api
> > > +   sysfs-api
> > > +   power_allocator
> > > +
> > > +   exynos_thermal
> > > +   exynos_thermal_emulation
> > > +   intel_powerclamp
> > > +   nouveau_thermal
> > > +   x86_pkg_temperature_thermal
> > > diff --git a/Documentation/thermal/intel_powerclamp.txt
> > > b/Documentation/thermal/intel_powerclamp.rst
> > > similarity index 76%
> > > rename from Documentation/thermal/intel_powerclamp.txt
> > > rename to Documentation/thermal/intel_powerclamp.rst
> > > index b5df21168fbc..3f6dfb0b3ea6 100644
> > > --- a/Documentation/thermal/intel_powerclamp.txt
> > > +++ b/Documentation/thermal/intel_powerclamp.rst
> > > @@ -1,10 +1,13 @@
> > > -			 =======================
> > > -			 INTEL POWERCLAMP DRIVER
> > > -			 =======================
> > > -By: Arjan van de Ven <arjan@linux.intel.com>
> > > -    Jacob Pan <jacob.jun.pan@linux.intel.com>
> > > +=======================
> > > +Intel Powerclamp Driver
> > > +=======================
> > > +
> > > +By:
> > > +  - Arjan van de Ven <arjan@linux.intel.com>
> > > +  - Jacob Pan <jacob.jun.pan@linux.intel.com>
> > > +
> > > +.. Contents:
> > >  
> > > -Contents:
> > >  	(*) Introduction
> > >  	    - Goals and Objectives
> > >  
> > > @@ -23,7 +26,6 @@ Contents:
> > >  	    - Generic Thermal Layer (sysfs)
> > >  	    - Kernel APIs (TBD)
> > >  
> > > -============
> > >  INTRODUCTION
> > >  ============
> > >  
> > > @@ -47,7 +49,6 @@ scalability, and user experience. In many
> > > cases,
> > > clear advantage is
> > >  shown over taking the CPU offline or modulating the CPU clock.
> > >  
> > >  
> > > -===================
> > >  THEORY OF OPERATION
> > >  ===================
> > >  
> > > @@ -57,11 +58,12 @@ Idle Injection
> > >  On modern Intel processors (Nehalem or later), package level C-
> > > state
> > >  residency is available in MSRs, thus also available to the
> > > kernel.
> > >  
> > > -These MSRs are:
> > > -      #define MSR_PKG_C2_RESIDENCY	0x60D
> > > -      #define MSR_PKG_C3_RESIDENCY	0x3F8
> > > -      #define MSR_PKG_C6_RESIDENCY	0x3F9
> > > -      #define MSR_PKG_C7_RESIDENCY	0x3FA
> > > +These MSRs are::
> > > +
> > > +      #define MSR_PKG_C2_RESIDENCY      0x60D
> > > +      #define MSR_PKG_C3_RESIDENCY      0x3F8
> > > +      #define MSR_PKG_C6_RESIDENCY      0x3F9
> > > +      #define MSR_PKG_C7_RESIDENCY      0x3FA
> > >  
> > >  If the kernel can also inject idle time to the system, then a
> > >  closed-loop control system can be established that manages
> > > package
> > > @@ -96,19 +98,21 @@ are not masked. Tests show that the extra
> > > wakeups
> > > from scheduler tick
> > >  have a dramatic impact on the effectiveness of the powerclamp
> > > driver
> > >  on large scale systems (Westmere system with 80 processors).
> > >  
> > > -CPU0
> > > -		  ____________          ____________
> > > -kidle_inject/0   |   sleep    |  mwait |  sleep     |
> > > -	_________|            |________|            |_______
> > > -			       duration
> > > -CPU1
> > > -		  ____________          ____________
> > > -kidle_inject/1   |   sleep    |  mwait |  sleep     |
> > > -	_________|            |________|            |_______
> > > -			      ^
> > > -			      |
> > > -			      |
> > > -			      roundup(jiffies, interval)
> > > +::
> > > +
> > > +  CPU0
> > > +		    ____________          ____________
> > > +  kidle_inject/0   |   sleep    |  mwait |  sleep     |
> > > +	  _________|            |________|            |_______
> > > +				 duration
> > > +  CPU1
> > > +		    ____________          ____________
> > > +  kidle_inject/1   |   sleep    |  mwait |  sleep     |
> > > +	  _________|            |________|            |_______
> > > +				^
> > > +				|
> > > +				|
> > > +				roundup(jiffies, interval)
> > >  
> > >  Only one CPU is allowed to collect statistics and update global
> > >  control parameters. This CPU is referred to as the controlling
> > > CPU
> > > in
> > > @@ -148,7 +152,7 @@ b) determine the amount of compensation
> > > needed at
> > > each target ratio
> > >  
> > >  Compensation to each target ratio consists of two parts:
> > >  
> > > -        a) steady state error compensation
> > > +	a) steady state error compensation
> > >  	This is to offset the error occurring when the system
> > > can
> > >  	enter idle without extra wakeups (such as external
> > > interrupts).
> > >  
> > > @@ -158,41 +162,42 @@ Compensation to each target ratio consists
> > > of
> > > two parts:
> > >  	slowing down CPU activities.
> > >  
> > >  A debugfs file is provided for the user to examine compensation
> > > -progress and results, such as on a Westmere system.
> > > -[jacob@nex01 ~]$ cat
> > > -/sys/kernel/debug/intel_powerclamp/powerclamp_calib
> > > -controlling cpu: 0
> > > -pct confidence steady dynamic (compensation)
> > > -0	0	0	0
> > > -1	1	0	0
> > > -2	1	1	0
> > > -3	3	1	0
> > > -4	3	1	0
> > > -5	3	1	0
> > > -6	3	1	0
> > > -7	3	1	0
> > > -8	3	1	0
> > > -...
> > > -30	3	2	0
> > > -31	3	2	0
> > > -32	3	1	0
> > > -33	3	2	0
> > > -34	3	1	0
> > > -35	3	2	0
> > > -36	3	1	0
> > > -37	3	2	0
> > > -38	3	1	0
> > > -39	3	2	0
> > > -40	3	3	0
> > > -41	3	1	0
> > > -42	3	2	0
> > > -43	3	1	0
> > > -44	3	1	0
> > > -45	3	2	0
> > > -46	3	3	0
> > > -47	3	0	0
> > > -48	3	2	0
> > > -49	3	3	0
> > > +progress and results, such as on a Westmere system::
> > > +
> > > +  [jacob@nex01 ~]$ cat
> > > +  /sys/kernel/debug/intel_powerclamp/powerclamp_calib
> > > +  controlling cpu: 0
> > > +  pct confidence steady dynamic (compensation)
> > > +  0       0       0       0
> > > +  1       1       0       0
> > > +  2       1       1       0
> > > +  3       3       1       0
> > > +  4       3       1       0
> > > +  5       3       1       0
> > > +  6       3       1       0
> > > +  7       3       1       0
> > > +  8       3       1       0
> > > +  ...
> > > +  30      3       2       0
> > > +  31      3       2       0
> > > +  32      3       1       0
> > > +  33      3       2       0
> > > +  34      3       1       0
> > > +  35      3       2       0
> > > +  36      3       1       0
> > > +  37      3       2       0
> > > +  38      3       1       0
> > > +  39      3       2       0
> > > +  40      3       3       0
> > > +  41      3       1       0
> > > +  42      3       2       0
> > > +  43      3       1       0
> > > +  44      3       1       0
> > > +  45      3       2       0
> > > +  46      3       3       0
> > > +  47      3       0       0
> > > +  48      3       2       0
> > > +  49      3       3       0
> > >  
> > >  Calibration occurs during runtime. No offline method is
> > > available.
> > >  Steady state compensation is used only when confidence levels of
> > > all
> > > @@ -217,9 +222,8 @@ keeps track of clamping kernel threads, even
> > > after they are migrated
> > >  to other CPUs, after a CPU offline event.
> > >  
> > >  
> > > -=====================
> > >  Performance Analysis
> > > -=====================
> > > +====================
> > >  This section describes the general performance data collected on
> > >  multiple systems, including Westmere (80P) and Ivy Bridge (4P,
> > > 8P).
> > >  
> > > @@ -257,16 +261,15 @@ achieve up to 40% better performance per
> > > watt.
> > > (measured by a spin
> > >  counter summed over per CPU counting threads spawned for all
> > > running
> > >  CPUs).
> > >  
> > > -====================
> > >  Usage and Interfaces
> > >  ====================
> > >  The powerclamp driver is registered to the generic thermal layer
> > > as
> > > a
> > > -cooling device. Currently, it’s not bound to any thermal zones.
> > > +cooling device. Currently, it’s not bound to any thermal zones::
> > >  
> > > -jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
> > > -cur_state:0
> > > -max_state:50
> > > -type:intel_powerclamp
> > > +  jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
> > > +  cur_state:0
> > > +  max_state:50
> > > +  type:intel_powerclamp
> > >  
> > >  cur_state allows user to set the desired idle percentage.
> > > Writing 0
> > > to
> > >  cur_state will stop idle injection. Writing a value between 1
> > > and
> > > @@ -278,9 +281,9 @@ cur_state returns value -1 instead of 0 which
> > > is
> > > to avoid confusing
> > >  100% busy state with the disabled state.
> > >  
> > >  Example usage:
> > > -- To inject 25% idle time
> > > -$ sudo sh -c "echo 25 >
> > > /sys/class/thermal/cooling_device80/cur_state
> > > -"
> > > +- To inject 25% idle time::
> > > +
> > > +	$ sudo sh -c "echo 25 >
> > > /sys/class/thermal/cooling_device80/cur_state
> > >  
> > >  If the system is not busy and has more than 25% idle time
> > > already,
> > >  then the powerclamp driver will not start idle injection. Using
> > > Top
> > > @@ -292,23 +295,23 @@ idle time is accounted as normal idle in
> > > that
> > > common code path is
> > >  taken as the idle task.
> > >  
> > >  In this example, 24.1% idle is shown. This helps the system
> > > admin or
> > > -user determine the cause of slowdown, when a powerclamp driver
> > > is in
> > > action.
> > > +user determine the cause of slowdown, when a powerclamp driver
> > > is in
> > > action::
> > >  
> > >  
> > > -Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0
> > > zombie
> > > -Cpu(s): 71.2%us,  4.7%sy,  0.0%ni,
> > > 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
> > > -Mem:   3943228k total,  1689632k used,  2253596k free,    74960k
> > > buffers
> > > -Swap:  4087804k total,        0k used,  4087804k free,   945336k
> > > cached
> > > +  Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0
> > > zombie
> > > +  Cpu(s): 71.2%us,  4.7%sy,  0.0%ni,
> > > 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
> > > +  Mem:   3943228k total,  1689632k used,  2253596k
> > > free,    74960k
> > > buffers
> > > +  Swap:  4087804k total,        0k used,  4087804k
> > > free,   945336k
> > > cached
> > >  
> > > -  PID USER      PR  NI  VIRT  RES  SHR S %CPU
> > > %MEM    TIME+  COMMAND
> > > - 3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16
> > > spin
> > > - 3341 root     -51   0     0    0    0 D   25  0.0   0:01.62
> > > kidle_inject/0
> > > - 3344 root     -51   0     0    0    0 D   25  0.0   0:01.60
> > > kidle_inject/3
> > > - 3342 root     -51   0     0    0    0 D   25  0.0   0:01.61
> > > kidle_inject/1
> > > - 3343 root     -51   0     0    0    0 D   25  0.0   0:01.60
> > > kidle_inject/2
> > > - 2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11
> > > firefox
> > > - 1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97
> > > Xorg
> > > - 2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68
> > > compiz
> > > +    PID USER      PR  NI  VIRT  RES  SHR S %CPU
> > > %MEM    TIME+  COMMAND
> > > +   3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16
> > > spin
> > > +   3341 root     -51   0     0    0    0 D   25  0.0   0:01.62
> > > kidle_inject/0
> > > +   3344 root     -51   0     0    0    0 D   25  0.0   0:01.60
> > > kidle_inject/3
> > > +   3342 root     -51   0     0    0    0 D   25  0.0   0:01.61
> > > kidle_inject/1
> > > +   3343 root     -51   0     0    0    0 D   25  0.0   0:01.60
> > > kidle_inject/2
> > > +   2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11
> > > firefox
> > > +   1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97
> > > Xorg
> > > +   2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68
> > > compiz
> > >  
> > >  Tests have shown that by using the powerclamp driver as a
> > > cooling
> > >  device, a PID based userspace thermal controller can manage to
> > > diff --git a/Documentation/thermal/nouveau_thermal
> > > b/Documentation/thermal/nouveau_thermal.rst
> > > similarity index 64%
> > > rename from Documentation/thermal/nouveau_thermal
> > > rename to Documentation/thermal/nouveau_thermal.rst
> > > index 6e17a11efcb0..37255fd6735d 100644
> > > --- a/Documentation/thermal/nouveau_thermal
> > > +++ b/Documentation/thermal/nouveau_thermal.rst
> > > @@ -1,13 +1,15 @@
> > > +=====================
> > >  Kernel driver nouveau
> > > -===================
> > > +=====================
> > >  
> > >  Supported chips:
> > > +
> > >  * NV43+
> > >  
> > >  Authors: Martin Peres (mupuf) <martin.peres@free.fr>
> > >  
> > >  Description
> > > ----------
> > > +-----------
> > >  
> > >  This driver allows to read the GPU core temperature, drive the
> > > GPU
> > > fan and
> > >  set temperature alarms.
> > > @@ -19,20 +21,25 @@ interface is likely not to work. This
> > > document
> > > may then not cover your situation
> > >  entirely.
> > >  
> > >  Temperature management
> > > ---------------------
> > > +----------------------
> > >  
> > >  Temperature is exposed under as a read-only HWMON attribute
> > > temp1_input.
> > >  
> > >  In order to protect the GPU from overheating, Nouveau supports 4
> > > configurable
> > >  temperature thresholds:
> > >  
> > > - * Fan_boost: Fan speed is set to 100% when reaching this
> > > temperature;
> > > - * Downclock: The GPU will be downclocked to reduce its power
> > > dissipation;
> > > - * Critical: The GPU is put on hold to further lower power
> > > dissipation;
> > > - * Shutdown: Shut the computer down to protect your GPU.
> > > + * Fan_boost:
> > > +	Fan speed is set to 100% when reaching this temperature;
> > > + * Downclock:
> > > +	The GPU will be downclocked to reduce its power
> > > dissipation;
> > > + * Critical:
> > > +	The GPU is put on hold to further lower power
> > > dissipation;
> > > + * Shutdown:
> > > +	Shut the computer down to protect your GPU.
> > >  
> > > -WARNING: Some of these thresholds may not be used by Nouveau
> > > depending
> > > -on your chipset.
> > > +WARNING:
> > > +	Some of these thresholds may not be used by Nouveau
> > > depending
> > > +	on your chipset.
> > >  
> > >  The default value for these thresholds comes from the GPU's
> > > vbios.
> > > These
> > >  thresholds can be configured thanks to the following HWMON
> > > attributes:
> > > @@ -46,19 +53,24 @@ NOTE: Remember that the values are stored as
> > > milli degrees Celsius. Don't forget
> > >  to multiply!
> > >  
> > >  Fan management
> > > -------------
> > > +--------------
> > >  
> > >  Not all cards have a drivable fan. If you do, then the following
> > > HWMON
> > >  attributes should be available:
> > >  
> > > - * pwm1_enable: Current fan management mode (NONE, MANUAL or
> > > AUTO);
> > > - * pwm1: Current PWM value (power percentage);
> > > - * pwm1_min: The minimum PWM speed allowed;
> > > - * pwm1_max: The maximum PWM speed allowed (bypassed when
> > > hitting
> > > Fan_boost);
> > > + * pwm1_enable:
> > > +	Current fan management mode (NONE, MANUAL or AUTO);
> > > + * pwm1:
> > > +	Current PWM value (power percentage);
> > > + * pwm1_min:
> > > +	The minimum PWM speed allowed;
> > > + * pwm1_max:
> > > +	The maximum PWM speed allowed (bypassed when hitting
> > > Fan_boost);
> > >  
> > >  You may also have the following attribute:
> > >  
> > > - * fan1_input: Speed in RPM of your fan.
> > > + * fan1_input:
> > > +	Speed in RPM of your fan.
> > >  
> > >  Your fan can be driven in different modes:
> > >  
> > > @@ -66,14 +78,16 @@ Your fan can be driven in different modes:
> > >   * 1: The fan can be driven in manual (use pwm1 to change the
> > > speed);
> > >   * 2; The fan is driven automatically depending on the
> > > temperature.
> > >  
> > > -NOTE: Be sure to use the manual mode if you want to drive the
> > > fan
> > > speed manually
> > > +NOTE:
> > > +  Be sure to use the manual mode if you want to drive the fan
> > > speed
> > > manually
> > >  
> > > -NOTE2: When operating in manual mode outside the vbios-defined
> > > -[PWM_min, PWM_max] range, the reported fan speed (RPM) may not
> > > be
> > > accurate
> > > -depending on your hardware.
> > > +NOTE2:
> > > +  When operating in manual mode outside the vbios-defined
> > > +  [PWM_min, PWM_max] range, the reported fan speed (RPM) may not
> > > be
> > > accurate
> > > +  depending on your hardware.
> > >  
> > >  Bug reports
> > > ----------
> > > +-----------
> > >  
> > >  Thermal management on Nouveau is new and may not work on all
> > > cards.
> > > If you have
> > >  inquiries, please ping mupuf on IRC (#nouveau, freenode).
> > > diff --git a/Documentation/thermal/power_allocator.txt
> > > b/Documentation/thermal/power_allocator.rst
> > > similarity index 74%
> > > rename from Documentation/thermal/power_allocator.txt
> > > rename to Documentation/thermal/power_allocator.rst
> > > index 9fb0ff06dca9..67b6a3297238 100644
> > > --- a/Documentation/thermal/power_allocator.txt
> > > +++ b/Documentation/thermal/power_allocator.rst
> > > @@ -1,3 +1,4 @@
> > > +=================================
> > >  Power allocator governor tunables
> > >  =================================
> > >  
> > > @@ -25,36 +26,36 @@ temperature as the control input and power as
> > > the
> > > controlled output:
> > >      P_max = k_p * e + k_i * err_integral + k_d * diff_err +
> > > sustainable_power
> > >  
> > >  where
> > > -    e = desired_temperature - current_temperature
> > > -    err_integral is the sum of previous errors
> > > -    diff_err = e - previous_error
> > > +   -  e = desired_temperature - current_temperature
> > > +   -  err_integral is the sum of previous errors
> > > +   -  diff_err = e - previous_error
> > >  
> > > -It is similar to the one depicted below:
> > > +It is similar to the one depicted below::
> > >  
> > > -                                      k_d
> > > -                                       |
> > > -current_temp                           |
> > > -     |                                 v
> > > -     |                +----------+   +---+
> > > -     |         +----->| diff_err |-->| X |------+
> > > -     |         |      +----------+   +---+      |
> > > -     |         |                                |      tdp      
> > >   ac
> > > tor
> > > -     |         |                      k_i       |       |  get_r
> > > eque
> > > sted_power()
> > > -     |         |                       |        |       |       
> > >  |  
> > >    |
> > > -     |         |                       |        |       |       
> > >  |  
> > >    | ...
> > > -     v         |                       v        v       v       
> > >  v  
> > >    v
> > > -   +---+       |      +-------+      +---+    +---+   +---+   +-
> > > ----
> > > -----+
> > > -   | S |-------+----->| sum e |----->| X |--->| S |-->| S |  
> > > -->|power     |  
> > > -   +---+       |      +-------+      +---+    +---+   +---
> > > +   |allocation|
> > > -     ^         |                                ^             +-
> > > ----
> > > -----+
> > > -     |         |                                |               
> > >  |  
> > >    |
> > > -     |         |        +---
> > > +                   |                |     |
> > > -     |         +------->| X |-------------------
> > > +                v     v
> > > -     |                  +---
> > > +                               granted
> > > performance
> > > -desired_temperature       ^
> > > -                          |
> > > -                          |
> > > -                      k_po/k_pu
> > > +				      k_d
> > > +				       |
> > > +  current_temp                         |
> > > +       |                               v
> > > +       |              +----------+   +---+
> > > +       |       +----->| diff_err |-->| X |------+
> > > +       |       |      +----------+   +---+      |
> > > +       |       |                                |      tdp      
> > >   ac
> > > tor
> > > +       |       |                      k_i       |       |  get_r
> > > eque
> > > sted_power()
> > > +       |       |                       |        |       |       
> > >  |  
> > >    |
> > > +       |       |                       |        |       |       
> > >  |  
> > >    | ...
> > > +       v       |                       v        v       v       
> > >  v  
> > >    v
> > > +     +---+     |      +-------+      +---+    +---+   +---+   +-
> > > ----
> > > -----+
> > > +     | S |-----+----->| sum e |----->| X |--->| S |-->| S |  
> > > -->|power     |  
> > > +     +---+     |      +-------+      +---+    +---+   +---
> > > +   |allocation|
> > > +       ^       |                                ^             +-
> > > ----
> > > -----+
> > > +       |       |                                |               
> > >  |  
> > >    |
> > > +       |       |        +---
> > > +                   |                |     |
> > > +       |       +------->| X |-------------------
> > > +                v     v
> > > +       |                +---
> > > +                               granted
> > > performance
> > > +  desired_temperature     ^
> > > +			  |
> > > +			  |
> > > +		      k_po/k_pu
> > >  
> > >  Sustainable power
> > >  -----------------
> > > @@ -73,7 +74,7 @@ is typically 2000mW, while on a 10" tablet is
> > > around 4500mW (may vary
> > >  depending on screen size).
> > >  
> > >  If you are using device tree, do add it as a property of the
> > > -thermal-zone.  For example:
> > > +thermal-zone.  For example::
> > >  
> > >  	thermal-zones {
> > >  		soc_thermal {
> > > @@ -85,7 +86,7 @@ thermal-zone.  For example:
> > >  Instead, if the thermal zone is registered from the platform
> > > code,
> > > pass a
> > >  `thermal_zone_params` that has a `sustainable_power`.  If no
> > >  `thermal_zone_params` were being passed, then something like
> > > below
> > > -will suffice:
> > > +will suffice::
> > >  
> > >  	static const struct thermal_zone_params tz_params = {
> > >  		.sustainable_power = 3500,
> > > @@ -112,18 +113,18 @@ available capacity at a low
> > > temperature.  On
> > > the other hand, a high
> > >  value of `k_pu` will result in the governor granting very high
> > > power
> > >  while temperature is low, and may lead to temperature
> > > overshooting.
> > >  
> > > -The default value for `k_pu` is:
> > > +The default value for `k_pu` is::
> > >  
> > >      2 * sustainable_power / (desired_temperature -
> > > switch_on_temp)
> > >  
> > >  This means that at `switch_on_temp` the output of the
> > > controller's
> > >  proportional term will be 2 * `sustainable_power`.  The default
> > > value
> > > -for `k_po` is:
> > > +for `k_po` is::
> > >  
> > >      sustainable_power / (desired_temperature - switch_on_temp)
> > >  
> > >  Focusing on the proportional and feed forward values of the PID
> > > -controller equation we have:
> > > +controller equation we have::
> > >  
> > >      P_max = k_p * e + sustainable_power
> > >  
> > > @@ -134,21 +135,23 @@ is the desired one, then the proportional
> > > component is zero and
> > >  thermal equilibrium under constant load.  `sustainable_power` is
> > > only
> > >  an estimate, which is the reason for closed-loop control such as
> > > this.
> > >  
> > > -Expanding `k_pu` we get:
> > > +Expanding `k_pu` we get::
> > > +
> > >      P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on)
> > > +
> > > -        sustainable_power
> > > +	sustainable_power
> > >  
> > > -where
> > > -    T_set is the desired temperature
> > > -    T is the current temperature
> > > -    T_on is the switch on temperature
> > > +where:
> > > +
> > > +    - T_set is the desired temperature
> > > +    - T is the current temperature
> > > +    - T_on is the switch on temperature
> > >  
> > >  When the current temperature is the switch_on temperature, the
> > > above
> > > -formula becomes:
> > > +formula becomes::
> > >  
> > >      P_max = 2 * sustainable_power * (T_set - T_on) / (T_set -
> > > T_on)
> > > +
> > > -        sustainable_power = 2 * sustainable_power +
> > > sustainable_power =
> > > -        3 * sustainable_power
> > > +	sustainable_power = 2 * sustainable_power +
> > > sustainable_power =
> > > +	3 * sustainable_power
> > >  
> > >  Therefore, the proportional term alone linearly decreases power
> > > from
> > >  3 * `sustainable_power` to `sustainable_power` as the
> > > temperature
> > > @@ -178,11 +181,18 @@ Cooling device power API
> > >  Cooling devices controlled by this governor must supply the
> > > additional
> > >  "power" API in their `cooling_device_ops`.  It consists on three
> > > ops:
> > >  
> > > -1. int get_requested_power(struct thermal_cooling_device *cdev,
> > > -	struct thermal_zone_device *tz, u32 *power);
> > > -@cdev: The `struct thermal_cooling_device` pointer
> > > -@tz: thermal zone in which we are currently operating
> > > -@power: pointer in which to store the calculated power
> > > +1. ::
> > > +
> > > +    int get_requested_power(struct thermal_cooling_device *cdev,
> > > +			    struct thermal_zone_device *tz, u32
> > > *power);
> > > +
> > > +
> > > +@cdev:
> > > +	The `struct thermal_cooling_device` pointer
> > > +@tz:
> > > +	thermal zone in which we are currently operating
> > > +@power:
> > > +	pointer in which to store the calculated power
> > >  
> > >  `get_requested_power()` calculates the power requested by the
> > > device
> > >  in milliwatts and stores it in @power .  It should return 0 on
> > > @@ -190,23 +200,37 @@ success, -E* on failure.  This is currently
> > > used by the power
> > >  allocator governor to calculate how much power to give to each
> > > cooling
> > >  device.
> > >  
> > > -2. int state2power(struct thermal_cooling_device *cdev, struct
> > > -        thermal_zone_device *tz, unsigned long state, u32
> > > *power);
> > > -@cdev: The `struct thermal_cooling_device` pointer
> > > -@tz: thermal zone in which we are currently operating
> > > -@state: A cooling device state
> > > -@power: pointer in which to store the equivalent power
> > > +2. ::
> > > +
> > > +	int state2power(struct thermal_cooling_device *cdev,
> > > struct
> > > +			thermal_zone_device *tz, unsigned long
> > > state,
> > > +			u32 *power);
> > > +
> > > +@cdev:
> > > +	The `struct thermal_cooling_device` pointer
> > > +@tz:
> > > +	thermal zone in which we are currently operating
> > > +@state:
> > > +	A cooling device state
> > > +@power:
> > > +	pointer in which to store the equivalent power
> > >  
> > >  Convert cooling device state @state into power consumption in
> > >  milliwatts and store it in @power.  It should return 0 on
> > > success,
> > > -E*
> > >  on failure.  This is currently used by thermal core to calculate
> > > the
> > >  maximum power that an actor can consume.
> > >  
> > > -3. int power2state(struct thermal_cooling_device *cdev, u32
> > > power,
> > > -	unsigned long *state);
> > > -@cdev: The `struct thermal_cooling_device` pointer
> > > -@power: power in milliwatts
> > > -@state: pointer in which to store the resulting state
> > > +3. ::
> > > +
> > > +	int power2state(struct thermal_cooling_device *cdev, u32
> > > power,
> > > +			unsigned long *state);
> > > +
> > > +@cdev:
> > > +	The `struct thermal_cooling_device` pointer
> > > +@power:
> > > +	power in milliwatts
> > > +@state:
> > > +	pointer in which to store the resulting state
> > >  
> > >  Calculate a cooling device state that would make the device
> > > consume
> > > at
> > >  most @power mW and store it in @state.  It should return 0 on
> > > success,
> > > diff --git a/Documentation/thermal/sysfs-api.txt
> > > b/Documentation/thermal/sysfs-api.rst
> > > similarity index 66%
> > > rename from Documentation/thermal/sysfs-api.txt
> > > rename to Documentation/thermal/sysfs-api.rst
> > > index c3fa500df92c..e4930761d3e5 100644
> > > --- a/Documentation/thermal/sysfs-api.txt
> > > +++ b/Documentation/thermal/sysfs-api.rst
> > > @@ -1,3 +1,4 @@
> > > +===================================
> > >  Generic Thermal Sysfs driver How To
> > >  ===================================
> > >  
> > > @@ -9,6 +10,7 @@ Copyright (c)  2008 Intel Corporation
> > >  
> > >  
> > >  0. Introduction
> > > +===============
> > >  
> > >  The generic thermal sysfs provides a set of interfaces for
> > > thermal
> > > zone
> > >  devices (sensors) and thermal cooling devices (fan,
> > > processor...) to
> > > register
> > > @@ -25,59 +27,90 @@ An intelligent thermal management application
> > > can
> > > make decisions based on
> > >  inputs from thermal zone attributes (the current temperature and
> > > trip point
> > >  temperature) and throttle appropriate devices.
> > >  
> > > -[0-*]	denotes any positive number starting from 0
> > > -[1-*]	denotes any positive number starting from 1
> > > +- `[0-*]`	denotes any positive number starting from 0
> > > +- `[1-*]`	denotes any positive number starting from 1
> > >  
> > >  1. thermal sysfs driver interface functions
> > > +===========================================
> > >  
> > >  1.1 thermal zone device interface
> > > -1.1.1 struct thermal_zone_device
> > > *thermal_zone_device_register(char
> > > *type,
> > > -		int trips, int mask, void *devdata,
> > > -		struct thermal_zone_device_ops *ops,
> > > -		const struct thermal_zone_params *tzp,
> > > -		int passive_delay, int polling_delay))
> > > +---------------------------------
> > > +
> > > +    ::
> > > +
> > > +	struct thermal_zone_device
> > > +	*thermal_zone_device_register(char *type,
> > > +				      int trips, int mask, void
> > > *devdata,
> > > +				      struct
> > > thermal_zone_device_ops
> > > *ops,
> > > +				      const struct
> > > thermal_zone_params *tzp,
> > > +				      int passive_delay, int
> > > polling_delay))
> > >  
> > >      This interface function adds a new thermal zone device
> > > (sensor)
> > > to
> > > -    /sys/class/thermal folder as thermal_zone[0-*]. It tries to
> > > bind
> > > all the
> > > +    /sys/class/thermal folder as `thermal_zone[0-*]`. It tries
> > > to
> > > bind all the
> > >      thermal cooling devices registered at the same time.
> > >  
> > > -    type: the thermal zone type.
> > > -    trips: the total number of trip points this thermal zone
> > > supports.
> > > -    mask: Bit string: If 'n'th bit is set, then trip point 'n'
> > > is
> > > writeable.
> > > -    devdata: device private data
> > > -    ops: thermal zone device call-backs.
> > > -	.bind: bind the thermal zone device with a thermal
> > > cooling
> > > device.
> > > -	.unbind: unbind the thermal zone device with a thermal
> > > cooling device.
> > > -	.get_temp: get the current temperature of the thermal
> > > zone.
> > > -	.set_trips: set the trip points window. Whenever the
> > > current
> > > temperature
> > > +    type:
> > > +	the thermal zone type.
> > > +    trips:
> > > +	the total number of trip points this thermal zone
> > > supports.
> > > +    mask:
> > > +	Bit string: If 'n'th bit is set, then trip point 'n' is
> > > writeable.
> > > +    devdata:
> > > +	device private data
> > > +    ops:
> > > +	thermal zone device call-backs.
> > > +
> > > +	.bind:
> > > +		bind the thermal zone device with a thermal
> > > cooling
> > > device.
> > > +	.unbind:
> > > +		unbind the thermal zone device with a thermal
> > > cooling device.
> > > +	.get_temp:
> > > +		get the current temperature of the thermal zone.
> > > +	.set_trips:
> > > +		    set the trip points window. Whenever the
> > > current
> > > temperature
> > >  		    is updated, the trip points immediately
> > > below
> > > and above the
> > >  		    current temperature are found.
> > > -	.get_mode: get the current mode (enabled/disabled) of
> > > the
> > > thermal zone.
> > > -	    - "enabled" means the kernel thermal management is
> > > enabled.
> > > -	    - "disabled" will prevent kernel thermal driver
> > > action
> > > upon trip points
> > > -	      so that user applications can take charge of
> > > thermal
> > > management.
> > > -	.set_mode: set the mode (enabled/disabled) of the
> > > thermal
> > > zone.
> > > -	.get_trip_type: get the type of certain trip point.
> > > -	.get_trip_temp: get the temperature above which the
> > > certain
> > > trip point
> > > +	.get_mode:
> > > +		   get the current mode (enabled/disabled) of
> > > the
> > > thermal zone.
> > > +
> > > +			- "enabled" means the kernel thermal
> > > management is
> > > +			  enabled.
> > > +			- "disabled" will prevent kernel thermal
> > > driver action
> > > +			  upon trip points so that user
> > > applications
> > > can take
> > > +			  charge of thermal management.
> > > +	.set_mode:
> > > +		set the mode (enabled/disabled) of the thermal
> > > zone.
> > > +	.get_trip_type:
> > > +		get the type of certain trip point.
> > > +	.get_trip_temp:
> > > +			get the temperature above which the
> > > certain
> > > trip point
> > >  			will be fired.
> > > -	.set_emul_temp: set the emulation temperature which
> > > helps in
> > > debugging
> > > +	.set_emul_temp:
> > > +			set the emulation temperature which
> > > helps in
> > > debugging
> > >  			different threshold temperature points.
> > > -    tzp: thermal zone platform parameters.
> > > -    passive_delay: number of milliseconds to wait between polls
> > > when
> > > +    tzp:
> > > +	thermal zone platform parameters.
> > > +    passive_delay:
> > > +	number of milliseconds to wait between polls when
> > >  	performing passive cooling.
> > > -    polling_delay: number of milliseconds to wait between polls
> > > when
> > > checking
> > > +    polling_delay:
> > > +	number of milliseconds to wait between polls when
> > > checking
> > >  	whether trip points have been crossed (0 for interrupt
> > > driven systems).
> > >  
> > > +    ::
> > >  
> > > -1.1.2 void thermal_zone_device_unregister(struct
> > > thermal_zone_device
> > > *tz)
> > > +	void thermal_zone_device_unregister(struct
> > > thermal_zone_device *tz)
> > >  
> > >      This interface function removes the thermal zone device.
> > >      It deletes the corresponding entry from /sys/class/thermal
> > > folder and
> > >      unbinds all the thermal cooling devices it uses.
> > >  
> > > -1.1.3 struct thermal_zone_device
> > > *thermal_zone_of_sensor_register(
> > > -		struct device *dev, int sensor_id, void *data,
> > > -		const struct thermal_zone_of_device_ops *ops)
> > > +	::
> > > +
> > > +	   struct thermal_zone_device
> > > +	   *thermal_zone_of_sensor_register(struct device *dev,
> > > int
> > > sensor_id,
> > > +				void *data,
> > > +				const struct
> > > thermal_zone_of_device_ops *ops)
> > >  
> > >  	This interface adds a new sensor to a DT thermal zone.
> > >  	This function will search the list of thermal zones
> > > described in
> > > @@ -87,25 +120,33 @@ temperature) and throttle appropriate
> > > devices.
> > >  	thermal zone device.
> > >  
> > >  	The parameters for this interface are:
> > > -	dev:		Device node of sensor containing
> > > valid
> > > node pointer in
> > > +
> > > +	dev:
> > > +			Device node of sensor containing valid
> > > node
> > > pointer in
> > >  			dev->of_node.
> > > -	sensor_id:	a sensor identifier, in case the
> > > sensor IP
> > > has more
> > > +	sensor_id:
> > > +			a sensor identifier, in case the sensor
> > > IP
> > > has more
> > >  			than one sensors
> > > -	data:		a private pointer (owned by the
> > > caller)
> > > that will be
> > > +	data:
> > > +			a private pointer (owned by the caller)
> > > that
> > > will be
> > >  			passed back, when a temperature reading
> > > is
> > > needed.
> > > -	ops:		struct thermal_zone_of_device_ops *.
> > > +	ops:
> > > +			`struct thermal_zone_of_device_ops *`.
> > >  
> > > -			get_temp:	a pointer to a function
> > > that reads the
> > > +			==============  ========================
> > > ====
> > > ===========
> > > +			get_temp	a pointer to a function
> > > that
> > > reads the
> > >  					sensor temperature. This
> > > is
> > > mandatory
> > >  					callback provided by
> > > sensor
> > > driver.
> > > -			set_trips:      a pointer to a function
> > > that
> > > sets a
> > > +			set_trips	a pointer to a function
> > > that sets a
> > >  					temperature window. When
> > > this window is
> > >  					left the driver must
> > > inform
> > > the thermal
> > >  					core via
> > > thermal_zone_device_update.
> > > -			get_trend: 	a pointer to a
> > > function
> > > that reads the
> > > +			get_trend 	a pointer to a
> > > function
> > > that reads the
> > >  					sensor temperature
> > > trend.
> > > -			set_emul_temp:	a pointer to a
> > > function that sets
> > > +			set_emul_temp	a pointer to a
> > > function
> > > that sets
> > >  					sensor emulated
> > > temperature.
> > > +			==============  ========================
> > > ====
> > > ===========
> > > +
> > >  	The thermal zone temperature is provided by the
> > > get_temp()
> > > function
> > >  	pointer of thermal_zone_of_device_ops. When called, it
> > > will
> > >  	have the private pointer @data back.
> > > @@ -114,8 +155,10 @@ temperature) and throttle appropriate
> > > devices.
> > >  	handle. Caller should check the return handle with
> > > IS_ERR()
> > > for finding
> > >  	whether success or not.
> > >  
> > > -1.1.4 void thermal_zone_of_sensor_unregister(struct device *dev,
> > > -		struct thermal_zone_device *tzd)
> > > +	::
> > > +
> > > +	    void thermal_zone_of_sensor_unregister(struct device
> > > *dev,
> > > +						   struct
> > > thermal_zone_device *tzd)
> > >  
> > >  	This interface unregisters a sensor from a DT thermal
> > > zone
> > > which was
> > >  	successfully added by interface
> > > thermal_zone_of_sensor_register().
> > > @@ -124,21 +167,29 @@ temperature) and throttle appropriate
> > > devices.
> > >  	interface. It will also silent the zone by remove the
> > > .get_temp() and
> > >  	get_trend() thermal zone device callbacks.
> > >  
> > > -1.1.5 struct thermal_zone_device
> > > *devm_thermal_zone_of_sensor_register(
> > > -		struct device *dev, int sensor_id,
> > > -		void *data, const struct
> > > thermal_zone_of_device_ops
> > > *ops)
> > > +	::
> > > +
> > > +	  struct thermal_zone_device
> > > +	  *devm_thermal_zone_of_sensor_register(struct device
> > > *dev,
> > > +				int sensor_id,
> > > +				void *data,
> > > +				const struct
> > > thermal_zone_of_device_ops *ops)
> > >  
> > >  	This interface is resource managed version of
> > >  	thermal_zone_of_sensor_register().
> > > +
> > >  	All details of thermal_zone_of_sensor_register()
> > > described
> > > in
> > >  	section 1.1.3 is applicable here.
> > > +
> > >  	The benefit of using this interface to register sensor
> > > is
> > > that it
> > >  	is not require to explicitly call
> > > thermal_zone_of_sensor_unregister()
> > >  	in error path or during driver unbinding as this is done
> > > by
> > > driver
> > >  	resource manager.
> > >  
> > > -1.1.6 void devm_thermal_zone_of_sensor_unregister(struct device
> > > *dev,
> > > -		struct thermal_zone_device *tzd)
> > > +	::
> > > +
> > > +		void
> > > devm_thermal_zone_of_sensor_unregister(struct
> > > device *dev,
> > > +						struct
> > > thermal_zone_device *tzd)
> > >  
> > >  	This interface is resource managed version of
> > >  	thermal_zone_of_sensor_unregister().
> > > @@ -147,123 +198,186 @@ temperature) and throttle appropriate
> > > devices.
> > >  	Normally this function will not need to be called and
> > > the
> > > resource
> > >  	management code will ensure that the resource is freed.
> > >  
> > > -1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz)
> > > +	::
> > > +
> > > +		int thermal_zone_get_slope(struct
> > > thermal_zone_device *tz)
> > >  
> > >  	This interface is used to read the slope attribute value
> > >  	for the thermal zone device, which might be useful for
> > > platform
> > >  	drivers for temperature calculations.
> > >  
> > > -1.1.8 int thermal_zone_get_offset(struct thermal_zone_device
> > > *tz)
> > > +	::
> > > +
> > > +		int thermal_zone_get_offset(struct
> > > thermal_zone_device *tz)
> > >  
> > >  	This interface is used to read the offset attribute
> > > value
> > >  	for the thermal zone device, which might be useful for
> > > platform
> > >  	drivers for temperature calculations.
> > >  
> > >  1.2 thermal cooling device interface
> > > -1.2.1 struct thermal_cooling_device
> > > *thermal_cooling_device_register(char *name,
> > > -		void *devdata, struct thermal_cooling_device_ops
> > > *)
> > > +------------------------------------
> > > +
> > > +
> > > +    ::
> > > +
> > > +	struct thermal_cooling_device
> > > +	*thermal_cooling_device_register(char *name,
> > > +			void *devdata, struct
> > > thermal_cooling_device_ops *)
> > >  
> > >      This interface function adds a new thermal cooling device
> > > (fan/processor/...)
> > > -    to /sys/class/thermal/ folder as cooling_device[0-*]. It
> > > tries
> > > to bind itself
> > > +    to /sys/class/thermal/ folder as `cooling_device[0-*]`. It
> > > tries
> > > to bind itself
> > >      to all the thermal zone devices registered at the same time.
> > > -    name: the cooling device name.
> > > -    devdata: device private data.
> > > -    ops: thermal cooling devices call-backs.
> > > -	.get_max_state: get the Maximum throttle state of the
> > > cooling device.
> > > -	.get_cur_state: get the Currently requested throttle
> > > state
> > > of the cooling device.
> > > -	.set_cur_state: set the Current throttle state of the
> > > cooling device.
> > > -
> > > -1.2.2 void thermal_cooling_device_unregister(struct
> > > thermal_cooling_device *cdev)
> > > +
> > > +    name:
> > > +	the cooling device name.
> > > +    devdata:
> > > +	device private data.
> > > +    ops:
> > > +	thermal cooling devices call-backs.
> > > +
> > > +	.get_max_state:
> > > +		get the Maximum throttle state of the cooling
> > > device.
> > > +	.get_cur_state:
> > > +		get the Currently requested throttle state of
> > > the
> > > +		cooling device.
> > > +	.set_cur_state:
> > > +		set the Current throttle state of the cooling
> > > device.
> > > +
> > > +    ::
> > > +
> > > +	void thermal_cooling_device_unregister(struct
> > > thermal_cooling_device *cdev)
> > >  
> > >      This interface function removes the thermal cooling device.
> > >      It deletes the corresponding entry from /sys/class/thermal
> > > folder and
> > >      unbinds itself from all the thermal zone devices using it.
> > >  
> > >  1.3 interface for binding a thermal zone device with a thermal
> > > cooling device
> > > -1.3.1 int thermal_zone_bind_cooling_device(struct
> > > thermal_zone_device *tz,
> > > -	int trip, struct thermal_cooling_device *cdev,
> > > -	unsigned long upper, unsigned long lower, unsigned int
> > > weight);
> > > +--------------------------------------------------------------
> > > ----
> > > -----------
> > > +
> > > +    ::
> > > +
> > > +	int thermal_zone_bind_cooling_device(struct
> > > thermal_zone_device *tz,
> > > +		int trip, struct thermal_cooling_device *cdev,
> > > +		unsigned long upper, unsigned long lower,
> > > unsigned
> > > int weight);
> > >  
> > >      This interface function binds a thermal cooling device to a
> > > particular trip
> > >      point of a thermal zone device.
> > > +
> > >      This function is usually called in the thermal zone device
> > > .bind
> > > callback.
> > > -    tz: the thermal zone device
> > > -    cdev: thermal cooling device
> > > -    trip: indicates which trip point in this thermal zone the
> > > cooling device
> > > -          is associated with.
> > > -    upper:the Maximum cooling state for this trip point.
> > > -          THERMAL_NO_LIMIT means no upper limit,
> > > +
> > > +    tz:
> > > +	  the thermal zone device
> > > +    cdev:
> > > +	  thermal cooling device
> > > +    trip:
> > > +	  indicates which trip point in this thermal zone the
> > > cooling device
> > > +	  is associated with.
> > > +    upper:
> > > +	  the Maximum cooling state for this trip point.
> > > +	  THERMAL_NO_LIMIT means no upper limit,
> > >  	  and the cooling device can be in max_state.
> > > -    lower:the Minimum cooling state can be used for this trip
> > > point.
> > > -          THERMAL_NO_LIMIT means no lower limit,
> > > +    lower:
> > > +	  the Minimum cooling state can be used for this trip
> > > point.
> > > +	  THERMAL_NO_LIMIT means no lower limit,
> > >  	  and the cooling device can be in cooling state 0.
> > > -    weight: the influence of this cooling device in this thermal
> > > -            zone.  See 1.4.1 below for more information.
> > > +    weight:
> > > +	  the influence of this cooling device in this thermal
> > > +	  zone.  See 1.4.1 below for more information.
> > >  
> > > -1.3.2 int thermal_zone_unbind_cooling_device(struct
> > > thermal_zone_device *tz,
> > > -		int trip, struct thermal_cooling_device *cdev);
> > > +    ::
> > > +
> > > +	int thermal_zone_unbind_cooling_device(struct
> > > thermal_zone_device *tz,
> > > +				int trip, struct
> > > thermal_cooling_device *cdev);
> > >  
> > >      This interface function unbinds a thermal cooling device
> > > from a
> > > particular
> > >      trip point of a thermal zone device. This function is
> > > usually
> > > called in
> > >      the thermal zone device .unbind callback.
> > > -    tz: the thermal zone device
> > > -    cdev: thermal cooling device
> > > -    trip: indicates which trip point in this thermal zone the
> > > cooling device
> > > -          is associated with.
> > > +
> > > +    tz:
> > > +	the thermal zone device
> > > +    cdev:
> > > +	thermal cooling device
> > > +    trip:
> > > +	indicates which trip point in this thermal zone the
> > > cooling
> > > device
> > > +	is associated with.
> > >  
> > >  1.4 Thermal Zone Parameters
> > > -1.4.1 struct thermal_bind_params
> > > +---------------------------
> > > +
> > > +    ::
> > > +
> > > +	struct thermal_bind_params
> > > +
> > >      This structure defines the following parameters that are
> > > used to
> > > bind
> > >      a zone with a cooling device for a particular trip point.
> > > -    .cdev: The cooling device pointer
> > > -    .weight: The 'influence' of a particular cooling device on
> > > this
> > > -             zone. This is relative to the rest of the cooling
> > > -             devices. For example, if all cooling devices have a
> > > -             weight of 1, then they all contribute the same. You
> > > can
> > > -             use percentages if you want, but it's not
> > > mandatory. A
> > > -             weight of 0 means that this cooling device doesn't
> > > -             contribute to the cooling of this zone unless all
> > > cooling
> > > -             devices have a weight of 0. If all weights are 0,
> > > then
> > > -             they all contribute the same.
> > > -    .trip_mask:This is a bit mask that gives the binding
> > > relation
> > > between
> > > -               this thermal zone and cdev, for a particular trip
> > > point.
> > > -               If nth bit is set, then the cdev and thermal zone
> > > are
> > > bound
> > > -               for trip point n.
> > > -    .binding_limits: This is an array of cooling state limits.
> > > Must
> > > have
> > > -                     exactly 2 *
> > > thermal_zone.number_of_trip_points.
> > > It is an
> > > -                     array consisting of tuples <lower-state
> > > upper-  
> > > state> of  
> > > -                     state limits. Each trip will be associated
> > > with
> > > one state
> > > -                     limit tuple when binding. A NULL pointer
> > > means
> > > -                     <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on
> > > all
> > > trips.
> > > -                     These limits are used when binding a cdev
> > > to a
> > > trip point.
> > > -    .match: This call back returns success(0) if the 'tz and
> > > cdev'
> > > need to
> > > +
> > > +    .cdev:
> > > +	     The cooling device pointer
> > > +    .weight:
> > > +	     The 'influence' of a particular cooling device on
> > > this
> > > +	     zone. This is relative to the rest of the cooling
> > > +	     devices. For example, if all cooling devices have a
> > > +	     weight of 1, then they all contribute the same. You
> > > can
> > > +	     use percentages if you want, but it's not
> > > mandatory. A
> > > +	     weight of 0 means that this cooling device doesn't
> > > +	     contribute to the cooling of this zone unless all
> > > cooling
> > > +	     devices have a weight of 0. If all weights are 0,
> > > then
> > > +	     they all contribute the same.
> > > +    .trip_mask:
> > > +	       This is a bit mask that gives the binding
> > > relation
> > > between
> > > +	       this thermal zone and cdev, for a particular trip
> > > point.
> > > +	       If nth bit is set, then the cdev and thermal zone
> > > are
> > > bound
> > > +	       for trip point n.
> > > +    .binding_limits:
> > > +		     This is an array of cooling state limits.
> > > Must
> > > have
> > > +		     exactly 2 *
> > > thermal_zone.number_of_trip_points.
> > > It is an
> > > +		     array consisting of tuples <lower-state
> > > upper-  
> > > state> of  
> > > +		     state limits. Each trip will be associated
> > > with
> > > one state
> > > +		     limit tuple when binding. A NULL pointer
> > > means
> > > +		     <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on
> > > all
> > > trips.
> > > +		     These limits are used when binding a cdev
> > > to a
> > > trip point.
> > > +    .match:
> > > +	    This call back returns success(0) if the 'tz and
> > > cdev'
> > > need to
> > >  	    be bound, as per platform data.
> > > -1.4.2 struct thermal_zone_params
> > > +
> > > +    ::
> > > +
> > > +	struct thermal_zone_params
> > > +
> > >      This structure defines the platform level parameters for a
> > > thermal zone.
> > >      This data, for each thermal zone should come from the
> > > platform
> > > layer.
> > >      This is an optional feature where some platforms can choose
> > > not
> > > to
> > >      provide this data.
> > > -    .governor_name: Name of the thermal governor used for this
> > > zone
> > > -    .no_hwmon: a boolean to indicate if the thermal to hwmon
> > > sysfs
> > > interface
> > > -               is required. when no_hwmon == false, a hwmon
> > > sysfs
> > > interface
> > > -               will be created. when no_hwmon == true, nothing
> > > will
> > > be done.
> > > -               In case the thermal_zone_params is NULL, the
> > > hwmon
> > > interface
> > > -               will be created (for backward compatibility).
> > > -    .num_tbps: Number of thermal_bind_params entries for this
> > > zone
> > > -    .tbp: thermal_bind_params entries
> > > +
> > > +    .governor_name:
> > > +	       Name of the thermal governor used for this zone
> > > +    .no_hwmon:
> > > +	       a boolean to indicate if the thermal to hwmon
> > > sysfs
> > > interface
> > > +	       is required. when no_hwmon == false, a hwmon
> > > sysfs
> > > interface
> > > +	       will be created. when no_hwmon == true, nothing
> > > will
> > > be done.
> > > +	       In case the thermal_zone_params is NULL, the
> > > hwmon
> > > interface
> > > +	       will be created (for backward compatibility).
> > > +    .num_tbps:
> > > +	       Number of thermal_bind_params entries for this
> > > zone
> > > +    .tbp:
> > > +	       thermal_bind_params entries
> > >  
> > >  2. sysfs attributes structure
> > > +=============================
> > >  
> > > +==	================
> > >  RO	read only value
> > >  WO	write only value
> > >  RW	read/write value
> > > +==	================
> > >  
> > >  Thermal sysfs attributes will be represented under
> > > /sys/class/thermal.
> > >  Hwmon sysfs I/F extension is also available under
> > > /sys/class/hwmon
> > >  if hwmon is compiled in or built as a module.
> > >  
> > > -Thermal zone device sys I/F, created once it's registered:
> > > -/sys/class/thermal/thermal_zone[0-*]:
> > > +Thermal zone device sys I/F, created once it's registered::
> > > +
> > > +  /sys/class/thermal/thermal_zone[0-*]:
> > >      |---type:			Type of the thermal zone
> > >      |---temp:			Current temperature
> > >      |---mode:			Working mode of the thermal
> > > zone
> > > @@ -282,8 +396,9 @@ Thermal zone device sys I/F, created once
> > > it's
> > > registered:
> > >      |---slope:                  Slope constant applied as linear
> > > extrapolation
> > >      |---offset:                 Offset constant applied as
> > > linear
> > > extrapolation
> > >  
> > > -Thermal cooling device sys I/F, created once it's registered:
> > > -/sys/class/thermal/cooling_device[0-*]:
> > > +Thermal cooling device sys I/F, created once it's registered::
> > > +
> > > +  /sys/class/thermal/cooling_device[0-*]:
> > >      |---type:			Type of the cooling
> > > device(processor/fan/...)
> > >      |---max_state:		Maximum cooling state of the
> > > cooling device
> > >      |---cur_state:		Current cooling state of the
> > > cooling device
> > > @@ -299,11 +414,13 @@ the relationship between a thermal zone and
> > > its
> > > associated cooling device.
> > >  They are created/removed for each successful execution of
> > >  thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_dev
> > > ice.
> > >  
> > > -/sys/class/thermal/thermal_zone[0-*]:
> > > +::
> > > +
> > > +  /sys/class/thermal/thermal_zone[0-*]:
> > >      |---cdev[0-*]:		[0-*]th cooling device in
> > > current
> > > thermal zone
> > >      |---cdev[0-*]_trip_point:	Trip point that cdev[0-*]
> > > is
> > > associated with
> > >      |---cdev[0-*]_weight:       Influence of the cooling device
> > > in
> > > -                                this thermal zone
> > > +				this thermal zone
> > >  
> > >  Besides the thermal zone device sysfs I/F and cooling device
> > > sysfs
> > > I/F,
> > >  the generic thermal driver also creates a hwmon sysfs I/F for
> > > each
> > > _type_
> > > @@ -311,16 +428,17 @@ of thermal zone device. E.g. the generic
> > > thermal driver registers one hwmon
> > >  class device and build the associated hwmon sysfs I/F for all
> > > the
> > > registered
> > >  ACPI thermal zones.
> > >  
> > > -/sys/class/hwmon/hwmon[0-*]:
> > > +::
> > > +
> > > +  /sys/class/hwmon/hwmon[0-*]:
> > >      |---name:			The type of the thermal
> > > zone
> > > devices
> > >      |---temp[1-*]_input:	The current temperature of
> > > thermal
> > > zone [1-*]
> > >      |---temp[1-*]_critical:	The critical trip point of
> > > thermal zone [1-*]
> > >  
> > >  Please read Documentation/hwmon/sysfs-interface.rst for
> > > additional
> > > information.
> > >  
> > > -***************************
> > > -* Thermal zone attributes *
> > > -***************************
> > > +Thermal zone attributes
> > > +-----------------------
> > >  
> > >  type
> > >  	Strings which represent the thermal zone type.
> > > @@ -340,54 +458,67 @@ mode
> > >  	This file gives information about the algorithm that is
> > > currently
> > >  	managing the thermal zone. It can be either default
> > > kernel
> > > based
> > >  	algorithm or user space application.
> > > -	enabled		= enable Kernel Thermal
> > > management.
> > > -	disabled	= Preventing kernel thermal zone driver
> > > actions upon
> > > +
> > > +	enabled
> > > +			  enable Kernel Thermal management.
> > > +	disabled
> > > +			  Preventing kernel thermal zone driver
> > > actions upon
> > >  			  trip points so that user application
> > > can
> > > take full
> > >  			  charge of the thermal management.
> > > +
> > >  	RW, Optional
> > >  
> > >  policy
> > >  	One of the various thermal governors used for a
> > > particular
> > > zone.
> > > +
> > >  	RW, Required
> > >  
> > >  available_policies
> > >  	Available thermal governors which can be used for a
> > > particular zone.
> > > +
> > >  	RO, Required
> > >  
> > > -trip_point_[0-*]_temp
> > > +`trip_point_[0-*]_temp`
> > >  	The temperature above which trip point will be fired.
> > > +
> > >  	Unit: millidegree Celsius
> > > +
> > >  	RO, Optional
> > >  
> > > -trip_point_[0-*]_type
> > > +`trip_point_[0-*]_type`
> > >  	Strings which indicate the type of the trip point.
> > > -	E.g. it can be one of critical, hot, passive, active[0-
> > > *]
> > > for ACPI
> > > +
> > > +	E.g. it can be one of critical, hot, passive, `active[0-
> > > *]`
> > > for ACPI
> > >  	thermal zone.
> > > +
> > >  	RO, Optional
> > >  
> > > -trip_point_[0-*]_hyst
> > > +`trip_point_[0-*]_hyst`
> > >  	The hysteresis value for a trip point, represented as an
> > > integer
> > >  	Unit: Celsius
> > >  	RW, Optional
> > >  
> > > -cdev[0-*]
> > > +`cdev[0-*]`
> > >  	Sysfs link to the thermal cooling device node where the
> > > sys
> > > I/F
> > >  	for cooling device throttling control represents.
> > > +
> > >  	RO, Optional
> > >  
> > > -cdev[0-*]_trip_point
> > > -	The trip point in this thermal zone which cdev[0-*] is
> > > associated
> > > +`cdev[0-*]_trip_point`
> > > +	The trip point in this thermal zone which `cdev[0-*]` is
> > > associated
> > >  	with; -1 means the cooling device is not associated with
> > > any
> > > trip
> > >  	point.
> > > +
> > >  	RO, Optional
> > >  
> > > -cdev[0-*]_weight
> > > -        The influence of cdev[0-*] in this thermal zone. This
> > > value
> > > -        is relative to the rest of cooling devices in the
> > > thermal
> > > -        zone. For example, if a cooling device has a weight
> > > double
> > > -        than that of other, it's twice as effective in cooling
> > > the
> > > -        thermal zone.
> > > -        RW, Optional
> > > +`cdev[0-*]_weight`
> > > +	The influence of `cdev[0-*]` in this thermal zone. This
> > > value
> > > +	is relative to the rest of cooling devices in the
> > > thermal
> > > +	zone. For example, if a cooling device has a weight
> > > double
> > > +	than that of other, it's twice as effective in cooling
> > > the
> > > +	thermal zone.
> > > +
> > > +	RW, Optional
> > >  
> > >  passive
> > >  	Attribute is only present for zones in which the passive
> > > cooling
> > > @@ -395,8 +526,11 @@ passive
> > >  	and can be set to a temperature (in millidegrees) to
> > > enable
> > > a
> > >  	passive trip point for the zone. Activation is done by
> > > polling with
> > >  	an interval of 1 second.
> > > +
> > >  	Unit: millidegrees Celsius
> > > +
> > >  	Valid values: 0 (disabled) or greater than 1000
> > > +
> > >  	RW, Optional
> > >  
> > >  emul_temp
> > > @@ -407,17 +541,21 @@ emul_temp
> > >  	threshold and its associated cooling action. This is
> > > write
> > > only node
> > >  	and writing 0 on this node should disable emulation.
> > >  	Unit: millidegree Celsius
> > > +
> > >  	WO, Optional
> > >  
> > > -	  WARNING: Be careful while enabling this option on
> > > production systems,
> > > -	  because userland can easily disable the thermal policy
> > > by
> > > simply
> > > -	  flooding this sysfs node with low temperature values.
> > > +	  WARNING:
> > > +	    Be careful while enabling this option on production
> > > systems,
> > > +	    because userland can easily disable the thermal
> > > policy
> > > by simply
> > > +	    flooding this sysfs node with low temperature
> > > values.
> > >  
> > >  sustainable_power
> > >  	An estimate of the sustained power that can be
> > > dissipated by
> > >  	the thermal zone. Used by the power allocator governor.
> > > For
> > > -	more information see
> > > Documentation/thermal/power_allocator.txt
> > > +	more information see
> > > Documentation/thermal/power_allocator.rst
> > > +
> > >  	Unit: milliwatts
> > > +
> > >  	RW, Optional
> > >  
> > >  k_po
> > > @@ -425,7 +563,8 @@ k_po
> > >  	controller during temperature overshoot. Temperature
> > > overshoot
> > >  	is when the current temperature is above the "desired
> > >  	temperature" trip point. For more information see
> > > -	Documentation/thermal/power_allocator.txt
> > > +	Documentation/thermal/power_allocator.rst
> > > +
> > >  	RW, Optional
> > >  
> > >  k_pu
> > > @@ -433,20 +572,23 @@ k_pu
> > >  	controller during temperature undershoot. Temperature
> > > undershoot
> > >  	is when the current temperature is below the "desired
> > >  	temperature" trip point. For more information see
> > > -	Documentation/thermal/power_allocator.txt
> > > +	Documentation/thermal/power_allocator.rst
> > > +
> > >  	RW, Optional
> > >  
> > >  k_i
> > >  	The integral term of the power allocator governor's PID
> > >  	controller. This term allows the PID controller to
> > > compensate
> > >  	for long term drift. For more information see
> > > -	Documentation/thermal/power_allocator.txt
> > > +	Documentation/thermal/power_allocator.rst
> > > +
> > >  	RW, Optional
> > >  
> > >  k_d
> > >  	The derivative term of the power allocator governor's
> > > PID
> > >  	controller. For more information see
> > > -	Documentation/thermal/power_allocator.txt
> > > +	Documentation/thermal/power_allocator.rst
> > > +
> > >  	RW, Optional
> > >  
> > >  integral_cutoff
> > > @@ -456,8 +598,10 @@ integral_cutoff
> > >  	example, if integral_cutoff is 0, then the integral term
> > > only
> > >  	accumulates error when temperature is above the desired
> > >  	temperature trip point. For more information see
> > > -	Documentation/thermal/power_allocator.txt
> > > +	Documentation/thermal/power_allocator.rst
> > > +
> > >  	Unit: millidegree Celsius
> > > +
> > >  	RW, Optional
> > >  
> > >  slope
> > > @@ -465,6 +609,7 @@ slope
> > >  	to determine a hotspot temperature based off the
> > > sensor's
> > >  	raw readings. It is up to the device driver to determine
> > >  	the usage of these values.
> > > +
> > >  	RW, Optional
> > >  
> > >  offset
> > > @@ -472,28 +617,33 @@ offset
> > >  	to determine a hotspot temperature based off the
> > > sensor's
> > >  	raw readings. It is up to the device driver to determine
> > >  	the usage of these values.
> > > +
> > >  	RW, Optional
> > >  
> > > -*****************************
> > > -* Cooling device attributes *
> > > -*****************************
> > > +Cooling device attributes
> > > +-------------------------
> > >  
> > >  type
> > >  	String which represents the type of device, e.g:
> > > +
> > >  	- for generic ACPI: should be "Fan", "Processor" or
> > > "LCD"
> > >  	- for memory controller device on intel_menlow platform:
> > >  	  should be "Memory controller".
> > > +
> > >  	RO, Required
> > >  
> > >  max_state
> > >  	The maximum permissible cooling state of this cooling
> > > device.
> > > +
> > >  	RO, Required
> > >  
> > >  cur_state
> > >  	The current cooling state of this cooling device.
> > >  	The value can any integer numbers between 0 and
> > > max_state:
> > > +
> > >  	- cur_state == 0 means no cooling
> > >  	- cur_state == max_state means the maximum cooling.
> > > +
> > >  	RW, Required
> > >  
> > >  stats/reset
> > > @@ -508,9 +658,11 @@ stats/time_in_state_ms:
> > >  	units here is 10mS (similar to other time exported in
> > > /proc).
> > >  	RO, Required
> > >  
> > > +
> > >  stats/total_trans:
> > >  	A single positive value showing the total number of
> > > times
> > > the state of a
> > >  	cooling device is changed.
> > > +
> > >  	RO, Required
> > >  
> > >  stats/trans_table:
> > > @@ -522,6 +674,7 @@ stats/trans_table:
> > >  	RO, Required
> > >  
> > >  3. A simple implementation
> > > +==========================
> > >  
> > >  ACPI thermal zone may support multiple trip points like
> > > critical,
> > > hot,
> > >  passive, active. If an ACPI thermal zone supports critical,
> > > passive,
> > > @@ -532,11 +685,10 @@ thermal_cooling_device. Both are considered
> > > to
> > > have the same
> > >  effectiveness in cooling the thermal zone.
> > >  
> > >  If the processor is listed in _PSL method, and the fan is listed
> > > in
> > > _AL0
> > > -method, the sys I/F structure will be built like this:
> > > +method, the sys I/F structure will be built like this::
> > >  
> > > -/sys/class/thermal:
> > > -
> > > -|thermal_zone1:
> > > + /sys/class/thermal:
> > > +  |thermal_zone1:
> > >      |---type:			acpitz
> > >      |---temp:			37000
> > >      |---mode:			enabled
> > > @@ -557,24 +709,24 @@ method, the sys I/F structure will be built
> > > like this:
> > >      |---cdev1_trip_point:	2	/* cdev1 can be used
> > > for
> > > active[0]*/
> > >      |---cdev1_weight:           1024
> > >  
> > > -|cooling_device0:
> > > +  |cooling_device0:
> > >      |---type:			Processor
> > >      |---max_state:		8
> > >      |---cur_state:		0
> > >  
> > > -|cooling_device3:
> > > +  |cooling_device3:
> > >      |---type:			Fan
> > >      |---max_state:		2
> > >      |---cur_state:		0
> > >  
> > > -/sys/class/hwmon:
> > > -
> > > -|hwmon0:
> > > + /sys/class/hwmon:
> > > +  |hwmon0:
> > >      |---name:			acpitz
> > >      |---temp1_input:		37000
> > >      |---temp1_crit:		100000
> > >  
> > >  4. Event Notification
> > > +=====================
> > >  
> > >  The framework includes a simple notification mechanism, in the
> > > form
> > > of a
> > >  netlink event. Netlink socket initialization is done during the
> > > _init_
> > > @@ -587,21 +739,28 @@ event will be one of:{THERMAL_AUX0,
> > > THERMAL_AUX1, THERMAL_CRITICAL,
> > >  THERMAL_DEV_FAULT}. Notification can be sent when the current
> > > temperature
> > >  crosses any of the configured thresholds.
> > >  
> > > -5. Export Symbol APIs:
> > > +5. Export Symbol APIs
> > > +=====================
> > > +
> > > +5.1. get_tz_trend
> > > +-----------------
> > >  
> > > -5.1: get_tz_trend:
> > >  This function returns the trend of a thermal zone, i.e the rate
> > > of
> > > change
> > >  of temperature of the thermal zone. Ideally, the thermal sensor
> > > drivers
> > >  are supposed to implement the callback. If they don't, the
> > > thermal
> > >  framework calculated the trend by comparing the previous and the
> > > current
> > >  temperature values.
> > >  
> > > -5.2:get_thermal_instance:
> > > +5.2. get_thermal_instance
> > > +-------------------------
> > > +
> > >  This function returns the thermal_instance corresponding to a
> > > given
> > >  {thermal_zone, cooling_device, trip_point} combination. Returns
> > > NULL
> > >  if such an instance does not exist.
> > >  
> > > -5.3:thermal_notify_framework:
> > > +5.3. thermal_notify_framework
> > > +-----------------------------
> > > +
> > >  This function handles the trip events from sensor drivers. It
> > > starts
> > >  throttling the cooling devices according to the policy
> > > configured.
> > >  For CRITICAL and HOT trip points, this notifies the respective
> > > drivers,
> > > @@ -609,12 +768,15 @@ and does actual throttling for other trip
> > > points i.e ACTIVE and PASSIVE.
> > >  The throttling policy is based on the configured platform data;
> > > if
> > > no
> > >  platform data is provided, this uses the step_wise throttling
> > > policy.
> > >  
> > > -5.4:thermal_cdev_update:
> > > +5.4. thermal_cdev_update
> > > +------------------------
> > > +
> > >  This function serves as an arbitrator to set the state of a
> > > cooling
> > >  device. It sets the cooling device to the deepest cooling state
> > > if
> > >  possible.
> > >  
> > > -6. thermal_emergency_poweroff:
> > > +6. thermal_emergency_poweroff
> > > +=============================
> > >  
> > >  On an event of critical trip temperature crossing. Thermal
> > > framework
> > >  allows the system to shutdown gracefully by calling
> > > orderly_poweroff().
> > > diff --git a/Documentation/thermal/x86_pkg_temperature_thermal
> > > b/Documentation/thermal/x86_pkg_temperature_thermal.rst
> > > similarity index 80%
> > > rename from Documentation/thermal/x86_pkg_temperature_thermal
> > > rename to Documentation/thermal/x86_pkg_temperature_thermal.rst
> > > index 17a3a4c0a0ca..f134dbd3f5a9 100644
> > > --- a/Documentation/thermal/x86_pkg_temperature_thermal
> > > +++ b/Documentation/thermal/x86_pkg_temperature_thermal.rst
> > > @@ -1,19 +1,23 @@
> > > +===================================
> > >  Kernel driver: x86_pkg_temp_thermal
> > > -===================
> > > +===================================
> > >  
> > >  Supported chips:
> > > +
> > >  * x86: with package level thermal management
> > > +
> > >  (Verify using: CPUID.06H:EAX[bit 6] =1)
> > >  
> > >  Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.co
> > > m>
> > >  
> > >  Reference
> > > ----
> > > +---------
> > > +
> > >  Intel® 64 and IA-32 Architectures Software Developer’s Manual
> > > (Jan,
> > > 2013):
> > >  Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
> > >  
> > >  Description
> > > ----------
> > > +-----------
> > >  
> > >  This driver register CPU digital temperature package level
> > > sensor as
> > > a thermal
> > >  zone with maximum two user mode configurable trip points. Number
> > > of
> > > trip points
> > > @@ -25,23 +29,27 @@ take any action to control temperature.
> > >  Threshold management
> > >  --------------------
> > >  Each package will register as a thermal zone under
> > > /sys/class/thermal.
> > > -Example:
> > > -/sys/class/thermal/thermal_zone1
> > > +
> > > +Example::
> > > +
> > > +	/sys/class/thermal/thermal_zone1
> > >  
> > >  This contains two trip points:
> > > +
> > >  - trip_point_0_temp
> > >  - trip_point_1_temp
> > >  
> > >  User can set any temperature between 0 to TJ-Max temperature.
> > > Temperature units
> > > -are in milli-degree Celsius. Refer to
> > > "Documentation/thermal/sysfs-
> > > api.txt" for
> > > +are in milli-degree Celsius. Refer to
> > > "Documentation/thermal/sysfs-
> > > api.rst" for
> > >  thermal sys-fs details.
> > >  
> > >  Any value other than 0 in these trip points, can trigger thermal
> > > notifications.
> > >  Setting 0, stops sending thermal notifications.
> > >  
> > > -Thermal notifications: To get kobject-uevent notifications, set
> > > the
> > > thermal zone
> > > -policy to "user_space". For example: echo -n "user_space" >
> > > policy
> > > -
> > > -
> > > +Thermal notifications:
> > > +To get kobject-uevent notifications, set the thermal zone
> > > +policy to "user_space".
> > >  
> > > +For example::
> > >  
> > > +	echo -n "user_space" > policy
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index d9e214f68e52..b2254bc8e495 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -15687,7 +15687,7 @@ M:	Viresh Kumar <viresh.kumar@lina
> > > ro.o  
> > > rg>  
> > >  M:	Javi Merino <javi.merino@kernel.org>
> > >  L:	linux-pm@vger.kernel.org
> > >  S:	Supported
> > > -F:	Documentation/thermal/cpu-cooling-api.txt
> > > +F:	Documentation/thermal/cpu-cooling-api.rst
> > >  F:	drivers/thermal/cpu_cooling.c
> > >  F:	include/linux/cpu_cooling.h
> > >  
> > > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > > index 15a4ca5d7099..681047f8cc05 100644
> > > --- a/include/linux/thermal.h
> > > +++ b/include/linux/thermal.h
> > > @@ -251,7 +251,7 @@ struct thermal_bind_params {
> > >  	 * platform characterization. This value is relative to
> > > the
> > >  	 * rest of the weights so a cooling device whose weight
> > > is
> > >  	 * double that of another cooling device is twice as
> > > -	 * effective. See Documentation/thermal/sysfs-api.txt
> > > for
> > > more
> > > +	 * effective. See Documentation/thermal/sysfs-api.rst
> > > for
> > > more
> > >  	 * information.
> > >  	 */
> > >  	int weight;
> > > @@ -259,7 +259,7 @@ struct thermal_bind_params {
> > >  	/*
> > >  	 * This is a bit mask that gives the binding relation
> > > between this
> > >  	 * thermal zone and cdev, for a particular trip point.
> > > -	 * See Documentation/thermal/sysfs-api.txt for more
> > > information.
> > > +	 * See Documentation/thermal/sysfs-api.rst for more
> > > information.
> > >  	 */
> > >  	int trip_mask;
> > >    
> 
> 
> Thanks,
> Mauro

^ permalink raw reply

* Re: [PATCH 2/2] ACPI: PM: Allow transitions to D0 to occur in special cases
From: Mika Westerberg @ 2019-06-25 14:14 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux ACPI, Bjorn Helgaas, Linux PM, LKML, Zhang Rui
In-Reply-To: <2807567.5m5tnf7bLv@kreacher>

On Tue, Jun 25, 2019 at 02:06:13PM +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> If a device with ACPI PM is left in D0 during a system-wide
> transition to the S3 (suspend-to-RAM) or S4 (hibernation) sleep
> state, the actual state of the device need not be D0 during resume
> from it, although its power.state value will still reflect D0 (that
> is, the power state from before the system-wide transition).
> 
> In that case, the acpi_device_set_power() call made to ensure that
> the power state of the device will be D0 going forward has no effect,
> because the new state (D0) is equal to the one reflected by the
> device's power.state value.  That does not affect power resources,
> which are taken care of by acpi_resume_power_resources() called from
> acpi_pm_finish() during resume from system-wide sleep states, but it
> still may be necessary to invoke _PS0 for the device on top of that
> in order to finalize its transition to D0.
> 
> For this reason, modify acpi_device_set_power() to allow transitions
> to D0 to occur even if D0 is the current power state of the device
> according to its power.state value.
> 
> That will not affect power resources, which are assumed to be in
> the right configuration already (as reflected by the current values
> of their reference counters), but it may cause _PS0 to be evaluated
> for the device.  However, evaluating _PS0 for a device already in D0
> may lead to confusion in general, so invoke _PSC (if present) to
> check the device's current power state upfront and only evaluate
> _PS0 for it if _PSC has returned a power state different from D0.
> [If _PSC is not present or the evaluation of it fails, the power
> state of the device is assumed to be D0 at this point.]
> 
> Fixes: 20dacb71ad28 (ACPI / PM: Rework device power management to follow ACPI 6)
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>

^ permalink raw reply

* Re: [PATCH 1/2] ACPI: PM: Avoid evaluating _PS3 on transitions from D3hot to D3cold
From: Mika Westerberg @ 2019-06-25 14:11 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux ACPI, Bjorn Helgaas, Linux PM, LKML, Zhang Rui
In-Reply-To: <3012059.oderKuhLE3@kreacher>

On Tue, Jun 25, 2019 at 02:04:45PM +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> If the power state of a device with ACPI PM is changed from D3hot to
> D3cold, it merely is a matter of dropping references to additional
> power resources (specifically, those in the list returned by _PR3),
> and the _PS3 method should not be invoked for the device then (as
> it has already been evaluated during the previous transition to
> D3hot).
> 
> Fixes: 20dacb71ad28 (ACPI / PM: Rework device power management to follow ACPI 6)
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>

^ permalink raw reply

* [regression, bisected] Keyboard not responding after resuming from suspend/hibernate
From: Numan Demirdöğen @ 2019-06-25 13:54 UTC (permalink / raw)
  To: linux-pm; +Cc: rjw, len.brown, pavel, guido.aulisi

If laptop is put to suspend or hibernate by closing lid, via power
manager or by using any other method and then it is resumed/waked up,
keyboard is not responding but mouse or trackball can be used. Although
I can wake laptop up by keyboard, after that I am stuck at the password
prompt. This bug is present ever since using 4.10-rc1 kernel and mostly
on Sony laptops. The last working kernel version is 4.9.0-rc2.

git bisect points 9d659ae14b545c4296e812c70493bfdc999b5c1c 
as the first bad commit[1].

I tried some kernel parameters related to i8042 driver:
i8042.debug=1 i8042.reset=1	keyboard not working
i8042.debug=1 i8042.kbdreset=1	keyboard not working
i8042.debug=1 i8042.nomux=1	keyboard not working
i8042.debug=1 i8042.noaux=1	keyboard working, but touchpad not
working

A user reported that on some rare occasions, keyboard responded to key
press but it remained pressed forever even if stopped pressing it. And
another user reported that passing the options i8042.reset=1
i8042.dumbkbd=1 i8042.direct=1 resulted in the keyboard functioning
after resume. However, there was a long delay before the keyboard or
mouse responded to input on the lock screen.

This one line patch, which can be a hint, from Takashi Iwai essentially
reverts the commit 9d659ae14b545 mentioned in the above and keyboard is
working as expected after resuming from suspend/hibernate, if this
patch is applied. 

--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -59,7 +59,7 @@ EXPORT_SYMBOL(__mutex_init);
  * Bit2 indicates handoff has been done and we're waiting for pickup.
  */
 #define MUTEX_FLAG_WAITERS	0x01
-#define MUTEX_FLAG_HANDOFF	0x02
+#define MUTEX_FLAG_HANDOFF	0x00
 #define MUTEX_FLAG_PICKUP	0x04
 
 #define MUTEX_FLAGS		0x07
 
- The first bug report on bugzilla.kernel.org[2].
- LKML thread[3]
- Another report on OpenSUSE bugzilla[4]

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/commit/?id=9d659ae14b545c4296e812c70493bfdc999b5c1c
[2] https://bugzilla.kernel.org/show_bug.cgi?id=195471
[3] https://lkml.org/lkml/2018/8/31/707
[4]  https://bugzilla.opensuse.org/show_bug.cgi?id=1114588

^ permalink raw reply

* Re: [PATCH v1 04/22] docs: thermal: convert to ReST
From: Zhang Rui @ 2019-06-25 13:40 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, linux-kernel, Jonathan Corbet,
	Amit Daniel Kachhap, Viresh Kumar, Javi Merino, Kukjin Kim,
	Krzysztof Kozlowski, Eduardo Valentin, Daniel Lezcano, linux-pm,
	linux-arm-kernel, linux-samsung-soc, Arjan van de Ven
In-Reply-To: <23fafb70bfc9bd8b7f306f2502617d8f8794eae5.1560891322.git.mchehab+samsung@kernel.org>

On 二, 2019-06-18 at 18:05 -0300, Mauro Carvalho Chehab wrote:
> Rename the thermal documentation files to ReST, add an
> index for them and adjust in order to produce a nice html
> output via the Sphinx build system.
> 
> At its new index.rst, let's add a :orphan: while this is not linked
> to
> the main index.rst file, in order to avoid build warnings.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>

Acked-by: Zhang Rui <rui.zhang@intel.com>

should I apply this patch or you have a separate tree for all these
changes?

thanks,
rui
> ---
>  ...pu-cooling-api.txt => cpu-cooling-api.rst} |  39 +-
>  .../{exynos_thermal => exynos_thermal.rst}    |  47 +-
>  ...emulation => exynos_thermal_emulation.rst} |  66 +--
>  Documentation/thermal/index.rst               |  18 +
>  ...el_powerclamp.txt => intel_powerclamp.rst} | 177 +++----
>  .../{nouveau_thermal => nouveau_thermal.rst}  |  54 +-
>  ...ower_allocator.txt => power_allocator.rst} | 140 ++---
>  .../thermal/{sysfs-api.txt => sysfs-api.rst}  | 490 ++++++++++++--
> ----
>  ...hermal => x86_pkg_temperature_thermal.rst} |  28 +-
>  MAINTAINERS                                   |   2 +-
>  include/linux/thermal.h                       |   4 +-
>  11 files changed, 665 insertions(+), 400 deletions(-)
>  rename Documentation/thermal/{cpu-cooling-api.txt => cpu-cooling-
> api.rst} (82%)
>  rename Documentation/thermal/{exynos_thermal => exynos_thermal.rst}
> (67%)
>  rename Documentation/thermal/{exynos_thermal_emulation =>
> exynos_thermal_emulation.rst} (36%)
>  create mode 100644 Documentation/thermal/index.rst
>  rename Documentation/thermal/{intel_powerclamp.txt =>
> intel_powerclamp.rst} (76%)
>  rename Documentation/thermal/{nouveau_thermal =>
> nouveau_thermal.rst} (64%)
>  rename Documentation/thermal/{power_allocator.txt =>
> power_allocator.rst} (74%)
>  rename Documentation/thermal/{sysfs-api.txt => sysfs-api.rst} (66%)
>  rename Documentation/thermal/{x86_pkg_temperature_thermal =>
> x86_pkg_temperature_thermal.rst} (80%)
> 
> diff --git a/Documentation/thermal/cpu-cooling-api.txt
> b/Documentation/thermal/cpu-cooling-api.rst
> similarity index 82%
> rename from Documentation/thermal/cpu-cooling-api.txt
> rename to Documentation/thermal/cpu-cooling-api.rst
> index 7df567eaea1a..645d914c45a6 100644
> --- a/Documentation/thermal/cpu-cooling-api.txt
> +++ b/Documentation/thermal/cpu-cooling-api.rst
> @@ -1,5 +1,6 @@
> +=======================
>  CPU cooling APIs How To
> -===================================
> +=======================
>  
>  Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
>  
> @@ -8,40 +9,54 @@ Updated: 6 Jan 2015
>  Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.
> com)
>  
>  0. Introduction
> +===============
>  
>  The generic cpu cooling(freq clipping) provides
> registration/unregistration APIs
>  to the caller. The binding of the cooling devices to the trip point
> is left for
>  the user. The registration APIs returns the cooling device pointer.
>  
>  1. cpu cooling APIs
> +===================
>  
>  1.1 cpufreq registration/unregistration APIs
> -1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
> -	struct cpumask *clip_cpus)
> +--------------------------------------------
> +
> +    ::
> +
> +	struct thermal_cooling_device
> +	*cpufreq_cooling_register(struct cpumask *clip_cpus)
>  
>      This interface function registers the cpufreq cooling device
> with the name
>      "thermal-cpufreq-%x". This api can support multiple instances of
> cpufreq
>      cooling devices.
>  
> -   clip_cpus: cpumask of cpus where the frequency constraints will
> happen.
> +   clip_cpus:
> +	cpumask of cpus where the frequency constraints will happen.
>  
> -1.1.2 struct thermal_cooling_device *of_cpufreq_cooling_register(
> -					struct cpufreq_policy
> *policy)
> +    ::
> +
> +	struct thermal_cooling_device
> +	*of_cpufreq_cooling_register(struct cpufreq_policy *policy)
>  
>      This interface function registers the cpufreq cooling device
> with
>      the name "thermal-cpufreq-%x" linking it with a device tree
> node, in
>      order to bind it via the thermal DT code. This api can support
> multiple
>      instances of cpufreq cooling devices.
>  
> -    policy: CPUFreq policy.
> +    policy:
> +	CPUFreq policy.
>  
> -1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device
> *cdev)
> +
> +    ::
> +
> +	void cpufreq_cooling_unregister(struct
> thermal_cooling_device *cdev)
>  
>      This interface function unregisters the "thermal-cpufreq-%x"
> cooling device.
>  
>      cdev: Cooling device pointer which has to be unregistered.
>  
>  2. Power models
> +===============
>  
>  The power API registration functions provide a simple power model
> for
>  CPUs.  The current power is calculated as dynamic power (static
> power isn't
> @@ -65,9 +80,9 @@ For a given processor implementation the primary
> factors are:
>    variation.  In pathological cases this variation can be
> significant,
>    but typically it is of a much lesser impact than the factors
> above.
>  
> -A high level dynamic power consumption model may then be represented
> as:
> +A high level dynamic power consumption model may then be represented
> as::
>  
> -Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
> +	Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
>  
>  f(run) here represents the described execution behaviour and its
>  result has a units of Watts/Hz/Volt^2 (this often expressed in
> @@ -80,9 +95,9 @@ factors.  Therefore, in initial implementation that
> contribution is
>  represented as a constant coefficient.  This is a simplification
>  consistent with the relative contribution to overall power
> variation.
>  
> -In this simplified representation our model becomes:
> +In this simplified representation our model becomes::
>  
> -Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
> +	Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
>  
>  Where `capacitance` is a constant that represents an indicative
>  running time dynamic power coefficient in fundamental units of
> diff --git a/Documentation/thermal/exynos_thermal
> b/Documentation/thermal/exynos_thermal.rst
> similarity index 67%
> rename from Documentation/thermal/exynos_thermal
> rename to Documentation/thermal/exynos_thermal.rst
> index 9010c4416967..5bd556566c70 100644
> --- a/Documentation/thermal/exynos_thermal
> +++ b/Documentation/thermal/exynos_thermal.rst
> @@ -1,8 +1,11 @@
> +========================
>  Kernel driver exynos_tmu
> -=================
> +========================
>  
>  Supported chips:
> +
>  * ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
> +
>    Datasheet: Not publicly available
>  
>  Authors: Donggeun Kim <dg77.kim@samsung.com>
> @@ -19,32 +22,39 @@ Temperature can be taken from the temperature
> code.
>  There are three equations converting from temperature to temperature
> code.
>  
>  The three equations are:
> -  1. Two point trimming
> +  1. Two point trimming::
> +
>  	Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
>  
> -  2. One point trimming
> +  2. One point trimming::
> +
>  	Tc = T + TI1 - 25
>  
> -  3. No trimming
> +  3. No trimming::
> +
>  	Tc = T + 50
>  
> -  Tc: Temperature code, T: Temperature,
> -  TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO
> register)
> +  Tc:
> +       Temperature code, T: Temperature,
> +  TI1:
> +       Trimming info for 25 degree Celsius (stored at TRIMINFO
> register)
>         Temperature code measured at 25 degree Celsius which is
> unchanged
> -  TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO
> register)
> +  TI2:
> +       Trimming info for 85 degree Celsius (stored at TRIMINFO
> register)
>         Temperature code measured at 85 degree Celsius which is
> unchanged
>  
>  TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
>  when temperature exceeds pre-defined levels.
>  The maximum number of configurable threshold is five.
> -The threshold levels are defined as follows:
> +The threshold levels are defined as follows::
> +
>    Level_0: current temperature > trigger_level_0 + threshold
>    Level_1: current temperature > trigger_level_1 + threshold
>    Level_2: current temperature > trigger_level_2 + threshold
>    Level_3: current temperature > trigger_level_3 + threshold
>  
> -  The threshold and each trigger_level are set
> -  through the corresponding registers.
> +The threshold and each trigger_level are set
> +through the corresponding registers.
>  
>  When an interrupt occurs, this driver notify kernel thermal
> framework
>  with the function exynos_report_trigger.
> @@ -54,24 +64,27 @@ it can be used to synchronize the cooling action.
>  TMU driver description:
>  -----------------------
>  
> -The exynos thermal driver is structured as,
> +The exynos thermal driver is structured as::
>  
>  					Kernel Core thermal
> framework
>  				(thermal_core.c, step_wise.c,
> cpu_cooling.c)
>  								^
>  								|
>  								|
> -TMU configuration data -------> TMU Driver  <------> Exynos Core
> thermal wrapper
> -(exynos_tmu_data.c)	      (exynos_tmu.c)	   (exynos_th
> ermal_common.c)
> -(exynos_tmu_data.h)	      (exynos_tmu.h)	   (exynos_th
> ermal_common.h)
> +  TMU configuration data -----> TMU Driver  <----> Exynos Core
> thermal wrapper
> +  (exynos_tmu_data.c)	      (exynos_tmu.c)	   (exynos_
> thermal_common.c)
> +  (exynos_tmu_data.h)	      (exynos_tmu.h)	   (exynos_
> thermal_common.h)
>  
> -a) TMU configuration data: This consist of TMU register
> offsets/bitfields
> +a) TMU configuration data:
> +		This consist of TMU register offsets/bitfields
>  		described through structure exynos_tmu_registers.
> Also several
>  		other platform data (struct
> exynos_tmu_platform_data) members
>  		are used to configure the TMU.
> -b) TMU driver: This component initialises the TMU controller and
> sets different
> +b) TMU driver:
> +		This component initialises the TMU controller and
> sets different
>  		thresholds. It invokes core thermal implementation
> with the call
>  		exynos_report_trigger.
> -c) Exynos Core thermal wrapper: This provides 3 wrapper function to
> use the
> +c) Exynos Core thermal wrapper:
> +		This provides 3 wrapper function to use the
>  		Kernel core thermal framework. They are
> exynos_unregister_thermal,
>  		exynos_register_thermal and exynos_report_trigger.
> diff --git a/Documentation/thermal/exynos_thermal_emulation
> b/Documentation/thermal/exynos_thermal_emulation.rst
> similarity index 36%
> rename from Documentation/thermal/exynos_thermal_emulation
> rename to Documentation/thermal/exynos_thermal_emulation.rst
> index b15efec6ca28..c21d10838bc5 100644
> --- a/Documentation/thermal/exynos_thermal_emulation
> +++ b/Documentation/thermal/exynos_thermal_emulation.rst
> @@ -1,5 +1,6 @@
> -EXYNOS EMULATION MODE
> -========================
> +=====================
> +Exynos Emulation Mode
> +=====================
>  
>  Copyright (C) 2012 Samsung Electronics
>  
> @@ -8,46 +9,53 @@ Written by Jonghwa Lee <jonghwa3.lee@samsung.com>
>  Description
>  -----------
>  
> -Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for
> thermal management unit.
> -Thermal emulation mode supports software debug for TMU's operation.
> User can set temperature
> -manually with software code and TMU will read current temperature
> from user value not from
> -sensor's value.
> +Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for
> thermal
> +management unit. Thermal emulation mode supports software debug for
> +TMU's operation. User can set temperature manually with software
> code
> +and TMU will read current temperature from user value not from
> sensor's
> +value.
>  
> -Enabling CONFIG_THERMAL_EMULATION option will make this support
> available.
> -When it's enabled, sysfs node will be created as
> +Enabling CONFIG_THERMAL_EMULATION option will make this support
> +available. When it's enabled, sysfs node will be created as
>  /sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
>  
> -The sysfs node, 'emul_node', will contain value 0 for the initial
> state. When you input any
> -temperature you want to update to sysfs node, it automatically
> enable emulation mode and
> -current temperature will be changed into it.
> -(Exynos also supports user changeable delay time which would be used
> to delay of
> - changing temperature. However, this node only uses same delay of
> real sensing time, 938us.)
> +The sysfs node, 'emul_node', will contain value 0 for the initial
> state.
> +When you input any temperature you want to update to sysfs node, it
> +automatically enable emulation mode and current temperature will be
> +changed into it.
>  
> -Exynos emulation mode requires synchronous of value changing and
> enabling. It means when you
> -want to update the any value of delay or next temperature, then you
> have to enable emulation
> -mode at the same time. (Or you have to keep the mode enabling.) If
> you don't, it fails to
> -change the value to updated one and just use last succeessful value
> repeatedly. That's why
> -this node gives users the right to change termerpature only. Just
> one interface makes it more
> -simply to use.
> +(Exynos also supports user changeable delay time which would be used
> to
> +delay of changing temperature. However, this node only uses same
> delay
> +of real sensing time, 938us.)
> +
> +Exynos emulation mode requires synchronous of value changing and
> +enabling. It means when you want to update the any value of delay or
> +next temperature, then you have to enable emulation mode at the same
> +time. (Or you have to keep the mode enabling.) If you don't, it
> fails to
> +change the value to updated one and just use last succeessful value
> +repeatedly. That's why this node gives users the right to change
> +termerpature only. Just one interface makes it more simply to use.
>  
>  Disabling emulation mode only requires writing value 0 to sysfs
> node.
>  
> +::
>  
> -TEMP	120 |
> +
> +  TEMP	120 |
>  	    |
>  	100 |
>  	    |
>  	 80 |
> -	    |		     	 	 +-----------
> -	 60 |      		     	 |	    |
> -	    |	           +-------------|          |
> +	    |				 +-----------
> +	 60 |      			 |	    |
> +	    |		   +-------------|          |
>  	 40 |              |         	 |          |
> -	    |		   |	     	 |          |
> -	 20 |		   |	     	 |          +-
> ---------
> -	    |	 	   |	     	 |          |
>           |
> +	    |		   |		 |          |
> +	 20 |		   |		 |          +----
> ------
> +	    |		   |		 |          |      
>     |
>  	  0
> |______________|_____________|__________|__________|_________
> -		   A	    	 A	    A	   	
>        A     TIME
> +		   A		 A	    A		 
>       A     TIME
>  		   |<----->|	 |<----->|  |<----->|	   
>     |
>  		   | 938us |  	 |	 |  |       |       
>    |
> -emulation    :  0  50	   |  	 70      |  20      |    
>       0
> -current temp :   sensor   50		 70         20	  
>     sensor
> +  emulation   : 0  50	   |  	 70      |  20      |    
>       0
> +  current temp:   sensor   50		 70         20	 
>      sensor
> diff --git a/Documentation/thermal/index.rst
> b/Documentation/thermal/index.rst
> new file mode 100644
> index 000000000000..8c1c00146cad
> --- /dev/null
> +++ b/Documentation/thermal/index.rst
> @@ -0,0 +1,18 @@
> +:orphan:
> +
> +=======
> +Thermal
> +=======
> +
> +.. toctree::
> +   :maxdepth: 1
> +
> +   cpu-cooling-api
> +   sysfs-api
> +   power_allocator
> +
> +   exynos_thermal
> +   exynos_thermal_emulation
> +   intel_powerclamp
> +   nouveau_thermal
> +   x86_pkg_temperature_thermal
> diff --git a/Documentation/thermal/intel_powerclamp.txt
> b/Documentation/thermal/intel_powerclamp.rst
> similarity index 76%
> rename from Documentation/thermal/intel_powerclamp.txt
> rename to Documentation/thermal/intel_powerclamp.rst
> index b5df21168fbc..3f6dfb0b3ea6 100644
> --- a/Documentation/thermal/intel_powerclamp.txt
> +++ b/Documentation/thermal/intel_powerclamp.rst
> @@ -1,10 +1,13 @@
> -			 =======================
> -			 INTEL POWERCLAMP DRIVER
> -			 =======================
> -By: Arjan van de Ven <arjan@linux.intel.com>
> -    Jacob Pan <jacob.jun.pan@linux.intel.com>
> +=======================
> +Intel Powerclamp Driver
> +=======================
> +
> +By:
> +  - Arjan van de Ven <arjan@linux.intel.com>
> +  - Jacob Pan <jacob.jun.pan@linux.intel.com>
> +
> +.. Contents:
>  
> -Contents:
>  	(*) Introduction
>  	    - Goals and Objectives
>  
> @@ -23,7 +26,6 @@ Contents:
>  	    - Generic Thermal Layer (sysfs)
>  	    - Kernel APIs (TBD)
>  
> -============
>  INTRODUCTION
>  ============
>  
> @@ -47,7 +49,6 @@ scalability, and user experience. In many cases,
> clear advantage is
>  shown over taking the CPU offline or modulating the CPU clock.
>  
>  
> -===================
>  THEORY OF OPERATION
>  ===================
>  
> @@ -57,11 +58,12 @@ Idle Injection
>  On modern Intel processors (Nehalem or later), package level C-state
>  residency is available in MSRs, thus also available to the kernel.
>  
> -These MSRs are:
> -      #define MSR_PKG_C2_RESIDENCY	0x60D
> -      #define MSR_PKG_C3_RESIDENCY	0x3F8
> -      #define MSR_PKG_C6_RESIDENCY	0x3F9
> -      #define MSR_PKG_C7_RESIDENCY	0x3FA
> +These MSRs are::
> +
> +      #define MSR_PKG_C2_RESIDENCY      0x60D
> +      #define MSR_PKG_C3_RESIDENCY      0x3F8
> +      #define MSR_PKG_C6_RESIDENCY      0x3F9
> +      #define MSR_PKG_C7_RESIDENCY      0x3FA
>  
>  If the kernel can also inject idle time to the system, then a
>  closed-loop control system can be established that manages package
> @@ -96,19 +98,21 @@ are not masked. Tests show that the extra wakeups
> from scheduler tick
>  have a dramatic impact on the effectiveness of the powerclamp driver
>  on large scale systems (Westmere system with 80 processors).
>  
> -CPU0
> -		  ____________          ____________
> -kidle_inject/0   |   sleep    |  mwait |  sleep     |
> -	_________|            |________|            |_______
> -			       duration
> -CPU1
> -		  ____________          ____________
> -kidle_inject/1   |   sleep    |  mwait |  sleep     |
> -	_________|            |________|            |_______
> -			      ^
> -			      |
> -			      |
> -			      roundup(jiffies, interval)
> +::
> +
> +  CPU0
> +		    ____________          ____________
> +  kidle_inject/0   |   sleep    |  mwait |  sleep     |
> +	  _________|            |________|            |_______
> +				 duration
> +  CPU1
> +		    ____________          ____________
> +  kidle_inject/1   |   sleep    |  mwait |  sleep     |
> +	  _________|            |________|            |_______
> +				^
> +				|
> +				|
> +				roundup(jiffies, interval)
>  
>  Only one CPU is allowed to collect statistics and update global
>  control parameters. This CPU is referred to as the controlling CPU
> in
> @@ -148,7 +152,7 @@ b) determine the amount of compensation needed at
> each target ratio
>  
>  Compensation to each target ratio consists of two parts:
>  
> -        a) steady state error compensation
> +	a) steady state error compensation
>  	This is to offset the error occurring when the system can
>  	enter idle without extra wakeups (such as external
> interrupts).
>  
> @@ -158,41 +162,42 @@ Compensation to each target ratio consists of
> two parts:
>  	slowing down CPU activities.
>  
>  A debugfs file is provided for the user to examine compensation
> -progress and results, such as on a Westmere system.
> -[jacob@nex01 ~]$ cat
> -/sys/kernel/debug/intel_powerclamp/powerclamp_calib
> -controlling cpu: 0
> -pct confidence steady dynamic (compensation)
> -0	0	0	0
> -1	1	0	0
> -2	1	1	0
> -3	3	1	0
> -4	3	1	0
> -5	3	1	0
> -6	3	1	0
> -7	3	1	0
> -8	3	1	0
> -...
> -30	3	2	0
> -31	3	2	0
> -32	3	1	0
> -33	3	2	0
> -34	3	1	0
> -35	3	2	0
> -36	3	1	0
> -37	3	2	0
> -38	3	1	0
> -39	3	2	0
> -40	3	3	0
> -41	3	1	0
> -42	3	2	0
> -43	3	1	0
> -44	3	1	0
> -45	3	2	0
> -46	3	3	0
> -47	3	0	0
> -48	3	2	0
> -49	3	3	0
> +progress and results, such as on a Westmere system::
> +
> +  [jacob@nex01 ~]$ cat
> +  /sys/kernel/debug/intel_powerclamp/powerclamp_calib
> +  controlling cpu: 0
> +  pct confidence steady dynamic (compensation)
> +  0       0       0       0
> +  1       1       0       0
> +  2       1       1       0
> +  3       3       1       0
> +  4       3       1       0
> +  5       3       1       0
> +  6       3       1       0
> +  7       3       1       0
> +  8       3       1       0
> +  ...
> +  30      3       2       0
> +  31      3       2       0
> +  32      3       1       0
> +  33      3       2       0
> +  34      3       1       0
> +  35      3       2       0
> +  36      3       1       0
> +  37      3       2       0
> +  38      3       1       0
> +  39      3       2       0
> +  40      3       3       0
> +  41      3       1       0
> +  42      3       2       0
> +  43      3       1       0
> +  44      3       1       0
> +  45      3       2       0
> +  46      3       3       0
> +  47      3       0       0
> +  48      3       2       0
> +  49      3       3       0
>  
>  Calibration occurs during runtime. No offline method is available.
>  Steady state compensation is used only when confidence levels of all
> @@ -217,9 +222,8 @@ keeps track of clamping kernel threads, even
> after they are migrated
>  to other CPUs, after a CPU offline event.
>  
>  
> -=====================
>  Performance Analysis
> -=====================
> +====================
>  This section describes the general performance data collected on
>  multiple systems, including Westmere (80P) and Ivy Bridge (4P, 8P).
>  
> @@ -257,16 +261,15 @@ achieve up to 40% better performance per watt.
> (measured by a spin
>  counter summed over per CPU counting threads spawned for all running
>  CPUs).
>  
> -====================
>  Usage and Interfaces
>  ====================
>  The powerclamp driver is registered to the generic thermal layer as
> a
> -cooling device. Currently, it’s not bound to any thermal zones.
> +cooling device. Currently, it’s not bound to any thermal zones::
>  
> -jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
> -cur_state:0
> -max_state:50
> -type:intel_powerclamp
> +  jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
> +  cur_state:0
> +  max_state:50
> +  type:intel_powerclamp
>  
>  cur_state allows user to set the desired idle percentage. Writing 0
> to
>  cur_state will stop idle injection. Writing a value between 1 and
> @@ -278,9 +281,9 @@ cur_state returns value -1 instead of 0 which is
> to avoid confusing
>  100% busy state with the disabled state.
>  
>  Example usage:
> -- To inject 25% idle time
> -$ sudo sh -c "echo 25 >
> /sys/class/thermal/cooling_device80/cur_state
> -"
> +- To inject 25% idle time::
> +
> +	$ sudo sh -c "echo 25 >
> /sys/class/thermal/cooling_device80/cur_state
>  
>  If the system is not busy and has more than 25% idle time already,
>  then the powerclamp driver will not start idle injection. Using Top
> @@ -292,23 +295,23 @@ idle time is accounted as normal idle in that
> common code path is
>  taken as the idle task.
>  
>  In this example, 24.1% idle is shown. This helps the system admin or
> -user determine the cause of slowdown, when a powerclamp driver is in
> action.
> +user determine the cause of slowdown, when a powerclamp driver is in
> action::
>  
>  
> -Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0 zombie
> -Cpu(s): 71.2%us,  4.7%sy,  0.0%ni,
> 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
> -Mem:   3943228k total,  1689632k used,  2253596k free,    74960k
> buffers
> -Swap:  4087804k total,        0k used,  4087804k free,   945336k
> cached
> +  Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0
> zombie
> +  Cpu(s): 71.2%us,  4.7%sy,  0.0%ni,
> 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
> +  Mem:   3943228k total,  1689632k used,  2253596k free,    74960k
> buffers
> +  Swap:  4087804k total,        0k used,  4087804k free,   945336k
> cached
>  
> -  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> - 3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16 spin
> - 3341 root     -51   0     0    0    0 D   25  0.0   0:01.62
> kidle_inject/0
> - 3344 root     -51   0     0    0    0 D   25  0.0   0:01.60
> kidle_inject/3
> - 3342 root     -51   0     0    0    0 D   25  0.0   0:01.61
> kidle_inject/1
> - 3343 root     -51   0     0    0    0 D   25  0.0   0:01.60
> kidle_inject/2
> - 2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11 firefox
> - 1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97 Xorg
> - 2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68 compiz
> +    PID USER      PR  NI  VIRT  RES  SHR S %CPU
> %MEM    TIME+  COMMAND
> +   3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16 spin
> +   3341 root     -51   0     0    0    0 D   25  0.0   0:01.62
> kidle_inject/0
> +   3344 root     -51   0     0    0    0 D   25  0.0   0:01.60
> kidle_inject/3
> +   3342 root     -51   0     0    0    0 D   25  0.0   0:01.61
> kidle_inject/1
> +   3343 root     -51   0     0    0    0 D   25  0.0   0:01.60
> kidle_inject/2
> +   2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11
> firefox
> +   1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97 Xorg
> +   2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68
> compiz
>  
>  Tests have shown that by using the powerclamp driver as a cooling
>  device, a PID based userspace thermal controller can manage to
> diff --git a/Documentation/thermal/nouveau_thermal
> b/Documentation/thermal/nouveau_thermal.rst
> similarity index 64%
> rename from Documentation/thermal/nouveau_thermal
> rename to Documentation/thermal/nouveau_thermal.rst
> index 6e17a11efcb0..37255fd6735d 100644
> --- a/Documentation/thermal/nouveau_thermal
> +++ b/Documentation/thermal/nouveau_thermal.rst
> @@ -1,13 +1,15 @@
> +=====================
>  Kernel driver nouveau
> -===================
> +=====================
>  
>  Supported chips:
> +
>  * NV43+
>  
>  Authors: Martin Peres (mupuf) <martin.peres@free.fr>
>  
>  Description
> ----------
> +-----------
>  
>  This driver allows to read the GPU core temperature, drive the GPU
> fan and
>  set temperature alarms.
> @@ -19,20 +21,25 @@ interface is likely not to work. This document
> may then not cover your situation
>  entirely.
>  
>  Temperature management
> ---------------------
> +----------------------
>  
>  Temperature is exposed under as a read-only HWMON attribute
> temp1_input.
>  
>  In order to protect the GPU from overheating, Nouveau supports 4
> configurable
>  temperature thresholds:
>  
> - * Fan_boost: Fan speed is set to 100% when reaching this
> temperature;
> - * Downclock: The GPU will be downclocked to reduce its power
> dissipation;
> - * Critical: The GPU is put on hold to further lower power
> dissipation;
> - * Shutdown: Shut the computer down to protect your GPU.
> + * Fan_boost:
> +	Fan speed is set to 100% when reaching this temperature;
> + * Downclock:
> +	The GPU will be downclocked to reduce its power dissipation;
> + * Critical:
> +	The GPU is put on hold to further lower power dissipation;
> + * Shutdown:
> +	Shut the computer down to protect your GPU.
>  
> -WARNING: Some of these thresholds may not be used by Nouveau
> depending
> -on your chipset.
> +WARNING:
> +	Some of these thresholds may not be used by Nouveau
> depending
> +	on your chipset.
>  
>  The default value for these thresholds comes from the GPU's vbios.
> These
>  thresholds can be configured thanks to the following HWMON
> attributes:
> @@ -46,19 +53,24 @@ NOTE: Remember that the values are stored as
> milli degrees Celsius. Don't forget
>  to multiply!
>  
>  Fan management
> -------------
> +--------------
>  
>  Not all cards have a drivable fan. If you do, then the following
> HWMON
>  attributes should be available:
>  
> - * pwm1_enable: Current fan management mode (NONE, MANUAL or AUTO);
> - * pwm1: Current PWM value (power percentage);
> - * pwm1_min: The minimum PWM speed allowed;
> - * pwm1_max: The maximum PWM speed allowed (bypassed when hitting
> Fan_boost);
> + * pwm1_enable:
> +	Current fan management mode (NONE, MANUAL or AUTO);
> + * pwm1:
> +	Current PWM value (power percentage);
> + * pwm1_min:
> +	The minimum PWM speed allowed;
> + * pwm1_max:
> +	The maximum PWM speed allowed (bypassed when hitting
> Fan_boost);
>  
>  You may also have the following attribute:
>  
> - * fan1_input: Speed in RPM of your fan.
> + * fan1_input:
> +	Speed in RPM of your fan.
>  
>  Your fan can be driven in different modes:
>  
> @@ -66,14 +78,16 @@ Your fan can be driven in different modes:
>   * 1: The fan can be driven in manual (use pwm1 to change the
> speed);
>   * 2; The fan is driven automatically depending on the temperature.
>  
> -NOTE: Be sure to use the manual mode if you want to drive the fan
> speed manually
> +NOTE:
> +  Be sure to use the manual mode if you want to drive the fan speed
> manually
>  
> -NOTE2: When operating in manual mode outside the vbios-defined
> -[PWM_min, PWM_max] range, the reported fan speed (RPM) may not be
> accurate
> -depending on your hardware.
> +NOTE2:
> +  When operating in manual mode outside the vbios-defined
> +  [PWM_min, PWM_max] range, the reported fan speed (RPM) may not be
> accurate
> +  depending on your hardware.
>  
>  Bug reports
> ----------
> +-----------
>  
>  Thermal management on Nouveau is new and may not work on all cards.
> If you have
>  inquiries, please ping mupuf on IRC (#nouveau, freenode).
> diff --git a/Documentation/thermal/power_allocator.txt
> b/Documentation/thermal/power_allocator.rst
> similarity index 74%
> rename from Documentation/thermal/power_allocator.txt
> rename to Documentation/thermal/power_allocator.rst
> index 9fb0ff06dca9..67b6a3297238 100644
> --- a/Documentation/thermal/power_allocator.txt
> +++ b/Documentation/thermal/power_allocator.rst
> @@ -1,3 +1,4 @@
> +=================================
>  Power allocator governor tunables
>  =================================
>  
> @@ -25,36 +26,36 @@ temperature as the control input and power as the
> controlled output:
>      P_max = k_p * e + k_i * err_integral + k_d * diff_err +
> sustainable_power
>  
>  where
> -    e = desired_temperature - current_temperature
> -    err_integral is the sum of previous errors
> -    diff_err = e - previous_error
> +   -  e = desired_temperature - current_temperature
> +   -  err_integral is the sum of previous errors
> +   -  diff_err = e - previous_error
>  
> -It is similar to the one depicted below:
> +It is similar to the one depicted below::
>  
> -                                      k_d
> -                                       |
> -current_temp                           |
> -     |                                 v
> -     |                +----------+   +---+
> -     |         +----->| diff_err |-->| X |------+
> -     |         |      +----------+   +---+      |
> -     |         |                                |      tdp        ac
> tor
> -     |         |                      k_i       |       |  get_reque
> sted_power()
> -     |         |                       |        |       |        |  
>    |
> -     |         |                       |        |       |        |  
>    | ...
> -     v         |                       v        v       v        v  
>    v
> -   +---+       |      +-------+      +---+    +---+   +---+   +-----
> -----+
> -   | S |-------+----->| sum e |----->| X |--->| S |-->| S |
> -->|power     |
> -   +---+       |      +-------+      +---+    +---+   +---
> +   |allocation|
> -     ^         |                                ^             +-----
> -----+
> -     |         |                                |                |  
>    |
> -     |         |        +---
> +                   |                |     |
> -     |         +------->| X |-------------------
> +                v     v
> -     |                  +---+                               granted
> performance
> -desired_temperature       ^
> -                          |
> -                          |
> -                      k_po/k_pu
> +				      k_d
> +				       |
> +  current_temp                         |
> +       |                               v
> +       |              +----------+   +---+
> +       |       +----->| diff_err |-->| X |------+
> +       |       |      +----------+   +---+      |
> +       |       |                                |      tdp        ac
> tor
> +       |       |                      k_i       |       |  get_reque
> sted_power()
> +       |       |                       |        |       |        |  
>    |
> +       |       |                       |        |       |        |  
>    | ...
> +       v       |                       v        v       v        v  
>    v
> +     +---+     |      +-------+      +---+    +---+   +---+   +-----
> -----+
> +     | S |-----+----->| sum e |----->| X |--->| S |-->| S |
> -->|power     |
> +     +---+     |      +-------+      +---+    +---+   +---
> +   |allocation|
> +       ^       |                                ^             +-----
> -----+
> +       |       |                                |                |  
>    |
> +       |       |        +---
> +                   |                |     |
> +       |       +------->| X |-------------------
> +                v     v
> +       |                +---+                               granted
> performance
> +  desired_temperature     ^
> +			  |
> +			  |
> +		      k_po/k_pu
>  
>  Sustainable power
>  -----------------
> @@ -73,7 +74,7 @@ is typically 2000mW, while on a 10" tablet is
> around 4500mW (may vary
>  depending on screen size).
>  
>  If you are using device tree, do add it as a property of the
> -thermal-zone.  For example:
> +thermal-zone.  For example::
>  
>  	thermal-zones {
>  		soc_thermal {
> @@ -85,7 +86,7 @@ thermal-zone.  For example:
>  Instead, if the thermal zone is registered from the platform code,
> pass a
>  `thermal_zone_params` that has a `sustainable_power`.  If no
>  `thermal_zone_params` were being passed, then something like below
> -will suffice:
> +will suffice::
>  
>  	static const struct thermal_zone_params tz_params = {
>  		.sustainable_power = 3500,
> @@ -112,18 +113,18 @@ available capacity at a low temperature.  On
> the other hand, a high
>  value of `k_pu` will result in the governor granting very high power
>  while temperature is low, and may lead to temperature overshooting.
>  
> -The default value for `k_pu` is:
> +The default value for `k_pu` is::
>  
>      2 * sustainable_power / (desired_temperature - switch_on_temp)
>  
>  This means that at `switch_on_temp` the output of the controller's
>  proportional term will be 2 * `sustainable_power`.  The default
> value
> -for `k_po` is:
> +for `k_po` is::
>  
>      sustainable_power / (desired_temperature - switch_on_temp)
>  
>  Focusing on the proportional and feed forward values of the PID
> -controller equation we have:
> +controller equation we have::
>  
>      P_max = k_p * e + sustainable_power
>  
> @@ -134,21 +135,23 @@ is the desired one, then the proportional
> component is zero and
>  thermal equilibrium under constant load.  `sustainable_power` is
> only
>  an estimate, which is the reason for closed-loop control such as
> this.
>  
> -Expanding `k_pu` we get:
> +Expanding `k_pu` we get::
> +
>      P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
> -        sustainable_power
> +	sustainable_power
>  
> -where
> -    T_set is the desired temperature
> -    T is the current temperature
> -    T_on is the switch on temperature
> +where:
> +
> +    - T_set is the desired temperature
> +    - T is the current temperature
> +    - T_on is the switch on temperature
>  
>  When the current temperature is the switch_on temperature, the above
> -formula becomes:
> +formula becomes::
>  
>      P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on)
> +
> -        sustainable_power = 2 * sustainable_power +
> sustainable_power =
> -        3 * sustainable_power
> +	sustainable_power = 2 * sustainable_power +
> sustainable_power =
> +	3 * sustainable_power
>  
>  Therefore, the proportional term alone linearly decreases power from
>  3 * `sustainable_power` to `sustainable_power` as the temperature
> @@ -178,11 +181,18 @@ Cooling device power API
>  Cooling devices controlled by this governor must supply the
> additional
>  "power" API in their `cooling_device_ops`.  It consists on three
> ops:
>  
> -1. int get_requested_power(struct thermal_cooling_device *cdev,
> -	struct thermal_zone_device *tz, u32 *power);
> -@cdev: The `struct thermal_cooling_device` pointer
> -@tz: thermal zone in which we are currently operating
> -@power: pointer in which to store the calculated power
> +1. ::
> +
> +    int get_requested_power(struct thermal_cooling_device *cdev,
> +			    struct thermal_zone_device *tz, u32
> *power);
> +
> +
> +@cdev:
> +	The `struct thermal_cooling_device` pointer
> +@tz:
> +	thermal zone in which we are currently operating
> +@power:
> +	pointer in which to store the calculated power
>  
>  `get_requested_power()` calculates the power requested by the device
>  in milliwatts and stores it in @power .  It should return 0 on
> @@ -190,23 +200,37 @@ success, -E* on failure.  This is currently
> used by the power
>  allocator governor to calculate how much power to give to each
> cooling
>  device.
>  
> -2. int state2power(struct thermal_cooling_device *cdev, struct
> -        thermal_zone_device *tz, unsigned long state, u32 *power);
> -@cdev: The `struct thermal_cooling_device` pointer
> -@tz: thermal zone in which we are currently operating
> -@state: A cooling device state
> -@power: pointer in which to store the equivalent power
> +2. ::
> +
> +	int state2power(struct thermal_cooling_device *cdev, struct
> +			thermal_zone_device *tz, unsigned long
> state,
> +			u32 *power);
> +
> +@cdev:
> +	The `struct thermal_cooling_device` pointer
> +@tz:
> +	thermal zone in which we are currently operating
> +@state:
> +	A cooling device state
> +@power:
> +	pointer in which to store the equivalent power
>  
>  Convert cooling device state @state into power consumption in
>  milliwatts and store it in @power.  It should return 0 on success,
> -E*
>  on failure.  This is currently used by thermal core to calculate the
>  maximum power that an actor can consume.
>  
> -3. int power2state(struct thermal_cooling_device *cdev, u32 power,
> -	unsigned long *state);
> -@cdev: The `struct thermal_cooling_device` pointer
> -@power: power in milliwatts
> -@state: pointer in which to store the resulting state
> +3. ::
> +
> +	int power2state(struct thermal_cooling_device *cdev, u32
> power,
> +			unsigned long *state);
> +
> +@cdev:
> +	The `struct thermal_cooling_device` pointer
> +@power:
> +	power in milliwatts
> +@state:
> +	pointer in which to store the resulting state
>  
>  Calculate a cooling device state that would make the device consume
> at
>  most @power mW and store it in @state.  It should return 0 on
> success,
> diff --git a/Documentation/thermal/sysfs-api.txt
> b/Documentation/thermal/sysfs-api.rst
> similarity index 66%
> rename from Documentation/thermal/sysfs-api.txt
> rename to Documentation/thermal/sysfs-api.rst
> index c3fa500df92c..e4930761d3e5 100644
> --- a/Documentation/thermal/sysfs-api.txt
> +++ b/Documentation/thermal/sysfs-api.rst
> @@ -1,3 +1,4 @@
> +===================================
>  Generic Thermal Sysfs driver How To
>  ===================================
>  
> @@ -9,6 +10,7 @@ Copyright (c)  2008 Intel Corporation
>  
>  
>  0. Introduction
> +===============
>  
>  The generic thermal sysfs provides a set of interfaces for thermal
> zone
>  devices (sensors) and thermal cooling devices (fan, processor...) to
> register
> @@ -25,59 +27,90 @@ An intelligent thermal management application can
> make decisions based on
>  inputs from thermal zone attributes (the current temperature and
> trip point
>  temperature) and throttle appropriate devices.
>  
> -[0-*]	denotes any positive number starting from 0
> -[1-*]	denotes any positive number starting from 1
> +- `[0-*]`	denotes any positive number starting from 0
> +- `[1-*]`	denotes any positive number starting from 1
>  
>  1. thermal sysfs driver interface functions
> +===========================================
>  
>  1.1 thermal zone device interface
> -1.1.1 struct thermal_zone_device *thermal_zone_device_register(char
> *type,
> -		int trips, int mask, void *devdata,
> -		struct thermal_zone_device_ops *ops,
> -		const struct thermal_zone_params *tzp,
> -		int passive_delay, int polling_delay))
> +---------------------------------
> +
> +    ::
> +
> +	struct thermal_zone_device
> +	*thermal_zone_device_register(char *type,
> +				      int trips, int mask, void
> *devdata,
> +				      struct thermal_zone_device_ops
> *ops,
> +				      const struct
> thermal_zone_params *tzp,
> +				      int passive_delay, int
> polling_delay))
>  
>      This interface function adds a new thermal zone device (sensor)
> to
> -    /sys/class/thermal folder as thermal_zone[0-*]. It tries to bind
> all the
> +    /sys/class/thermal folder as `thermal_zone[0-*]`. It tries to
> bind all the
>      thermal cooling devices registered at the same time.
>  
> -    type: the thermal zone type.
> -    trips: the total number of trip points this thermal zone
> supports.
> -    mask: Bit string: If 'n'th bit is set, then trip point 'n' is
> writeable.
> -    devdata: device private data
> -    ops: thermal zone device call-backs.
> -	.bind: bind the thermal zone device with a thermal cooling
> device.
> -	.unbind: unbind the thermal zone device with a thermal
> cooling device.
> -	.get_temp: get the current temperature of the thermal zone.
> -	.set_trips: set the trip points window. Whenever the current
> temperature
> +    type:
> +	the thermal zone type.
> +    trips:
> +	the total number of trip points this thermal zone supports.
> +    mask:
> +	Bit string: If 'n'th bit is set, then trip point 'n' is
> writeable.
> +    devdata:
> +	device private data
> +    ops:
> +	thermal zone device call-backs.
> +
> +	.bind:
> +		bind the thermal zone device with a thermal cooling
> device.
> +	.unbind:
> +		unbind the thermal zone device with a thermal
> cooling device.
> +	.get_temp:
> +		get the current temperature of the thermal zone.
> +	.set_trips:
> +		    set the trip points window. Whenever the current
> temperature
>  		    is updated, the trip points immediately below
> and above the
>  		    current temperature are found.
> -	.get_mode: get the current mode (enabled/disabled) of the
> thermal zone.
> -	    - "enabled" means the kernel thermal management is
> enabled.
> -	    - "disabled" will prevent kernel thermal driver action
> upon trip points
> -	      so that user applications can take charge of thermal
> management.
> -	.set_mode: set the mode (enabled/disabled) of the thermal
> zone.
> -	.get_trip_type: get the type of certain trip point.
> -	.get_trip_temp: get the temperature above which the certain
> trip point
> +	.get_mode:
> +		   get the current mode (enabled/disabled) of the
> thermal zone.
> +
> +			- "enabled" means the kernel thermal
> management is
> +			  enabled.
> +			- "disabled" will prevent kernel thermal
> driver action
> +			  upon trip points so that user applications
> can take
> +			  charge of thermal management.
> +	.set_mode:
> +		set the mode (enabled/disabled) of the thermal zone.
> +	.get_trip_type:
> +		get the type of certain trip point.
> +	.get_trip_temp:
> +			get the temperature above which the certain
> trip point
>  			will be fired.
> -	.set_emul_temp: set the emulation temperature which helps in
> debugging
> +	.set_emul_temp:
> +			set the emulation temperature which helps in
> debugging
>  			different threshold temperature points.
> -    tzp: thermal zone platform parameters.
> -    passive_delay: number of milliseconds to wait between polls when
> +    tzp:
> +	thermal zone platform parameters.
> +    passive_delay:
> +	number of milliseconds to wait between polls when
>  	performing passive cooling.
> -    polling_delay: number of milliseconds to wait between polls when
> checking
> +    polling_delay:
> +	number of milliseconds to wait between polls when checking
>  	whether trip points have been crossed (0 for interrupt
> driven systems).
>  
> +    ::
>  
> -1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device
> *tz)
> +	void thermal_zone_device_unregister(struct
> thermal_zone_device *tz)
>  
>      This interface function removes the thermal zone device.
>      It deletes the corresponding entry from /sys/class/thermal
> folder and
>      unbinds all the thermal cooling devices it uses.
>  
> -1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register(
> -		struct device *dev, int sensor_id, void *data,
> -		const struct thermal_zone_of_device_ops *ops)
> +	::
> +
> +	   struct thermal_zone_device
> +	   *thermal_zone_of_sensor_register(struct device *dev, int
> sensor_id,
> +				void *data,
> +				const struct
> thermal_zone_of_device_ops *ops)
>  
>  	This interface adds a new sensor to a DT thermal zone.
>  	This function will search the list of thermal zones
> described in
> @@ -87,25 +120,33 @@ temperature) and throttle appropriate devices.
>  	thermal zone device.
>  
>  	The parameters for this interface are:
> -	dev:		Device node of sensor containing valid
> node pointer in
> +
> +	dev:
> +			Device node of sensor containing valid node
> pointer in
>  			dev->of_node.
> -	sensor_id:	a sensor identifier, in case the sensor IP
> has more
> +	sensor_id:
> +			a sensor identifier, in case the sensor IP
> has more
>  			than one sensors
> -	data:		a private pointer (owned by the caller)
> that will be
> +	data:
> +			a private pointer (owned by the caller) that
> will be
>  			passed back, when a temperature reading is
> needed.
> -	ops:		struct thermal_zone_of_device_ops *.
> +	ops:
> +			`struct thermal_zone_of_device_ops *`.
>  
> -			get_temp:	a pointer to a function
> that reads the
> +			==============  ============================
> ===========
> +			get_temp	a pointer to a function that
> reads the
>  					sensor temperature. This is
> mandatory
>  					callback provided by sensor
> driver.
> -			set_trips:      a pointer to a function that
> sets a
> +			set_trips	a pointer to a function
> that sets a
>  					temperature window. When
> this window is
>  					left the driver must inform
> the thermal
>  					core via
> thermal_zone_device_update.
> -			get_trend: 	a pointer to a function
> that reads the
> +			get_trend 	a pointer to a function
> that reads the
>  					sensor temperature trend.
> -			set_emul_temp:	a pointer to a
> function that sets
> +			set_emul_temp	a pointer to a function
> that sets
>  					sensor emulated temperature.
> +			==============  ============================
> ===========
> +
>  	The thermal zone temperature is provided by the get_temp()
> function
>  	pointer of thermal_zone_of_device_ops. When called, it will
>  	have the private pointer @data back.
> @@ -114,8 +155,10 @@ temperature) and throttle appropriate devices.
>  	handle. Caller should check the return handle with IS_ERR()
> for finding
>  	whether success or not.
>  
> -1.1.4 void thermal_zone_of_sensor_unregister(struct device *dev,
> -		struct thermal_zone_device *tzd)
> +	::
> +
> +	    void thermal_zone_of_sensor_unregister(struct device
> *dev,
> +						   struct
> thermal_zone_device *tzd)
>  
>  	This interface unregisters a sensor from a DT thermal zone
> which was
>  	successfully added by interface
> thermal_zone_of_sensor_register().
> @@ -124,21 +167,29 @@ temperature) and throttle appropriate devices.
>  	interface. It will also silent the zone by remove the
> .get_temp() and
>  	get_trend() thermal zone device callbacks.
>  
> -1.1.5 struct thermal_zone_device
> *devm_thermal_zone_of_sensor_register(
> -		struct device *dev, int sensor_id,
> -		void *data, const struct thermal_zone_of_device_ops
> *ops)
> +	::
> +
> +	  struct thermal_zone_device
> +	  *devm_thermal_zone_of_sensor_register(struct device *dev,
> +				int sensor_id,
> +				void *data,
> +				const struct
> thermal_zone_of_device_ops *ops)
>  
>  	This interface is resource managed version of
>  	thermal_zone_of_sensor_register().
> +
>  	All details of thermal_zone_of_sensor_register() described
> in
>  	section 1.1.3 is applicable here.
> +
>  	The benefit of using this interface to register sensor is
> that it
>  	is not require to explicitly call
> thermal_zone_of_sensor_unregister()
>  	in error path or during driver unbinding as this is done by
> driver
>  	resource manager.
>  
> -1.1.6 void devm_thermal_zone_of_sensor_unregister(struct device
> *dev,
> -		struct thermal_zone_device *tzd)
> +	::
> +
> +		void devm_thermal_zone_of_sensor_unregister(struct
> device *dev,
> +						struct
> thermal_zone_device *tzd)
>  
>  	This interface is resource managed version of
>  	thermal_zone_of_sensor_unregister().
> @@ -147,123 +198,186 @@ temperature) and throttle appropriate
> devices.
>  	Normally this function will not need to be called and the
> resource
>  	management code will ensure that the resource is freed.
>  
> -1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz)
> +	::
> +
> +		int thermal_zone_get_slope(struct
> thermal_zone_device *tz)
>  
>  	This interface is used to read the slope attribute value
>  	for the thermal zone device, which might be useful for
> platform
>  	drivers for temperature calculations.
>  
> -1.1.8 int thermal_zone_get_offset(struct thermal_zone_device *tz)
> +	::
> +
> +		int thermal_zone_get_offset(struct
> thermal_zone_device *tz)
>  
>  	This interface is used to read the offset attribute value
>  	for the thermal zone device, which might be useful for
> platform
>  	drivers for temperature calculations.
>  
>  1.2 thermal cooling device interface
> -1.2.1 struct thermal_cooling_device
> *thermal_cooling_device_register(char *name,
> -		void *devdata, struct thermal_cooling_device_ops *)
> +------------------------------------
> +
> +
> +    ::
> +
> +	struct thermal_cooling_device
> +	*thermal_cooling_device_register(char *name,
> +			void *devdata, struct
> thermal_cooling_device_ops *)
>  
>      This interface function adds a new thermal cooling device
> (fan/processor/...)
> -    to /sys/class/thermal/ folder as cooling_device[0-*]. It tries
> to bind itself
> +    to /sys/class/thermal/ folder as `cooling_device[0-*]`. It tries
> to bind itself
>      to all the thermal zone devices registered at the same time.
> -    name: the cooling device name.
> -    devdata: device private data.
> -    ops: thermal cooling devices call-backs.
> -	.get_max_state: get the Maximum throttle state of the
> cooling device.
> -	.get_cur_state: get the Currently requested throttle state
> of the cooling device.
> -	.set_cur_state: set the Current throttle state of the
> cooling device.
> -
> -1.2.2 void thermal_cooling_device_unregister(struct
> thermal_cooling_device *cdev)
> +
> +    name:
> +	the cooling device name.
> +    devdata:
> +	device private data.
> +    ops:
> +	thermal cooling devices call-backs.
> +
> +	.get_max_state:
> +		get the Maximum throttle state of the cooling
> device.
> +	.get_cur_state:
> +		get the Currently requested throttle state of the
> +		cooling device.
> +	.set_cur_state:
> +		set the Current throttle state of the cooling
> device.
> +
> +    ::
> +
> +	void thermal_cooling_device_unregister(struct
> thermal_cooling_device *cdev)
>  
>      This interface function removes the thermal cooling device.
>      It deletes the corresponding entry from /sys/class/thermal
> folder and
>      unbinds itself from all the thermal zone devices using it.
>  
>  1.3 interface for binding a thermal zone device with a thermal
> cooling device
> -1.3.1 int thermal_zone_bind_cooling_device(struct
> thermal_zone_device *tz,
> -	int trip, struct thermal_cooling_device *cdev,
> -	unsigned long upper, unsigned long lower, unsigned int
> weight);
> +------------------------------------------------------------------
> -----------
> +
> +    ::
> +
> +	int thermal_zone_bind_cooling_device(struct
> thermal_zone_device *tz,
> +		int trip, struct thermal_cooling_device *cdev,
> +		unsigned long upper, unsigned long lower, unsigned
> int weight);
>  
>      This interface function binds a thermal cooling device to a
> particular trip
>      point of a thermal zone device.
> +
>      This function is usually called in the thermal zone device .bind
> callback.
> -    tz: the thermal zone device
> -    cdev: thermal cooling device
> -    trip: indicates which trip point in this thermal zone the
> cooling device
> -          is associated with.
> -    upper:the Maximum cooling state for this trip point.
> -          THERMAL_NO_LIMIT means no upper limit,
> +
> +    tz:
> +	  the thermal zone device
> +    cdev:
> +	  thermal cooling device
> +    trip:
> +	  indicates which trip point in this thermal zone the
> cooling device
> +	  is associated with.
> +    upper:
> +	  the Maximum cooling state for this trip point.
> +	  THERMAL_NO_LIMIT means no upper limit,
>  	  and the cooling device can be in max_state.
> -    lower:the Minimum cooling state can be used for this trip point.
> -          THERMAL_NO_LIMIT means no lower limit,
> +    lower:
> +	  the Minimum cooling state can be used for this trip point.
> +	  THERMAL_NO_LIMIT means no lower limit,
>  	  and the cooling device can be in cooling state 0.
> -    weight: the influence of this cooling device in this thermal
> -            zone.  See 1.4.1 below for more information.
> +    weight:
> +	  the influence of this cooling device in this thermal
> +	  zone.  See 1.4.1 below for more information.
>  
> -1.3.2 int thermal_zone_unbind_cooling_device(struct
> thermal_zone_device *tz,
> -		int trip, struct thermal_cooling_device *cdev);
> +    ::
> +
> +	int thermal_zone_unbind_cooling_device(struct
> thermal_zone_device *tz,
> +				int trip, struct
> thermal_cooling_device *cdev);
>  
>      This interface function unbinds a thermal cooling device from a
> particular
>      trip point of a thermal zone device. This function is usually
> called in
>      the thermal zone device .unbind callback.
> -    tz: the thermal zone device
> -    cdev: thermal cooling device
> -    trip: indicates which trip point in this thermal zone the
> cooling device
> -          is associated with.
> +
> +    tz:
> +	the thermal zone device
> +    cdev:
> +	thermal cooling device
> +    trip:
> +	indicates which trip point in this thermal zone the cooling
> device
> +	is associated with.
>  
>  1.4 Thermal Zone Parameters
> -1.4.1 struct thermal_bind_params
> +---------------------------
> +
> +    ::
> +
> +	struct thermal_bind_params
> +
>      This structure defines the following parameters that are used to
> bind
>      a zone with a cooling device for a particular trip point.
> -    .cdev: The cooling device pointer
> -    .weight: The 'influence' of a particular cooling device on this
> -             zone. This is relative to the rest of the cooling
> -             devices. For example, if all cooling devices have a
> -             weight of 1, then they all contribute the same. You can
> -             use percentages if you want, but it's not mandatory. A
> -             weight of 0 means that this cooling device doesn't
> -             contribute to the cooling of this zone unless all
> cooling
> -             devices have a weight of 0. If all weights are 0, then
> -             they all contribute the same.
> -    .trip_mask:This is a bit mask that gives the binding relation
> between
> -               this thermal zone and cdev, for a particular trip
> point.
> -               If nth bit is set, then the cdev and thermal zone are
> bound
> -               for trip point n.
> -    .binding_limits: This is an array of cooling state limits. Must
> have
> -                     exactly 2 * thermal_zone.number_of_trip_points.
> It is an
> -                     array consisting of tuples <lower-state upper-
> state> of
> -                     state limits. Each trip will be associated with
> one state
> -                     limit tuple when binding. A NULL pointer means
> -                     <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on all
> trips.
> -                     These limits are used when binding a cdev to a
> trip point.
> -    .match: This call back returns success(0) if the 'tz and cdev'
> need to
> +
> +    .cdev:
> +	     The cooling device pointer
> +    .weight:
> +	     The 'influence' of a particular cooling device on this
> +	     zone. This is relative to the rest of the cooling
> +	     devices. For example, if all cooling devices have a
> +	     weight of 1, then they all contribute the same. You can
> +	     use percentages if you want, but it's not mandatory. A
> +	     weight of 0 means that this cooling device doesn't
> +	     contribute to the cooling of this zone unless all
> cooling
> +	     devices have a weight of 0. If all weights are 0, then
> +	     they all contribute the same.
> +    .trip_mask:
> +	       This is a bit mask that gives the binding relation
> between
> +	       this thermal zone and cdev, for a particular trip
> point.
> +	       If nth bit is set, then the cdev and thermal zone are
> bound
> +	       for trip point n.
> +    .binding_limits:
> +		     This is an array of cooling state limits. Must
> have
> +		     exactly 2 * thermal_zone.number_of_trip_points.
> It is an
> +		     array consisting of tuples <lower-state upper-
> state> of
> +		     state limits. Each trip will be associated with
> one state
> +		     limit tuple when binding. A NULL pointer means
> +		     <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on all
> trips.
> +		     These limits are used when binding a cdev to a
> trip point.
> +    .match:
> +	    This call back returns success(0) if the 'tz and cdev'
> need to
>  	    be bound, as per platform data.
> -1.4.2 struct thermal_zone_params
> +
> +    ::
> +
> +	struct thermal_zone_params
> +
>      This structure defines the platform level parameters for a
> thermal zone.
>      This data, for each thermal zone should come from the platform
> layer.
>      This is an optional feature where some platforms can choose not
> to
>      provide this data.
> -    .governor_name: Name of the thermal governor used for this zone
> -    .no_hwmon: a boolean to indicate if the thermal to hwmon sysfs
> interface
> -               is required. when no_hwmon == false, a hwmon sysfs
> interface
> -               will be created. when no_hwmon == true, nothing will
> be done.
> -               In case the thermal_zone_params is NULL, the hwmon
> interface
> -               will be created (for backward compatibility).
> -    .num_tbps: Number of thermal_bind_params entries for this zone
> -    .tbp: thermal_bind_params entries
> +
> +    .governor_name:
> +	       Name of the thermal governor used for this zone
> +    .no_hwmon:
> +	       a boolean to indicate if the thermal to hwmon sysfs
> interface
> +	       is required. when no_hwmon == false, a hwmon sysfs
> interface
> +	       will be created. when no_hwmon == true, nothing will
> be done.
> +	       In case the thermal_zone_params is NULL, the hwmon
> interface
> +	       will be created (for backward compatibility).
> +    .num_tbps:
> +	       Number of thermal_bind_params entries for this zone
> +    .tbp:
> +	       thermal_bind_params entries
>  
>  2. sysfs attributes structure
> +=============================
>  
> +==	================
>  RO	read only value
>  WO	write only value
>  RW	read/write value
> +==	================
>  
>  Thermal sysfs attributes will be represented under
> /sys/class/thermal.
>  Hwmon sysfs I/F extension is also available under /sys/class/hwmon
>  if hwmon is compiled in or built as a module.
>  
> -Thermal zone device sys I/F, created once it's registered:
> -/sys/class/thermal/thermal_zone[0-*]:
> +Thermal zone device sys I/F, created once it's registered::
> +
> +  /sys/class/thermal/thermal_zone[0-*]:
>      |---type:			Type of the thermal zone
>      |---temp:			Current temperature
>      |---mode:			Working mode of the thermal
> zone
> @@ -282,8 +396,9 @@ Thermal zone device sys I/F, created once it's
> registered:
>      |---slope:                  Slope constant applied as linear
> extrapolation
>      |---offset:                 Offset constant applied as linear
> extrapolation
>  
> -Thermal cooling device sys I/F, created once it's registered:
> -/sys/class/thermal/cooling_device[0-*]:
> +Thermal cooling device sys I/F, created once it's registered::
> +
> +  /sys/class/thermal/cooling_device[0-*]:
>      |---type:			Type of the cooling
> device(processor/fan/...)
>      |---max_state:		Maximum cooling state of the
> cooling device
>      |---cur_state:		Current cooling state of the
> cooling device
> @@ -299,11 +414,13 @@ the relationship between a thermal zone and its
> associated cooling device.
>  They are created/removed for each successful execution of
>  thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
>  
> -/sys/class/thermal/thermal_zone[0-*]:
> +::
> +
> +  /sys/class/thermal/thermal_zone[0-*]:
>      |---cdev[0-*]:		[0-*]th cooling device in current
> thermal zone
>      |---cdev[0-*]_trip_point:	Trip point that cdev[0-*] is
> associated with
>      |---cdev[0-*]_weight:       Influence of the cooling device in
> -                                this thermal zone
> +				this thermal zone
>  
>  Besides the thermal zone device sysfs I/F and cooling device sysfs
> I/F,
>  the generic thermal driver also creates a hwmon sysfs I/F for each
> _type_
> @@ -311,16 +428,17 @@ of thermal zone device. E.g. the generic
> thermal driver registers one hwmon
>  class device and build the associated hwmon sysfs I/F for all the
> registered
>  ACPI thermal zones.
>  
> -/sys/class/hwmon/hwmon[0-*]:
> +::
> +
> +  /sys/class/hwmon/hwmon[0-*]:
>      |---name:			The type of the thermal zone
> devices
>      |---temp[1-*]_input:	The current temperature of thermal
> zone [1-*]
>      |---temp[1-*]_critical:	The critical trip point of
> thermal zone [1-*]
>  
>  Please read Documentation/hwmon/sysfs-interface.rst for additional
> information.
>  
> -***************************
> -* Thermal zone attributes *
> -***************************
> +Thermal zone attributes
> +-----------------------
>  
>  type
>  	Strings which represent the thermal zone type.
> @@ -340,54 +458,67 @@ mode
>  	This file gives information about the algorithm that is
> currently
>  	managing the thermal zone. It can be either default kernel
> based
>  	algorithm or user space application.
> -	enabled		= enable Kernel Thermal management.
> -	disabled	= Preventing kernel thermal zone driver
> actions upon
> +
> +	enabled
> +			  enable Kernel Thermal management.
> +	disabled
> +			  Preventing kernel thermal zone driver
> actions upon
>  			  trip points so that user application can
> take full
>  			  charge of the thermal management.
> +
>  	RW, Optional
>  
>  policy
>  	One of the various thermal governors used for a particular
> zone.
> +
>  	RW, Required
>  
>  available_policies
>  	Available thermal governors which can be used for a
> particular zone.
> +
>  	RO, Required
>  
> -trip_point_[0-*]_temp
> +`trip_point_[0-*]_temp`
>  	The temperature above which trip point will be fired.
> +
>  	Unit: millidegree Celsius
> +
>  	RO, Optional
>  
> -trip_point_[0-*]_type
> +`trip_point_[0-*]_type`
>  	Strings which indicate the type of the trip point.
> -	E.g. it can be one of critical, hot, passive, active[0-*]
> for ACPI
> +
> +	E.g. it can be one of critical, hot, passive, `active[0-*]`
> for ACPI
>  	thermal zone.
> +
>  	RO, Optional
>  
> -trip_point_[0-*]_hyst
> +`trip_point_[0-*]_hyst`
>  	The hysteresis value for a trip point, represented as an
> integer
>  	Unit: Celsius
>  	RW, Optional
>  
> -cdev[0-*]
> +`cdev[0-*]`
>  	Sysfs link to the thermal cooling device node where the sys
> I/F
>  	for cooling device throttling control represents.
> +
>  	RO, Optional
>  
> -cdev[0-*]_trip_point
> -	The trip point in this thermal zone which cdev[0-*] is
> associated
> +`cdev[0-*]_trip_point`
> +	The trip point in this thermal zone which `cdev[0-*]` is
> associated
>  	with; -1 means the cooling device is not associated with any
> trip
>  	point.
> +
>  	RO, Optional
>  
> -cdev[0-*]_weight
> -        The influence of cdev[0-*] in this thermal zone. This value
> -        is relative to the rest of cooling devices in the thermal
> -        zone. For example, if a cooling device has a weight double
> -        than that of other, it's twice as effective in cooling the
> -        thermal zone.
> -        RW, Optional
> +`cdev[0-*]_weight`
> +	The influence of `cdev[0-*]` in this thermal zone. This
> value
> +	is relative to the rest of cooling devices in the thermal
> +	zone. For example, if a cooling device has a weight double
> +	than that of other, it's twice as effective in cooling the
> +	thermal zone.
> +
> +	RW, Optional
>  
>  passive
>  	Attribute is only present for zones in which the passive
> cooling
> @@ -395,8 +526,11 @@ passive
>  	and can be set to a temperature (in millidegrees) to enable
> a
>  	passive trip point for the zone. Activation is done by
> polling with
>  	an interval of 1 second.
> +
>  	Unit: millidegrees Celsius
> +
>  	Valid values: 0 (disabled) or greater than 1000
> +
>  	RW, Optional
>  
>  emul_temp
> @@ -407,17 +541,21 @@ emul_temp
>  	threshold and its associated cooling action. This is write
> only node
>  	and writing 0 on this node should disable emulation.
>  	Unit: millidegree Celsius
> +
>  	WO, Optional
>  
> -	  WARNING: Be careful while enabling this option on
> production systems,
> -	  because userland can easily disable the thermal policy by
> simply
> -	  flooding this sysfs node with low temperature values.
> +	  WARNING:
> +	    Be careful while enabling this option on production
> systems,
> +	    because userland can easily disable the thermal policy
> by simply
> +	    flooding this sysfs node with low temperature values.
>  
>  sustainable_power
>  	An estimate of the sustained power that can be dissipated by
>  	the thermal zone. Used by the power allocator governor. For
> -	more information see
> Documentation/thermal/power_allocator.txt
> +	more information see
> Documentation/thermal/power_allocator.rst
> +
>  	Unit: milliwatts
> +
>  	RW, Optional
>  
>  k_po
> @@ -425,7 +563,8 @@ k_po
>  	controller during temperature overshoot. Temperature
> overshoot
>  	is when the current temperature is above the "desired
>  	temperature" trip point. For more information see
> -	Documentation/thermal/power_allocator.txt
> +	Documentation/thermal/power_allocator.rst
> +
>  	RW, Optional
>  
>  k_pu
> @@ -433,20 +572,23 @@ k_pu
>  	controller during temperature undershoot. Temperature
> undershoot
>  	is when the current temperature is below the "desired
>  	temperature" trip point. For more information see
> -	Documentation/thermal/power_allocator.txt
> +	Documentation/thermal/power_allocator.rst
> +
>  	RW, Optional
>  
>  k_i
>  	The integral term of the power allocator governor's PID
>  	controller. This term allows the PID controller to
> compensate
>  	for long term drift. For more information see
> -	Documentation/thermal/power_allocator.txt
> +	Documentation/thermal/power_allocator.rst
> +
>  	RW, Optional
>  
>  k_d
>  	The derivative term of the power allocator governor's PID
>  	controller. For more information see
> -	Documentation/thermal/power_allocator.txt
> +	Documentation/thermal/power_allocator.rst
> +
>  	RW, Optional
>  
>  integral_cutoff
> @@ -456,8 +598,10 @@ integral_cutoff
>  	example, if integral_cutoff is 0, then the integral term
> only
>  	accumulates error when temperature is above the desired
>  	temperature trip point. For more information see
> -	Documentation/thermal/power_allocator.txt
> +	Documentation/thermal/power_allocator.rst
> +
>  	Unit: millidegree Celsius
> +
>  	RW, Optional
>  
>  slope
> @@ -465,6 +609,7 @@ slope
>  	to determine a hotspot temperature based off the sensor's
>  	raw readings. It is up to the device driver to determine
>  	the usage of these values.
> +
>  	RW, Optional
>  
>  offset
> @@ -472,28 +617,33 @@ offset
>  	to determine a hotspot temperature based off the sensor's
>  	raw readings. It is up to the device driver to determine
>  	the usage of these values.
> +
>  	RW, Optional
>  
> -*****************************
> -* Cooling device attributes *
> -*****************************
> +Cooling device attributes
> +-------------------------
>  
>  type
>  	String which represents the type of device, e.g:
> +
>  	- for generic ACPI: should be "Fan", "Processor" or "LCD"
>  	- for memory controller device on intel_menlow platform:
>  	  should be "Memory controller".
> +
>  	RO, Required
>  
>  max_state
>  	The maximum permissible cooling state of this cooling
> device.
> +
>  	RO, Required
>  
>  cur_state
>  	The current cooling state of this cooling device.
>  	The value can any integer numbers between 0 and max_state:
> +
>  	- cur_state == 0 means no cooling
>  	- cur_state == max_state means the maximum cooling.
> +
>  	RW, Required
>  
>  stats/reset
> @@ -508,9 +658,11 @@ stats/time_in_state_ms:
>  	units here is 10mS (similar to other time exported in
> /proc).
>  	RO, Required
>  
> +
>  stats/total_trans:
>  	A single positive value showing the total number of times
> the state of a
>  	cooling device is changed.
> +
>  	RO, Required
>  
>  stats/trans_table:
> @@ -522,6 +674,7 @@ stats/trans_table:
>  	RO, Required
>  
>  3. A simple implementation
> +==========================
>  
>  ACPI thermal zone may support multiple trip points like critical,
> hot,
>  passive, active. If an ACPI thermal zone supports critical, passive,
> @@ -532,11 +685,10 @@ thermal_cooling_device. Both are considered to
> have the same
>  effectiveness in cooling the thermal zone.
>  
>  If the processor is listed in _PSL method, and the fan is listed in
> _AL0
> -method, the sys I/F structure will be built like this:
> +method, the sys I/F structure will be built like this::
>  
> -/sys/class/thermal:
> -
> -|thermal_zone1:
> + /sys/class/thermal:
> +  |thermal_zone1:
>      |---type:			acpitz
>      |---temp:			37000
>      |---mode:			enabled
> @@ -557,24 +709,24 @@ method, the sys I/F structure will be built
> like this:
>      |---cdev1_trip_point:	2	/* cdev1 can be used for
> active[0]*/
>      |---cdev1_weight:           1024
>  
> -|cooling_device0:
> +  |cooling_device0:
>      |---type:			Processor
>      |---max_state:		8
>      |---cur_state:		0
>  
> -|cooling_device3:
> +  |cooling_device3:
>      |---type:			Fan
>      |---max_state:		2
>      |---cur_state:		0
>  
> -/sys/class/hwmon:
> -
> -|hwmon0:
> + /sys/class/hwmon:
> +  |hwmon0:
>      |---name:			acpitz
>      |---temp1_input:		37000
>      |---temp1_crit:		100000
>  
>  4. Event Notification
> +=====================
>  
>  The framework includes a simple notification mechanism, in the form
> of a
>  netlink event. Netlink socket initialization is done during the
> _init_
> @@ -587,21 +739,28 @@ event will be one of:{THERMAL_AUX0,
> THERMAL_AUX1, THERMAL_CRITICAL,
>  THERMAL_DEV_FAULT}. Notification can be sent when the current
> temperature
>  crosses any of the configured thresholds.
>  
> -5. Export Symbol APIs:
> +5. Export Symbol APIs
> +=====================
> +
> +5.1. get_tz_trend
> +-----------------
>  
> -5.1: get_tz_trend:
>  This function returns the trend of a thermal zone, i.e the rate of
> change
>  of temperature of the thermal zone. Ideally, the thermal sensor
> drivers
>  are supposed to implement the callback. If they don't, the thermal
>  framework calculated the trend by comparing the previous and the
> current
>  temperature values.
>  
> -5.2:get_thermal_instance:
> +5.2. get_thermal_instance
> +-------------------------
> +
>  This function returns the thermal_instance corresponding to a given
>  {thermal_zone, cooling_device, trip_point} combination. Returns NULL
>  if such an instance does not exist.
>  
> -5.3:thermal_notify_framework:
> +5.3. thermal_notify_framework
> +-----------------------------
> +
>  This function handles the trip events from sensor drivers. It starts
>  throttling the cooling devices according to the policy configured.
>  For CRITICAL and HOT trip points, this notifies the respective
> drivers,
> @@ -609,12 +768,15 @@ and does actual throttling for other trip
> points i.e ACTIVE and PASSIVE.
>  The throttling policy is based on the configured platform data; if
> no
>  platform data is provided, this uses the step_wise throttling
> policy.
>  
> -5.4:thermal_cdev_update:
> +5.4. thermal_cdev_update
> +------------------------
> +
>  This function serves as an arbitrator to set the state of a cooling
>  device. It sets the cooling device to the deepest cooling state if
>  possible.
>  
> -6. thermal_emergency_poweroff:
> +6. thermal_emergency_poweroff
> +=============================
>  
>  On an event of critical trip temperature crossing. Thermal framework
>  allows the system to shutdown gracefully by calling
> orderly_poweroff().
> diff --git a/Documentation/thermal/x86_pkg_temperature_thermal
> b/Documentation/thermal/x86_pkg_temperature_thermal.rst
> similarity index 80%
> rename from Documentation/thermal/x86_pkg_temperature_thermal
> rename to Documentation/thermal/x86_pkg_temperature_thermal.rst
> index 17a3a4c0a0ca..f134dbd3f5a9 100644
> --- a/Documentation/thermal/x86_pkg_temperature_thermal
> +++ b/Documentation/thermal/x86_pkg_temperature_thermal.rst
> @@ -1,19 +1,23 @@
> +===================================
>  Kernel driver: x86_pkg_temp_thermal
> -===================
> +===================================
>  
>  Supported chips:
> +
>  * x86: with package level thermal management
> +
>  (Verify using: CPUID.06H:EAX[bit 6] =1)
>  
>  Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
>  
>  Reference
> ----
> +---------
> +
>  Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan,
> 2013):
>  Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
>  
>  Description
> ----------
> +-----------
>  
>  This driver register CPU digital temperature package level sensor as
> a thermal
>  zone with maximum two user mode configurable trip points. Number of
> trip points
> @@ -25,23 +29,27 @@ take any action to control temperature.
>  Threshold management
>  --------------------
>  Each package will register as a thermal zone under
> /sys/class/thermal.
> -Example:
> -/sys/class/thermal/thermal_zone1
> +
> +Example::
> +
> +	/sys/class/thermal/thermal_zone1
>  
>  This contains two trip points:
> +
>  - trip_point_0_temp
>  - trip_point_1_temp
>  
>  User can set any temperature between 0 to TJ-Max temperature.
> Temperature units
> -are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-
> api.txt" for
> +are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-
> api.rst" for
>  thermal sys-fs details.
>  
>  Any value other than 0 in these trip points, can trigger thermal
> notifications.
>  Setting 0, stops sending thermal notifications.
>  
> -Thermal notifications: To get kobject-uevent notifications, set the
> thermal zone
> -policy to "user_space". For example: echo -n "user_space" > policy
> -
> -
> +Thermal notifications:
> +To get kobject-uevent notifications, set the thermal zone
> +policy to "user_space".
>  
> +For example::
>  
> +	echo -n "user_space" > policy
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d9e214f68e52..b2254bc8e495 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15687,7 +15687,7 @@ M:	Viresh Kumar <viresh.kumar@linaro.o
> rg>
>  M:	Javi Merino <javi.merino@kernel.org>
>  L:	linux-pm@vger.kernel.org
>  S:	Supported
> -F:	Documentation/thermal/cpu-cooling-api.txt
> +F:	Documentation/thermal/cpu-cooling-api.rst
>  F:	drivers/thermal/cpu_cooling.c
>  F:	include/linux/cpu_cooling.h
>  
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 15a4ca5d7099..681047f8cc05 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -251,7 +251,7 @@ struct thermal_bind_params {
>  	 * platform characterization. This value is relative to the
>  	 * rest of the weights so a cooling device whose weight is
>  	 * double that of another cooling device is twice as
> -	 * effective. See Documentation/thermal/sysfs-api.txt for
> more
> +	 * effective. See Documentation/thermal/sysfs-api.rst for
> more
>  	 * information.
>  	 */
>  	int weight;
> @@ -259,7 +259,7 @@ struct thermal_bind_params {
>  	/*
>  	 * This is a bit mask that gives the binding relation
> between this
>  	 * thermal zone and cdev, for a particular trip point.
> -	 * See Documentation/thermal/sysfs-api.txt for more
> information.
> +	 * See Documentation/thermal/sysfs-api.rst for more
> information.
>  	 */
>  	int trip_mask;
>  

^ permalink raw reply

* Re: [PATCH v2] PCI: PM: Skip devices in D0 for suspend-to-idle
From: Jon Hunter @ 2019-06-25 13:26 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PCI, Bjorn Helgaas, Linux PM, Linux ACPI, LKML,
	Mika Westerberg, Keith Busch, Kai-Heng Feng, linux-tegra
In-Reply-To: <2287147.DxjcvLeq6l@kreacher>


On 25/06/2019 00:09, Rafael J. Wysocki wrote:
> On Tuesday, June 25, 2019 12:20:26 AM CEST Rafael J. Wysocki wrote:
>> On Mon, Jun 24, 2019 at 11:37 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>>>
>>> On Mon, Jun 24, 2019 at 2:43 PM Jon Hunter <jonathanh@nvidia.com> wrote:
>>>>
>>>> Hi Rafael,
>>>>
>>>> On 13/06/2019 22:59, Rafael J. Wysocki wrote:
>>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>>
>>>>> Commit d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>>>> attempted to avoid a problem with devices whose drivers want them to
>>>>> stay in D0 over suspend-to-idle and resume, but it did not go as far
>>>>> as it should with that.
>>>>>
>>>>> Namely, first of all, the power state of a PCI bridge with a
>>>>> downstream device in D0 must be D0 (based on the PCI PM spec r1.2,
>>>>> sec 6, table 6-1, if the bridge is not in D0, there can be no PCI
>>>>> transactions on its secondary bus), but that is not actively enforced
>>>>> during system-wide PM transitions, so use the skip_bus_pm flag
>>>>> introduced by commit d491f2b75237 for that.
>>>>>
>>>>> Second, the configuration of devices left in D0 (whatever the reason)
>>>>> during suspend-to-idle need not be changed and attempting to put them
>>>>> into D0 again by force is pointless, so explicitly avoid doing that.
>>>>>
>>>>> Fixes: d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>>>> Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>>>>> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>>>
>>>> I have noticed a regression in both the mainline and -next branches on
>>>> one of our boards when testing suspend. The bisect is point to this
>>>> commit and reverting on top of mainline does fix the problem. So far I
>>>> have not looked at this in close detail but kernel log is showing ...
>>>
>>> Can you please collect a log like that, but with dynamic debug in
>>> pci-driver.c enabled?
>>>
>>> Note that reverting this commit is rather out of the question, so we
>>> need to get to the bottom of the failure.
>>
>> I suspect that there is a problem with the pm_suspend_via_firmware()
>> check which returns 'false' on the affected board, but the platform
>> actually removes power from devices left in D0 during suspend.
>>
>> I guess it would be more appropriate to check something like
>> pm_suspend_no_platform() which would return 'true' in the
>> suspend-to-idle patch w/ ACPI.
> 
> So I wonder if the patch below makes any difference?
> 
> ---
>  drivers/pci/pci-driver.c |    8 ++++----
>  include/linux/suspend.h  |   26 ++++++++++++++++++++++++--
>  kernel/power/suspend.c   |    3 +++
>  3 files changed, 31 insertions(+), 6 deletions(-)
> 
> Index: linux-pm/include/linux/suspend.h
> ===================================================================
> --- linux-pm.orig/include/linux/suspend.h
> +++ linux-pm/include/linux/suspend.h
> @@ -209,8 +209,9 @@ extern int suspend_valid_only_mem(suspen
>  
>  extern unsigned int pm_suspend_global_flags;
>  
> -#define PM_SUSPEND_FLAG_FW_SUSPEND	(1 << 0)
> -#define PM_SUSPEND_FLAG_FW_RESUME	(1 << 1)
> +#define PM_SUSPEND_FLAG_FW_SUSPEND	BIT(0)
> +#define PM_SUSPEND_FLAG_FW_RESUME	BIT(1)
> +#define PM_SUSPEND_FLAG_NO_PLATFORM	BIT(2)
>  
>  static inline void pm_suspend_clear_flags(void)
>  {
> @@ -227,6 +228,11 @@ static inline void pm_set_resume_via_fir
>  	pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
>  }
>  
> +static inline void pm_set_suspend_no_platform(void)
> +{
> +	pm_suspend_global_flags |= PM_SUSPEND_FLAG_NO_PLATFORM;
> +}
> +
>  /**
>   * pm_suspend_via_firmware - Check if platform firmware will suspend the system.
>   *
> @@ -268,6 +274,22 @@ static inline bool pm_resume_via_firmwar
>  	return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
>  }
>  
> +/**
> + * pm_suspend_no_platform - Check if platform may change device power states.
> + *
> + * To be called during system-wide power management transitions to sleep states
> + * or during the subsequent system-wide transitions back to the working state.
> + *
> + * Return 'true' if the power states of devices remain under full control of the
> + * kernel throughout the system-wide suspend and resume cycle in progress (that
> + * is, if a device is put into a certain power state during suspend, it can be
> + * expected to remain in that state during resume).
> + */
> +static inline bool pm_suspend_no_platform(void)
> +{
> +	return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_NO_PLATFORM);
> +}
> +
>  /* Suspend-to-idle state machnine. */
>  enum s2idle_states {
>  	S2IDLE_STATE_NONE,      /* Not suspended/suspending. */
> Index: linux-pm/kernel/power/suspend.c
> ===================================================================
> --- linux-pm.orig/kernel/power/suspend.c
> +++ linux-pm/kernel/power/suspend.c
> @@ -493,6 +493,9 @@ int suspend_devices_and_enter(suspend_st
>  
>  	pm_suspend_target_state = state;
>  
> +	if (state == PM_SUSPEND_TO_IDLE)
> +		pm_set_suspend_no_platform();
> +
>  	error = platform_suspend_begin(state);
>  	if (error)
>  		goto Close;
> Index: linux-pm/drivers/pci/pci-driver.c
> ===================================================================
> --- linux-pm.orig/drivers/pci/pci-driver.c
> +++ linux-pm/drivers/pci/pci-driver.c
> @@ -870,7 +870,7 @@ static int pci_pm_suspend_noirq(struct d
>  			pci_dev->bus->self->skip_bus_pm = true;
>  	}
>  
> -	if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) {
> +	if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
>  		dev_dbg(dev, "PCI PM: Skipped\n");
>  		goto Fixup;
>  	}
> @@ -925,10 +925,10 @@ static int pci_pm_resume_noirq(struct de
>  	/*
>  	 * In the suspend-to-idle case, devices left in D0 during suspend will
>  	 * stay in D0, so it is not necessary to restore or update their
> -	 * configuration here and attempting to put them into D0 again may
> -	 * confuse some firmware, so avoid doing that.
> +	 * configuration here and attempting to put them into D0 again is
> +	 * pointless, so avoid doing that.
>  	 */
> -	if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware())
> +	if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
>  		pci_pm_default_resume_early(pci_dev);
>  
>  	pci_fixup_device(pci_fixup_resume_early, pci_dev);

I can confirm that above works for me. So ...

Tested-by: Jon Hunter <jonathanh@nvidia.com>

This looks better ...

[   52.545820] PM: suspend entry (deep)
[   52.549547] Filesystems sync: 0.000 seconds
[   52.553966] Freezing user space processes ... (elapsed 0.001 seconds) done.
[   52.562375] OOM killer disabled.
[   52.565684] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
[   52.574426] printk: Suspending console(s) (use no_console_suspend to debug)
[   52.590255] r8169 0000:01:00.0 eth0: Link is Down
[   52.590483] pci_generic_config_write32: 22 callbacks suppressed
[   52.590488] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x9c may corrupt adjacent RW1C bits
[   52.794091] r8169 0000:01:00.0: PCI PM: Suspend power state: D3hot
[   52.794128] pcieport 0000:00:02.0: PCI PM: Suspend power state: D0
[   52.805674] Disabling non-boot CPUs ...
[   52.809257] Entering suspend state LP1
[   52.809284] Enabling non-boot CPUs ...
[   52.810184] CPU1 is up
[   52.810973] CPU2 is up
[   52.811819] CPU3 is up
[   52.822259] tegra-pcie 1003000.pcie: probing port 1, using 1 lanes
[   52.840085] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x4c may corrupt adjacent RW1C bits
[   52.840096] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x88 may corrupt adjacent RW1C bits
[   52.840101] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x90 may corrupt adjacent RW1C bits
[   52.840106] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x98 may corrupt adjacent RW1C bits
[   52.840111] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x9c may corrupt adjacent RW1C bits
[   52.840116] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0xa8 may corrupt adjacent RW1C bits
[   52.840121] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0xb0 may corrupt adjacent RW1C bits
[   52.840155] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x52 may corrupt adjacent RW1C bits
[   52.840160] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x52 may corrupt adjacent RW1C bits
[   52.840184] pcieport 0000:00:02.0: nv_msi_ht_cap_quirk didn't locate host bridge
[   52.864252] tegra-pcie 1003000.pcie: Slot present pin change, signature: 00000004
[   53.024171] r8169 0000:01:00.0 eth0: Link is Down
[   53.376438] ata1: SATA link down (SStatus 0 SControl 300)
[   55.881131] r8169 0000:01:00.0 eth0: Link is Up - 1Gbps/Full - flow control rx/tx
[   56.012154] OOM killer enabled.
[   56.015295] Restarting tasks ... done.
[   56.019415] PM: suspend exit
[   56.045929] PM: suspend entry (deep)
[   56.049565] Filesystems sync: 0.000 seconds
[   56.053906] Freezing user space processes ... (elapsed 0.001 seconds) done.
[   56.062205] OOM killer disabled.
[   56.065462] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
[   56.074193] printk: Suspending console(s) (use no_console_suspend to debug)
[   56.096375] r8169 0000:01:00.0 eth0: Link is Down
[   56.304070] r8169 0000:01:00.0: PCI PM: Suspend power state: D3hot
[   56.304111] pcieport 0000:00:02.0: PCI PM: Suspend power state: D0
[   56.314134] tegra-pcie 1003000.pcie: PME Ack is not received on port: 1
[   56.325777] Disabling non-boot CPUs ...
[   56.328540] Entering suspend state LP1
[   56.328571] Enabling non-boot CPUs ...
[   56.329687] CPU1 is up
[   56.330694] CPU2 is up
[   56.331772] CPU3 is up
[   56.332396] tegra-pcie 1003000.pcie: probing port 1, using 1 lanes
[   56.350134] pcieport 0000:00:02.0: nv_msi_ht_cap_quirk didn't locate host bridge
[   56.374241] tegra-pcie 1003000.pcie: Slot present pin change, signature: 00000004
[   56.534158] r8169 0000:01:00.0 eth0: Link is Down
[   56.886516] ata1: SATA link down (SStatus 0 SControl 300)
[   59.417895] OOM killer enabled.
[   59.421025] Restarting tasks ... done.
[   59.425305] PM: suspend exit
[   60.756040] r8169 0000:01:00.0 eth0: Link is Up - 1Gbps/Full - flow control rx/tx

Thanks!
Jon

-- 
nvpublic

^ permalink raw reply

* Re: [PATCH 1/3] notifier: Fix broken error handling pattern
From: Peter Zijlstra @ 2019-06-25 13:22 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: Jessica Yu, linux-kernel, jikos, mbenes, pmladek, ast, daniel,
	akpm, Rafael J. Wysocki, Pavel Machek, Len Brown, Sam Protsenko,
	Thomas Gleixner, Greg Kroah-Hartman, Alexios Zavras,
	Allison Randal, Vasily Averin, Todd Brandt, linux-pm
In-Reply-To: <20190625121334.x3dyvhwsuryxevrz@treble>

On Tue, Jun 25, 2019 at 07:13:34AM -0500, Josh Poimboeuf wrote:
> On Tue, Jun 25, 2019 at 09:38:21AM +0200, Peter Zijlstra wrote:
> > > > @@ -156,43 +169,30 @@ int atomic_notifier_chain_unregister(str
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
> > > >  
> > > > -/**
> > > > - *	__atomic_notifier_call_chain - Call functions in an atomic notifier chain
> > > > - *	@nh: Pointer to head of the atomic notifier chain
> > > > - *	@val: Value passed unmodified to notifier function
> > > > - *	@v: Pointer passed unmodified to notifier function
> > > > - *	@nr_to_call: See the comment for notifier_call_chain.
> > > > - *	@nr_calls: See the comment for notifier_call_chain.
> > > > - *
> > > > - *	Calls each function in a notifier chain in turn.  The functions
> > > > - *	run in an atomic context, so they must not block.
> > > > - *	This routine uses RCU to synchronize with changes to the chain.
> > > > - *
> > > > - *	If the return value of the notifier can be and'ed
> > > > - *	with %NOTIFY_STOP_MASK then atomic_notifier_call_chain()
> > > > - *	will return immediately, with the return value of
> > > > - *	the notifier function which halted execution.
> > > > - *	Otherwise the return value is the return value
> > > > - *	of the last notifier function called.
> > > > - */
> > > 
> > > Why remove the useful comment?
> > 
> > Because I delete the whole function ?
> 
> I viewed it as more of a rename... Regardless would the comment not
> still be useful for the non-double-underscore version of the function?

I never got that far, I just deleted the whole thing without reading it.
But yes, with a few tweaks it should apply to the normal function.

^ permalink raw reply

* Re: [PATCH v2] PCI: PM: Skip devices in D0 for suspend-to-idle
From: Jon Hunter @ 2019-06-25 12:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PCI, Bjorn Helgaas, Linux PM, Linux ACPI, LKML,
	Mika Westerberg, Keith Busch, Kai-Heng Feng, linux-tegra
In-Reply-To: <2287147.DxjcvLeq6l@kreacher>


On 25/06/2019 00:09, Rafael J. Wysocki wrote:
> On Tuesday, June 25, 2019 12:20:26 AM CEST Rafael J. Wysocki wrote:
>> On Mon, Jun 24, 2019 at 11:37 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>>>
>>> On Mon, Jun 24, 2019 at 2:43 PM Jon Hunter <jonathanh@nvidia.com> wrote:
>>>>
>>>> Hi Rafael,
>>>>
>>>> On 13/06/2019 22:59, Rafael J. Wysocki wrote:
>>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>>
>>>>> Commit d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>>>> attempted to avoid a problem with devices whose drivers want them to
>>>>> stay in D0 over suspend-to-idle and resume, but it did not go as far
>>>>> as it should with that.
>>>>>
>>>>> Namely, first of all, the power state of a PCI bridge with a
>>>>> downstream device in D0 must be D0 (based on the PCI PM spec r1.2,
>>>>> sec 6, table 6-1, if the bridge is not in D0, there can be no PCI
>>>>> transactions on its secondary bus), but that is not actively enforced
>>>>> during system-wide PM transitions, so use the skip_bus_pm flag
>>>>> introduced by commit d491f2b75237 for that.
>>>>>
>>>>> Second, the configuration of devices left in D0 (whatever the reason)
>>>>> during suspend-to-idle need not be changed and attempting to put them
>>>>> into D0 again by force is pointless, so explicitly avoid doing that.
>>>>>
>>>>> Fixes: d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>>>> Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>>>>> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>>>
>>>> I have noticed a regression in both the mainline and -next branches on
>>>> one of our boards when testing suspend. The bisect is point to this
>>>> commit and reverting on top of mainline does fix the problem. So far I
>>>> have not looked at this in close detail but kernel log is showing ...
>>>
>>> Can you please collect a log like that, but with dynamic debug in
>>> pci-driver.c enabled?
>>>
>>> Note that reverting this commit is rather out of the question, so we
>>> need to get to the bottom of the failure.
>>
>> I suspect that there is a problem with the pm_suspend_via_firmware()
>> check which returns 'false' on the affected board, but the platform
>> actually removes power from devices left in D0 during suspend.
>>
>> I guess it would be more appropriate to check something like
>> pm_suspend_no_platform() which would return 'true' in the
>> suspend-to-idle patch w/ ACPI.
> 
> So I wonder if the patch below makes any difference?

Thanks. I will try this now and let you know.

Cheers!
Jon

-- 
nvpublic

^ permalink raw reply

* Re: [PATCH v2] PCI: PM: Skip devices in D0 for suspend-to-idle
From: Jon Hunter @ 2019-06-25 12:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PCI, Bjorn Helgaas, Linux PM, Linux ACPI,
	LKML, Mika Westerberg, Keith Busch, Kai-Heng Feng, linux-tegra
In-Reply-To: <CAJZ5v0hdtXqoK84DpYtyMSCnkR9zOHFiUPAzWZDtkFmEjyWD1g@mail.gmail.com>


On 24/06/2019 22:37, Rafael J. Wysocki wrote:
> On Mon, Jun 24, 2019 at 2:43 PM Jon Hunter <jonathanh@nvidia.com> wrote:
>>
>> Hi Rafael,
>>
>> On 13/06/2019 22:59, Rafael J. Wysocki wrote:
>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>
>>> Commit d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>> attempted to avoid a problem with devices whose drivers want them to
>>> stay in D0 over suspend-to-idle and resume, but it did not go as far
>>> as it should with that.
>>>
>>> Namely, first of all, the power state of a PCI bridge with a
>>> downstream device in D0 must be D0 (based on the PCI PM spec r1.2,
>>> sec 6, table 6-1, if the bridge is not in D0, there can be no PCI
>>> transactions on its secondary bus), but that is not actively enforced
>>> during system-wide PM transitions, so use the skip_bus_pm flag
>>> introduced by commit d491f2b75237 for that.
>>>
>>> Second, the configuration of devices left in D0 (whatever the reason)
>>> during suspend-to-idle need not be changed and attempting to put them
>>> into D0 again by force is pointless, so explicitly avoid doing that.
>>>
>>> Fixes: d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
>>> Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>>> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>>
>> I have noticed a regression in both the mainline and -next branches on
>> one of our boards when testing suspend. The bisect is point to this
>> commit and reverting on top of mainline does fix the problem. So far I
>> have not looked at this in close detail but kernel log is showing ...
> 
> Can you please collect a log like that, but with dynamic debug in
> pci-driver.c enabled?

Yes, here you go ...

[   52.939258] PM: suspend entry (deep)
[   52.942963] Filesystems sync: 0.000 seconds
[   52.947596] Freezing user space processes ... (elapsed 0.001 seconds) done.
[   52.956145] OOM killer disabled.
[   52.959371] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
[   52.968088] printk: Suspending console(s) (use no_console_suspend to debug)
[   52.992168] r8169 0000:01:00.0 eth0: Link is Down
[   52.992245] pci_generic_config_write32: 22 callbacks suppressed
[   52.992250] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x9c may corrupt adjacent RW1C bits
[   53.204186] r8169 0000:01:00.0: PCI PM: Suspend power state: D3hot
[   53.204221] pcieport 0000:00:02.0: PCI PM: Suspend power state: D0
[   53.204224] pcieport 0000:00:02.0: PCI PM: Skipped
[   53.215716] Disabling non-boot CPUs ...
[   53.218833] Entering suspend state LP1
[   53.218860] Enabling non-boot CPUs ...
[   53.219731] CPU1 is up
[   53.220482] CPU2 is up
[   53.221289] CPU3 is up
[   53.221850] tegra-pcie 1003000.pcie: probing port 1, using 1 lanes
[   53.239925] pcieport 0000:00:02.0: nv_msi_ht_cap_quirk didn't locate host bridge
[   53.264145] r8169 0000:01:00.0: Refused to change power state, currently in D3
[   53.326969] tegra-pcie 1003000.pcie: Slot present pin change, signature: 00000004
[   53.326975] tegra-pcie 1003000.pcie: Response decoding error, signature: 10010045
[   53.326978] tegra-pcie 1003000.pcie:   FPCI address: fe10010044
[   53.327091] tegra-pcie 1003000.pcie: Response decoding error, signature: 2000000c
[   53.327095] tegra-pcie 1003000.pcie:   FPCI address:   2000000c
[   53.327099] tegra-pcie 1003000.pcie: Response decoding error, signature: 20000001
[   53.327102] tegra-pcie 1003000.pcie:   FPCI address:   20000000
[   53.347944] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x88 may corrupt adjacent RW1C bits
[   53.347955] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x90 may corrupt adjacent RW1C bits
[   53.347962] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x98 may corrupt adjacent RW1C bits
[   53.347969] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x9c may corrupt adjacent RW1C bits
[   53.347977] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0xa8 may corrupt adjacent RW1C bits
[   53.347984] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0xb0 may corrupt adjacent RW1C bits
[   53.348025] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x52 may corrupt adjacent RW1C bits
[   53.348033] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x52 may corrupt adjacent RW1C bits
[   53.348043] pci_bus 0000:00: 2-byte config write to 0000:00:02.0 offset 0x5c may corrupt adjacent RW1C bits
[   53.358310] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   53.358592] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.394498] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.394789] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.395072] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.395352] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.395635] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.395919] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.396209] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.396488] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.396771] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.397055] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.397330] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.397608] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.397884] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.398162] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.398441] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.398721] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.399006] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.399295] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   53.399579] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.234501] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.234819] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.235104] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.235386] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.235403] Generic Realtek PHY r8169-100:00: Master/Slave resolution failed, maybe conflicting manual settings?
[   54.235406] ------------[ cut here ]------------
[   54.235416] WARNING: CPU: 3 PID: 112 at /home/jonathanh/workdir/tegra/mlt-linux_torvalds/kernel/drivers/net/phy/phy.c:735 phy_error+0x1c/0x54
[   54.235419] Modules linked in: ttm
[   54.235429] CPU: 3 PID: 112 Comm: kworker/3:1 Not tainted 5.2.0-rc6-dirty #3
[   54.235431] Hardware name: NVIDIA Tegra SoC (Flattened Device Tree)
[   54.235441] Workqueue: events_power_efficient phy_state_machine
[   54.235455] [<c0112244>] (unwind_backtrace) from [<c010cad8>] (show_stack+0x10/0x14)
[   54.235463] [<c010cad8>] (show_stack) from [<c0a606a4>] (dump_stack+0xb4/0xc8)
[   54.235471] [<c0a606a4>] (dump_stack) from [<c0123cbc>] (__warn+0xe0/0xf8)
[   54.235477] [<c0123cbc>] (__warn) from [<c0123dec>] (warn_slowpath_null+0x40/0x48)
[   54.235482] [<c0123dec>] (warn_slowpath_null) from [<c0617470>] (phy_error+0x1c/0x54)
[   54.235488] [<c0617470>] (phy_error) from [<c0618564>] (phy_state_machine+0x64/0x1c0)
[   54.235498] [<c0618564>] (phy_state_machine) from [<c013e744>] (process_one_work+0x204/0x578)
[   54.235503] [<c013e744>] (process_one_work) from [<c013f444>] (worker_thread+0x44/0x584)
[   54.235507] [<c013f444>] (worker_thread) from [<c01445d4>] (kthread+0x148/0x150)
[   54.235512] [<c01445d4>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
[   54.235515] Exception stack(0xe9ea1fb0 to 0xe9ea1ff8)
[   54.235518] 1fa0:                                     00000000 00000000 00000000 00000000
[   54.235522] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[   54.235525] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[   54.235528] ---[ end trace 772a7ce78ffff5e6 ]---
[   54.235551] r8169 0000:01:00.0 eth0: Link is Down
[   54.245804] r8169 0000:01:00.0 eth0: rtl_chipcmd_cond == 1 (loop: 100, delay: 100).
[   54.256058] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.266257] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.276454] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.286656] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.296860] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.307064] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.317263] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.327464] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.337660] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.347902] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.358102] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.368303] r8169 0000:01:00.0 eth0: rtl_eriar_cond == 1 (loop: 100, delay: 100).
[   54.369471] r8169 0000:01:00.0 eth0: rtl_ephyar_cond == 1 (loop: 100, delay: 10).
[   54.370637] r8169 0000:01:00.0 eth0: rtl_ephyar_cond == 1 (loop: 100, delay: 10).
[   54.371799] r8169 0000:01:00.0 eth0: rtl_ephyar_cond == 1 (loop: 100, delay: 10).
[   54.372961] r8169 0000:01:00.0 eth0: rtl_ephyar_cond == 1 (loop: 100, delay: 10).
[   54.373416] r8169 0000:01:00.0 eth0: rtl_ocp_gphy_cond == 1 (loop: 10, delay: 25).
[   54.716510] ata1: SATA link down (SStatus 0 SControl 300)
[   56.998780] OOM killer enabled.
[   57.001909] Restarting tasks ... done.
[   57.007392] PM: suspend exit
[   73.144767] nfs: server 192.168.99.1 not responding, still trying
[   77.624567] nfs: server 192.168.99.1 not responding, still trying

Cheers
Jon

-- 
nvpublic

^ permalink raw reply

* Re: [PATCH 1/3] notifier: Fix broken error handling pattern
From: Josh Poimboeuf @ 2019-06-25 12:13 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jessica Yu, linux-kernel, jikos, mbenes, pmladek, ast, daniel,
	akpm, Rafael J. Wysocki, Pavel Machek, Len Brown, Sam Protsenko,
	Thomas Gleixner, Greg Kroah-Hartman, Alexios Zavras,
	Allison Randal, Vasily Averin, Todd Brandt, linux-pm
In-Reply-To: <20190625073821.GQ3436@hirez.programming.kicks-ass.net>

On Tue, Jun 25, 2019 at 09:38:21AM +0200, Peter Zijlstra wrote:
> > > @@ -156,43 +169,30 @@ int atomic_notifier_chain_unregister(str
> > >  }
> > >  EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
> > >  
> > > -/**
> > > - *	__atomic_notifier_call_chain - Call functions in an atomic notifier chain
> > > - *	@nh: Pointer to head of the atomic notifier chain
> > > - *	@val: Value passed unmodified to notifier function
> > > - *	@v: Pointer passed unmodified to notifier function
> > > - *	@nr_to_call: See the comment for notifier_call_chain.
> > > - *	@nr_calls: See the comment for notifier_call_chain.
> > > - *
> > > - *	Calls each function in a notifier chain in turn.  The functions
> > > - *	run in an atomic context, so they must not block.
> > > - *	This routine uses RCU to synchronize with changes to the chain.
> > > - *
> > > - *	If the return value of the notifier can be and'ed
> > > - *	with %NOTIFY_STOP_MASK then atomic_notifier_call_chain()
> > > - *	will return immediately, with the return value of
> > > - *	the notifier function which halted execution.
> > > - *	Otherwise the return value is the return value
> > > - *	of the last notifier function called.
> > > - */
> > 
> > Why remove the useful comment?
> 
> Because I delete the whole function ?

I viewed it as more of a rename... Regardless would the comment not
still be useful for the non-double-underscore version of the function?

-- 
Josh

^ permalink raw reply

* [PATCH] PCI: PM/ACPI: Refresh all stale power state data in pci_pm_complete()
From: Rafael J. Wysocki @ 2019-06-25 12:09 UTC (permalink / raw)
  To: Linux PCI
  Cc: Linux ACPI, Linux PM, LKML, Bjorn Helgaas, Mika Westerberg,
	Lukas Wunner

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

In pci_pm_complete() there are checks to decide whether or not to
resume devices that were left in runtime-suspend during the preceding
system-wide transition into a sleep state.  They involve checking the
current power state of the device and comparing it with the power
state of it set before the preceding system-wide transition, but the
platform component of the device's power state is not handled
correctly in there.

Namely, on platforms with ACPI, the device power state information
needs to be updated with care, so that the reference counters of
power resources used by the device (if any) are set to ensure that
the refreshed power state of it will be maintained going forward.

To that end, introduce a new ->refresh_state() platform PM callback
for PCI devices, for asking the platform to refresh the device power
state data and ensure that the corresponding power state will be
maintained going forward, make it invoke acpi_device_update_power()
(for devices with ACPI PM) on platforms with ACPI and make
pci_pm_complete() use it, through a new pci_refresh_power_state()
wrapper function.

Fixes: a0d2a959d3da (PCI: Avoid unnecessary resume after direct-complete)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/pci-acpi.c   |    9 +++++++++
 drivers/pci/pci-driver.c |    9 ++++++++-
 drivers/pci/pci.c        |   21 +++++++++++++++++++++
 drivers/pci/pci.h        |    4 ++++
 4 files changed, 42 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -691,6 +691,14 @@ static pci_power_t acpi_pci_get_power_st
 	return state_conv[state];
 }
 
+static void acpi_pci_refresh_power_state(struct pci_dev *dev)
+{
+	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+
+	if (adev && acpi_device_power_manageable(adev))
+		acpi_device_update_power(adev, NULL);
+}
+
 static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
 {
 	while (bus->parent) {
@@ -748,6 +756,7 @@ static const struct pci_platform_pm_ops
 	.is_manageable = acpi_pci_power_manageable,
 	.set_state = acpi_pci_set_power_state,
 	.get_state = acpi_pci_get_power_state,
+	.refresh_state = acpi_pci_refresh_power_state,
 	.choose_state = acpi_pci_choose_state,
 	.set_wakeup = acpi_pci_wakeup,
 	.need_resume = acpi_pci_need_resume,
Index: linux-pm/drivers/pci/pci.h
===================================================================
--- linux-pm.orig/drivers/pci/pci.h
+++ linux-pm/drivers/pci/pci.h
@@ -51,6 +51,8 @@ int pci_bus_error_reset(struct pci_dev *
  *
  * @get_state: queries the platform firmware for a device's current power state
  *
+ * @refresh_state: asks the platform to refresh the device's power state data
+ *
  * @choose_state: returns PCI power state of given device preferred by the
  *		  platform; to be used during system-wide transitions from a
  *		  sleeping state to the working state and vice versa
@@ -69,6 +71,7 @@ struct pci_platform_pm_ops {
 	bool (*is_manageable)(struct pci_dev *dev);
 	int (*set_state)(struct pci_dev *dev, pci_power_t state);
 	pci_power_t (*get_state)(struct pci_dev *dev);
+	void (*refresh_state)(struct pci_dev *dev);
 	pci_power_t (*choose_state)(struct pci_dev *dev);
 	int (*set_wakeup)(struct pci_dev *dev, bool enable);
 	bool (*need_resume)(struct pci_dev *dev);
@@ -76,6 +79,7 @@ struct pci_platform_pm_ops {
 
 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops);
 void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
+void pci_refresh_power_state(struct pci_dev *dev);
 void pci_power_up(struct pci_dev *dev);
 void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
Index: linux-pm/drivers/pci/pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pci.c
+++ linux-pm/drivers/pci/pci.c
@@ -777,6 +777,12 @@ static inline pci_power_t platform_pci_g
 	return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN;
 }
 
+static inline void platform_pci_refresh_power_state(struct pci_dev *dev)
+{
+	if (pci_platform_pm && pci_platform_pm->refresh_state)
+		pci_platform_pm->refresh_state(dev);
+}
+
 static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
 {
 	return pci_platform_pm ?
@@ -938,6 +944,21 @@ void pci_update_current_state(struct pci
 }
 
 /**
+ * pci_refresh_power_state - Refresh the given device's power state data
+ * @dev: Target PCI device.
+ *
+ * Ask the platform to refresh the devices power state information and invoke
+ * pci_update_current_state() to update its current PCI power state.
+ */
+void pci_refresh_power_state(struct pci_dev *dev)
+{
+	if (platform_pci_power_manageable(dev))
+		platform_pci_refresh_power_state(dev);
+
+	pci_update_current_state(dev, dev->current_state);
+}
+
+/**
  * pci_power_up - Put the given device into D0 forcibly
  * @dev: PCI device to power up
  */
Index: linux-pm/drivers/pci/pci-driver.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-driver.c
+++ linux-pm/drivers/pci/pci-driver.c
@@ -710,7 +710,14 @@ static void pci_pm_complete(struct devic
 	if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) {
 		pci_power_t pre_sleep_state = pci_dev->current_state;
 
-		pci_update_current_state(pci_dev, pci_dev->current_state);
+		pci_refresh_power_state(pci_dev);
+		/*
+		 * On platforms with ACPI this check may also trigger for
+		 * devices sharing power resources if one of those power
+		 * resources has been activated as a result of a change of the
+		 * power state of another device sharing it.  However, in that
+		 * case it is also better to resume the device, in general.
+		 */
 		if (pci_dev->current_state < pre_sleep_state)
 			pm_request_resume(dev);
 	}




^ permalink raw reply

* [PATCH 0/2] ACPI: PM: Fix two issues in acpi_device_set_power()
From: Rafael J. Wysocki @ 2019-06-25 12:03 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Bjorn Helgaas, Linux PM, Mika Westerberg, LKML, Zhang Rui

Hi All,

There are two, arguably minor, issues in acpi_device_set_power() that have been
introduced while making the code follow the ACPI 6 recommendations.

One of them is that, if the device is in D3hot, transitioning it into D3cold only
involves dropping references to some power resources and it should not
involve evaluating _PS3 which may happen currently.

The second one is that it sometimes is necessary to update the power state
of a device to D0 even if it was put into D0 previously, so that needs to be
possible.

Please refer to the patch changelogs for details.

Thanks,
Rafael




^ permalink raw reply

* [PATCH 1/2] ACPI: PM: Avoid evaluating _PS3 on transitions from D3hot to D3cold
From: Rafael J. Wysocki @ 2019-06-25 12:04 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Bjorn Helgaas, Linux PM, Mika Westerberg, LKML, Zhang Rui
In-Reply-To: <10419005.Mb09WM6RCc@kreacher>

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

If the power state of a device with ACPI PM is changed from D3hot to
D3cold, it merely is a matter of dropping references to additional
power resources (specifically, those in the list returned by _PR3),
and the _PS3 method should not be invoked for the device then (as
it has already been evaluated during the previous transition to
D3hot).

Fixes: 20dacb71ad28 (ACPI / PM: Rework device power management to follow ACPI 6)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/device_pm.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -215,9 +215,15 @@ int acpi_device_set_power(struct acpi_de
 			return -ENODEV;
 		}
 
-		result = acpi_dev_pm_explicit_set(device, state);
-		if (result)
-			goto end;
+		/*
+		 * If the device goes from D3hot to D3cold, _PS3 has been
+		 * evaluated for it already, so skip it in that case.
+		 */
+		if (device->power.state < ACPI_STATE_D3_HOT) {
+			result = acpi_dev_pm_explicit_set(device, state);
+			if (result)
+				goto end;
+		}
 
 		if (device->power.flags.power_resources)
 			result = acpi_power_transition(device, target_state);




^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox