Skip to contentSkip to conversation

Add Hardware Spinlock class

PATCH Superseded Benjamin Gaignard 2 participants 6 messages Nov 16, 2018 – Nov 27, 2018

Subsystems (5)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v4 cover Add Hardware Spinlock class

version 4:
- make timeout loop more robust

version 3:
- use dev_get_parent
- add Review-by

version 2:
- use -ETIMEDOUT and -ENOSYS for errors cases
- do not test if ops is valid
- remove useless include
- add a private structure to store base address
- be more verbose in configuration flag description and commit message
- log the error after hwspinlock_get_by_index()

This series add a news class to support hardware spinlock. Hardware spinlock could be used to protect critical sections of code between multi-processors.

The proposed API remain simple with only 3 functions to be called client:
- hwspinlock_get_by_index: get a hardware spinlock by integer index from device-tree node
- hwspinlock_lock_timeout: lock the hardware spinlock
- hwspinlock_unlock: unlock the hardware spinlock

Driver API offert 4 operations:
- of_xlate: translate a client's device-tree (OF) hardware specifier
- lock: lock the hardware spinlock
- unlock: unlock the hardware spinlock
- relax: wait time between two calls to lock operations

Benjamin Gaignard (4):
dm: Add Hardware Spinlock class
clk: stm32: add hardware spinlock clock
hwspinlock: add stm32 hardware spinlock support
pinctrl: stm32: make pinctrl use hwspinlock

 arch/arm/dts/stm32mp157c-ed1.dts        |   8 ++
 arch/arm/dts/stm32mp157c.dtsi           |   9 ++
 arch/sandbox/dts/test.dts               |   4 +
 arch/sandbox/include/asm/state.h        |   1 +
 configs/sandbox_defconfig               |   2 +
 configs/stm32mp15_basic_defconfig       |   2 +
 drivers/Kconfig                         |   2 +
 drivers/Makefile                        |   1 +
 drivers/clk/clk_stm32mp1.c              |   3 +
 drivers/hwspinlock/Kconfig              |  24 ++++++
 drivers/hwspinlock/Makefile             |   7 ++
 drivers/hwspinlock/hwspinlock-uclass.c  | 144 ++++++++++++++++++++++++++++++++
 drivers/hwspinlock/sandbox_hwspinlock.c |  56 +++++++++++++
 drivers/hwspinlock/stm32_hwspinlock.c   |  92 ++++++++++++++++++++
 drivers/pinctrl/pinctrl_stm32.c         |  27 ++++++
 include/dm/uclass-id.h                  |   1 +
 include/hwspinlock.h                    | 140 +++++++++++++++++++++++++++++++
 test/dm/Makefile                        |   1 +
 test/dm/hwspinlock.c                    |  40 +++++++++
 19 files changed, 564 insertions(+)
 create mode 100644 drivers/hwspinlock/Kconfig
 create mode 100644 drivers/hwspinlock/Makefile
 create mode 100644 drivers/hwspinlock/hwspinlock-uclass.c
 create mode 100644 drivers/hwspinlock/sandbox_hwspinlock.c
 create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c
 create mode 100644 include/hwspinlock.h
 create mode 100644 test/dm/hwspinlock.c
Signature · 1 line
2.15.0
#1 lore raw

PATCH v4 1/4 dm: Add Hardware Spinlock class

From: Benjamin Gaignard <[email protected]>

This is uclass for Hardware Spinlocks.
It implements two mandatory operations: lock and unlock and one optional relax operation.

---
version 4:
- make timeout loop more robust

 arch/sandbox/dts/test.dts               |   4 +
 arch/sandbox/include/asm/state.h        |   1 +
 configs/sandbox_defconfig               |   2 +
 drivers/Kconfig                         |   2 +
 drivers/Makefile                        |   1 +
 drivers/hwspinlock/Kconfig              |  16 ++++
 drivers/hwspinlock/Makefile             |   6 ++
 drivers/hwspinlock/hwspinlock-uclass.c  | 144 ++++++++++++++++++++++++++++++++
 drivers/hwspinlock/sandbox_hwspinlock.c |  56 +++++++++++++
 include/dm/uclass-id.h                  |   1 +
 include/hwspinlock.h                    | 140 +++++++++++++++++++++++++++++++
 test/dm/Makefile                        |   1 +
 test/dm/hwspinlock.c                    |  40 +++++++++
 13 files changed, 414 insertions(+)
 create mode 100644 drivers/hwspinlock/Kconfig
 create mode 100644 drivers/hwspinlock/Makefile
 create mode 100644 drivers/hwspinlock/hwspinlock-uclass.c
 create mode 100644 drivers/hwspinlock/sandbox_hwspinlock.c
 create mode 100644 include/hwspinlock.h
 create mode 100644 test/dm/hwspinlock.c
arch/sandbox/dts/test.dts +4 -0
index 57e0dd7663..50cd2f89e0 100644
@@ -712,6 +712,10 @@
 	sandbox_tee {
 		compatible = "sandbox,tee";
 	};
+
+	hwspinlock at 0 {
+		compatible = "sandbox,hwspinlock";
+	};
 };
 
 #include "sandbox_pmic.dtsi"
arch/sandbox/include/asm/state.h +1 -0
index dcb6d5f568..a5d7c6aaf3 100644
@@ -99,6 +99,7 @@ struct sandbox_state {
 
 	ulong next_tag;			/* Next address tag to allocate */
 	struct list_head mapmem_head;	/* struct sandbox_mapmem_entry */
+	bool hwspinlock;		/* Hardware Spinlock status */
 };
 
 /* Minimum space we guarantee in the state FDT when calling read/write*/
configs/sandbox_defconfig +2 -0
index 2ce336fc81..36b67be2df 100644
@@ -97,6 +97,8 @@ CONFIG_BOARD=y
 CONFIG_BOARD_SANDBOX=y
 CONFIG_PM8916_GPIO=y
 CONFIG_SANDBOX_GPIO=y
+CONFIG_DM_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_SANDBOX=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_I2C_CROS_EC_LDO=y
drivers/Kconfig +2 -0
index 927a2b87f6..7e6ca7cd3e 100644
@@ -40,6 +40,8 @@ source "drivers/fpga/Kconfig"
 
 source "drivers/gpio/Kconfig"
 
+source "drivers/hwspinlock/Kconfig"
+
 source "drivers/i2c/Kconfig"
 
 source "drivers/input/Kconfig"
drivers/Makefile +1 -0
index fb38b67541..0ef56fb416 100644
@@ -111,4 +111,5 @@ obj-$(CONFIG_W1) += w1/
 obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
 
 obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
+obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/
 endif
drivers/hwspinlock/Kconfig new file +16 -0
new file mode 100644
index 0000000000..de367fd2a9
@@ -0,0 +1,16 @@
+menu "Hardware Spinlock Support"
+
+config DM_HWSPINLOCK
+	bool "Enable U-Boot hardware spinlock support"
+	help
+	  This option enables U-Boot hardware spinlock support
+
+config HWSPINLOCK_SANDBOX
+	bool "Enable Hardware Spinlock support for Sandbox"
+	depends on SANDBOX && DM_HWSPINLOCK
+	help
+	  Enable hardware spinlock support in Sandbox. This is a dummy device that
+	  can be probed and support all the methods of HWSPINLOCK, but does not
+	  really do anything.
+
+endmenu
drivers/hwspinlock/Makefile new file +6 -0
new file mode 100644
index 0000000000..2704d6814f
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+#
+# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+
+obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o
+obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o
drivers/hwspinlock/hwspinlock-uclass.c new file +144 -0

144 lines not on this page · raw message

drivers/hwspinlock/sandbox_hwspinlock.c new file +56 -0

56 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 269a2c6e72..6193017432 100644
@@ -40,6 +40,7 @@ enum uclass_id {
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_FS_FIRMWARE_LOADER,		/* Generic loader */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
+	UCLASS_HWSPINLOCK,	/* Hardware semaphores */
 	UCLASS_FIRMWARE,	/* Firmware */
 	UCLASS_I2C,		/* I2C bus */
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
include/hwspinlock.h new file +140 -0

140 lines not on this page · raw message

test/dm/Makefile +1 -0
index b490cf2862..9b3b0bf202 100644
@@ -19,6 +19,7 @@ obj-$(CONFIG_CLK) += clk.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_FIRMWARE) += firmware.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
+obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
 obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_LED) += led.o
 obj-$(CONFIG_DM_MAILBOX) += mailbox.o
test/dm/hwspinlock.c new file +40 -0
new file mode 100644
index 0000000000..09ec38b4f3
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <hwspinlock.h>
+#include <asm/state.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Test that hwspinlock driver functions are called */
+static int dm_test_hwspinlock_base(struct unit_test_state *uts)
+{
+	struct sandbox_state *state = state_get_current();
+	struct hwspinlock hws;
+
+	ut_assertok(uclass_get_device(UCLASS_HWSPINLOCK, 0, &hws.dev));
+	ut_assertnonnull(hws.dev);
+	ut_asserteq(false, state->hwspinlock);
+
+	hws.id = 0;
+	ut_assertok(hwspinlock_lock_timeout(&hws, 1));
+	ut_asserteq(true, state->hwspinlock);
+
+	ut_assertok(hwspinlock_unlock(&hws));
+	ut_asserteq(false, state->hwspinlock);
+
+	ut_assertok(hwspinlock_lock_timeout(&hws, 1));
+	ut_assertok(!hwspinlock_lock_timeout(&hws, 1));
+
+	ut_assertok(hwspinlock_unlock(&hws));
+	ut_assertok(!hwspinlock_unlock(&hws));
+
+	return 0;
+}
+
+DM_TEST(dm_test_hwspinlock_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Signature · 1 line
2.15.0
#2 lore raw

PATCH v4 2/4 clk: stm32: add hardware spinlock clock

In reply to Benjamin Gaignard

From: Benjamin Gaignard <[email protected]>

Add hardware spinlock in the list of the clocks.

---
 drivers/clk/clk_stm32mp1.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/clk/clk_stm32mp1.c +3 -0
index 6a8c7b754f..b7c5d34fe0 100644
@@ -104,6 +104,7 @@
 #define RCC_MP_APB2ENSETR	0XA08
 #define RCC_MP_APB3ENSETR	0xA10
 #define RCC_MP_AHB2ENSETR	0xA18
+#define RCC_MP_AHB3ENSETR	0xA20
 #define RCC_MP_AHB4ENSETR	0xA28
 
 /* used for most of SELR register */
@@ -534,6 +535,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
 	STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
 	STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
 
+	STM32MP1_CLK_SET_CLR(RCC_MP_AHB3ENSETR, 11, HSEM, _UNKNOWN_SEL),
+
 	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
 	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
 	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
Signature · 1 line
2.15.0
#3 lore raw

PATCH v4 3/4 hwspinlock: add stm32 hardware spinlock support

In reply to Benjamin Gaignard

Implement hardware spinlock support for STM32MP1.

---
 arch/arm/dts/stm32mp157c-ed1.dts      |  4 ++
 arch/arm/dts/stm32mp157c.dtsi         |  9 ++++
 configs/stm32mp15_basic_defconfig     |  2 +
 drivers/hwspinlock/Kconfig            |  8 +++
 drivers/hwspinlock/Makefile           |  1 +
 drivers/hwspinlock/stm32_hwspinlock.c | 92 +++++++++++++++++++++++++++++++++++
 6 files changed, 116 insertions(+)
 create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c
arch/arm/dts/stm32mp157c-ed1.dts +4 -0
index f8b7701167..fc277dd7d2 100644
@@ -365,6 +365,10 @@
 	usb33d-supply = <&usb33>;
 };
 
+&hwspinlock {
+	status = "okay";
+};
+
 &usbphyc_port0 {
 	phy-supply = <&vdd_usb>;
 	vdda1v1-supply = <&reg11>;
arch/arm/dts/stm32mp157c.dtsi +9 -0
index 33c5981869..37cadfa30c 100644
@@ -690,6 +690,15 @@
 			status = "disabled";
 		};
 
+		hwspinlock: hwspinlock at 4c000000 {
+			compatible = "st,stm32-hwspinlock";
+			#hwlock-cells = <1>;
+			reg = <0x4c000000 0x400>;
+			clocks = <&rcc HSEM>;
+			clock-names = "hwspinlock";
+			status = "disabled";
+		};
+
 		rcc: rcc at 50000000 {
 			compatible = "st,stm32mp1-rcc", "syscon";
 			reg = <0x50000000 0x1000>;
configs/stm32mp15_basic_defconfig +2 -0
index 3bf7538089..c8409fd04e 100644
@@ -32,6 +32,8 @@ CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1"
 CONFIG_STM32_ADC=y
+CONFIG_DM_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_STM32=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_STM32F7=y
 CONFIG_LED=y
drivers/hwspinlock/Kconfig +8 -0
index de367fd2a9..96d4f5d6ca 100644
@@ -13,4 +13,12 @@ config HWSPINLOCK_SANDBOX
 	  can be probed and support all the methods of HWSPINLOCK, but does not
 	  really do anything.
 
+config HWSPINLOCK_STM32
+	bool "Enable Hardware Spinlock support for STM32"
+	depends on ARCH_STM32MP && DM_HWSPINLOCK
+	help
+	  Enable hardware spinlock support in STM32MP. Hardware spinlocks are
+	  hardware mutex which provide a synchronisation mechanism for the
+	  various processors on the SoC.
+
 endmenu
drivers/hwspinlock/Makefile +1 -0
index 2704d6814f..289b12a256 100644
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o
 obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o
+obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o
drivers/hwspinlock/stm32_hwspinlock.c new file +92 -0

92 lines not on this page · raw message

Signature · 1 line
2.15.0
#4 lore raw

PATCH v4 4/4 pinctrl: stm32: make pinctrl use hwspinlock

In reply to Benjamin Gaignard

From: Benjamin Gaignard <[email protected]>

Protect configuration registers with a hardware spinlock.

If a hwspinlock is defined in the device-tree node used it to be sure that none of the others processors on the SoC could change the configuration at the same time.

---
 arch/arm/dts/stm32mp157c-ed1.dts |  4 ++++
 drivers/pinctrl/pinctrl_stm32.c  | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)
arch/arm/dts/stm32mp157c-ed1.dts +4 -0
index fc277dd7d2..7a9b742d36 100644
@@ -369,6 +369,10 @@
 	status = "okay";
 };
 
+&pinctrl {
+	hwlocks = <&hwspinlock 0>;
+};
+
 &usbphyc_port0 {
 	phy-supply = <&vdd_usb>;
 	vdda1v1-supply = <&reg11>;
drivers/pinctrl/pinctrl_stm32.c +27 -0
index 31285cdd57..402b7803fc 100644
@@ -1,6 +1,7 @@
 #include <common.h>
 #include <dm.h>
 #include <dm/pinctrl.h>
+#include <hwspinlock.h>
 #include <asm/arch/gpio.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
@@ -19,12 +20,20 @@ static int stm32_gpio_config(struct gpio_desc *desc,
 {
 	struct stm32_gpio_priv *priv = dev_get_priv(desc->dev);
 	struct stm32_gpio_regs *regs = priv->regs;
+	struct hwspinlock *hws = dev_get_priv(dev_get_parent(desc->dev));
 	u32 index;
+	int ret;
 
 	if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 ||
 	    ctl->pupd > 2 || ctl->speed > 3)
 		return -EINVAL;
 
+	ret = hwspinlock_lock_timeout(hws, 1);
+	if (ret == -ETIME) {
+		dev_err(desc->dev, "HWSpinlock timeout\n");
+		return ret;
+	}
+
 	index = (desc->offset & 0x07) * 4;
 	clrsetbits_le32(&regs->afr[desc->offset >> 3], AFR_MASK << index,
 			ctl->af << index);
@@ -39,6 +48,8 @@ static int stm32_gpio_config(struct gpio_desc *desc,
 	index = desc->offset;
 	clrsetbits_le32(&regs->otyper, OTYPE_MSK << index, ctl->otype << index);
 
+	hwspinlock_unlock(hws);
+
 	return 0;
 }
 
@@ -176,6 +187,20 @@ static int stm32_pinctrl_set_state_simple(struct udevice *dev,
 }
 #endif /* PINCTRL_FULL */
 
+static int stm32_pinctrl_probe(struct udevice *dev)
+{
+	struct hwspinlock *hws = dev_get_priv(dev);
+	int err;
+
+	/* hwspinlock property is optional, just log the error */
+	err = hwspinlock_get_by_index(dev, 0, hws);
+	if (err)
+		debug("%s: hwspinlock_get_by_index may have failed (%d)\n",
+		      __func__, err);
+
+	return 0;
+}
+
 static struct pinctrl_ops stm32_pinctrl_ops = {
 #if CONFIG_IS_ENABLED(PINCTRL_FULL)
 	.set_state		= stm32_pinctrl_set_state,
@@ -200,4 +225,6 @@ U_BOOT_DRIVER(pinctrl_stm32) = {
 	.of_match	= stm32_pinctrl_ids,
 	.ops		= &stm32_pinctrl_ops,
 	.bind		= dm_scan_fdt_dev,
+	.probe		= stm32_pinctrl_probe,
+	.priv_auto_alloc_size = sizeof(struct hwspinlock),
 };
Signature · 1 line
2.15.0
#5 lore raw

PATCH v4 4/4 pinctrl: stm32: make pinctrl use hwspinlock

Quoted 11 lines · Benjamin Gaignard

From: Benjamin Gaignard <[email protected]>

Protect configuration registers with a hardware spinlock.

If a hwspinlock is defined in the device-tree node used it to be sure that none of the others processors on the SoC could change the configuration at the same time.

[snip]

drivers/pinctrl/pinctrl_stm32.c U_BOOT_DRIVER(pinctrl_stm32) = { · line 230

Quoted 7 lines
drivers/pinctrl/pinctrl_stm32.c +2 -0
@@ -200,4 +225,6 @@ U_BOOT_DRIVER(pinctrl_stm32) = {
 	.of_match	= stm32_pinctrl_ids,
 	.ops		= &stm32_pinctrl_ops,
 	.bind		= dm_scan_fdt_dev,
+	.probe		= stm32_pinctrl_probe,
+	.priv_auto_alloc_size = sizeof(struct hwspinlock),
 };

This hunk here no longer applies directly and it's not obviously correct to me how to fix it without also testing on hardware to be confident. Please rebase the series, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181126/87fc28fc/attachment.sig>