devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
To: conor.dooley@microchip.com
Cc: robh+dt@kernel.org, damien.lemoal@wdc.com,
	jassisinghbrar@gmail.com, aou@eecs.berkeley.edu,
	paul.walmsley@sifive.com, palmer@dabbelt.com,
	devicetree@vger.kernel.org, linux-riscv@lists.infradead.org,
	lewis.hanly@microchip.com, cyril.jean@microchip.com,
	daire.mcnamara@microchip.com, atish.patra@wdc.com,
	anup.patel@wdc.com, david.abdurachmanov@gmail.com,
	j.neuschaefer@gmx.net
Subject: Re: [PATCH v3 1/5] mbox: add polarfire soc system controller mailbox
Date: Sat, 2 Jan 2021 14:01:45 +0100	[thread overview]
Message-ID: <X/BuucfqPGpE/S1r@latitude> (raw)
In-Reply-To: <20201223163255.28992-1-conor.dooley@microchip.com>

[-- Attachment #1: Type: text/plain, Size: 8544 bytes --]

Hello,

I've added review comments below. Some of them might be more detailed
than necessary, and reflect my opinion rather than something that must
be fixed. Anyway, I hope my comments make sense.

On Wed, Dec 23, 2020 at 04:32:55PM +0000, conor.dooley@microchip.com wrote:
> From: Conor Dooley <conor.dooley@microchip.com>
> 
> This driver adds support for the single mailbox channel of the MSS
> system controller on the Microchip PolarFire SoC.
> 
> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
> ---
[...]
> +#define SERVICES_CR_OFFSET		0x50u
> +#define SERVICES_SR_OFFSET		0x54u
> +#define MAILBOX_REG_OFFSET		0x800u
> +#define MSS_SYS_BUSY			-EBUSY
> +#define MSS_SYS_PARAM_ERR		-EINVAL

Defining your own aliases for -Esomething is rather uncommon.

> +#define MSS_SYS_MAILBOX_DATA_OFFSET	0u
> +#define SCB_MASK_WIDTH			16u
> +
> +/* SCBCTRL service control register */
> +
> +#define SCB_CTRL_REQ (0)
> +#define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ)
> +
> +#define SCB_CTRL_BUSY (1)
> +#define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY)
> +
> +#define SCB_CTRL_ABORT (2)
> +#define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT)
> +
> +#define SCB_CTRL_NOTIFY (3)
> +#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
> +
> +#define SCB_CTRL_POS (16)
> +#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
> +
> +/* SCBCTRL service status registers */

registers -> register ?
It seems to be only one status register.

> +
> +#define SCB_STATUS_REQ (0)
> +#define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ)
> +
> +#define SCB_STATUS_BUSY (1)
> +#define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY)
> +
> +#define SCB_STATUS_ABORT (2)
> +#define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT)
> +
> +#define SCB_STATUS_NOTIFY (3)
> +#define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY)
> +
> +#define SCB_STATUS_POS (16)
> +#define SCB_STATUS_MASK GENMASK(SCB_STATUS_POS + SCB_MASK_WIDTH, SCB_STATUS_POS)
> +
> +struct mpfs_mbox {
> +	struct mbox_controller controller;
> +	struct device *dev;
> +	int irq;
> +	void __iomem *mailbox_base;
> +	void __iomem *int_reg;
> +	struct mbox_chan *chan;
> +	u16 response_size;
> +	u16 response_offset;
> +};
> +
> +static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
> +{
> +	u32 status;
> +
> +	status = readl_relaxed(mbox->mailbox_base + SERVICES_SR_OFFSET);
> +
> +	return status & SCB_STATUS_BUSY_MASK;
> +}
> +
> +static struct mpfs_mbox *mbox_chan_to_mpfs_mbox(struct mbox_chan *chan)
> +{
> +	if (!chan)
> +		return NULL;
> +
> +	return (struct mpfs_mbox *)chan->con_priv;
> +}
> +
> +static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
> +{
> +	u32 index;
> +	u32 *word_buf;
> +	u8 *byte_buf;
> +	u8 byte_off;
> +	u8 extra_bits;
> +	u8 i;
> +	u32 mailbox_val = 0u;
> +	u16 mbox_offset;
> +	u16 mbox_options_select;
> +	u32 mbox_tx_trigger;

the mbox_ prefix seems unnecessary because the whole driver deals with
a mailbox.

Some of the variables are only used in if/for scopes below. I'd move
their declaration down into these scopes, to make the outer scope of the
function a little easier to understand.

> +	struct mpfs_mss_msg *msg = data;
> +	struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
> +
> +	mbox_offset = msg->mailbox_offset;

mbox_offset is only used once. The indirection of storing the value in
another variable makes the code slightly slower to read, IMO.

> +	mbox->response_size = msg->response_size;
> +	mbox->response_offset = msg->response_offset;
> +
> +	if (mpfs_mbox_busy(mbox))
> +		return MSS_SYS_BUSY;
> +
> +	mbox_options_select = ((mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));
> +	mbox_tx_trigger = (((mbox_options_select << SCB_CTRL_POS) &
> +		SCB_CTRL_MASK) | SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK);

Slightly reformatted, you could save a few parentheses:

	mbox_options_select = (mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu);
	mbox_tx_trigger = (mbox_options_select << SCB_CTRL_POS) & SCB_CTRL_MASK;
	mbox_tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;


> +	/* Code for MSS_SYS_PARAM_ERR is not implemented with this version of driver. */

What is the "code for MSS_SYS_PARAM_ERR" semantically? Input validation?

> +	writel_relaxed(0, mbox->int_reg);

What does a write to mbox->int_reg do? Does it acknowledge an interrupt?
It would be interesting to have an explaining comment here.

> +
> +	if (msg->cmd_data_size) {
> +		byte_buf = msg->cmd_data;
> +
> +		for (index = 0; index < (msg->cmd_data_size / 4); index++)
> +			writel_relaxed(word_buf[index],
> +				       mbox->mailbox_base + MAILBOX_REG_OFFSET + index);

word_buf is uninitialized.

In mpfs_mbox_rx_data, you access the registers at mbox->mailbox_base +
MAILBOX_REG_OFFSET in steps of four bytes, here you increment the offset
in steps of one byte, because the index isn't scaled. This seems wrong.

> +		extra_bits = msg->cmd_data_size & 3;
> +		if (extra_bits) {
> +			byte_off = ALIGN_DOWN(msg->cmd_data_size, 4);
> +			byte_buf = msg->cmd_data + byte_off;
> +
> +			mailbox_val = readl_relaxed(mbox->mailbox_base +
> +						    MAILBOX_REG_OFFSET + index);
> +
> +			for (i = 0u; i < extra_bits; i++) {
> +				mailbox_val &= ~(0xffu << (i * 8u));
> +				mailbox_val |= (byte_buf[i] << (i * 8u));
> +			}
> +
> +			writel_relaxed(mailbox_val,
> +				       mbox->mailbox_base + MAILBOX_REG_OFFSET + index);
> +		}
> +	}
> +

I'd move the calculation of mbox_tx_trigger down here, right before its
use, because it's not necessary for the code above (if I'm reading it
correctly).

> +	writel_relaxed(mbox_tx_trigger, mbox->mailbox_base + SERVICES_CR_OFFSET);
> +
> +	return 0;
> +}
> +
> +static inline bool mpfs_mbox_pending(struct mpfs_mbox *mbox)
> +{
> +	u32 status;
> +
> +	status = readl_relaxed(mbox->mailbox_base + SERVICES_SR_OFFSET);
> +
> +	return !(status & SCB_STATUS_BUSY_MASK);
> +}
> +
> +static void mpfs_mbox_rx_data(struct mbox_chan *chan)
> +{
> +	struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
> +	u32 *data;
> +	u32 i;
> +	u32 response_limit;
> +
> +	data = devm_kzalloc(mbox->dev, sizeof(*data) * mbox->response_size, GFP_ATOMIC);

The use of devm_ seems bogus here, because the allocated data does not
have the same lifetime as the device; it is allocated and freed for
every RX event.

However, please use kcalloc instead of kzalloc, so you don't have to do
the multiplication manually. kcalloc checks for overflows.

> +	if (!data)
> +		dev_err(mbox->dev, "failed to assign memory for response\n", -ENOMEM);

There is no format specifier for parameter -ENOMEM.

In the !data case, the code will still run into the loop below, and
probably cause a crash.

> +
> +	response_limit = mbox->response_size + mbox->response_offset;
> +	if (mpfs_mbox_pending(mbox) && mbox->response_size > 0U) {
> +		for (i = mbox->response_offset; i < response_limit; i++) {
> +			data[i - mbox->response_offset] =
> +				readl_relaxed(mbox->mailbox_base + MAILBOX_REG_OFFSET + i * 0x4);
> +		}
> +	}

It seems slightly easier to me to let the loop run from zero to
mbox->response_size-1. Most importantly, it becomes easy to see that
data is not accessed out of bounds.  (But it's your choice)

	if (mpfs_mbox_pending(mbox)) {
		for (i = 0; i < mbox->response_size; i++) {
			data[i] = readl_relaxed(mbox->mailbox_base + MAILBOX_REG_OFFSET +
			                        (i + mbox->response_offset) * 0x4);
		}
	}


> +
> +	mbox_chan_received_data(chan, (void *)data);
> +	devm_kfree(mbox->dev, data);
> +}
> +
> +static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
> +{
> +	struct mbox_chan *chan = (struct mbox_chan *)data;

This cast and the one at the end of mpfs_mbox_rx_data are somewhat
uncessary, because C allows implicit conversion of void pointers to and
from other pointer types.

> +	struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
> +
> +	writel_relaxed(0, mbox->int_reg);
> +
> +	mpfs_mbox_rx_data(chan);
> +
> +	mbox_chan_txdone(chan, 0);
> +	return IRQ_HANDLED;
> +}
[...]
> +++ b/include/soc/microchip/mpfs.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + *
> + * Microchip PolarFire SoC (MPFS) mailbox

This is mpfs.h, but the comment implies it's only for mailbox-related
code, not for all of the Microchip PolarFire SoC. Is this intentional?


Best regards,
Jonathan Neuschäfer

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2021-01-02 13:04 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-23 16:32 [PATCH v3 0/5] Add support for the PolarFire SoC system controller conor.dooley
2020-12-23 16:32 ` [PATCH v3 1/5] mbox: add polarfire soc system controller mailbox conor.dooley
2021-01-02 13:01   ` Jonathan Neuschäfer [this message]
2021-01-21 12:46     ` Conor.Dooley
2021-01-21 13:38       ` Jonathan Neuschäfer
2020-12-23 16:33 ` [PATCH v3 2/5] dt-bindings: add bindings for polarfire soc mailbox conor.dooley
2020-12-31 18:34   ` Rob Herring
2021-01-02 11:30   ` Jonathan Neuschäfer
2020-12-23 16:33 ` [PATCH v3 4/5] dt-bindings: add bindings for polarfire soc system controller conor.dooley
2021-01-05 21:25   ` Jonathan Neuschäfer
2021-01-08  2:31   ` Rob Herring
2021-01-06 19:25 ` [PATCH v3 0/5] Add support for the PolarFire SoC " Atish Patra
2021-01-07 11:49   ` Cyril.Jean

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=X/BuucfqPGpE/S1r@latitude \
    --to=j.neuschaefer@gmx.net \
    --cc=anup.patel@wdc.com \
    --cc=aou@eecs.berkeley.edu \
    --cc=atish.patra@wdc.com \
    --cc=conor.dooley@microchip.com \
    --cc=cyril.jean@microchip.com \
    --cc=daire.mcnamara@microchip.com \
    --cc=damien.lemoal@wdc.com \
    --cc=david.abdurachmanov@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=jassisinghbrar@gmail.com \
    --cc=lewis.hanly@microchip.com \
    --cc=linux-riscv@lists.infradead.org \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).