Re: [PATCH v2 4/6] clk: renesas: rzv2h: Switch MSTOP configuration to per-bit basis

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Geert,

Thank you for the review.

On Fri, Dec 27, 2024 at 3:49 PM Geert Uytterhoeven <geert@xxxxxxxxxxxxxx> wrote:
>
> Hi Prabhakar,
>
> On Mon, Dec 23, 2024 at 6:37 PM Prabhakar <prabhakar.csengg@xxxxxxxxx> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
> >
> > 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@xxxxxxxxxxxxxx>
>
> Thanks for your patch!
>
> > --- 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,
>
> Note to self: to be folded into commit 61302a455696728c ("clk: renesas:
> rzv2h: Add support for RZ/G3E SoC") in renesas-clk.
>
> >  };
> > 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,
>
> Note to self: to be folded into commit 7bd4cb3d6b7c43f0 ("clk:
> renesas: rzv2h: Add MSTOP support") in renesas-clk, just like the
> rest below.
>
> > --- 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 */
>
> If you think you need this comment, please move it two lines up,
> as it also applies to those lines.
>
> > +#define GET_MSTOP_IDX(mask)    ((FIELD_GET(BUS_MSTOP_IDX_MASK, (mask))) - 1)
>
> I think subtracting one here is the wrong abstraction (see below)...
>
As agreed below, I'll get rid of this macro.

> >
> >  #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
>
> Array of mstop values?
>
OK.

> >   * @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;
> >  };
>
> > @@ -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));
>
> No need for parentheses around mstop_data.
>
OK.

> > +       u16 mstop_index = GET_MSTOP_IDX(mstop_data);
> > +       unsigned int index = mstop_index * 16;
>
> mstop_index already has one subtracted inside GET_MSTOP_IDX(),
> because you need that for indexing priv->mstop_count[]...
>
> >         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) {
>
> Please make mstop_mask unsigned long instead of using a
> non-portable cast.
>
OK.

> > +               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));
>
> ... hence you have to re-add one here, which will be subtracted again
> inside CPG_BUS_MSTOP().
>
> So what about:
>   1. Dropping macro GET_MSTOP_IDX(),
>   2. Using mstop_index = FIELD_GET(BUS_MSTOP_BITS_MASK, mstop_data),
>      so you can call CPG_BUS_MSTOP(mstop_index) directly,
>   3. Letting priv->mstop_count point 16 entries before the allocated
>      array, so you can index it by the logical mstop number directly.
>
Something like below?

static void rzv2h_mod_clock_mstop_enable(struct rzv2h_cpg_priv *priv,
                     u32 mstop_data)
{
    unsigned long mstop_mask = FIELD_GET(BUS_MSTOP_BITS_MASK, mstop_data);
    u16 mstop_index = FIELD_GET(BUS_MSTOP_IDX_MASK, mstop_data);
    unsigned int index = (mstop_index - 1) * 16;
    atomic_t *mstop = &priv->mstop_count[index];
    unsigned long flags;
    unsigned int i;
    u32 val = 0;

    spin_lock_irqsave(&priv->rmw_lock, flags);
    for_each_set_bit(i, &mstop_mask, 16) {
        if (!atomic_read(&mstop[i]))
            val |= BIT(i) << 16;
        atomic_inc(&mstop[i]);
    }
    if (val)
        writel(val, priv->base + CPG_BUS_MSTOP(mstop_index));
    spin_unlock_irqrestore(&priv->rmw_lock, flags);
}

static void rzv2h_mod_clock_mstop_disable(struct rzv2h_cpg_priv *priv,
                      u32 mstop_data)
{
    unsigned long mstop_mask = FIELD_GET(BUS_MSTOP_BITS_MASK, mstop_data);
    u16 mstop_index = FIELD_GET(BUS_MSTOP_IDX_MASK, mstop_data);
    unsigned int index = (mstop_index - 1) * 16;
    atomic_t *mstop = &priv->mstop_count[index];
    unsigned long flags;
    unsigned int i;
    u32 val = 0;

    spin_lock_irqsave(&priv->rmw_lock, flags);
    for_each_set_bit(i, &mstop_mask, 16) {
        if (!atomic_read(&mstop[i]) ||
            atomic_dec_and_test(&mstop[i]))
            val |= BIT(i) << 16 | BIT(i);
    }
    if (val)
        writel(val, priv->base + CPG_BUS_MSTOP(mstop_index));
    spin_unlock_irqrestore(&priv->rmw_lock, flags);
}


>
> >         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]))
>
> Why the first part of the check?
> Because you only enable, and never disable, mstop bits in the initial
> synchronization in rzv2h_cpg_register_mod_clk()?
>
no, that's to avoid underflow.

> > +                       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;
>
> This may call rzv2h_mod_clock_is_enabled() twice, as readl() is a
> compiler barrier.  You can avoid that using:
>
>     bool enabled = rzv2h_mod_clock_is_enabled(hw);
>     if (enabled == enable)
>             return 0;
>
OK.

> > +
> >         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);
> >         }
> >
>
> > @@ -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);
> >
Ive updated this code, to handle a case where critical clocks are
turned ON by bootloader. Now updated code looks like below:

    /*
     * 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.
     */
    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);
    } else if (clock->mstop_data != BUS_MSTOP_NONE && mod->critical) {
        unsigned long mstop_mask = FIELD_GET(BUS_MSTOP_BITS_MASK,
clock->mstop_data);
        u16 mstop_index = FIELD_GET(BUS_MSTOP_IDX_MASK, clock->mstop_data);
        unsigned int index = (mstop_index - 1) * 16;
        atomic_t *mstop = &priv->mstop_count[index];
        unsigned long flags;
        unsigned int i;
        u32 val = 0;

        /*
         * Critical clocks are turned ON immediately upon registration, and the
         * MSTOP counter is updated through the rzv2h_mod_clock_enable() path.
         * However, if the critical clocks were already turned ON by the initial
         * bootloader, synchronize the atomic counter here and clear
the MSTOP bit.
         */
        spin_lock_irqsave(&priv->rmw_lock, flags);
        for_each_set_bit(i, &mstop_mask, 16) {
            if (atomic_read(&mstop[i]))
                continue;
            val |= BIT(i) << 16;
            atomic_inc(&mstop[i]);
        }
        if (val)
            writel(val, priv->base + CPG_BUS_MSTOP(mstop_index));
        spin_unlock_irqrestore(&priv->rmw_lock, flags);
    }

> >         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);
>
> devm_kcalloc() ...
>
> > +       if (!priv->mstop_count)
> > +               return -ENOMEM;
> > +       for (i = 0; i < info->num_mstop_bits; i++)
> > +               atomic_set(&priv->mstop_count[i], 0);
>
> ... so you don't need to zero them.
>
OK.

Cheers,
Prabhakar





[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux