summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2023-04-14 15:30:13 +0300
committerArnd Bergmann <arnd@arndb.de>2023-04-14 15:30:15 +0300
commit3d3b32a6dd1ebb06668c291f793fa7a34810cfe4 (patch)
tree89a88645f2403667b19f9b2b11a29caeb8312647 /drivers/soc
parent871e766df429c90c774f6720ed425bcd422e6f19 (diff)
parent4dd472bdafcb660bea17bc63a97d06e24fcb36ed (diff)
downloadlinux-3d3b32a6dd1ebb06668c291f793fa7a34810cfe4.tar.xz
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: Conor 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: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/canaan/Kconfig5
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c56
2 files changed, 41 insertions, 20 deletions
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
index 2527cf5757ec..43ced2bf8444 100644
--- a/drivers/soc/canaan/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -3,8 +3,9 @@
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
+ select PM
+ select MFD_SYSCON
help
Canaan Kendryte K210 SoC system controller driver.
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 6e20207b5756..216d9f4ea0ce 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -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)) {