diff options
author | Arnd Bergmann <arnd@arndb.de> | 2023-04-14 14:30:13 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2023-04-14 14:30:15 +0200 |
commit | 3d3b32a6dd1ebb06668c291f793fa7a34810cfe4 (patch) | |
tree | 89a88645f2403667b19f9b2b11a29caeb8312647 /drivers/soc | |
parent | 871e766df429c90c774f6720ed425bcd422e6f19 (diff) | |
parent | 4dd472bdafcb660bea17bc63a97d06e24fcb36ed (diff) | |
download | lwn-3d3b32a6dd1ebb06668c291f793fa7a34810cfe4.tar.gz lwn-3d3b32a6dd1ebb06668c291f793fa7a34810cfe4.zip |
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/Kconfig | 5 | ||||
-rw-r--r-- | drivers/soc/microchip/mpfs-sys-controller.c | 56 |
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)) { |