[PATCH v3 10/23] clk: Add clock driver for the RISC-V RPMI clock service group

Andy Shevchenko andriy.shevchenko at linux.intel.com
Mon May 12 00:07:56 PDT 2025


On Sun, May 11, 2025 at 07:09:26PM +0530, Anup Patel wrote:
> From: Rahul Pathak <rpathak at ventanamicro.com>
> 
> The RPMI specification defines a clock service group which can be
> accessed via SBI MPXY extension or dedicated S-mode RPMI transport.
> 
> Add mailbox client based clock driver for the RISC-V RPMI clock
> service group.

...

> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/mailbox/riscv-rpmi-message.h>

Just to point out again that the above misses a lot of headers definitions
and/or APIs this driver uses. Follow IWYU principle.

...

> +#define GET_RATE_U64(hi_u32, lo_u32)	((u64)(hi_u32) << 32 | (lo_u32))

Hmm... Perhaps add this kind of macro to wordpart.h ? IIRC not only this driver
uses something like this.

...

> +enum rpmi_clk_type {
> +	RPMI_CLK_DISCRETE = 0,
> +	RPMI_CLK_LINEAR = 1,

> +	RPMI_CLK_TYPE_MAX_IDX,

No comma for the terminator. Please, clean all these cases.

> +};

...

> +union rpmi_clk_rates {
> +	u64 discrete[RPMI_CLK_DISCRETE_MAX_NUM_RATES];
> +	struct {
> +		u64 min;
> +		u64 max;
> +		u64 step;
> +	} linear;

Have you looked at the linear ranges library we have in the kernel? Can you
utilise it here?

> +};

...

> +struct rpmi_clk {
> +	struct rpmi_clk_context *context;
> +	u32 id;
> +	u32 num_rates;
> +	u32 transition_latency;
> +	enum rpmi_clk_type type;
> +	union rpmi_clk_rates *rates;
> +	char name[RPMI_CLK_NAME_LEN];
> +	struct clk_hw hw;

Just a reminder to use `pahole` to check that your data layout is optimised for
memory consumption.

> +};

...

> +struct rpmi_get_supp_rates_rx {
> +	u32 status;
> +	u32 flags;
> +	u32 remaining;
> +	u32 returned;
> +	u32 rates[];
> +};

Is it ABI? (I mean if this is interface with some kind of FW)
If so, Use proper endianess aware types. Same Q for all data
types defined in this driver.

...

> +			for (j = 0; j < rx->returned; j++) {
> +				if (rateidx >= (clk_rate_idx + rx->returned))

Too many parentheses.

> +					break;
> +				rpmi_clk->rates->discrete[rateidx++] =
> +					GET_RATE_U64(rate_discrete[j].hi,
> +						     rate_discrete[j].lo);
> +			}
> +		}

...

> +	devm_kfree(context->dev, rx);

Why?! This is a red flag to point that here is misunderstanding or abuse of
managed resources approach. Either use __Free() from cleanup.h or don't call
devm_kfree(). The latter must have a very good justification to explain why.

> +	return 0;

(this is even not an error path, where it might have a little argument for)

...

> +	/* Keep the requested rate if the clock format
> +	 * is of discrete type. Let the platform which
> +	 * is actually controlling the clock handle that.
> +	 */

/*
 * Use proper style for the multi-line comments. You can
 * refer to this comment as an example.
 */

...

> +out:

Redundant label. Note, the labels are recommended to be named after the flow
they will run if goto. This one can be named as out_literally_with_return_0,
which makes it obvious how useless it is.

> +	return 0;

...

> +	rates = devm_kzalloc(dev, sizeof(union rpmi_clk_rates), GFP_KERNEL);

sizeof(*...)

> +	if (!rates)
> +		return ERR_PTR(-ENOMEM);
> +
> +	rpmi_clk = devm_kzalloc(dev, sizeof(struct rpmi_clk), GFP_KERNEL);

Ditto.

> +	if (!rpmi_clk)
> +		return ERR_PTR(-ENOMEM);

...

> +	ret = rpmi_clk_get_supported_rates(clkid, rpmi_clk);
> +	if (ret)
> +		return dev_err_ptr_probe(dev, ret,
> +			"Get supported rates failed for clk-%u, %d\n", clkid, ret);

Indentation issues. Repetitive ret in the message. Please, get familiar with
the format dev_err_probe() uses.

...

> +	int ret, num_clocks, i;

Why is 'i' signed?

...

> +	/* Allocate RPMI clock context */
> +	context = devm_kzalloc(dev, sizeof(*context), GFP_KERNEL);

Ha-ha, you have even inconsistent style in the same file! So, go through the
whole series and make sure that the style used in each file is consistent.

> +	if (!context)
> +		return -ENOMEM;

...

> +	/* Validate RPMI specification version */
> +	rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SPEC_VERSION);
> +	ret = rpmi_mbox_send_message(context->chan, &msg);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to get spec version\n");
> +		goto fail_free_channel;

This is simply wrong. You should not do goto before any devm_*() calls.
The error path and ->remove(), if present) is broken. Fix it accordingly.

Here should be

		return dev_err_probe(...);

it's your homework to understand how to achieve that. Plenty of the examples in
the kernel.

> +	}

...

> +enum rpmi_clock_service_id {
> +	RPMI_CLK_SRV_ENABLE_NOTIFICATION = 0x01,
> +	RPMI_CLK_SRV_GET_NUM_CLOCKS = 0x02,
> +	RPMI_CLK_SRV_GET_ATTRIBUTES = 0x03,
> +	RPMI_CLK_SRV_GET_SUPPORTED_RATES = 0x04,
> +	RPMI_CLK_SRV_SET_CONFIG = 0x05,
> +	RPMI_CLK_SRV_GET_CONFIG = 0x06,
> +	RPMI_CLK_SRV_SET_RATE = 0x07,
> +	RPMI_CLK_SRV_GET_RATE = 0x08,

> +	RPMI_CLK_SRV_ID_MAX_COUNT,

No comma in the terminator line.

> +};

-- 
With Best Regards,
Andy Shevchenko





More information about the linux-riscv mailing list