lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241223173708.384108-5-prabhakar.mahadev-lad.rj@bp.renesas.com>
Date: Mon, 23 Dec 2024 17:37:06 +0000
From: Prabhakar <prabhakar.csengg@...il.com>
To: Geert Uytterhoeven <geert+renesas@...der.be>,
	Michael Turquette <mturquette@...libre.com>,
	Stephen Boyd <sboyd@...nel.org>
Cc: linux-renesas-soc@...r.kernel.org,
	linux-clk@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Prabhakar <prabhakar.csengg@...il.com>,
	Biju Das <biju.das.jz@...renesas.com>,
	Fabrizio Castro <fabrizio.castro.jz@...esas.com>,
	Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
Subject: [PATCH v2 4/6] clk: renesas: rzv2h: Switch MSTOP configuration to per-bit basis

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>

Refactor MSTOP handling to switch from group-based to per-bit
configuration. Introduce atomic counters for each MSTOP bit and update
enable/disable logic.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
---
v1->v2
- New patch
---
 drivers/clk/renesas/r9a09g047-cpg.c |   2 +
 drivers/clk/renesas/r9a09g057-cpg.c |   2 +
 drivers/clk/renesas/rzv2h-cpg.c     | 168 +++++++++++++---------------
 drivers/clk/renesas/rzv2h-cpg.h     |   5 +
 4 files changed, 84 insertions(+), 93 deletions(-)

diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c
index 7945b9f95b95..536d922bed70 100644
--- a/drivers/clk/renesas/r9a09g047-cpg.c
+++ b/drivers/clk/renesas/r9a09g047-cpg.c
@@ -145,4 +145,6 @@ const struct rzv2h_cpg_info r9a09g047_cpg_info __initconst = {
 	/* Resets */
 	.resets = r9a09g047_resets,
 	.num_resets = ARRAY_SIZE(r9a09g047_resets),
+
+	.num_mstop_bits = 208,
 };
diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c
index 59dadedb2217..a45b4020996b 100644
--- a/drivers/clk/renesas/r9a09g057-cpg.c
+++ b/drivers/clk/renesas/r9a09g057-cpg.c
@@ -275,4 +275,6 @@ const struct rzv2h_cpg_info r9a09g057_cpg_info __initconst = {
 	/* Resets */
 	.resets = r9a09g057_resets,
 	.num_resets = ARRAY_SIZE(r9a09g057_resets),
+
+	.num_mstop_bits = 192,
 };
diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index 29b1ce003370..154ad0db6dca 100644
--- a/drivers/clk/renesas/rzv2h-cpg.c
+++ b/drivers/clk/renesas/rzv2h-cpg.c
@@ -43,6 +43,8 @@
 
 #define CPG_BUS_1_MSTOP		(0xd00)
 #define CPG_BUS_MSTOP(m)	(CPG_BUS_1_MSTOP + ((m) - 1) * 4)
+/* On RZ/V2H(P) and RZ/G3E CPG_BUS_m_MSTOP starts from m = 1 */
+#define GET_MSTOP_IDX(mask)	((FIELD_GET(BUS_MSTOP_IDX_MASK, (mask))) - 1)
 
 #define KDIV(val)		((s16)FIELD_GET(GENMASK(31, 16), (val)))
 #define MDIV(val)		FIELD_GET(GENMASK(15, 6), (val))
@@ -68,6 +70,7 @@
  * @resets: Array of resets
  * @num_resets: Number of Module Resets in info->resets[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @mstop_count: Array of mstop
  * @rcdev: Reset controller entity
  */
 struct rzv2h_cpg_priv {
@@ -82,17 +85,13 @@ struct rzv2h_cpg_priv {
 	unsigned int num_resets;
 	unsigned int last_dt_core_clk;
 
+	atomic_t *mstop_count;
+
 	struct reset_controller_dev rcdev;
 };
 
 #define rcdev_to_priv(x)	container_of(x, struct rzv2h_cpg_priv, rcdev)
 
-struct rzv2h_mstop {
-	u16 idx;
-	u16 mask;
-	refcount_t ref_cnt;
-};
-
 struct pll_clk {
 	struct rzv2h_cpg_priv *priv;
 	void __iomem *base;
@@ -107,7 +106,7 @@ struct pll_clk {
  * struct mod_clock - Module clock
  *
  * @priv: CPG private data
- * @mstop: handle to cpg bus mstop data
+ * @mstop_data: mstop data relating to module clock
  * @hw: handle between common and hardware-specific interfaces
  * @no_pm: flag to indicate PM is not supported
  * @on_index: register offset
@@ -117,7 +116,7 @@ struct pll_clk {
  */
 struct mod_clock {
 	struct rzv2h_cpg_priv *priv;
-	struct rzv2h_mstop *mstop;
+	unsigned int mstop_data;
 	struct clk_hw hw;
 	bool no_pm;
 	u8 on_index;
@@ -446,36 +445,65 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
 }
 
 static void rzv2h_mod_clock_mstop_enable(struct rzv2h_cpg_priv *priv,
-					 struct mod_clock *clock)
+					 u32 mstop_data)
 {
+	u16 mstop_mask = FIELD_GET(BUS_MSTOP_BITS_MASK, (mstop_data));
+	u16 mstop_index = GET_MSTOP_IDX(mstop_data);
+	unsigned int index = mstop_index * 16;
 	unsigned long flags;
-	u32 val;
+	unsigned int i;
+	u32 val = 0;
 
 	spin_lock_irqsave(&priv->rmw_lock, flags);
-	if (!refcount_read(&clock->mstop->ref_cnt)) {
-		val = clock->mstop->mask << 16;
-		writel(val, priv->base + CPG_BUS_MSTOP(clock->mstop->idx));
-		refcount_set(&clock->mstop->ref_cnt, 1);
-	} else {
-		refcount_inc(&clock->mstop->ref_cnt);
+	for_each_set_bit(i, (unsigned long *)&mstop_mask, 16) {
+		if (!atomic_read(&priv->mstop_count[index + i]))
+			val |= BIT(i) << 16;
+		atomic_inc(&priv->mstop_count[index + i]);
 	}
+	if (val)
+		writel(val, priv->base + CPG_BUS_MSTOP(mstop_index + 1));
 	spin_unlock_irqrestore(&priv->rmw_lock, flags);
 }
 
 static void rzv2h_mod_clock_mstop_disable(struct rzv2h_cpg_priv *priv,
-					  struct mod_clock *clock)
+					  u32 mstop_data)
 {
+	u16 mstop_mask = FIELD_GET(BUS_MSTOP_BITS_MASK, (mstop_data));
+	u16 mstop_index = GET_MSTOP_IDX(mstop_data);
+	unsigned int index = mstop_index * 16;
 	unsigned long flags;
-	u32 val;
+	unsigned int i;
+	u32 val = 0;
 
 	spin_lock_irqsave(&priv->rmw_lock, flags);
-	if (refcount_dec_and_test(&clock->mstop->ref_cnt)) {
-		val = clock->mstop->mask << 16 | clock->mstop->mask;
-		writel(val, priv->base + CPG_BUS_MSTOP(clock->mstop->idx));
+	for_each_set_bit(i, (unsigned long *)&mstop_mask, 16) {
+		if (!atomic_read(&priv->mstop_count[index + i]) ||
+		    atomic_dec_and_test(&priv->mstop_count[index + i]))
+			val |= BIT(i) << 16 | BIT(i);
 	}
+	if (val)
+		writel(val, priv->base + CPG_BUS_MSTOP(mstop_index + 1));
 	spin_unlock_irqrestore(&priv->rmw_lock, flags);
 }
 
+static int rzv2h_mod_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mod_clock *clock = to_mod_clock(hw);
+	struct rzv2h_cpg_priv *priv = clock->priv;
+	u32 bitmask;
+	u32 offset;
+
+	if (clock->mon_index >= 0) {
+		offset = GET_CLK_MON_OFFSET(clock->mon_index);
+		bitmask = BIT(clock->mon_bit);
+	} else {
+		offset = GET_CLK_ON_OFFSET(clock->on_index);
+		bitmask = BIT(clock->on_bit);
+	}
+
+	return readl(priv->base + offset) & bitmask;
+}
+
 static int rzv2h_mod_clock_endisable(struct clk_hw *hw, bool enable)
 {
 	struct mod_clock *clock = to_mod_clock(hw);
@@ -489,15 +517,19 @@ static int rzv2h_mod_clock_endisable(struct clk_hw *hw, bool enable)
 	dev_dbg(dev, "CLK_ON 0x%x/%pC %s\n", reg, hw->clk,
 		enable ? "ON" : "OFF");
 
+	if ((rzv2h_mod_clock_is_enabled(hw) && enable) ||
+	    (!rzv2h_mod_clock_is_enabled(hw) && !enable))
+		return 0;
+
 	value = bitmask << 16;
 	if (enable) {
 		value |= bitmask;
 		writel(value, priv->base + reg);
-		if (clock->mstop)
-			rzv2h_mod_clock_mstop_enable(priv, clock);
+		if (clock->mstop_data != BUS_MSTOP_NONE)
+			rzv2h_mod_clock_mstop_enable(priv, clock->mstop_data);
 	} else {
-		if (clock->mstop)
-			rzv2h_mod_clock_mstop_disable(priv, clock);
+		if (clock->mstop_data != BUS_MSTOP_NONE)
+			rzv2h_mod_clock_mstop_disable(priv, clock->mstop_data);
 		writel(value, priv->base + reg);
 	}
 
@@ -525,73 +557,12 @@ static void rzv2h_mod_clock_disable(struct clk_hw *hw)
 	rzv2h_mod_clock_endisable(hw, false);
 }
 
-static int rzv2h_mod_clock_is_enabled(struct clk_hw *hw)
-{
-	struct mod_clock *clock = to_mod_clock(hw);
-	struct rzv2h_cpg_priv *priv = clock->priv;
-	u32 bitmask;
-	u32 offset;
-
-	if (clock->mon_index >= 0) {
-		offset = GET_CLK_MON_OFFSET(clock->mon_index);
-		bitmask = BIT(clock->mon_bit);
-	} else {
-		offset = GET_CLK_ON_OFFSET(clock->on_index);
-		bitmask = BIT(clock->on_bit);
-	}
-
-	return readl(priv->base + offset) & bitmask;
-}
-
 static const struct clk_ops rzv2h_mod_clock_ops = {
 	.enable = rzv2h_mod_clock_enable,
 	.disable = rzv2h_mod_clock_disable,
 	.is_enabled = rzv2h_mod_clock_is_enabled,
 };
 
-static struct rzv2h_mstop
-*rzv2h_cpg_get_mstop(struct rzv2h_cpg_priv *priv, struct mod_clock *clock, u32 mstop_data)
-{
-	struct rzv2h_mstop *mstop;
-	unsigned int i;
-
-	for (i = 0; i < priv->num_mod_clks; i++) {
-		struct mod_clock *clk;
-		struct clk_hw *hw;
-
-		if (priv->clks[priv->num_core_clks + i] == ERR_PTR(-ENOENT))
-			continue;
-
-		hw = __clk_get_hw(priv->clks[priv->num_core_clks + i]);
-		clk = to_mod_clock(hw);
-		if (!clk->mstop)
-			continue;
-
-		if (BUS_MSTOP(clk->mstop->idx, clk->mstop->mask) == mstop_data) {
-			if (rzv2h_mod_clock_is_enabled(&clock->hw)) {
-				if (refcount_read(&clk->mstop->ref_cnt))
-					refcount_inc(&clk->mstop->ref_cnt);
-				else
-					refcount_set(&clk->mstop->ref_cnt, 1);
-			}
-			return clk->mstop;
-		}
-	}
-
-	mstop = devm_kzalloc(priv->dev, sizeof(*mstop), GFP_KERNEL);
-	if (!mstop)
-		return NULL;
-
-	mstop->idx = FIELD_GET(BUS_MSTOP_IDX_MASK, (mstop_data));
-	mstop->mask = FIELD_GET(BUS_MSTOP_BITS_MASK, (mstop_data));
-	if (rzv2h_mod_clock_is_enabled(&clock->hw))
-		refcount_set(&mstop->ref_cnt, 1);
-	else
-		refcount_set(&mstop->ref_cnt, 0);
-
-	return mstop;
-}
-
 static void __init
 rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod,
 			   struct rzv2h_cpg_priv *priv)
@@ -638,6 +609,7 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod,
 	clock->no_pm = mod->no_pm;
 	clock->priv = priv;
 	clock->hw.init = &init;
+	clock->mstop_data = mod->mstop_data;
 
 	ret = devm_clk_hw_register(dev, &clock->hw);
 	if (ret) {
@@ -647,13 +619,16 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod,
 
 	priv->clks[id] = clock->hw.clk;
 
-	if (mod->mstop_data != BUS_MSTOP_NONE) {
-		clock->mstop = rzv2h_cpg_get_mstop(priv, clock, mod->mstop_data);
-		if (!clock->mstop) {
-			clk = ERR_PTR(-ENOMEM);
-			goto fail;
-		}
-	}
+	/*
+	 * Ensure the module clocks and MSTOP bits are synchronized when they are
+	 * turned ON by the bootloader. Enable MSTOP bits for module clocks that were
+	 * turned ON in an earlier boot stage. Skip critical clocks, as they will be
+	 * turned ON immediately upon registration, and the MSTOP counter will be
+	 * updated through the rzv2h_mod_clock_enable() path.
+	 */
+	if (clock->mstop_data != BUS_MSTOP_NONE &&
+	    !mod->critical && rzv2h_mod_clock_is_enabled(&clock->hw))
+		rzv2h_mod_clock_mstop_enable(priv, clock->mstop_data);
 
 	return;
 
@@ -922,6 +897,13 @@ static int __init rzv2h_cpg_probe(struct platform_device *pdev)
 	if (!clks)
 		return -ENOMEM;
 
+	priv->mstop_count = devm_kmalloc_array(dev, info->num_mstop_bits,
+					       sizeof(*priv->mstop_count), GFP_KERNEL);
+	if (!priv->mstop_count)
+		return -ENOMEM;
+	for (i = 0; i < info->num_mstop_bits; i++)
+		atomic_set(&priv->mstop_count[i], 0);
+
 	priv->resets = devm_kmemdup(dev, info->resets, sizeof(*info->resets) *
 				    info->num_resets, GFP_KERNEL);
 	if (!priv->resets)
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index f918620c4650..a772304f9057 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -193,6 +193,9 @@ struct rzv2h_reset {
  *
  * @resets: Array of Module Reset definitions
  * @num_resets: Number of entries in resets[]
+ *
+ * @num_mstop_bits: Maximum number of MSTOP bits supported, equivalent to the
+ *		    number of CPG_BUS_m_MSTOP registers multiplied by 16.
  */
 struct rzv2h_cpg_info {
 	/* Core Clocks */
@@ -209,6 +212,8 @@ struct rzv2h_cpg_info {
 	/* Resets */
 	const struct rzv2h_reset *resets;
 	unsigned int num_resets;
+
+	unsigned int num_mstop_bits;
 };
 
 extern const struct rzv2h_cpg_info r9a09g047_cpg_info;
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ