Unverified Commit 3d3b32a6 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'riscv-soc-for-v6.4' of...

Merge tag 'riscv-soc-for-v6.4' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux

 into soc/drivers

RISC-V SoC drivers for v6.4

Microchip:
Mailbox controller & client changes for the system controller on
PolarFire SoC. The controller bits have been acked by Jassi.
Primarily the changes work around a "hardware" bug (really the system
controller's software, but it may as well be hardware as customers
cannot change it) where interrupts are not generated if a service fails.
The mailbox controller driver is tweaked to use polling, rather than
interrupt, mode and there are some changes to timeout code required in
the client driver as a result. There's some opportunistic cleanup that I
performed while doing the swap too.

Canaan:
A single fix for some randconfig issues that crop up when !mmu is
enabled for 32-bit kernels, due to my changes in a previous release that
swapped out select based entablement of the driver.

Signed-off-by: default avatarConor Dooley <conor.dooley@microchip.com>

* tag 'riscv-soc-for-v6.4' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux:
  soc: microchip: mpfs: add a prefix to rx_callback()
  soc: microchip: mpfs: handle timeouts and failed services differently
  soc: microchip: mpfs: simplify error handling in mpfs_blocking_transaction()
  soc: microchip: mpfs: use a consistent completion timeout
  soc: microchip: mpfs: fix some horrible alignment
  mailbox: mpfs: check the service status in .tx_done()
  mailbox: mpfs: ditch a useless busy check
  mailbox: mpfs: switch to txdone_poll
  mailbox: mpfs: fix an incorrect mask width
  soc: canaan: Make K210_SYSCTL depend on CLK_K210

Link: https://lore.kernel.org/r/20230406-islamist-mop-81d651b8830d@spud


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 871e766d 4dd472bd
Loading
Loading
Loading
Loading
+31 −24
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@
#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)

#define SCB_CTRL_POS (16)
#define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH - 1, SCB_CTRL_POS)

/* SCBCTRL service status register */

@@ -79,6 +79,27 @@ static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
	return status & SCB_STATUS_BUSY_MASK;
}

static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan)
{
	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
	struct mpfs_mss_response *response = mbox->response;
	u32 val;

	if (mpfs_mbox_busy(mbox))
		return false;

	/*
	 * The service status is stored in bits 31:16 of the SERVICES_SR
	 * register & is only valid when the system controller is not busy.
	 * Failed services are intended to generated interrupts, but in reality
	 * this does not happen, so the status must be checked here.
	 */
	val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
	response->resp_status = (val & SCB_STATUS_MASK) >> SCB_STATUS_POS;

	return true;
}

static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
{
	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
@@ -118,6 +139,7 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
	}

	opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));

	tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK;
	tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
	writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET);
@@ -130,7 +152,7 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
	struct mpfs_mss_response *response = mbox->response;
	u16 num_words = ALIGN((response->resp_size), (4)) / 4U;
	u32 i, status;
	u32 i;

	if (!response->resp_msg) {
		dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
@@ -138,8 +160,6 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
	}

	/*
	 * The status is stored in bits 31:16 of the SERVICES_SR register.
	 * It is only valid when BUSY == 0.
	 * We should *never* get an interrupt while the controller is
	 * still in the busy state. If we do, something has gone badly
	 * wrong & the content of the mailbox would not be valid.
@@ -150,25 +170,11 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
		return;
	}

	status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);

	/*
	 * If the status of the individual servers is non-zero, the service has
	 * failed. The contents of the mailbox at this point are not be valid,
	 * so don't bother reading them. Set the status so that the driver
	 * implementing the service can handle the result.
	 */
	response->resp_status = (status & SCB_STATUS_MASK) >> SCB_STATUS_POS;
	if (response->resp_status)
		return;

	if (!mpfs_mbox_busy(mbox)) {
	for (i = 0; i < num_words; i++) {
		response->resp_msg[i] =
			readl_relaxed(mbox->mbox_base
				      + mbox->resp_offset + i * 0x4);
	}
	}

	mbox_chan_received_data(chan, response);
}
@@ -182,7 +188,6 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)

	mpfs_mbox_rx_data(chan);

	mbox_chan_txdone(chan, 0);
	return IRQ_HANDLED;
}

@@ -212,6 +217,7 @@ static const struct mbox_chan_ops mpfs_mbox_ops = {
	.send_data = mpfs_mbox_send_data,
	.startup = mpfs_mbox_startup,
	.shutdown = mpfs_mbox_shutdown,
	.last_tx_done = mpfs_mbox_last_tx_done,
};

static int mpfs_mbox_probe(struct platform_device *pdev)
@@ -247,7 +253,8 @@ static int mpfs_mbox_probe(struct platform_device *pdev)
	mbox->controller.num_chans = 1;
	mbox->controller.chans = mbox->chans;
	mbox->controller.ops = &mpfs_mbox_ops;
	mbox->controller.txdone_irq = true;
	mbox->controller.txdone_poll = true;
	mbox->controller.txpoll_period = 10u;

	ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
	if (ret) {
+3 −2
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
config SOC_K210_SYSCTL
	bool "Canaan Kendryte K210 SoC system controller"
	depends on RISCV && SOC_CANAAN && OF
	depends on COMMON_CLK_K210
	default SOC_CANAAN
	select PM
	select MFD_SYSCON
+38 −18
Original line number Diff line number Diff line
@@ -11,12 +11,19 @@
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/mailbox_client.h>
#include <linux/platform_device.h>
#include <soc/microchip/mpfs.h>

/*
 * This timeout must be long, as some services (example: image authentication)
 * take significant time to complete
 */
#define MPFS_SYS_CTRL_TIMEOUT_MS 30000

static DEFINE_MUTEX(transaction_lock);

struct mpfs_sys_controller {
@@ -28,35 +35,47 @@ struct mpfs_sys_controller {

int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
{
	int ret, err;
	unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
	int ret;

	err = mutex_lock_interruptible(&transaction_lock);
	if (err)
		return err;
	ret = mutex_lock_interruptible(&transaction_lock);
	if (ret)
		return ret;

	reinit_completion(&sys_controller->c);

	ret = mbox_send_message(sys_controller->chan, msg);
	if (ret >= 0) {
		if (wait_for_completion_timeout(&sys_controller->c, HZ)) {
			ret = 0;
		} else {
			ret = -ETIMEDOUT;
			dev_warn(sys_controller->client.dev,
				 "MPFS sys controller transaction timeout\n");
	if (ret < 0) {
		dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n");
		goto out;
	}

	/*
	 * Unfortunately, the system controller will only deliver an interrupt
	 * if a service succeeds. mbox_send_message() will block until the busy
	 * flag is gone. If the busy flag is gone but no interrupt has arrived
	 * to trigger the rx callback then the service can be deemed to have
	 * failed.
	 * The caller can then interrogate msg::response::resp_status to
	 * determine the cause of the failure.
	 * mbox_send_message() returns positive integers in the success path, so
	 * ret needs to be cleared if we do get an interrupt.
	 */
	if (!wait_for_completion_timeout(&sys_controller->c, timeout)) {
		ret = -EBADMSG;
		dev_warn(sys_controller->client.dev, "MPFS sys controller service failed\n");
	} else {
		dev_err(sys_controller->client.dev,
			"mpfs sys controller transaction returned %d\n", ret);
		ret = 0;
	}

out:
	mutex_unlock(&transaction_lock);

	return ret;
}
EXPORT_SYMBOL(mpfs_blocking_transaction);

static void rx_callback(struct mbox_client *client, void *msg)
static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg)
{
	struct mpfs_sys_controller *sys_controller =
		container_of(client, struct mpfs_sys_controller, client);
@@ -66,8 +85,8 @@ static void rx_callback(struct mbox_client *client, void *msg)

static void mpfs_sys_controller_delete(struct kref *kref)
{
	struct mpfs_sys_controller *sys_controller = container_of(kref, struct mpfs_sys_controller,
					       consumers);
	struct mpfs_sys_controller *sys_controller =
		container_of(kref, struct mpfs_sys_controller, consumers);

	mbox_free_channel(sys_controller->chan);
	kfree(sys_controller);
@@ -102,8 +121,9 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
		return -ENOMEM;

	sys_controller->client.dev = dev;
	sys_controller->client.rx_callback = rx_callback;
	sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback;
	sys_controller->client.tx_block = 1U;
	sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);

	sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
	if (IS_ERR(sys_controller->chan)) {