RE: [RFC PATCH 6/8] mailbox: Add RISC-V SBI message proxy (MPXY) based mailbox driver

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

 




> -----Original Message-----
> From: Anup Patel <apatel@xxxxxxxxxxxxxxxx>
> Sent: Monday, December 16, 2024 4:48 PM
> To: Michael Turquette <mturquette@xxxxxxxxxxxx>; Stephen Boyd
> <sboyd@xxxxxxxxxx>; Rob Herring <robh@xxxxxxxxxx>; Krzysztof Kozlowski
> <krzk+dt@xxxxxxxxxx>; Conor Dooley <conor+dt@xxxxxxxxxx>; Jassi Brar
> <jassisinghbrar@xxxxxxxxx>
> Cc: Palmer Dabbelt <palmer@xxxxxxxxxxx>; Paul Walmsley
> <paul.walmsley@xxxxxxxxxx>; Sunil V L <sunilvl@xxxxxxxxxxxxxxxx>; Rahul
> Pathak <rpathak@xxxxxxxxxxxxxxxx>; Leyfoon Tan
> <leyfoon.tan@xxxxxxxxxxxxxxxx>; Atish Patra <atishp@xxxxxxxxxxxxxx>;
> Andrew Jones <ajones@xxxxxxxxxxxxxxxx>; Anup Patel
> <anup@xxxxxxxxxxxxxx>; linux-clk@xxxxxxxxxxxxxxx;
> devicetree@xxxxxxxxxxxxxxx; linux-riscv@xxxxxxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx; Anup Patel <apatel@xxxxxxxxxxxxxxxx>
> Subject: [RFC PATCH 6/8] mailbox: Add RISC-V SBI message proxy (MPXY)
> based mailbox driver
> 
> Add a mailbox controller driver for the new SBI message proxy extension
> which is part of the SBI v3.0 specification.
> 
> Co-developed-by: Rahul Pathak <rpathak@xxxxxxxxxxxxxxxx>
> Signed-off-by: Rahul Pathak <rpathak@xxxxxxxxxxxxxxxx>
> Signed-off-by: Anup Patel <apatel@xxxxxxxxxxxxxxxx>
> ---
>  drivers/mailbox/Kconfig               |  11 +
>  drivers/mailbox/Makefile              |   2 +
>  drivers/mailbox/riscv-sbi-mpxy-mbox.c | 979
> ++++++++++++++++++++++++++
>  3 files changed, 992 insertions(+)
>  create mode 100644 drivers/mailbox/riscv-sbi-mpxy-mbox.c
> 

[...]

> sbi-mpxy-mbox.c
> new file mode 100644
> index 000000000000..0592df3028f9
> --- /dev/null
> +++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
> @@ -0,0 +1,979 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * RISC-V SBI Message Proxy (MPXY) mailbox controller driver
> + *
> + * Copyright (C) 2024 Ventana Micro Systems Inc.
> + */
> +
> +#include <asm/sbi.h>
> +#include <linux/cpu.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/jump_label.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/mailbox/riscv-rpmi-message.h>

> +#include <linux/mm.h>
> +#include <linux/msi.h>
> +#include <linux/module.h>
> +#include <linux/of_irq.h>
Sorting include header files based on alphanumeric.

> +#include <linux/percpu.h>
> +#include <linux/platform_device.h>
> +#include <linux/smp.h>
> +
> +/* ====== SBI MPXY extension data structures ====== */
> +
> +/* SBI MPXY MSI related channel attributes */ struct sbi_mpxy_msi_info
> +{
> +	/* Lower 32-bits of the MSI target address */
> +	u32 msi_addr_lo;
> +	/* Upper 32-bits of the MSI target address */
> +	u32 msi_addr_hi;
> +	/* MSI data value */
> +	u32 msi_data;
> +};
> +
> +/*
> + * SBI MPXY standard channel attributes.
> + *
> + * NOTE: The sequence of attribute fields are as-per the
> + * defined sequence in the attribute table in spec (or
> + * as-per the enum sbi_mpxy_attribute_id).
> + */
> +struct sbi_mpxy_channel_attrs {
> +	/* Message protocol ID */
> +	u32 msg_proto_id;
> +	/* Message protocol Version */
Don't need capital letter for "version" .

> +	u32 msg_proto_version;
> +	/* Message protocol maximum message length */
> +	u32 msg_max_len;
> +	/* Message protocol message send timeout in microseconds */
> +	u32 msg_send_timeout;
> +	/* Message protocol message completion timeout in microseconds */
> +	u32 msg_completion_timeout;
> +	/* Bit array for channel capabilities */
> +	u32 capability;
> +	/* SSE Event Id */
Same for 'event'.
> +	u32 sse_event_id;
> +	/* MSI enable/disable control knob */
> +	u32 msi_control;
> +	/* Channel MSI info */
> +	struct sbi_mpxy_msi_info msi_info;
> +	/* Events State Control */
Same here

> +	u32 events_state_ctrl;
> +};
> +
> +/*


[...]

> +
> +static int mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
> +				       void *tx, unsigned long tx_len,
> +				       void *rx, unsigned long max_rx_len,
> +				       unsigned long *rx_len)
> +{
> +	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
> +	unsigned long rx_bytes;
> +	struct sbiret sret;
> +
> +	if (!mpxy->shmem_active)
> +		return -ENODEV;
> +	if (!tx && tx_len)
> +		return -EINVAL;
> +
> +	get_cpu();
> +
> +	/* Message protocols allowed to have no data in messages */
> +	if (tx_len)
> +		memcpy(mpxy->shmem, tx, tx_len);
> +
> +	sret = sbi_ecall(SBI_EXT_MPXY,
> SBI_EXT_MPXY_SEND_MSG_WITH_RESP,
> +			 channel_id, msg_id, tx_len, 0, 0, 0);
> +	if (rx && !sret.error) {
> +		rx_bytes = sret.value;
> +		rx_bytes = min(max_rx_len, rx_bytes);

Caller should know if the rx_bytes is larger than max_rx_len?

> +		memcpy(rx, mpxy->shmem, rx_bytes);
> +		if (rx_len)
> +			*rx_len = rx_bytes;
> +	}
> +
> +	put_cpu();
> +	return sbi_err_map_linux_errno(sret.error);
> +}
> +

[...]

> +
> +static int mpxy_mbox_setup_msi(struct mbox_chan *chan,
> +			       struct mpxy_mbox_channel *mchan) {
> +	struct device *dev = mchan->mbox->dev;
> +	int rc;
> +
> +	/* Do nothing if MSI not supported */
> +	if (mchan->msi_irq == U32_MAX)
> +		return 0;
> +
> +	/* Request channel MSI handler */
> +	rc = request_threaded_irq(mchan->msi_irq,
> +				  mpxy_mbox_irq_event,
> +				  mpxy_mbox_irq_thread,
> +				  0, dev_name(dev), chan);
> +	if (rc) {
> +		dev_err(dev, "failed to request MPXY channel 0x%x IRQ\n",
> +			mchan->channel_id);
> +		return rc;
> +	}
> +
> +	/* Enable channel MSI control */
> +	mchan->attrs.msi_control = 1;
> +	rc = mpxy_write_attrs(mchan->channel_id,
> SBI_MPXY_ATTR_MSI_CONTROL,
> +			      1, &mchan->attrs.msi_control);
> +	if (rc) {
> +		dev_err(dev, "enable MSI control failed for MPXY channel
> 0x%x\n",
> +			mchan->channel_id);
> +		free_irq(mchan->msi_irq, chan);

Set mchan->attrs.msi_control = 0 if failed?

> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mpxy_mbox_cleanup_msi(struct mbox_chan *chan,
> +				  struct mpxy_mbox_channel *mchan)
> +{
> +	struct device *dev = mchan->mbox->dev;
> +	int rc;
> +
> +	/* Do nothing if MSI not supported */
> +	if (mchan->msi_irq == U32_MAX)


Should check if(!mchan->attrs.msi_control) instead of mchan->msi_irq?


> +		return;
> +
> +	/* Disable channel MSI control */
> +	mchan->attrs.msi_control = 0;
> +	rc = mpxy_write_attrs(mchan->channel_id,
> SBI_MPXY_ATTR_MSI_CONTROL,
> +			      1, &mchan->attrs.msi_control);
> +	if (rc) {
> +		dev_err(dev, "disable MSI control failed for MPXY channel
> 0x%x\n",
> +			mchan->channel_id);
> +	}
> +
> +	/* Free channel MSI handler */
> +	free_irq(mchan->msi_irq, chan);
> +}
> +
> +static int mpxy_mbox_setup_events(struct mpxy_mbox_channel *mchan) {
> +	struct device *dev = mchan->mbox->dev;
> +	int rc;
> +
> +	/* Do nothing if events state not supported */
> +	if (!mchan->have_events_state)
> +		return 0;
> +
> +	/* Enable channel events state */
> +	mchan->attrs.events_state_ctrl = 1;
> +	rc = mpxy_write_attrs(mchan->channel_id,
> SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
> +			      1, &mchan->attrs.events_state_ctrl);
> +	if (rc) {
> +		dev_err(dev, "enable events state failed for MPXY channel
> 0x%x\n",
> +			mchan->channel_id);

Should set mchan->attrs.events_state_ctrl = 0; ?

> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mpxy_mbox_cleanup_events(struct mpxy_mbox_channel
> *mchan) {
> +	struct device *dev = mchan->mbox->dev;
> +	int rc;
> +
> +	/* Do nothing if events state not supported */
> +	if (!mchan->have_events_state)
Check also if (!mchan->attrs.events_state_ctrl)?

> +		return;
> +
> +	/* Disable channel events state */
> +	mchan->attrs.events_state_ctrl = 0;
> +	rc = mpxy_write_attrs(mchan->channel_id,
> SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
> +			      1, &mchan->attrs.events_state_ctrl);
> +	if (rc) {
> +		dev_err(dev, "disbable events state failed for MPXY channel

Typo ' disbable'.

> 0x%x\n",
> +			mchan->channel_id);
> +	}
> +}
> +


[...]


> +
> +static int mpxy_mbox_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct mpxy_mbox_channel *mchan;
> +	struct mpxy_mbox *mbox;
> +	int i, msi_idx, rc;
> +	u32 *channel_ids;
> +
> +	/*
> +	 * Initialize MPXY shared memory only once. This also ensures
> +	 * that SBI MPXY mailbox is probed only once.
> +	 */
> +	if (mpxy_shmem_init_done) {
> +		dev_err(dev, "SBI MPXY mailbox already initialized\n");
> +		return -EALREADY;
> +	}
> +
> +	/* Probe for SBI MPXY extension */
> +	if (sbi_spec_version < sbi_mk_version(1, 0) ||
> +	    sbi_probe_extension(SBI_EXT_MPXY) <= 0) {
> +		dev_info(dev, "SBI MPXY extension not available\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Setup cpuhp notifier for per-CPU MPXY shared memory */
> +	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sbi-mpxy-
> shmem",
> +			  mpxy_setup_shmem, mpxy_cleanup_shmem);
> +
> +	/* Mark as MPXY shared memory initialization done */
> +	mpxy_shmem_init_done = true;
> +
> +	/* Allocate mailbox instance */
> +	mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
> +	if (!mbox)
> +		return -ENOMEM;
> +	mbox->dev = dev;
> +	platform_set_drvdata(pdev, mbox);
> +
> +	/* Find-out of number of channels */
> +	rc = mpxy_get_channel_count(&mbox->channel_count);
> +	if (rc) {
> +		dev_err(dev, "failed to get number of MPXY channels\n");
Suggest print 'rc' value when error. Same for other error messages below.

> +		return rc;
> +	}
> +	if (!mbox->channel_count) {
> +		dev_err(dev, "no MPXY channels available\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Allocate and fetch all channel IDs */
> +	channel_ids = devm_kcalloc(dev, mbox->channel_count,
> +				   sizeof(*channel_ids), GFP_KERNEL);
> +	if (!channel_ids)
> +		return -ENOMEM;
> +	rc = mpxy_get_channel_ids(mbox->channel_count, channel_ids);
> +	if (rc) {
> +		dev_err(dev, "failed to get number of MPXY channels\n");
> +		return rc;
> +	}
> +

[...]

Regards
Ley Foon





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux