linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements
@ 2019-04-11 22:02 Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 1/5] clk: tegra: emc: Don't enable EMC clock manually Dmitry Osipenko
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

Hello, I was helping with fixing EMC clock scaling on T124 Nyan Big and
in process found some weak points in the code. Primarily the ram code
parsing didn't work if device-tree defines memory timings for multiple
ram codes and after fixing that I spotted few other things that could be
improved.

Dmitry Osipenko (5):
  clk: tegra: emc: Don't enable EMC clock manually
  clk: tegra: emc: Support multiple ram codes parsing
  clk: tegra: emc: Fix EMC max-rate clamping
  clk: tegra: emc: Replace BUG() with WARN_ONCE()
  clk: tegra: divider: Mark Memory Controller clock as read-only

 drivers/clk/tegra/clk-divider.c |  5 +--
 drivers/clk/tegra/clk-emc.c     | 57 ++++++++++++++++++++-------------
 2 files changed, 38 insertions(+), 24 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v1 1/5] clk: tegra: emc: Don't enable EMC clock manually
  2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
@ 2019-04-11 22:02 ` Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 2/5] clk: tegra: emc: Support multiple ram codes parsing Dmitry Osipenko
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

The EMC clock marked as critical, hence it is already enabled at the
registration time.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-emc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index 0621a3a82ea6..23416982e7c7 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -532,7 +532,5 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
 	/* Allow debugging tools to see the EMC clock */
 	clk_register_clkdev(clk, "emc", "tegra-clk-debug");
 
-	clk_prepare_enable(clk);
-
 	return clk;
 };
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 2/5] clk: tegra: emc: Support multiple ram codes parsing
  2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 1/5] clk: tegra: emc: Don't enable EMC clock manually Dmitry Osipenko
@ 2019-04-11 22:02 ` Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 3/5] clk: tegra: emc: Fix EMC max-rate clamping Dmitry Osipenko
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

The timings parser doesn't append timings, but instead it parses only
the first timing and hence doesn't store all of the timings when
device-tree has timings for multiple ram codes. In a result EMC scaling
doesn't work if timings are missing.

Tested-by: Steev Klimaszewski <steev@kali.org>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-emc.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index 23416982e7c7..28068584ff6e 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -121,18 +121,23 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 	struct tegra_clk_emc *tegra;
 	u8 ram_code = tegra_read_ram_code();
 	struct emc_timing *timing = NULL;
-	int i;
+	int i, k;
 
 	tegra = container_of(hw, struct tegra_clk_emc, hw);
 
-	for (i = 0; i < tegra->num_timings; i++) {
+	for (k = 0; k < tegra->num_timings; k++) {
+		if (tegra->timings[k].ram_code == ram_code)
+			break;
+	}
+
+	for (i = k; i < tegra->num_timings; i++) {
 		if (tegra->timings[i].ram_code != ram_code)
-			continue;
+			break;
 
 		timing = tegra->timings + i;
 
 		if (timing->rate > req->max_rate) {
-			i = max(i, 1);
+			i = max(i, k + 1);
 			req->rate = tegra->timings[i - 1].rate;
 			return 0;
 		}
@@ -282,7 +287,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra,
 	for (i = timing_index+1; i < tegra->num_timings; i++) {
 		timing = tegra->timings + i;
 		if (timing->ram_code != ram_code)
-			continue;
+			break;
 
 		if (emc_parent_clk_sources[timing->parent_index] !=
 		    emc_parent_clk_sources[
@@ -293,7 +298,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra,
 	for (i = timing_index-1; i >= 0; --i) {
 		timing = tegra->timings + i;
 		if (timing->ram_code != ram_code)
-			continue;
+			break;
 
 		if (emc_parent_clk_sources[timing->parent_index] !=
 		    emc_parent_clk_sources[
@@ -433,19 +438,23 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
 				struct device_node *node,
 				u32 ram_code)
 {
+	struct emc_timing *timings_ptr;
 	struct device_node *child;
 	int child_count = of_get_child_count(node);
 	int i = 0, err;
+	size_t size;
+
+	size = (tegra->num_timings + child_count) * sizeof(struct emc_timing);
 
-	tegra->timings = kcalloc(child_count, sizeof(struct emc_timing),
-				 GFP_KERNEL);
+	tegra->timings = krealloc(tegra->timings, size, GFP_KERNEL);
 	if (!tegra->timings)
 		return -ENOMEM;
 
-	tegra->num_timings = child_count;
+	timings_ptr = tegra->timings + tegra->num_timings;
+	tegra->num_timings += child_count;
 
 	for_each_child_of_node(node, child) {
-		struct emc_timing *timing = tegra->timings + (i++);
+		struct emc_timing *timing = timings_ptr + (i++);
 
 		err = load_one_timing_from_dt(tegra, timing, child);
 		if (err) {
@@ -456,7 +465,7 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
 		timing->ram_code = ram_code;
 	}
 
-	sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing),
+	sort(timings_ptr, child_count, sizeof(struct emc_timing),
 	     cmp_timings, NULL);
 
 	return 0;
@@ -499,10 +508,10 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
 		 * fuses until the apbmisc driver is loaded.
 		 */
 		err = load_timings_from_dt(tegra, node, node_ram_code);
-		of_node_put(node);
-		if (err)
+		if (err) {
+			of_node_put(node);
 			return ERR_PTR(err);
-		break;
+		}
 	}
 
 	if (tegra->num_timings == 0)
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 3/5] clk: tegra: emc: Fix EMC max-rate clamping
  2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 1/5] clk: tegra: emc: Don't enable EMC clock manually Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 2/5] clk: tegra: emc: Support multiple ram codes parsing Dmitry Osipenko
@ 2019-04-11 22:02 ` Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 4/5] clk: tegra: emc: Replace BUG() with WARN_ONCE() Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only Dmitry Osipenko
  4 siblings, 0 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

When a clk user requests rate that is higher than the maximum possible,
the rate shall be clamped to the maximum and not to the current value.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-emc.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index 28068584ff6e..9a0179235939 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -121,7 +121,7 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 	struct tegra_clk_emc *tegra;
 	u8 ram_code = tegra_read_ram_code();
 	struct emc_timing *timing = NULL;
-	int i, k;
+	int i, k, t;
 
 	tegra = container_of(hw, struct tegra_clk_emc, hw);
 
@@ -130,12 +130,17 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 			break;
 	}
 
-	for (i = k; i < tegra->num_timings; i++) {
-		if (tegra->timings[i].ram_code != ram_code)
+	for (t = k; t < tegra->num_timings; t++) {
+		if (tegra->timings[t].ram_code != ram_code)
 			break;
+	}
 
+	for (i = k; i < t; i++) {
 		timing = tegra->timings + i;
 
+		if (timing->rate < req->rate && i != t - 1)
+			continue;
+
 		if (timing->rate > req->max_rate) {
 			i = max(i, k + 1);
 			req->rate = tegra->timings[i - 1].rate;
@@ -145,10 +150,8 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 		if (timing->rate < req->min_rate)
 			continue;
 
-		if (timing->rate >= req->rate) {
-			req->rate = timing->rate;
-			return 0;
-		}
+		req->rate = timing->rate;
+		return 0;
 	}
 
 	if (timing) {
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 4/5] clk: tegra: emc: Replace BUG() with WARN_ONCE()
  2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2019-04-11 22:02 ` [PATCH v1 3/5] clk: tegra: emc: Fix EMC max-rate clamping Dmitry Osipenko
@ 2019-04-11 22:02 ` Dmitry Osipenko
  2019-04-11 22:02 ` [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only Dmitry Osipenko
  4 siblings, 0 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

There is no justification for the BUG() in this code.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-emc.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index 9a0179235939..93ecb538e59b 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -222,7 +222,10 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
 
 	if (emc_get_parent(&tegra->hw) == timing->parent_index &&
 	    clk_get_rate(timing->parent) != timing->parent_rate) {
-		BUG();
+		WARN_ONCE(1, "parent %s rate mismatch %lu %lu\n",
+			  __clk_get_name(timing->parent),
+			  clk_get_rate(timing->parent),
+			  timing->parent_rate);
 		return -EINVAL;
 	}
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only
  2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2019-04-11 22:02 ` [PATCH v1 4/5] clk: tegra: emc: Replace BUG() with WARN_ONCE() Dmitry Osipenko
@ 2019-04-11 22:02 ` Dmitry Osipenko
  2019-04-12 13:54   ` Dmitry Osipenko
  4 siblings, 1 reply; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-11 22:02 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

The Memory Controller clock rate can't be simply changed and nothing in
kernel need to change the rate, hence let's make the clock read-only.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-divider.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 205fe8ff63f0..f891bbb0d06d 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -175,6 +175,7 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
 				  void __iomem *reg, spinlock_t *lock)
 {
 	return clk_register_divider_table(NULL, name, parent_name,
-					  CLK_IS_CRITICAL, reg, 16, 1, 0,
-					  mc_div_table, lock);
+					  CLK_IS_CRITICAL |
+					  CLK_DIVIDER_READ_ONLY,
+					  reg, 16, 1, 0, mc_div_table, lock);
 }
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only
  2019-04-11 22:02 ` [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only Dmitry Osipenko
@ 2019-04-12 13:54   ` Dmitry Osipenko
  0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Osipenko @ 2019-04-12 13:54 UTC (permalink / raw)
  To: Peter De Schrijver, Prashant Gaikwad, Michael Turquette,
	Stephen Boyd, Thierry Reding, Jonathan Hunter, Joseph Lo
  Cc: linux-clk, linux-tegra, linux-kernel

12.04.2019 1:02, Dmitry Osipenko пишет:
> The Memory Controller clock rate can't be simply changed and nothing in
> kernel need to change the rate, hence let's make the clock read-only.
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  drivers/clk/tegra/clk-divider.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
> index 205fe8ff63f0..f891bbb0d06d 100644
> --- a/drivers/clk/tegra/clk-divider.c
> +++ b/drivers/clk/tegra/clk-divider.c
> @@ -175,6 +175,7 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
>  				  void __iomem *reg, spinlock_t *lock)
>  {
>  	return clk_register_divider_table(NULL, name, parent_name,
> -					  CLK_IS_CRITICAL, reg, 16, 1, 0,
> -					  mc_div_table, lock);
> +					  CLK_IS_CRITICAL |
> +					  CLK_DIVIDER_READ_ONLY,
> +					  reg, 16, 1, 0, mc_div_table, lock);
>  }
> 

Turned out there is a bug here, the read-only flag is the divider's flag and hence it shall be:

 {
 	return clk_register_divider_table(NULL, name, parent_name,
-					  CLK_IS_CRITICAL |
-					  CLK_DIVIDER_READ_ONLY,
-					  reg, 16, 1, 0, mc_div_table, lock);
+					  CLK_IS_CRITICAL,
+					  reg, 16, 1, CLK_DIVIDER_READ_ONLY,
+					  mc_div_table, lock);
 }

I'll fix it up in v2.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-04-12 13:54 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-11 22:02 [PATCH v1 0/5] clk: tegra: EMC/MC clock fixes and improvements Dmitry Osipenko
2019-04-11 22:02 ` [PATCH v1 1/5] clk: tegra: emc: Don't enable EMC clock manually Dmitry Osipenko
2019-04-11 22:02 ` [PATCH v1 2/5] clk: tegra: emc: Support multiple ram codes parsing Dmitry Osipenko
2019-04-11 22:02 ` [PATCH v1 3/5] clk: tegra: emc: Fix EMC max-rate clamping Dmitry Osipenko
2019-04-11 22:02 ` [PATCH v1 4/5] clk: tegra: emc: Replace BUG() with WARN_ONCE() Dmitry Osipenko
2019-04-11 22:02 ` [PATCH v1 5/5] clk: tegra: divider: Mark Memory Controller clock as read-only Dmitry Osipenko
2019-04-12 13:54   ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).