Skip to contentSkip to conversation

Turris Omnia MCU driver

PATCH Superseded Marek Behún 8 participants 34 messages Mar 23, 2024 – Apr 2, 2024 1 message not in the archive

Subsystems (16)

v5 of 13 Superseded Latest is v13 →

lore
Share & tools
lore

Marek Behún

author maintainer
#0 lore raw

v5 cover Turris Omnia MCU driver

Hello Andy, Linus, Arnd, Gregory, and others,

I am sending v5 of the series adding Turris Omnia MCU driver. See the cover letters for v1, v2, v3 and v4:
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/

Changes since v4:
- added new patches
06/11 devm-helpers: Add resource managed version of irq_create_mapping() 07/11 platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG 08/11 devm-helpers: Add resource managed version of debugfs directory create
function
09/11 platform: cznic: turris-omnia-mcu: Add support for digital message
signing via debugfs
- for changes specific to patches which were also sent in previous versions see the notes in those patches

Marek Behún (11):
dt-bindings: arm: add cznic,turris-omnia-mcu binding
platform: cznic: Add preliminary support for Turris Omnia MCU
platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
platform: cznic: turris-omnia-mcu: Add support for MCU watchdog
devm-helpers: Add resource managed version of irq_create_mapping()
platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG
devm-helpers: Add resource managed version of debugfs directory create
function
platform: cznic: turris-omnia-mcu: Add support for digital message
signing via debugfs
ARM: dts: turris-omnia: Add MCU system-controller node
ARM: dts: turris-omnia: Add GPIO key node for front button

 .../ABI/testing/debugfs-turris-omnia-mcu      |   13 +
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  126 ++
 .../bindings/arm/cznic,turris-omnia-mcu.yaml  |   86 ++
 MAINTAINERS                                   |    5 +
 .../dts/marvell/armada-385-turris-omnia.dts   |   35 +-
 drivers/crypto/caam/ctrl.c                    |   16 +-
 drivers/crypto/caam/jr.c                      |    8 +-
 drivers/gpio/gpio-mockup.c                    |   11 +-
 drivers/gpu/drm/bridge/ti-sn65dsi86.c         |   13 +-
 drivers/hwmon/hp-wmi-sensors.c                |   15 +-
 drivers/hwmon/mr75203.c                       |   15 +-
 drivers/hwmon/pmbus/pmbus_core.c              |   16 +-
 drivers/platform/Kconfig                      |    2 +
 drivers/platform/Makefile                     |    1 +
 drivers/platform/cznic/Kconfig                |   51 +
 drivers/platform/cznic/Makefile               |   10 +
 .../platform/cznic/turris-omnia-mcu-base.c    |  406 +++++++
 .../platform/cznic/turris-omnia-mcu-debugfs.c |  216 ++++
 .../platform/cznic/turris-omnia-mcu-gpio.c    | 1056 +++++++++++++++++
 .../cznic/turris-omnia-mcu-sys-off-wakeup.c   |  258 ++++
 .../platform/cznic/turris-omnia-mcu-trng.c    |   89 ++
 .../cznic/turris-omnia-mcu-watchdog.c         |  122 ++
 drivers/platform/cznic/turris-omnia-mcu.h     |  214 ++++
 include/linux/devm-helpers.h                  |   94 ++
 include/linux/turris-omnia-mcu-interface.h    |  238 ++++
 25 files changed, 3044 insertions(+), 72 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-turris-omnia-mcu
 create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
 create mode 100644 Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
 create mode 100644 drivers/platform/cznic/Kconfig
 create mode 100644 drivers/platform/cznic/Makefile
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-debugfs.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-trng.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h
 create mode 100644 include/linux/turris-omnia-mcu-interface.h
Signature · 1 line
2.43.2
author maintainer
#1 lore raw

PATCH v5 1/11 dt-bindings: arm: add cznic,turris-omnia-mcu binding

Add binding for cznic,turris-omnia-mcu, the device-tree node representing the system-controller features provided by the MCU on the Turris Omnia router.

---
Changes from v4:
- #gpio-cells changed from 2 (pin number, flags) to 3 (bank, pin number, flags). This is because two years ago we added device-tree fixing code into U-Boot [1] which adds reset-gpios to PCIe controller nodes if these GPIOs are controllable via MCU, and the code adds the gpio specifiers to have 3 cells. Implementing this driver with twocell specifier breaks PCIe functionality for users which have upgraded U-Boot
- added documentation for #interrupt-cells and #gpio-cells

[1] https://source.denx.de/u-boot/u-boot/-/commit/1da53ae26afc

---
 .../bindings/arm/cznic,turris-omnia-mcu.yaml  | 86 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 87 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml new file +86 -0
new file mode 100644
index 000000000000..dd9ee21ee24d
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/cznic,turris-omnia-mcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CZ.NIC's Turris Omnia MCU
+
+maintainers:
+  - Marek Behún <[email protected]>
+
+description:
+  The MCU on Turris Omnia acts as a system controller providing additional
+  GPIOs, interrupts, watchdog, system power off and wakeup configuration.
+
+properties:
+  compatible:
+    const: cznic,turris-omnia-mcu
+
+  reg:
+    description: MCU I2C slave address
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+    description: |
+      The first cell specifies the interrupt number (0 to 63), the second cell
+      specifies interrupt type (which can be one of IRQ_TYPE_EDGE_RISING,
+      IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH).
+      The interrupt numbers correspond sequentially to GPIO numbers, taking the
+      GPIO banks into account:
+        IRQ number   GPIO bank   GPIO pin within bank
+           0 - 15      0           0 - 15
+          16 - 47      1           0 - 31
+          48 - 63      2           0 - 15
+      There are several exceptions:
+        IRQ number   meaning
+          11           LED panel brightness changed by button press
+          13           TRNG entropy ready
+          14           ECDSA message signature computation done
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+    description:
+      The first cell is bank number (0, 1 or 2), the second cell is pin number
+      within the bank (0 to 15 for banks 0 and 2, 0 to 31 for bank 1), and the
+      third cell specifies consumer flags.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - gpio-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        system-controller@2a {
+            compatible = "cznic,turris-omnia-mcu";
+            reg = <0x2a>;
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <11 IRQ_TYPE_NONE>;
+
+            gpio-controller;
+            #gpio-cells = <3>;
+
+            interrupt-controller;
+            #interrupt-cells = <2>;
+        };
+    };
MAINTAINERS +1 -0
index aa3b947fb080..89edfc2b875b 100644
@@ -2141,6 +2141,7 @@ W:	https://www.turris.cz/
 F:	Documentation/ABI/testing/debugfs-moxtet
 F:	Documentation/ABI/testing/sysfs-bus-moxtet-devices
 F:	Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
+F:	Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
 F:	Documentation/devicetree/bindings/bus/moxtet.txt
 F:	Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
 F:	Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
Signature · 1 line
2.43.2
#2 lore raw

Re: [PATCH v5 01/11] dt-bindings: arm: add cznic,turris-omnia-mcu binding

Quoted 6 lines · Marek Behún

Add binding for cznic,turris-omnia-mcu, the device-tree node representing the system-controller features provided by the MCU on the Turris Omnia router.

Quoted 10 lines

---
Changes from v4:
- #gpio-cells changed from 2 (pin number, flags) to 3 (bank, pin number, flags). This is because two years ago we added device-tree fixing code into U-Boot [1] which adds reset-gpios to PCIe controller nodes if these GPIOs are controllable via MCU, and the code adds the gpio specifiers to have 3 cells. Implementing this driver with twocell specifier breaks PCIe functionality for users which have upgraded U-Boot
- added documentation for #interrupt-cells and #gpio-cells

Please use scripts/get_maintainers.pl to get a list of necessary people and lists to CC. It might happen, that command when run on an older kernel, gives you outdated entries. Therefore please be sure you base your patches on recent Linux kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of people, so fix your workflow. Tools might also fail if you work on some ancient tree (don't, instead use mainline), work on fork of kernel (don't, instead use mainline) or you ignore some maintainers (really don't). Just use b4 and everything should be fine, although remember about b4 prep --auto-to-cc if you added new patches to the patchset.

You missed at least devicetree list (maybe more), so this won't be tested by automated tooling. Performing review on untested code might be a waste of time, thus I will skip this patch entirely till you follow the process allowing the patch to be tested.

Please kindly resend and include all necessary To/Cc entries.

Best regards,
Krzysztof

author maintainer
#3 lore raw

Re: [PATCH v5 01/11] dt-bindings: arm: add cznic,turris-omnia-mcu binding

Quoted 35 lines · On Tue, 26 Mar 2024 09:45:00 +0100 Krzysztof Kozlowski <[email protected]> wrote:
Quoted 6 lines · Marek Behún

Add binding for cznic,turris-omnia-mcu, the device-tree node representing the system-controller features provided by the MCU on the Turris Omnia router.

Quoted 10 lines

---
Changes from v4:
- #gpio-cells changed from 2 (pin number, flags) to 3 (bank, pin number, flags). This is because two years ago we added device-tree fixing code into U-Boot [1] which adds reset-gpios to PCIe controller nodes if these GPIOs are controllable via MCU, and the code adds the gpio specifiers to have 3 cells. Implementing this driver with twocell specifier breaks PCIe functionality for users which have upgraded U-Boot
- added documentation for #interrupt-cells and #gpio-cells

Please use scripts/get_maintainers.pl to get a list of necessary people and lists to CC. It might happen, that command when run on an older kernel, gives you outdated entries. Therefore please be sure you base your patches on recent Linux kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of people, so fix your workflow. Tools might also fail if you work on some ancient tree (don't, instead use mainline), work on fork of kernel (don't, instead use mainline) or you ignore some maintainers (really don't). Just use b4 and everything should be fine, although remember about b4 prep --auto-to-cc if you added new patches to the patchset.

You missed at least devicetree list (maybe more), so this won't be tested by automated tooling. Performing review on untested code might be a waste of time, thus I will skip this patch entirely till you follow the process allowing the patch to be tested.

Quoted 5 lines

Please kindly resend and include all necessary To/Cc entries.

Best regards,
Krzysztof

Will do in v5.

Marek

author maintainer
#4 lore raw

PATCH v5 2/11 platform: cznic: Add preliminary support for Turris Omnia MCU

In reply to Marek Behún

Add the basic skeleton for a new platform driver for the microcontroller found on the Turris Omnia board.

---
Changes since v4:
- added board information reading code and new sysfs files: board_revision, first_mac_address and serial_number. These are present if the MCU firmware supports the FEAT_BOARD_INFO feature, which is a new feature implemented for boards where MCU is also responsible for board information

---
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  81 ++++
 MAINTAINERS                                   |   3 +
 drivers/platform/Kconfig                      |   2 +
 drivers/platform/Makefile                     |   1 +
 drivers/platform/cznic/Kconfig                |  26 ++
 drivers/platform/cznic/Makefile               |   4 +
 .../platform/cznic/turris-omnia-mcu-base.c    | 349 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  71 ++++
 include/linux/turris-omnia-mcu-interface.h    | 238 ++++++++++++
 9 files changed, 775 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
 create mode 100644 drivers/platform/cznic/Kconfig
 create mode 100644 drivers/platform/cznic/Makefile
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h
 create mode 100644 include/linux/turris-omnia-mcu-interface.h
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +81 -0
new file mode 100644
index 000000000000..ff5e7cb00206
@@ -0,0 +1,81 @@
+What:		/sys/bus/i2c/devices/<mcu_device>/board_revision
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains board revision number.
+
+		Only available if board information is burned in the MCU (older
+		revisions have board information burned in the ATSHA204-A chip).
+
+		Format: %u.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/first_mac_address
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains device first MAC address. Each Turris Omnia is
+		allocated 3 MAC addresses. The two additional addresses are
+		computed from the first one by incrementing it.
+
+		Only available if board information is burned in the MCU (older
+		revisions have board information burned in the ATSHA204-A chip).
+
+		Format: %pM.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/fw_features
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Newer versions of the microcontroller firmware report the
+		features they support. These can be read from this file. If the
+		MCU firmware is too old, this file reads 0x0.
+
+		Format: 0x%x.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/fw_version_hash_application
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains the version hash (commit hash) of the application
+		part of the microcontroller firmware.
+
+		Format: %s.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/fw_version_hash_bootloader
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains the version hash (commit hash) of the bootloader
+		part of the microcontroller firmware.
+
+		Format: %s.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/mcu_type
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains the microcontroller type (STM32, GD32, MKL).
+
+		Format: %s.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/reset_selector
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains the selected factory reset level, determined by
+		how long the rear reset button was held by the user during board
+		reset.
+
+		Format: %i.
+
+What:		/sys/bus/i2c/devices/<mcu_device>/serial_number
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains the 64 bit long board serial number in hexadecimal
+		format.
+
+		Only available if board information is burned in the MCU (older
+		revisions have board information burned in the ATSHA204-A chip).
+
+		Format: %016X.
MAINTAINERS +3 -0
index 89edfc2b875b..529e16d386e8 100644
@@ -2139,6 +2139,7 @@ M:	Marek Behún <[email protected]>
 S:	Maintained
 W:	https://www.turris.cz/
 F:	Documentation/ABI/testing/debugfs-moxtet
+F:	Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
 F:	Documentation/ABI/testing/sysfs-bus-moxtet-devices
 F:	Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
 F:	Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
@@ -2152,10 +2153,12 @@ F:	drivers/firmware/turris-mox-rwtm.c
 F:	drivers/gpio/gpio-moxtet.c
 F:	drivers/leds/leds-turris-omnia.c
 F:	drivers/mailbox/armada-37xx-rwtm-mailbox.c
+F:	drivers/platform/cznic/
 F:	drivers/watchdog/armada_37xx_wdt.c
 F:	include/dt-bindings/bus/moxtet.h
 F:	include/linux/armada-37xx-rwtm-mailbox.h
 F:	include/linux/moxtet.h
+F:	include/linux/turris-omnia-mcu-interface.h
 
 ARM/FARADAY FA526 PORT
 M:	Hans Ulli Kroll <[email protected]>
drivers/platform/Kconfig +2 -0
index 868b20361769..fef907a94001 100644
@@ -7,6 +7,8 @@ source "drivers/platform/goldfish/Kconfig"
 
 source "drivers/platform/chrome/Kconfig"
 
+source "drivers/platform/cznic/Kconfig"
+
 source "drivers/platform/mellanox/Kconfig"
 
 source "drivers/platform/olpc/Kconfig"
drivers/platform/Makefile +1 -0
index 41640172975a..8bf189264374 100644
@@ -10,4 +10,5 @@ obj-$(CONFIG_MIPS)		+= mips/
 obj-$(CONFIG_OLPC_EC)		+= olpc/
 obj-$(CONFIG_GOLDFISH)		+= goldfish/
 obj-$(CONFIG_CHROME_PLATFORMS)	+= chrome/
+obj-$(CONFIG_CZNIC_PLATFORMS)	+= cznic/
 obj-$(CONFIG_SURFACE_PLATFORMS)	+= surface/
drivers/platform/cznic/Kconfig new file +26 -0
new file mode 100644
index 000000000000..f8560ff9c1af
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.rst.
+#
+
+menuconfig CZNIC_PLATFORMS
+	bool "Platform support for CZ.NIC's Turris hardware"
+	depends on MACH_ARMADA_38X || COMPILE_TEST
+	help
+	  Say Y here to be able to choose driver support for CZ.NIC's Turris
+	  devices. This option alone does not add any kernel code.
+
+if CZNIC_PLATFORMS
+
+config TURRIS_OMNIA_MCU
+	tristate "Turris Omnia MCU driver"
+	depends on MACH_ARMADA_38X || COMPILE_TEST
+	depends on I2C
+	help
+	  Say Y here to add support for the features implemented by the
+	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
+	  To compile this driver as a module, choose M here; the module will be
+	  called turris-omnia-mcu.
+
+endif # CZNIC_PLATFORMS
drivers/platform/cznic/Makefile new file +4 -0
new file mode 100644
index 000000000000..4d0a9586538c
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
+turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
drivers/platform/cznic/turris-omnia-mcu-base.c new file +349 -0

349 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h new file +71 -0

71 lines not on this page · raw message

include/linux/turris-omnia-mcu-interface.h new file +238 -0

238 lines not on this page · raw message

Signature · 1 line
2.43.2
#5 lore raw

Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU

Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:

Quoted 2 lines

Add the basic skeleton for a new platform driver for the microcontroller found on the Turris Omnia board.

...

drivers/platform/cznic/Makefile line 4

Quoted 6 lines

+++ b/drivers/platform/cznic/Makefile

drivers/platform/cznic/Makefile new file +4 -0
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
+turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o

'objs' is for user space. You need to use 'y'. Same applies to the entire series.

...

+ array_size.h
+ bits.h

drivers/platform/cznic/turris-omnia-mcu-base.c line 13

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +6 -0
+#include <linux/device.h>
+#include <linux/hex.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/turris-omnia-mcu-interface.h>
+#include <linux/types.h>

+ string.h

Quoted 1 line

+#include <linux/sysfs.h>

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 30

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +3 -0
+	err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
+						       CMD_GET_FW_VERSION_APP,
+			     reply, sizeof(reply));

Wouldn't be better to have a logical split?

	err = omnia_cmd_read(mcu->client,
			     bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
			     reply, sizeof(reply));

?

...

Review

Quoted 1 line
(quoted diff) +1 -0
+	struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));

What's wrong with dev_get_drvdata()?

...

Review

Quoted 2 lines
(quoted diff) +2 -0
+static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
+				char *buf)

One line?

...

Review

Quoted 1 line
(quoted diff) +1 -0
+	struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));

Use direct call (see above). Same applies to all such constructions in your code.

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 164

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+static const struct attribute_group omnia_mcu_base_group = {
+	.attrs = omnia_mcu_base_attrs,
+	.is_visible = omnia_mcu_base_attrs_visible,
+};
+
+static const struct attribute_group *omnia_mcu_groups[] = {
+	&omnia_mcu_base_group,
+	NULL
+};

__ATTRIBUTE_GROUPS()

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 344

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+static struct i2c_driver omnia_mcu_driver = {
+	.probe		= omnia_mcu_probe,
+	.driver		= {
+		.name	= "turris-omnia-mcu",
+		.of_match_table = of_omnia_mcu_match,
+		.dev_groups = omnia_mcu_groups,
+	},
+};
 
+

Redundant blank line.

Quoted 1 line

+module_i2c_driver(omnia_mcu_driver);

...

drivers/platform/cznic/turris-omnia-mcu.h line 9

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +2 -0
+#ifndef __TURRIS_OMNIA_MCU_H
+#define __TURRIS_OMNIA_MCU_H

+ array_size.h

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +4 -0
+#include <linux/i2c.h>
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>

...

drivers/platform/cznic/turris-omnia-mcu.h line 29

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +3 -0
+static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
+				 void *reply, unsigned int len)
+{

Why is this in the header?

Quoted 20 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +20 -0
+	struct i2c_msg msgs[2];
+	int ret;
+
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 1;
+	msgs[0].buf = &cmd;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = reply;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	return 0;
+}

...

include/linux/turris-omnia-mcu-interface.h line 11

Quoted 4 lines
include/linux/turris-omnia-mcu-interface.h new file +4 -0
+#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
+#define __TURRIS_OMNIA_MCU_INTERFACE_H
+
+#include <linux/bits.h>

+ bitfield.h

Quoted 1 line

+#endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#6 lore raw

Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU

Hi Andy,

thank you very much for the review. I have some notes and some questions, see below.

Quoted 6 lines · On Sun, 24 Mar 2024 13:01:55 +0200 Andy Shevchenko <[email protected]>…

Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:

Quoted 2 lines

Add the basic skeleton for a new platform driver for the microcontroller found on the Turris Omnia board.

...

Quoted 9 lines

drivers/platform/cznic/Makefile line 4

Quoted 6 lines

+++ b/drivers/platform/cznic/Makefile

drivers/platform/cznic/Makefile new file +4 -0
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
+turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o  

'objs' is for user space. You need to use 'y'. Same applies to the entire series.

Fixed for v6.

Quoted 3 lines

+ array_size.h
+ bits.h

Fixed for v6. Is there some tool for this?

Quoted 1 line

+ string.h

Fixed for v6.

Quoted 11 lines
Quoted 2 lines

+#include <linux/sysfs.h>

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 30

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +3 -0
+	err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
+						       CMD_GET_FW_VERSION_APP,
+			     reply, sizeof(reply));  

Wouldn't be better to have a logical split?

Quoted 3 lines
	err = omnia_cmd_read(mcu->client,
			     bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
			     reply, sizeof(reply));

Changed for v6 to

Quoted 4 lines
	err = omnia_cmd_read(mcu->client,
			     bootloader ? CMD_GET_FW_VERSION_BOOT
					: CMD_GET_FW_VERSION_APP,
			     reply, sizeof(reply));

There are still some people wanting only 80 columns, and the whole driver is written that way.

Quoted 8 lines

?

...

Review

Quoted 1 line
(quoted diff) +1 -0
+	struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));  

What's wrong with dev_get_drvdata()?

Fixed for v6.

Quoted 6 lines

...

Review

Quoted 2 lines
(quoted diff) +2 -0
+static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
+				char *buf)  

One line?

80 columns...

...

Quoted 11 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 164

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+static const struct attribute_group omnia_mcu_base_group = {
+	.attrs = omnia_mcu_base_attrs,
+	.is_visible = omnia_mcu_base_attrs_visible,
+};
+
+static const struct attribute_group *omnia_mcu_groups[] = {
+	&omnia_mcu_base_group,
+	NULL
+};  

__ATTRIBUTE_GROUPS()

The next patches add more groups into this array, after the whole series it looks like this:

static const struct attribute_group *omnia_mcu_groups[] = {
&omnia_mcu_base_group, &omnia_mcu_gpio_group, &omnia_mcu_poweroff_group,
NULL
};

There is no macro for that. Should I still use __ATTRIBUTE_GROUPS() in the first patch and than change it in the next one?

Quoted 12 lines

...

Quoted 8 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +8 -0
+static struct i2c_driver omnia_mcu_driver = {
+	.probe		= omnia_mcu_probe,
+	.driver		= {
+		.name	= "turris-omnia-mcu",
+		.of_match_table = of_omnia_mcu_match,
+		.dev_groups = omnia_mcu_groups,
+	},
+};  
Quoted 4 lines
Quoted 1 line

+

Redundant blank line.

Fixed for v6.

Quoted 8 lines
Quoted 1 line

+module_i2c_driver(omnia_mcu_driver);

...

drivers/platform/cznic/turris-omnia-mcu.h line 9

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +2 -0
+#ifndef __TURRIS_OMNIA_MCU_H
+#define __TURRIS_OMNIA_MCU_H  

+ array_size.h

Fixed for v6.

Quoted 8 lines
Quoted 5 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +4 -0
+#include <linux/i2c.h>
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>  

...

Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu.h line 29

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +3 -0
+static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
+				 void *reply, unsigned int len)
+{  

Why is this in the header?

I considered it a helper function that should be defined in the header file, like the rest of the cmd helpers in this file. If you disagree, I will put it into the -base.c file.

Quoted 24 lines
Quoted 21 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +20 -0
+	struct i2c_msg msgs[2];
+	int ret;
+
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 1;
+	msgs[0].buf = &cmd;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = reply;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	return 0;
+}  

...

Quoted 6 lines

include/linux/turris-omnia-mcu-interface.h line 11

Quoted 4 lines
include/linux/turris-omnia-mcu-interface.h new file +4 -0
+#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
+#define __TURRIS_OMNIA_MCU_INTERFACE_H
+
+#include <linux/bits.h>  

+ bitfield.h

Fixed for v6.

Quoted 3 lines
Quoted 2 lines

+#endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */

#7 lore raw

Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 5 lines · Marek Behún

Hi Andy,

thank you very much for the review. I have some notes and some questions, see below.

Btw, I'll look into other patches next week.

Quoted 3 lines
Quoted 1 line · On Sun, 24 Mar 2024 13:01:55 +0200 Andy Shevchenko <[email protected]>…

Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:

...

Quoted 12 lines
Quoted 9 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 30

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +3 -0
+   err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
+                                                  CMD_GET_FW_VERSION_APP,
+                        reply, sizeof(reply));

Wouldn't be better to have a logical split?

      err = omnia_cmd_read(mcu->client,
                           bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
                           reply, sizeof(reply));

Changed for v6 to

Quoted 7 lines
Quoted 4 lines
      err = omnia_cmd_read(mcu->client,
                           bootloader ? CMD_GET_FW_VERSION_BOOT
                                      : CMD_GET_FW_VERSION_APP,
                           reply, sizeof(reply));

There are still some people wanting only 80 columns, and the whole driver is written that way.

Hmm... Is it still a hard limit for drivers/platform/cznic for the _new_ code?

Quoted 1 line
Quoted 1 line

?

...

Quoted 6 lines
Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
+                           char *buf)

One line?

80 columns...

Ditto.

...

Quoted 10 lines
Quoted 6 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 164

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +4 -0
+static const struct attribute_group *omnia_mcu_groups[] = {
+   &omnia_mcu_base_group,
+   NULL
+};

__ATTRIBUTE_GROUPS()

The next patches add more groups into this array, after the whole series it looks like this:

Quoted 8 lines

static const struct attribute_group *omnia_mcu_groups[] = {
&omnia_mcu_base_group, &omnia_mcu_gpio_group, &omnia_mcu_poweroff_group,
NULL
};

There is no macro for that.

Good point.

Quoted 2 lines

Should I still use __ATTRIBUTE_GROUPS() in the first patch and than change it in the next one?

...

Quoted 9 lines
Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu.h line 29

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +3 -0
+static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
+                            void *reply, unsigned int len)
+{

Why is this in the header?

I considered it a helper function that should be defined in the header file, like the rest of the cmd helpers in this file. If you disagree, I will put it into the -base.c file.

I don't see the technical justification to hold it in the *.h rather than *.c. To me this one is big enough in C and likely in assembly to be copied to each user. Besides that aspect, it slows down the build a lot (mostly due to i2c.h inclusion which otherwise is not needed).

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
drivers/platform/cznic/turris-omnia-mcu.h new file +20 -0
+   struct i2c_msg msgs[2];
+   int ret;
+
+   msgs[0].addr = client->addr;
+   msgs[0].flags = 0;
+   msgs[0].len = 1;
+   msgs[0].buf = &cmd;
+   msgs[1].addr = client->addr;
+   msgs[1].flags = I2C_M_RD;
+   msgs[1].len = len;
+   msgs[1].buf = reply;
+
+   ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+   if (ret < 0)
+           return ret;
+   if (ret != ARRAY_SIZE(msgs))
+           return -EIO;
+
+   return 0;
+}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#8 lore raw

Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 8 lines · On Sun, 24 Mar 2024 17:30:39 +0200 Andy Shevchenko <[email protected]>…
Quoted 5 lines · Marek Behún

Hi Andy,

thank you very much for the review. I have some notes and some questions, see below.

Btw, I'll look into other patches next week.

Thx.

...

Quoted 5 lines
Quoted 3 lines

There are still some people wanting only 80 columns, and the whole driver is written that way.

Hmm... Is it still a hard limit for drivers/platform/cznic for the _new_ code?

I don't think so, but I personally would also prefer leaving this at 80 columns. Is this a problem?

Quoted 8 lines
Quoted 3 lines

I considered it a helper function that should be defined in the header file, like the rest of the cmd helpers in this file. If you disagree, I will put it into the -base.c file.

I don't see the technical justification to hold it in the *.h rather than *.c. To me this one is big enough in C and likely in assembly to be copied to each user. Besides that aspect, it slows down the build a lot (mostly due to i2c.h inclusion which otherwise is not needed).

OK, I moved it into -base.c.

Marek

#9 lore raw

Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU

In reply to Andy Shevchenko
Quoted 8 lines · Andy Shevchenko
Quoted 5 lines · Marek Behún

Hi Andy,

thank you very much for the review. I have some notes and some questions, see below.

Btw, I'll look into other patches next week.

Hello Andy,

did you have a chance to look at the other patches?

Marek

author maintainer
#10 lore raw

PATCH v5 3/11 platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

In reply to Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

---
Changes since v4:
- added definitions of TRNG and MESSAGE_SIGNED interrupts into the omnia_gpios array. These interrupts are for features supported in versions of MCU firmware
- changed OF gpio translation from default (twocell) to driver specific (threecell), for more information see the changes note in patch 01/11

---
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |   16 +
 drivers/platform/cznic/Kconfig                |   15 +
 drivers/platform/cznic/Makefile               |    1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |    3 +-
 .../platform/cznic/turris-omnia-mcu-gpio.c    | 1056 +++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |   61 +
 6 files changed, 1151 insertions(+), 1 deletion(-)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
index ff5e7cb00206..b27b60d00c87 100644
@@ -22,6 +22,22 @@ Description:	(RO) Contains device first MAC address. Each Turris Omnia is
 
 		Format: %pM.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/front_button_mode
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RW) The front button on the Turris Omnia router can be
+		configured either to change the intensity of all the LEDs on the
+		front panel, or to send the press event to the CPU as an
+		interrupt.
+
+		This file switches between these two modes:
+		- "mcu" makes the button press event be handled by the MCU to
+		  change the LEDs panel intensity.
+		- "cpu" makes the button press event be handled by the CPU.
+
+		Format: %s.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/fw_features
 Date:		July 2024
 KernelVersion:	6.10
drivers/platform/cznic/Kconfig +15 -0
index f8560ff9c1af..3a8c3edcd7e6 100644
@@ -17,9 +17,24 @@ config TURRIS_OMNIA_MCU
 	tristate "Turris Omnia MCU driver"
 	depends on MACH_ARMADA_38X || COMPILE_TEST
 	depends on I2C
+	select GPIOLIB
+	select GPIOLIB_IRQCHIP
 	help
 	  Say Y here to add support for the features implemented by the
 	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
+	  The features include:
+	  - GPIO pins
+	    - to get front button press events (the front button can be
+	      configured either to generate press events to the CPU or to change
+	      front LEDs panel brightness)
+	    - to enable / disable USB port voltage regulators and to detect
+	      USB overcurrent
+	    - to detect MiniPCIe / mSATA card presence in MiniPCIe port 0
+	    - to configure resets of various peripherals on board revisions 32+
+	    - to enable / disable the VHV voltage regulator to the SOC in order
+	      to be able to program SOC's OTP on board revisions 32+
+	    - to get input from the LED output pins of the WAN ethernet PHY, LAN
+	      switch and MiniPCIe ports
 	  To compile this driver as a module, choose M here; the module will be
 	  called turris-omnia-mcu.
 
drivers/platform/cznic/Makefile +1 -0
index 4d0a9586538c..a6177f5b4fff 100644
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
+turris-omnia-mcu-objs		+= turris-omnia-mcu-gpio.o
drivers/platform/cznic/turris-omnia-mcu-base.c +2 -1
index 27f08ce8f368..4edaf7a53242 100644
@@ -160,6 +160,7 @@ static const struct attribute_group omnia_mcu_base_group = {
 
 static const struct attribute_group *omnia_mcu_groups[] = {
 	&omnia_mcu_base_group,
+	&omnia_mcu_gpio_group,
 	NULL
 };
 
@@ -325,7 +326,7 @@ static int omnia_mcu_probe(struct i2c_client *client)
 					     "Cannot read board info\n");
 	}
 
-	return 0;
+	return omnia_mcu_register_gpiochip(mcu);
 }
 
 static const struct of_device_id of_omnia_mcu_match[] = {
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +1056 -0

1,056 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +61 -0

88 lines not on this page · raw message

Signature · 1 line
2.43.2
#11 lore raw

Re: [PATCH v5 03/11] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Hi Marek,

I can't say I did a proper review but browsing through the code without proper understanding of the platform raised one small question :)

Quoted 11 lines · Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

...

Quoted 7 lines

+/**
+ * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
+ * @dst: the destination u8 array of interleaved bytes
+ * @rising: rising mask
+ * @falling: falling mask
+ *
+ * Interleaves the little-endian bytes from @rising and @falling words.

This means the 'rising' and 'falling' should always be little-endian? Should the parameter types reflect this? Or should we see some cpu_to_le() calls? (Or, is this code just guaranteed to be always running on a le-machine?).

Quoted 26 lines

+ * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
+ * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
+ *
+ * The MCU receives interrupt mask and reports pending interrupt bitmap int this
+ * interleaved format. The rationale behind it is that the low-indexed bits are
+ * more important - in many cases, the user will be interested only in
+ * interrupts with indexes 0 to 7, and so the system can stop reading after
+ * first 2 bytes (r0, f0), to save time on the slow I2C bus.
+ *
+ * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
+ * and use an appropriate bitmap_* function once such a function exists.
+ */

drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +14 -0
+static void omnia_mask_interleave(u8 *dst, u32 rising, u32 falling)
+{
+	for (int i = 0; i < sizeof(u32); ++i) {
+		dst[2 * i] = rising >> (8 * i);
+		dst[2 * i + 1] = falling >> (8 * i);
+	}
+}
+
+/**
+ * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
+ *	@src: the source u8 array containing the interleaved bytes
+ *	@rising: pointer where to store the rising mask gathered from @src
+ *	@falling: pointer where to store the falling mask gathered from @src
+ *

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 621

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+ * This is the inverse function to omnia_mask_interleave.
+ */
+static void omnia_mask_deinterleave(const u8 *src, u32 *rising, u32 *falling)
+{
+	*rising = *falling = 0;
+
+	for (int i = 0; i < sizeof(u32); ++i) {
+		*rising |= src[2 * i] << (8 * i);
+		*falling |= src[2 * i + 1] << (8 * i);
+	}

Also here I could expect seeing le_to_cpu() unless I am (again :]) missing something.

Quoted 1 line

+}

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
author maintainer
#12 lore raw

Re: [PATCH v5 03/11] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 63 lines · On Mon, 25 Mar 2024 11:10:04 +0200 Matti Vaittinen <[email protected]>…

Hi Marek,

I can't say I did a proper review but browsing through the code without proper understanding of the platform raised one small question :)

Quoted 11 lines · Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

...

Quoted 7 lines

+/**
+ * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
+ * @dst: the destination u8 array of interleaved bytes
+ * @rising: rising mask
+ * @falling: falling mask
+ *
+ * Interleaves the little-endian bytes from @rising and @falling words.

This means the 'rising' and 'falling' should always be little-endian? Should the parameter types reflect this? Or should we see some cpu_to_le() calls? (Or, is this code just guaranteed to be always running on a le-machine?).

Quoted 31 lines

+ * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
+ * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
+ *
+ * The MCU receives interrupt mask and reports pending interrupt bitmap int this
+ * interleaved format. The rationale behind it is that the low-indexed bits are
+ * more important - in many cases, the user will be interested only in
+ * interrupts with indexes 0 to 7, and so the system can stop reading after
+ * first 2 bytes (r0, f0), to save time on the slow I2C bus.
+ *
+ * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
+ * and use an appropriate bitmap_* function once such a function exists.
+ */

drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +19 -0
+static void omnia_mask_interleave(u8 *dst, u32 rising, u32 falling)
+{
+	for (int i = 0; i < sizeof(u32); ++i) {
+		dst[2 * i] = rising >> (8 * i);
+		dst[2 * i + 1] = falling >> (8 * i);
+	}
+}
+
+/**
+ * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
+ *	@src: the source u8 array containing the interleaved bytes
+ *	@rising: pointer where to store the rising mask gathered from @src
+ *	@falling: pointer where to store the falling mask gathered from @src
+ *
+ * This is the inverse function to omnia_mask_interleave.
+ */
+static void omnia_mask_deinterleave(const u8 *src, u32 *rising, u32 *falling)
+{
+	*rising = *falling = 0;
Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 621

Quoted 5 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +5 -0
+
+	for (int i = 0; i < sizeof(u32); ++i) {
+		*rising |= src[2 * i] << (8 * i);
+		*falling |= src[2 * i + 1] << (8 * i);
+	}  

Also here I could expect seeing le_to_cpu() unless I am (again :]) missing something.

I don't understand. The rising and falling variables have native endiannes, as they should have.

And the src and dst are u8 arrays, which contain two LE32 unsigned integers, but these integers are interleaved. I am converting then to two native unsigned integers byte by byte, so I am basically doing what a theoretical le32_interleaved_le32_to_cpu() would have done if it did exist. Putting another le*_to_cpu() would only break things.

Marek

#13 lore raw

Re: [PATCH v5 03/11] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 75 lines · Marek Behún
Quoted 63 lines · On Mon, 25 Mar 2024 11:10:04 +0200 Matti Vaittinen <[email protected]>…

Hi Marek,

I can't say I did a proper review but browsing through the code without proper understanding of the platform raised one small question :)

Quoted 11 lines · Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

...

Quoted 7 lines

+/**
+ * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
+ * @dst: the destination u8 array of interleaved bytes
+ * @rising: rising mask
+ * @falling: falling mask
+ *
+ * Interleaves the little-endian bytes from @rising and @falling words.

This means the 'rising' and 'falling' should always be little-endian? Should the parameter types reflect this? Or should we see some cpu_to_le() calls? (Or, is this code just guaranteed to be always running on a le-machine?).

Quoted 31 lines

+ * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
+ * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
+ *
+ * The MCU receives interrupt mask and reports pending interrupt bitmap int this
+ * interleaved format. The rationale behind it is that the low-indexed bits are
+ * more important - in many cases, the user will be interested only in
+ * interrupts with indexes 0 to 7, and so the system can stop reading after
+ * first 2 bytes (r0, f0), to save time on the slow I2C bus.
+ *
+ * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
+ * and use an appropriate bitmap_* function once such a function exists.
+ */

drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +19 -0
+static void omnia_mask_interleave(u8 *dst, u32 rising, u32 falling)
+{
+	for (int i = 0; i < sizeof(u32); ++i) {
+		dst[2 * i] = rising >> (8 * i);
+		dst[2 * i + 1] = falling >> (8 * i);
+	}
+}
+
+/**
+ * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
+ *	@src: the source u8 array containing the interleaved bytes
+ *	@rising: pointer where to store the rising mask gathered from @src
+ *	@falling: pointer where to store the falling mask gathered from @src
+ *
+ * This is the inverse function to omnia_mask_interleave.
+ */
+static void omnia_mask_deinterleave(const u8 *src, u32 *rising, u32 *falling)
+{
+	*rising = *falling = 0;
Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 621

Quoted 5 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +5 -0
+
+	for (int i = 0; i < sizeof(u32); ++i) {
+		*rising |= src[2 * i] << (8 * i);
+		*falling |= src[2 * i + 1] << (8 * i);
+	}

Also here I could expect seeing le_to_cpu() unless I am (again :]) missing something.

Quoted 2 lines

I don't understand. The rising and falling variables have native endiannes, as they should have.

So, it was the last option then :) I was missing something.

Quoted 5 lines

And the src and dst are u8 arrays, which contain two LE32 unsigned integers, but these integers are interleaved. I am converting then to two native unsigned integers byte by byte, so I am basically doing what a theoretical le32_interleaved_le32_to_cpu() would have done if it did exist. Putting another le*_to_cpu() would only break things.

Thank you for the explanation. I commented way too hastily after a glance - missing the point you used shift and not u8 pointer to go through the 'rising' and 'falling' in interleave() - and the point that the result of deinterleave() was u8s. Very sorry for the noise.

Thanks for the patience!

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#14 lore raw

Re: [PATCH v5 03/11] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

In reply to Marek Behún

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 929

Quoted 9 lines · Marek Behún
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +9 -0
+static ssize_t front_button_mode_store(struct device *dev,
+				       struct device_attribute *a,
+				       const char *buf, size_t count)
+{
+	struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+	u8 mask, val;
+	int err, i;
+
+	mask = CTL_BUTTON_MODE;

No need for the mask variable. Just use CTL_BUTTON_MODE directly.

regards,
dan carpenter

Quoted 13 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +13 -0
+
+	i = sysfs_match_string(front_button_modes, buf);
+	if (i < 0)
+		return i;
+
+	val = i ? mask : 0;
+	err = omnia_ctl_cmd_locked(mcu, CMD_GENERAL_CONTROL, val, mask);
+	if (err)
+		return err;
+
+	return count;
+}
+static DEVICE_ATTR_RW(front_button_mode);
author maintainer
#15 lore raw

PATCH v5 4/11 platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup

In reply to Marek Behún

Add support for true board poweroff (MCU can disable all unnecessary voltage regulators) and wakeup at a specified time, implemented via a RTC driver so that the rtcwake utility can be used to configure it.

---
Changes since v4:
- the driver now registers the RTC with feature bit RTC_FEATURE_ALARM_WAKEUP_ONLY, as requested by Alexandre Belloni (see commit e99653afeb95 for explanation)

---
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  16 ++
 drivers/platform/cznic/Kconfig                |   4 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   5 +
 .../cznic/turris-omnia-mcu-sys-off-wakeup.c   | 258 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  20 ++
 6 files changed, 304 insertions(+)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
index b27b60d00c87..564119849388 100644
@@ -38,6 +38,22 @@ Description:	(RW) The front button on the Turris Omnia router can be
 
 		Format: %s.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/front_button_poweron
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RW) Newer versions of the microcontroller firmware of the
+		Turris Omnia router support powering off the router into true
+		low power mode. The router can be powered on by pressing the
+		front button.
+
+		This file configures whether front button power on is enabled.
+
+		This file is present only if the power off feature is supported
+		by the firmware.
+
+		Format: %i.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/fw_features
 Date:		July 2024
 KernelVersion:	6.10
drivers/platform/cznic/Kconfig +4 -0
index 3a8c3edcd7e6..0a752aa654fa 100644
@@ -19,10 +19,14 @@ config TURRIS_OMNIA_MCU
 	depends on I2C
 	select GPIOLIB
 	select GPIOLIB_IRQCHIP
+	select RTC_CLASS
 	help
 	  Say Y here to add support for the features implemented by the
 	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
 	  The features include:
+	  - board poweroff into true low power mode (with voltage regulators
+	    disabled) and the ability to configure wake up from this mode (via
+	    rtcwake)
 	  - GPIO pins
 	    - to get front button press events (the front button can be
 	      configured either to generate press events to the CPU or to change
drivers/platform/cznic/Makefile +1 -0
index a6177f5b4fff..6f1470d1f673 100644
@@ -3,3 +3,4 @@
 obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-gpio.o
+turris-omnia-mcu-objs		+= turris-omnia-mcu-sys-off-wakeup.o
drivers/platform/cznic/turris-omnia-mcu-base.c +5 -0
index 4edaf7a53242..6ab4494335ca 100644
@@ -161,6 +161,7 @@ static const struct attribute_group omnia_mcu_base_group = {
 static const struct attribute_group *omnia_mcu_groups[] = {
 	&omnia_mcu_base_group,
 	&omnia_mcu_gpio_group,
+	&omnia_mcu_poweroff_group,
 	NULL
 };
 
@@ -326,6 +327,10 @@ static int omnia_mcu_probe(struct i2c_client *client)
 					     "Cannot read board info\n");
 	}
 
+	err = omnia_mcu_register_sys_off_and_wakeup(mcu);
+	if (err)
+		return err;
+
 	return omnia_mcu_register_gpiochip(mcu);
 }
 
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +258 -0

258 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +20 -0
index 143c63001e8f..af9845d1c6d2 100644
@@ -13,9 +13,11 @@
 #include <linux/i2c.h>
 #include <linux/if_ether.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 struct omnia_mcu {
 	struct i2c_client *client;
@@ -35,6 +37,11 @@ struct omnia_mcu {
 	struct delayed_work button_release_emul_work;
 	u16 last_status;
 	bool button_pressed_emul;
+
+	/* RTC device for configuring wake-up */
+	struct rtc_device *rtcdev;
+	u32 rtc_alarm;
+	bool front_button_poweron;
 };
 
 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -47,6 +54,17 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
 	return ret < 0 ? ret : 0;
 }
 
+static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
+				      u32 val)
+{
+	u8 buf[5];
+
+	buf[0] = cmd;
+	put_unaligned_le32(val, &buf[1]);
+
+	return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
 static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
 				 void *reply, unsigned int len)
 {
@@ -126,7 +144,9 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
 }
 
 extern const struct attribute_group omnia_mcu_gpio_group;
+extern const struct attribute_group omnia_mcu_poweroff_group;
 
 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
+int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
 
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#16 lore raw

PATCH v5 5/11 platform: cznic: turris-omnia-mcu: Add support for MCU watchdog

In reply to Marek Behún

Add support for the watchdog mechanism provided by the MCU.

---
 drivers/platform/cznic/Kconfig                |   2 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   4 +
 .../cznic/turris-omnia-mcu-watchdog.c         | 122 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  24 ++++
 5 files changed, 153 insertions(+)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
drivers/platform/cznic/Kconfig +2 -0
index 0a752aa654fa..e2649cdecc38 100644
@@ -20,6 +20,7 @@ config TURRIS_OMNIA_MCU
 	select GPIOLIB
 	select GPIOLIB_IRQCHIP
 	select RTC_CLASS
+	select WATCHDOG_CORE
 	help
 	  Say Y here to add support for the features implemented by the
 	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
@@ -27,6 +28,7 @@ config TURRIS_OMNIA_MCU
 	  - board poweroff into true low power mode (with voltage regulators
 	    disabled) and the ability to configure wake up from this mode (via
 	    rtcwake)
+	  - MCU watchdog
 	  - GPIO pins
 	    - to get front button press events (the front button can be
 	      configured either to generate press events to the CPU or to change
drivers/platform/cznic/Makefile +1 -0
index 6f1470d1f673..a43997a12d74 100644
@@ -4,3 +4,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-gpio.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-objs		+= turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +4 -0
index 6ab4494335ca..5a45834003cd 100644
@@ -331,6 +331,10 @@ static int omnia_mcu_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
+	err = omnia_mcu_register_watchdog(mcu);
+	if (err)
+		return err;
+
 	return omnia_mcu_register_gpiochip(mcu);
 }
 
drivers/platform/cznic/turris-omnia-mcu-watchdog.c new file +122 -0

122 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +24 -0
index af9845d1c6d2..3e2c96079e64 100644
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <linux/rtc.h>
 #include <linux/types.h>
+#include <linux/watchdog.h>
 #include <linux/workqueue.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -42,6 +43,9 @@ struct omnia_mcu {
 	struct rtc_device *rtcdev;
 	u32 rtc_alarm;
 	bool front_button_poweron;
+
+	/* MCU watchdog */
+	struct watchdog_device wdt;
 };
 
 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -54,6 +58,25 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
 	return ret < 0 ? ret : 0;
 }
 
+static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd,
+				     u8 val)
+{
+	u8 buf[2] = { cmd, val };
+
+	return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
+static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd,
+				      u16 val)
+{
+	u8 buf[3];
+
+	buf[0] = cmd;
+	put_unaligned_le16(val, &buf[1]);
+
+	return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
 static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
 				      u32 val)
 {
@@ -148,5 +171,6 @@ extern const struct attribute_group omnia_mcu_poweroff_group;
 
 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
+int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
 
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#17 lore raw

PATCH v5 6/11 devm-helpers: Add resource managed version of irq_create_mapping()

In reply to Marek Behún

Add resource managed version of irq_create_mapping(), to help drivers automatically dispose a linux irq mapping when driver is detached.

The new function devm_irq_create_mapping() is not yet used, but the action function can be used in the FSL CAAM driver.

---
 drivers/crypto/caam/jr.c     |  8 ++----
 include/linux/devm-helpers.h | 54 ++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 6 deletions(-)
drivers/crypto/caam/jr.c +2 -6
index 26eba7de3fb0..ad0295b055f8 100644
@@ -7,6 +7,7 @@
  * Copyright 2019, 2023 NXP
  */
 
+#include <linux/devm-helpers.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -576,11 +577,6 @@ static int caam_jr_init(struct device *dev)
 	return error;
 }
 
-static void caam_jr_irq_dispose_mapping(void *data)
-{
-	irq_dispose_mapping((unsigned long)data);
-}
-
 /*
  * Probe routine for each detected JobR subsystem.
  */
@@ -656,7 +652,7 @@ static int caam_jr_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping,
+	error = devm_add_action_or_reset(jrdev, devm_irq_mapping_drop,
 					 (void *)(unsigned long)jrpriv->irq);
 	if (error)
 		return error;
include/linux/devm-helpers.h +54 -0

64 lines not on this page · raw message

Signature · 1 line
2.43.2
#18 lore raw

Re: [PATCH v5 06/11] devm-helpers: Add resource managed version of irq_create_mapping()

Quoted 50 lines · Marek Behún

Add resource managed version of irq_create_mapping(), to help drivers automatically dispose a linux irq mapping when driver is detached.

The new function devm_irq_create_mapping() is not yet used, but the action function can be used in the FSL CAAM driver.

---
  drivers/crypto/caam/jr.c     |  8 ++----
  include/linux/devm-helpers.h | 54 ++++++++++++++++++++++++++++++++++++
  2 files changed, 56 insertions(+), 6 deletions(-)
drivers/crypto/caam/jr.c +2 -6
index 26eba7de3fb0..ad0295b055f8 100644
@@ -7,6 +7,7 @@
   * Copyright 2019, 2023 NXP
   */
 
+#include <linux/devm-helpers.h>
  #include <linux/of_irq.h>
  #include <linux/of_address.h>
  #include <linux/platform_device.h>
@@ -576,11 +577,6 @@ static int caam_jr_init(struct device *dev)
  	return error;
  }
 
-static void caam_jr_irq_dispose_mapping(void *data)
-{
-	irq_dispose_mapping((unsigned long)data);
-}
-
  /*
   * Probe routine for each detected JobR subsystem.
   */
@@ -656,7 +652,7 @@ static int caam_jr_probe(struct platform_device *pdev)
  		return -EINVAL;
  	}
 
-	error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping,
+	error = devm_add_action_or_reset(jrdev, devm_irq_mapping_drop,
  					 (void *)(unsigned long)jrpriv->irq);
  	if (error)
  		return error;
include/linux/devm-helpers.h +0 -0
index 74891802200d..3805551fd433 100644

include/linux/devm-helpers.h line 29

Quoted 6 lines
include/linux/devm-helpers.h +2 -0
@@ -24,6 +24,8 @@
   */
 
  #include <linux/device.h>
+#include <linux/kconfig.h>
+#include <linux/irqdomain.h>
  #include <linux/workqueue.h>

My confidence level is not terribly high today, so I am likely to accept just about any counter arguments :) But ... More I think of this whole header, less convinced I am that this (the header) is a great idea. I wonder who has authored a concept like this... :rolleyes:

Pulling punch of unrelated APIs (or, unrelated except the devm-usage) in one header has potential to be including a lot of unneeded stuff to the users. I am under impression this can be bad for example for the build times.

I think that ideally the devm-APIs should live close to their non-devm counterparts, and this header should be just used as a last resort, when all the other options fail :) May I assume all other options have failed for the IRQ stuff?

Well, I will leave the big picture to the bigger minds. When just looking at the important things like the function names and coding style - this change looks Ok to me ;)

Quoted 58 lines
include/linux/devm-helpers.h +52 -0
  static inline void devm_delayed_work_drop(void *res)
@@ -76,4 +78,56 @@ static inline int devm_work_autocancel(struct device *dev,
  	return devm_add_action(dev, devm_work_drop, w);
  }
 
+/**
+ * devm_irq_mapping_drop - devm action for disposing an irq mapping
+ * @res:	linux irq number cast to the void * type
+ *
+ * devm_irq_mapping_drop() can be used as an action parameter for the
+ * devm_add_action_or_reset() function in order to automatically dispose
+ * a linux irq mapping when a device driver is detached.
+ */
+static inline void devm_irq_mapping_drop(void *res)
+{
+	irq_dispose_mapping((unsigned int)(unsigned long)res);
+}
+
+/**
+ * devm_irq_create_mapping - Resource managed version of irq_create_mapping()
+ * @dev:	Device which lifetime the mapping is bound to
+ * @domain:	domain owning this hardware interrupt or NULL for default domain
+ * @hwirq:	hardware irq number in that domain space
+ *
+ * Create an irq mapping to linux irq space which is automatically disposed when
+ * the driver is detached.
+ * devm_irq_create_mapping() can be used to omit the explicit
+ * irq_dispose_mapping() call when driver is detached.
+ *
+ * Returns a linux irq number on success, 0 if mapping could not be created, or
+ * a negative error number if devm action could not be added.
+ */
+static inline int devm_irq_create_mapping(struct device *dev,
+					  struct irq_domain *domain,
+					  irq_hw_number_t hwirq)
+{
+	unsigned int virq = irq_create_mapping(domain, hwirq);
+
+	if (!virq)
+		return 0;
+
+	/*
+	 * irq_dispose_mapping() is an empty function if CONFIG_IRQ_DOMAIN is
+	 * disabled. No need to register an action in that case.
+	 */
+	if (IS_ENABLED(CONFIG_IRQ_DOMAIN)) {
+		int err;
+
+		err = devm_add_action_or_reset(dev, devm_irq_mapping_drop,
+					       (void *)(unsigned long)virq);
+		if (err)
+			return err;
+	}
+
+	return virq;
+}
+
  #endif
Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
author maintainer
#19 lore raw

Re: [PATCH v5 06/11] devm-helpers: Add resource managed version of irq_create_mapping()

Quoted 68 lines · On Mon, 25 Mar 2024 11:40:20 +0200 Matti Vaittinen <[email protected]>…
Quoted 50 lines · Marek Behún

Add resource managed version of irq_create_mapping(), to help drivers automatically dispose a linux irq mapping when driver is detached.

The new function devm_irq_create_mapping() is not yet used, but the action function can be used in the FSL CAAM driver.

---
  drivers/crypto/caam/jr.c     |  8 ++----
  include/linux/devm-helpers.h | 54 ++++++++++++++++++++++++++++++++++++
  2 files changed, 56 insertions(+), 6 deletions(-)
drivers/crypto/caam/jr.c +2 -6
index 26eba7de3fb0..ad0295b055f8 100644
@@ -7,6 +7,7 @@
   * Copyright 2019, 2023 NXP
   */
 
+#include <linux/devm-helpers.h>
  #include <linux/of_irq.h>
  #include <linux/of_address.h>
  #include <linux/platform_device.h>
@@ -576,11 +577,6 @@ static int caam_jr_init(struct device *dev)
  	return error;
  }
 
-static void caam_jr_irq_dispose_mapping(void *data)
-{
-	irq_dispose_mapping((unsigned long)data);
-}
-
  /*
   * Probe routine for each detected JobR subsystem.
   */
@@ -656,7 +652,7 @@ static int caam_jr_probe(struct platform_device *pdev)
  		return -EINVAL;
  	}
 
-	error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping,
+	error = devm_add_action_or_reset(jrdev, devm_irq_mapping_drop,
  					 (void *)(unsigned long)jrpriv->irq);
  	if (error)
  		return error;
include/linux/devm-helpers.h +0 -0
index 74891802200d..3805551fd433 100644

include/linux/devm-helpers.h line 29

Quoted 6 lines
include/linux/devm-helpers.h +2 -0
@@ -24,6 +24,8 @@
   */
 
  #include <linux/device.h>
+#include <linux/kconfig.h>
+#include <linux/irqdomain.h>
  #include <linux/workqueue.h>  

My confidence level is not terribly high today, so I am likely to accept just about any counter arguments :) But ... More I think of this whole header, less convinced I am that this (the header) is a great idea. I wonder who has authored a concept like this... :rolleyes:

Pulling punch of unrelated APIs (or, unrelated except the devm-usage) in one header has potential to be including a lot of unneeded stuff to the users. I am under impression this can be bad for example for the build times.

Quoted 8 lines

I think that ideally the devm-APIs should live close to their non-devm counterparts, and this header should be just used as a last resort, when all the other options fail :) May I assume all other options have failed for the IRQ stuff?

Well, I will leave the big picture to the bigger minds. When just looking at the important things like the function names and coding style
- this change looks Ok to me ;)

If the authors of devm-helpers or someone else decide it should not exist (due for example of long build times), I am OK with that.

But currently this seems to me to be the proper place to put this into.

Marek

#20 lore raw

Re: [PATCH v5 06/11] devm-helpers: Add resource managed version of irq_create_mapping()

In reply to Marek Behún
Quoted 4 lines · Marek Behún

+/**
+ * devm_irq_create_mapping - Resource managed version of irq_create_mapping()
+ * @dev: Device which lifetime the mapping is bound to
+ * @domain: domain owning this hardware interrupt or NULL for default domain

Quoted 8 lines

+ * @hwirq: hardware irq number in that domain space
+ *
+ * Create an irq mapping to linux irq space which is automatically disposed when
+ * the driver is detached.
+ * devm_irq_create_mapping() can be used to omit the explicit
+ * irq_dispose_mapping() call when driver is detached.
+ *
+ * Returns a linux irq number on success, 0 if mapping could not be created, or

                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

include/linux/devm-helpers.h static inline int devm_work_autocancel(struct device *dev, · line 115

Quoted 10 lines

+ * a negative error number if devm action could not be added.
+ */

include/linux/devm-helpers.h +8 -0
+static inline int devm_irq_create_mapping(struct device *dev,
+					  struct irq_domain *domain,
+					  irq_hw_number_t hwirq)
+{
+	unsigned int virq = irq_create_mapping(domain, hwirq);
+
+	if (!virq)
+		return 0;

What is the point of returning zero instead of an error code? Neither of the callers that are introduced later in the patchset use this.

I understand that it matches some of the other legacy irq function behaviors, but I think we are trying to move away from that because it just leads to bugs.

Since we don't need the zero now, let's wait until we have a user before introducing this behavior. Then we can add a new function that returns zero, but we'll still encourage people to use the standard error code function where possible. And at the same time, when we do introduce the zero is an error code, function you should contact [email protected] so someone an write a static checker rule to detect the bugs that result from it.

regards,
dan carpenter

Quoted 21 lines
include/linux/devm-helpers.h +17 -0
+
+	/*
+	 * irq_dispose_mapping() is an empty function if CONFIG_IRQ_DOMAIN is
+	 * disabled. No need to register an action in that case.
+	 */
+	if (IS_ENABLED(CONFIG_IRQ_DOMAIN)) {
+		int err;
+
+		err = devm_add_action_or_reset(dev, devm_irq_mapping_drop,
+					       (void *)(unsigned long)virq);
+		if (err)
+			return err;
+	}
+
+	return virq;
+}
+
 #endif
Signature · 1 line
2.43.2
author maintainer
#21 lore raw

Re: [PATCH v5 06/11] devm-helpers: Add resource managed version of irq_create_mapping()

Quoted 33 lines · On Tue, 26 Mar 2024 12:00:25 +0300 Dan Carpenter <[email protected]>…
Quoted 4 lines · Marek Behún

+/**
+ * devm_irq_create_mapping - Resource managed version of irq_create_mapping()
+ * @dev: Device which lifetime the mapping is bound to
+ * @domain: domain owning this hardware interrupt or NULL for default domain

Quoted 8 lines

+ * @hwirq: hardware irq number in that domain space
+ *
+ * Create an irq mapping to linux irq space which is automatically disposed when
+ * the driver is detached.
+ * devm_irq_create_mapping() can be used to omit the explicit
+ * irq_dispose_mapping() call when driver is detached.
+ *
+ * Returns a linux irq number on success, 0 if mapping could not be created, or

                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

include/linux/devm-helpers.h static inline int devm_work_autocancel(struct device *dev, · line 115

Quoted 10 lines

+ * a negative error number if devm action could not be added.
+ */

include/linux/devm-helpers.h +8 -0
+static inline int devm_irq_create_mapping(struct device *dev,
+					  struct irq_domain *domain,
+					  irq_hw_number_t hwirq)
+{
+	unsigned int virq = irq_create_mapping(domain, hwirq);
+
+	if (!virq)
+		return 0;  

What is the point of returning zero instead of an error code? Neither of the callers that are introduced later in the patchset use this.

I understand that it matches some of the other legacy irq function behaviors, but I think we are trying to move away from that because it just leads to bugs.

Quoted 7 lines

Since we don't need the zero now, let's wait until we have a user before introducing this behavior. Then we can add a new function that returns zero, but we'll still encourage people to use the standard error code function where possible. And at the same time, when we do introduce the zero is an error code, function you should contact [email protected] so someone an write a static checker rule to detect the bugs that result from it.

Hi Dan,

the first user of this function is the very next patch of this series, and it does this:

+ irq = devm_irq_create_mapping(dev, mcu->gc.irq.domain, irq_idx);
+ if (irq <= 0)
+ return dev_err_probe(dev, irq ?: -ENXIO,
+ "Cannot map MESSAGE_SIGNED IRQ\n");

So it handles !irq as -ENXIO.

I looked into several users who do
virq = irq_create_mapping()
and then reutrn errno if !virq:

git grep -A 3 'virq = irq_create_mapping'

Some return -ENOMEM, some -ENXIO, some -EINVAL.

What do you think?

Or should I send this driver without introducing this helper for now?

Marek

#22 lore raw

Re: [PATCH v5 06/11] devm-helpers: Add resource managed version of irq_create_mapping()

Quoted 54 lines · Marek Behún
Quoted 33 lines · On Tue, 26 Mar 2024 12:00:25 +0300 Dan Carpenter <[email protected]>…
Quoted 4 lines · Marek Behún

+/**
+ * devm_irq_create_mapping - Resource managed version of irq_create_mapping()
+ * @dev: Device which lifetime the mapping is bound to
+ * @domain: domain owning this hardware interrupt or NULL for default domain

Quoted 8 lines

+ * @hwirq: hardware irq number in that domain space
+ *
+ * Create an irq mapping to linux irq space which is automatically disposed when
+ * the driver is detached.
+ * devm_irq_create_mapping() can be used to omit the explicit
+ * irq_dispose_mapping() call when driver is detached.
+ *
+ * Returns a linux irq number on success, 0 if mapping could not be created, or

                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

include/linux/devm-helpers.h static inline int devm_work_autocancel(struct device *dev, · line 115

Quoted 10 lines

+ * a negative error number if devm action could not be added.
+ */

include/linux/devm-helpers.h +8 -0
+static inline int devm_irq_create_mapping(struct device *dev,
+					  struct irq_domain *domain,
+					  irq_hw_number_t hwirq)
+{
+	unsigned int virq = irq_create_mapping(domain, hwirq);
+
+	if (!virq)
+		return 0;  

What is the point of returning zero instead of an error code? Neither of the callers that are introduced later in the patchset use this.

I understand that it matches some of the other legacy irq function behaviors, but I think we are trying to move away from that because it just leads to bugs.

Quoted 7 lines

Since we don't need the zero now, let's wait until we have a user before introducing this behavior. Then we can add a new function that returns zero, but we'll still encourage people to use the standard error code function where possible. And at the same time, when we do introduce the zero is an error code, function you should contact [email protected] so someone an write a static checker rule to detect the bugs that result from it.

Hi Dan,

the first user of this function is the very next patch of this series, and it does this:

(quoted diff) +4 -0
+	irq = devm_irq_create_mapping(dev, mcu->gc.irq.domain, irq_idx);
+	if (irq <= 0)
+		return dev_err_probe(dev, irq ?: -ENXIO,
+				     "Cannot map MESSAGE_SIGNED IRQ\n");
Quoted 1 line

So it handles !irq as -ENXIO.

Yeah. But imagine how much easier it would be if devm_irq_create_mapping() returned -ENXIO directly.

	irq = devm_irq_create_mapping();
	if (irq < 0)
		return dev_err_probe(dev, irq,
				     "Cannot map MESSAGE_SIGNED IRQ\n");
Quoted 10 lines

I looked into several users who do
virq = irq_create_mapping()
and then reutrn errno if !virq:

git grep -A 3 'virq = irq_create_mapping'

Some return -ENOMEM, some -ENXIO, some -EINVAL.

What do you think?

-ENXIO is fine.

regards,
dan carpenter

author maintainer
#23 lore raw

PATCH v5 7/11 platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG

In reply to Marek Behún

Add support for true random number generator provided by the MCU. New Omnia boards come without the Atmel SHA204-A chip. Instead the crypto functionality is provided by new microcontroller, which has a TRNG peripheral.

---
 drivers/platform/cznic/Kconfig                |  2 +
 drivers/platform/cznic/Makefile               |  1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |  6 +-
 .../platform/cznic/turris-omnia-mcu-gpio.c    |  2 +-
 .../platform/cznic/turris-omnia-mcu-trng.c    | 89 +++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  8 ++
 6 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-trng.c
drivers/platform/cznic/Kconfig +2 -0
index e2649cdecc38..750d5f47dba8 100644
@@ -19,6 +19,7 @@ config TURRIS_OMNIA_MCU
 	depends on I2C
 	select GPIOLIB
 	select GPIOLIB_IRQCHIP
+	select HW_RANDOM
 	select RTC_CLASS
 	select WATCHDOG_CORE
 	help
@@ -28,6 +29,7 @@ config TURRIS_OMNIA_MCU
 	  - board poweroff into true low power mode (with voltage regulators
 	    disabled) and the ability to configure wake up from this mode (via
 	    rtcwake)
+	  - true random number generator (if available on the MCU)
 	  - MCU watchdog
 	  - GPIO pins
 	    - to get front button press events (the front button can be
drivers/platform/cznic/Makefile +1 -0
index a43997a12d74..8fd4c6cbcb1b 100644
@@ -4,4 +4,5 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-gpio.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-objs		+= turris-omnia-mcu-trng.o
 turris-omnia-mcu-objs		+= turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +5 -1
index 5a45834003cd..30771004a627 100644
@@ -335,7 +335,11 @@ static int omnia_mcu_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
-	return omnia_mcu_register_gpiochip(mcu);
+	err = omnia_mcu_register_gpiochip(mcu);
+	if (err)
+		return err;
+
+	return omnia_mcu_register_trng(mcu);
 }
 
 static const struct of_device_id of_omnia_mcu_match[] = {
drivers/platform/cznic/turris-omnia-mcu-gpio.c +1 -1
index 7f885be23a47..90b2caa679ea 100644
@@ -161,7 +161,7 @@ static const struct omnia_gpio {
 };
 
 /* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
-static const u8 omnia_int_to_gpio_idx[32] = {
+const u8 omnia_int_to_gpio_idx[32] = {
 	[__bf_shf(INT_CARD_DET)]		= 4,
 	[__bf_shf(INT_MSATA_IND)]		= 5,
 	[__bf_shf(INT_USB30_OVC)]		= 6,
drivers/platform/cznic/turris-omnia-mcu-trng.c new file +89 -0

89 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +8 -0
index 3e2c96079e64..f5b8f7ed3e6e 100644
@@ -9,7 +9,9 @@
 #define __TURRIS_OMNIA_MCU_H
 
 #include <linux/bitops.h>
+#include <linux/completion.h>
 #include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
 #include <linux/i2c.h>
 #include <linux/if_ether.h>
 #include <linux/mutex.h>
@@ -46,6 +48,10 @@ struct omnia_mcu {
 
 	/* MCU watchdog */
 	struct watchdog_device wdt;
+
+	/* true random number generator */
+	struct hwrng trng;
+	struct completion trng_completion;
 };
 
 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -166,11 +172,13 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
 	return err ?: reply;
 }
 
+extern const u8 omnia_int_to_gpio_idx[32];
 extern const struct attribute_group omnia_mcu_gpio_group;
 extern const struct attribute_group omnia_mcu_poweroff_group;
 
 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
+int omnia_mcu_register_trng(struct omnia_mcu *mcu);
 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
 
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#24 lore raw

PATCH v5 8/11 devm-helpers: Add resource managed version of debugfs directory create function

In reply to Marek Behún

A few drivers register a devm action to remove a debugfs directory, implementing a one-liner function that calls debufs_remove_recursive(). Help drivers avoid this repeated implementations by adding managed version of debugfs directory create function.

Use the new function devm_debugfs_create_dir() in the following drivers:
drivers/crypto/caam/ctrl.c drivers/gpu/drm/bridge/ti-sn65dsi86.c drivers/hwmon/hp-wmi-sensors.c drivers/hwmon/mr75203.c drivers/hwmon/pmbus/pmbus_core.c

Also use the action function devm_debugfs_dir_recursive_drop() in driver
drivers/gpio/gpio-mockup.c

As per Dan Williams' request [1], do not touch the driver
drivers/cxl/mem.c

[1] https://lore.kernel.org/linux-gpio/65d7918b358a5_1ee3129432@dwillia2-mobl3.amr.corp.intel.com.notmuch/

---
 drivers/crypto/caam/ctrl.c            | 16 +++--------
 drivers/gpio/gpio-mockup.c            | 11 ++------
 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 13 ++-------
 drivers/hwmon/hp-wmi-sensors.c        | 15 ++--------
 drivers/hwmon/mr75203.c               | 15 ++++------
 drivers/hwmon/pmbus/pmbus_core.c      | 16 ++++-------
 include/linux/devm-helpers.h          | 40 +++++++++++++++++++++++++++
 7 files changed, 61 insertions(+), 65 deletions(-)
drivers/crypto/caam/ctrl.c +4 -12
index bdf367f3f679..ea3ed9a17f1a 100644
@@ -7,6 +7,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/devm-helpers.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
@@ -604,11 +605,6 @@ static int init_clocks(struct device *dev, const struct caam_imx_data *data)
 	return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv);
 }
 
-static void caam_remove_debugfs(void *root)
-{
-	debugfs_remove_recursive(root);
-}
-
 #ifdef CONFIG_FSL_MC_BUS
 static bool check_version(struct fsl_mc_version *mc_version, u32 major,
 			  u32 minor, u32 revision)
@@ -1058,13 +1054,9 @@ static int caam_probe(struct platform_device *pdev)
 	ctrlpriv->era = caam_get_era(perfmon);
 	ctrlpriv->domain = iommu_get_domain_for_dev(dev);
 
-	dfs_root = debugfs_create_dir(dev_name(dev), NULL);
-	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		ret = devm_add_action_or_reset(dev, caam_remove_debugfs,
-					       dfs_root);
-		if (ret)
-			return ret;
-	}
+	dfs_root = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(dfs_root))
+		return PTR_ERR(dfs_root);
 
 	caam_debugfs_init(ctrlpriv, perfmon, dfs_root);
 
drivers/gpio/gpio-mockup.c +3 -8
index 455eecf6380e..adbe0fe09490 100644
@@ -12,6 +12,7 @@
 #include <linux/cleanup.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/devm-helpers.h>
 #include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -390,13 +391,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
 	}
 }
 
-static void gpio_mockup_debugfs_cleanup(void *data)
-{
-	struct gpio_mockup_chip *chip = data;
-
-	debugfs_remove_recursive(chip->dbg_dir);
-}
-
 static void gpio_mockup_dispose_mappings(void *data)
 {
 	struct gpio_mockup_chip *chip = data;
@@ -480,7 +474,8 @@ static int gpio_mockup_probe(struct platform_device *pdev)
 
 	gpio_mockup_debugfs_setup(dev, chip);
 
-	return devm_add_action_or_reset(dev, gpio_mockup_debugfs_cleanup, chip);
+	return devm_add_action_or_reset(dev, devm_debugfs_dir_recursive_drop,
+					chip->dbg_dir);
 }
 
 static const struct of_device_id gpio_mockup_of_match[] = {
drivers/gpu/drm/bridge/ti-sn65dsi86.c +2 -11
index 84698a0b27a8..85987350f108 100644
@@ -10,6 +10,7 @@
 #include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/devm-helpers.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/i2c.h>
@@ -427,18 +428,12 @@ static int status_show(struct seq_file *s, void *data)
 
 DEFINE_SHOW_ATTRIBUTE(status);
 
-static void ti_sn65dsi86_debugfs_remove(void *data)
-{
-	debugfs_remove_recursive(data);
-}
-
 static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata)
 {
 	struct device *dev = pdata->dev;
 	struct dentry *debugfs;
-	int ret;
 
-	debugfs = debugfs_create_dir(dev_name(dev), NULL);
+	debugfs = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
 
 	/*
 	 * We might get an error back if debugfs wasn't enabled in the kernel
@@ -447,10 +442,6 @@ static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata)
 	if (IS_ERR_OR_NULL(debugfs))
 		return;
 
-	ret = devm_add_action_or_reset(dev, ti_sn65dsi86_debugfs_remove, debugfs);
-	if (ret)
-		return;
-
 	debugfs_create_file("status", 0600, debugfs, pdata, &status_fops);
 }
 
drivers/hwmon/hp-wmi-sensors.c +2 -13
index b5325d0e72b9..2a7c33763ce8 100644
@@ -23,6 +23,7 @@
 
 #include <linux/acpi.h>
 #include <linux/debugfs.h>
+#include <linux/devm-helpers.h>
 #include <linux/hwmon.h>
 #include <linux/jiffies.h>
 #include <linux/mutex.h>
@@ -1304,12 +1305,6 @@ static int current_reading_show(struct seq_file *seqf, void *ignored)
 }
 DEFINE_SHOW_ATTRIBUTE(current_reading);
 
-/* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */
-static void hp_wmi_devm_debugfs_remove(void *res)
-{
-	debugfs_remove_recursive(res);
-}
-
 /* hp_wmi_debugfs_init - create and populate debugfs directory tree */
 static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info,
 				struct hp_wmi_platform_events *pevents,
@@ -1320,21 +1315,15 @@ static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info,
 	struct dentry *debugfs;
 	struct dentry *entries;
 	struct dentry *dir;
-	int err;
 	u8 i;
 
 	/* dev_name() gives a not-very-friendly GUID for WMI devices. */
 	scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id);
 
-	debugfs = debugfs_create_dir(buf, NULL);
+	debugfs = devm_debugfs_create_dir(dev, buf, NULL);
 	if (IS_ERR(debugfs))
 		return;
 
-	err = devm_add_action_or_reset(dev, hp_wmi_devm_debugfs_remove,
-				       debugfs);
-	if (err)
-		return;
-
 	entries = debugfs_create_dir("sensor", debugfs);
 
 	for (i = 0; i < icount; i++, info++) {
drivers/hwmon/mr75203.c +5 -10
index 50a8b9c3f94d..50f348fca108 100644
@@ -10,6 +10,7 @@
 #include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/devm-helpers.h>
 #include <linux/hwmon.h>
 #include <linux/kstrtox.h>
 #include <linux/module.h>
@@ -216,17 +217,11 @@ static const struct file_operations pvt_ts_coeff_j_fops = {
 	.llseek = default_llseek,
 };
 
-static void devm_pvt_ts_dbgfs_remove(void *data)
-{
-	struct pvt_device *pvt = (struct pvt_device *)data;
-
-	debugfs_remove_recursive(pvt->dbgfs_dir);
-	pvt->dbgfs_dir = NULL;
-}
-
 static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
 {
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);
 
 	debugfs_create_u32("ts_coeff_h", 0644, pvt->dbgfs_dir,
 			   &pvt->ts_coeff.h);
@@ -237,7 +232,7 @@ static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
 	debugfs_create_file("ts_coeff_j", 0644, pvt->dbgfs_dir, pvt,
 			    &pvt_ts_coeff_j_fops);
 
-	return devm_add_action_or_reset(dev, devm_pvt_ts_dbgfs_remove, pvt);
+	return 0;
 }
 
 static umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type,
drivers/hwmon/pmbus/pmbus_core.c +5 -11
index cb4c65a7f288..88d27bb3b69a 100644
@@ -7,6 +7,7 @@
  */
 
 #include <linux/debugfs.h>
+#include <linux/devm-helpers.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
 #include <linux/module.h>
@@ -3336,13 +3337,6 @@ static const struct file_operations pmbus_debugfs_ops_mfr = {
 	.open = simple_open,
 };
 
-static void pmbus_remove_debugfs(void *data)
-{
-	struct dentry *entry = data;
-
-	debugfs_remove_recursive(entry);
-}
-
 static int pmbus_init_debugfs(struct i2c_client *client,
 			      struct pmbus_data *data)
 {
@@ -3357,8 +3351,9 @@ static int pmbus_init_debugfs(struct i2c_client *client,
 	 * Create the debugfs directory for this device. Use the hwmon device
 	 * name to avoid conflicts (hwmon numbers are globally unique).
 	 */
-	data->debugfs = debugfs_create_dir(dev_name(data->hwmon_dev),
-					   pmbus_debugfs_dir);
+	data->debugfs = devm_debugfs_create_dir(data->dev,
+						dev_name(data->hwmon_dev),
+						pmbus_debugfs_dir);
 	if (IS_ERR_OR_NULL(data->debugfs)) {
 		data->debugfs = NULL;
 		return -ENODEV;
@@ -3542,8 +3537,7 @@ static int pmbus_init_debugfs(struct i2c_client *client,
 		}
 	}
 
-	return devm_add_action_or_reset(data->dev,
-					pmbus_remove_debugfs, data->debugfs);
+	return 0;
 }
 #else
 static int pmbus_init_debugfs(struct i2c_client *client,
include/linux/devm-helpers.h +40 -0
index 3805551fd433..feefe152c752 100644
@@ -23,6 +23,7 @@
  * already ran.
  */
 
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/kconfig.h>
 #include <linux/irqdomain.h>
@@ -130,4 +131,43 @@ static inline int devm_irq_create_mapping(struct device *dev,
 	return virq;
 }
 
+static inline void devm_debugfs_dir_recursive_drop(void *res)
+{
+	debugfs_remove_recursive(res);
+}
+
+/**
+ * devm_debugfs_create_dir - Resource managed debugfs directory creation
+ * @dev:	Device which lifetime the directory is bound to
+ * @name:	a pointer to a string containing the name of the directory to
+ *		create
+ * @parent:	a pointer to the parent dentry for this file.  This should be a
+ *		directory dentry if set.  If this parameter is NULL, then the
+ *		directory will be created in the root of the debugfs filesystem.
+ *
+ * Create a debugfs directory which is automatically recursively removed when
+ * the driver is detached. A few drivers create debugfs directories which they
+ * want removed before driver is detached.
+ * devm_debugfs_create_dir() can be used to omit the explicit
+ * debugfs_remove_recursive() call when driver is detached.
+ */
+static inline struct dentry *
+devm_debugfs_create_dir(struct device *dev, const char *name,
+			struct dentry *parent)
+{
+	struct dentry *dentry;
+	int err;
+
+	dentry = debugfs_create_dir(name, parent);
+	if (IS_ERR(dentry))
+		return dentry;
+
+	err = devm_add_action_or_reset(dev, devm_debugfs_dir_recursive_drop,
+				       dentry);
+	if (err < 0)
+		return ERR_PTR(err);
+
+	return dentry;
+}
+
 #endif
Signature · 1 line
2.43.2
maintainer
#25 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

Quoted 5 lines · Marek Behún

A few drivers register a devm action to remove a debugfs directory, implementing a one-liner function that calls debufs_remove_recursive(). Help drivers avoid this repeated implementations by adding managed version of debugfs directory create function.

Quoted 8 lines

Use the new function devm_debugfs_create_dir() in the following drivers:

   drivers/crypto/caam/ctrl.c
   drivers/gpu/drm/bridge/ti-sn65dsi86.c
   drivers/hwmon/hp-wmi-sensors.c
   drivers/hwmon/mr75203.c
   drivers/hwmon/pmbus/pmbus_core.c

Please split this up into multiple patches, at least separating out the hwmon patches.

Guenter

author maintainer
#26 lore raw

PATCH v5 9/11 platform: cznic: turris-omnia-mcu: Add support for digital message signing via debugfs

In reply to Marek Behún

Add support for digital message signing with private key stored in the MCU. Boards with MKL MCUs have a NIST256p ECDSA private key created when manufactured. The private key is not readable from the MCU, but MCU allows for signing messages with it and retrieving the public key.

As described in a similar commit 50524d787de3 ("firmware:
turris-mox-rwtm: support ECDSA signatures via debugfs"):
The optimal solution would be to register an akcipher provider via kernel's crypto API, but crypto API does not yet support accessing akcipher API from userspace (and probably won't for some time, see
https://www.spinics.net/lists/linux-crypto/msg38388.html).

Therefore we add support for accessing this signature generation mechanism via debugfs for now, so that userspace can access it.

---
 .../ABI/testing/debugfs-turris-omnia-mcu      |  13 ++
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  13 ++
 MAINTAINERS                                   |   1 +
 drivers/platform/cznic/Kconfig                |   2 +
 drivers/platform/cznic/Makefile               |  12 +-
 .../platform/cznic/turris-omnia-mcu-base.c    |  45 +++-
 .../platform/cznic/turris-omnia-mcu-debugfs.c | 216 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  40 +++-
 8 files changed, 331 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-turris-omnia-mcu
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-debugfs.c
Documentation/ABI/testing/debugfs-turris-omnia-mcu new file +13 -0
new file mode 100644
index 000000000000..1665005c2dcd
@@ -0,0 +1,13 @@
+What:		/sys/kernel/debug/turris-omnia-mcu/do_sign
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:
+
+		======= ===========================================================
+		(Write) Message to sign with the ECDSA private key stored in MCU.
+		        The message must be exactly 32 bytes long (since this is
+		        intended to be a SHA-256 hash).
+		(Read)  The resulting signature, 64 bytes. This contains the R and
+			S values of the ECDSA signature, both in big-endian format.
+		======= ===========================================================
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +13 -0
index 564119849388..b239224cf9bc 100644
@@ -90,6 +90,19 @@ Description:	(RO) Contains the microcontroller type (STM32, GD32, MKL).
 
 		Format: %s.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/public_key
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains board ECDSA public key.
+
+		Only available if MCU supports signing messages with the ECDSA
+		algorithm. If so, the board has a private key stored in the MCU
+		that was generated during manufacture and cannot be retrieved
+		from the MCU.
+
+		Format: %s.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/reset_selector
 Date:		July 2024
 KernelVersion:	6.10
MAINTAINERS +1 -0
index 529e16d386e8..3706a4ec818e 100644
@@ -2139,6 +2139,7 @@ M:	Marek Behún <[email protected]>
 S:	Maintained
 W:	https://www.turris.cz/
 F:	Documentation/ABI/testing/debugfs-moxtet
+F:	Documentation/ABI/testing/debugfs-turris-omnia-mcu
 F:	Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
 F:	Documentation/ABI/testing/sysfs-bus-moxtet-devices
 F:	Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
drivers/platform/cznic/Kconfig +2 -0
index 750d5f47dba8..2d45495c0a2d 100644
@@ -30,6 +30,8 @@ config TURRIS_OMNIA_MCU
 	    disabled) and the ability to configure wake up from this mode (via
 	    rtcwake)
 	  - true random number generator (if available on the MCU)
+	  - ECDSA message signing with board private key (if available on the
+	    MCU)
 	  - MCU watchdog
 	  - GPIO pins
 	    - to get front button press events (the front button can be
drivers/platform/cznic/Makefile +7 -5
index 8fd4c6cbcb1b..22ac5075b750 100644
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
-turris-omnia-mcu-objs		:= turris-omnia-mcu-base.o
-turris-omnia-mcu-objs		+= turris-omnia-mcu-gpio.o
-turris-omnia-mcu-objs		+= turris-omnia-mcu-sys-off-wakeup.o
-turris-omnia-mcu-objs		+= turris-omnia-mcu-trng.o
-turris-omnia-mcu-objs		+= turris-omnia-mcu-watchdog.o
+turris-omnia-mcu-objs-y		:= turris-omnia-mcu-base.o
+turris-omnia-mcu-objs-y		+= turris-omnia-mcu-gpio.o
+turris-omnia-mcu-objs-y		+= turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-objs-y		+= turris-omnia-mcu-trng.o
+turris-omnia-mcu-objs-y		+= turris-omnia-mcu-watchdog.o
+turris-omnia-mcu-objs-$(CONFIG_DEBUG_FS) += turris-omnia-mcu-debugfs.o
+turris-omnia-mcu-objs		:= $(turris-omnia-mcu-objs-y)
drivers/platform/cznic/turris-omnia-mcu-base.c +44 -1

81 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu-debugfs.c new file +216 -0

216 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +35 -5
index f5b8f7ed3e6e..b4f1f2e8f936 100644
@@ -22,6 +22,9 @@
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
+#define OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN	33
+#define OMNIA_MCU_CRYPTO_SIGNATURE_LEN	64
+
 struct omnia_mcu {
 	struct i2c_client *client;
 	const char *type;
@@ -31,6 +34,7 @@ struct omnia_mcu {
 	u64 board_serial_number;
 	u8 board_first_mac[ETH_ALEN];
 	u8 board_revision;
+	u8 board_public_key[OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN];
 
 	/* GPIO chip */
 	struct gpio_chip gc;
@@ -52,6 +56,16 @@ struct omnia_mcu {
 	/* true random number generator */
 	struct hwrng trng;
 	struct completion trng_completion;
+
+#ifdef CONFIG_DEBUG_FS
+	/* MCU ECDSA message signing via debugfs */
+	struct dentry *debugfs_root;
+	struct completion msg_signed_completion;
+	struct mutex sign_lock;
+	unsigned int sign_state;
+	u8 signature[OMNIA_MCU_CRYPTO_SIGNATURE_LEN];
+	int sign_err;
+#endif
 };
 
 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -94,19 +108,20 @@ static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
 	return omnia_cmd_write(client, buf, sizeof(buf));
 }
 
-static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
-				 void *reply, unsigned int len)
+static inline int omnia_cmd_write_read(const struct i2c_client *client,
+				       void *cmd, unsigned int cmd_len,
+				       void *reply, unsigned int reply_len)
 {
 	struct i2c_msg msgs[2];
 	int ret;
 
 	msgs[0].addr = client->addr;
 	msgs[0].flags = 0;
-	msgs[0].len = 1;
-	msgs[0].buf = &cmd;
+	msgs[0].len = cmd_len;
+	msgs[0].buf = cmd;
 	msgs[1].addr = client->addr;
 	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = len;
+	msgs[1].len = reply_len;
 	msgs[1].buf = reply;
 
 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
@@ -118,6 +133,12 @@ static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
 	return 0;
 }
 
+static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
+				 void *reply, unsigned int len)
+{
+	return omnia_cmd_write_read(client, &cmd, 1, reply, len);
+}
+
 /* Returns 0 on success */
 static inline int omnia_cmd_read_bits(const struct i2c_client *client, u8 cmd,
 				      u32 bits, u32 *dst)
@@ -181,4 +202,13 @@ int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
 int omnia_mcu_register_trng(struct omnia_mcu *mcu);
 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
 
+#ifdef CONFIG_DEBUG_FS
+int omnia_mcu_register_debugfs(struct omnia_mcu *mcu);
+#else
+static inline int omnia_mcu_register_debugfs(struct omnia_mcu *mcu)
+{
+	return 0;
+}
+#endif
+
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#27 lore raw

PATCH v5 10/11 ARM: dts: turris-omnia: Add MCU system-controller node

In reply to Marek Behún

Turris Omnia's MCU provides various features that can be configured over I2C at address 0x2a. Add device-tree node.

Fixes 26ca8b52d6e1 ("ARM: dts: add support for Turris Omnia")

---
Changes since v4:
- #gpio-cells set to 3 instead of 2, see patch 01/11

---
 .../dts/marvell/armada-385-turris-omnia.dts   | 22 ++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +21 -1
index 7b755bb4e4e7..59079d63fe27 100644
@@ -218,7 +218,22 @@ i2c@0 {
 			#size-cells = <0>;
 			reg = <0>;
 
-			/* STM32F0 command interface at address 0x2a */
+			mcu: system-controller@2a {
+				compatible = "cznic,turris-omnia-mcu";
+				reg = <0x2a>;
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcu_pins>;
+
+				interrupt-parent = <&gpio1>;
+				interrupts = <11 IRQ_TYPE_NONE>;
+
+				gpio-controller;
+				#gpio-cells = <3>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
 
 			led-controller@2b {
 				compatible = "cznic,turris-omnia-leds";
@@ -501,6 +516,11 @@ fixed-link {
 };
 
 &pinctrl {
+	mcu_pins: mcu-pins {
+		marvell,pins = "mpp43";
+		marvell,function = "gpio";
+	};
+
 	pcawan_pins: pcawan-pins {
 		marvell,pins = "mpp46";
 		marvell,function = "gpio";
Signature · 1 line
2.43.2
author maintainer
#28 lore raw

PATCH v5 11/11 ARM: dts: turris-omnia: Add GPIO key node for front button

In reply to Marek Behún

Now that we have the MCU device-tree node, which acts as a GPIO controller, add GPIO key node for the front button.

Fixes 26ca8b52d6e1 ("ARM: dts: add support for Turris Omnia")

---
Changes since v4:
- gpio specifier has 3 args instead of 2, see patch 01/11

---
 .../boot/dts/marvell/armada-385-turris-omnia.dts    | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +13 -0
index 59079d63fe27..43202890c959 100644
@@ -112,6 +112,19 @@ sfp: sfp {
 		status = "disabled";
 	};
 
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		front-button {
+			label = "Front Button";
+			linux,code = <KEY_VENDOR>;
+			linux,can-disable;
+			gpios = <&mcu 0 12 GPIO_ACTIVE_HIGH>;
+			/* debouncing is done by the microcontroller */
+			debounce-interval = <0>;
+		};
+	};
+
 	sound {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "SPDIF";
Signature · 1 line
2.43.2

A message that is not in the archive (sent off-list or not yet received): 20240323164359.21642-9-kabel__6885.49310886941$1711212291$gmane$org@kernel.org

#30 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

Le 23/03/2024 à 17:43, Marek Behún a écrit :

Quoted 32 lines

A few drivers register a devm action to remove a debugfs directory, implementing a one-liner function that calls debufs_remove_recursive(). Help drivers avoid this repeated implementations by adding managed version of debugfs directory create function.

Use the new function devm_debugfs_create_dir() in the following drivers:

   drivers/crypto/caam/ctrl.c
   drivers/gpu/drm/bridge/ti-sn65dsi86.c
   drivers/hwmon/hp-wmi-sensors.c
   drivers/hwmon/mr75203.c
   drivers/hwmon/pmbus/pmbus_core.c

Also use the action function devm_debugfs_dir_recursive_drop() in driver
drivers/gpio/gpio-mockup.c

As per Dan Williams' request [1], do not touch the driver
drivers/cxl/mem.c

[1] https://lore.kernel.org/linux-gpio/65d7918b358a5_1ee3129432@dwillia2-mobl3.amr.corp.intel.com.notmuch/

---
  drivers/crypto/caam/ctrl.c            | 16 +++--------
  drivers/gpio/gpio-mockup.c            | 11 ++------
  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 13 ++-------
  drivers/hwmon/hp-wmi-sensors.c        | 15 ++--------
  drivers/hwmon/mr75203.c               | 15 ++++------
  drivers/hwmon/pmbus/pmbus_core.c      | 16 ++++-------
  include/linux/devm-helpers.h          | 40 +++++++++++++++++++++++++++
  7 files changed, 61 insertions(+), 65 deletions(-)

...

Quoted 27 lines
drivers/gpio/gpio-mockup.c +1 -7
index 455eecf6380e..adbe0fe09490 100644
@@ -12,6 +12,7 @@
  #include <linux/cleanup.h>
  #include <linux/debugfs.h>
  #include <linux/device.h>
+#include <linux/devm-helpers.h>
  #include <linux/gpio/driver.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
@@ -390,13 +391,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
  	}
  }
 
-static void gpio_mockup_debugfs_cleanup(void *data)
-{
-	struct gpio_mockup_chip *chip = data;
-
-	debugfs_remove_recursive(chip->dbg_dir);
-}
-
  static void gpio_mockup_dispose_mappings(void *data)
  {
  	struct gpio_mockup_chip *chip = data;

drivers/gpio/gpio-mockup.c static int gpio_mockup_probe(struct platform_device *pdev) · line 478

Quoted 6 lines
drivers/gpio/gpio-mockup.c +2 -1
@@ -480,7 +474,8 @@ static int gpio_mockup_probe(struct platform_device *pdev)
 
  	gpio_mockup_debugfs_setup(dev, chip);
 
-	return devm_add_action_or_reset(dev, gpio_mockup_debugfs_cleanup, chip);
+	return devm_add_action_or_reset(dev, devm_debugfs_dir_recursive_drop,
+					chip->dbg_dir);

This look strange. Shouldn't the debugfs_create_dir() call in gpio_mockup_debugfs_setup() be changed, instead?

(I've not look in the previous version if something was said about it, so apologies if already discussed)

Quoted 3 lines
drivers/gpio/gpio-mockup.c +0 -0
  }
 
  static const struct of_device_id gpio_mockup_of_match[] = {

...

Quoted 20 lines
drivers/hwmon/mr75203.c +1 -4
index 50a8b9c3f94d..50f348fca108 100644
@@ -10,6 +10,7 @@
  #include <linux/bits.h>
  #include <linux/clk.h>
  #include <linux/debugfs.h>
+#include <linux/devm-helpers.h>
  #include <linux/hwmon.h>
  #include <linux/kstrtox.h>
  #include <linux/module.h>
@@ -216,17 +217,11 @@ static const struct file_operations pvt_ts_coeff_j_fops = {
  	.llseek = default_llseek,
  };
 
-static void devm_pvt_ts_dbgfs_remove(void *data)
-{
-	struct pvt_device *pvt = (struct pvt_device *)data;
-

drivers/hwmon/mr75203.c static const struct file_operations pvt_ts_coeff_j_fops = { · line 224

Quoted 10 lines
drivers/hwmon/mr75203.c +3 -5
-	debugfs_remove_recursive(pvt->dbgfs_dir);
-	pvt->dbgfs_dir = NULL;
-}
-
  static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
  {
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);

Not sure if the test and error handling should be added here.
*If I'm correct*, functions related to debugfs already handle this case and just do nothing. And failure in debugfs related code is not considered as something that need to be reported and abort a probe function.

Maybe the same other (already existing) tests in this patch should be removed as well, in a separated patch.

just my 2c

CJ

Quoted 10 lines
drivers/hwmon/mr75203.c +1 -1
  	debugfs_create_u32("ts_coeff_h", 0644, pvt->dbgfs_dir,
  			   &pvt->ts_coeff.h);
@@ -237,7 +232,7 @@ static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
  	debugfs_create_file("ts_coeff_j", 0644, pvt->dbgfs_dir, pvt,
  			    &pvt_ts_coeff_j_fops);
 
-	return devm_add_action_or_reset(dev, devm_pvt_ts_dbgfs_remove, pvt);
+	return 0;
  }

...

author maintainer
#31 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

Quoted 9 lines · On Sat, 23 Mar 2024 22:10:40 +0100 Christophe JAILLET…

Review

Quoted 3 lines
(quoted diff) +2 -1
-	return devm_add_action_or_reset(dev, gpio_mockup_debugfs_cleanup, chip);
+	return devm_add_action_or_reset(dev, devm_debugfs_dir_recursive_drop,
+					chip->dbg_dir);  

This look strange. Shouldn't the debugfs_create_dir() call in gpio_mockup_debugfs_setup() be changed, instead?

(I've not look in the previous version if something was said about it, so apologies if already discussed)

Yeah, this specific user needs a more complicated refactoring.

I was reluctant to do more complicated refactors in the patch that also introduces these helpers.

But Guenter asked me to split the patch anyway...

Quoted 12 lines

Review

Quoted 6 lines
  static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
  {
(quoted diff) +3 -1
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);  

Not sure if the test and error handling should be added here. *If I'm correct*, functions related to debugfs already handle this case and just do nothing. And failure in debugfs related code is not considered as something that need to be reported and abort a probe function.

Quoted 2 lines

Maybe the same other (already existing) tests in this patch should be removed as well, in a separated patch.

Functions related to debugfs maybe do, but devm_ resource management functions may fail to allocate release structure, and those errors need to be handled, AFAIK.

Marek

#32 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

Le 23/03/2024 à 22:25, Marek Behún a écrit :

Quoted 3 lines

On Sat, 23 Mar 2024 22:10:40 +0100
Christophe JAILLET <[email protected]> wrote:

...

Quoted 12 lines
Quoted 12 lines

Review

Quoted 6 lines
   static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
   {
(quoted diff) +3 -1
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);

Not sure if the test and error handling should be added here. *If I'm correct*, functions related to debugfs already handle this case and just do nothing. And failure in debugfs related code is not considered as something that need to be reported and abort a probe function.

Quoted 6 lines
Quoted 2 lines

Maybe the same other (already existing) tests in this patch should be removed as well, in a separated patch.

Functions related to debugfs maybe do, but devm_ resource management functions may fail to allocate release structure, and those errors need to be handled, AFAIK.

I would say no.
If this memory allocation fails, then debugfs_create_dir() will not be called, but that's not a really big deal if the driver itself can still run normally without it.

Up to you to leave it as-is or remove what I think is a useless error handling.
At least, maybe it could be said in the commit log, so that maintainers can comment on it, if they don't spot the error handling you introduce.

CJ

Quoted 3 lines

Marek

author maintainer
#33 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

Quoted 22 lines · On Sun, 24 Mar 2024 10:21:28 +0100 Christophe JAILLET…

Le 23/03/2024 à 22:25, Marek Behún a écrit :

Quoted 3 lines

On Sat, 23 Mar 2024 22:10:40 +0100
Christophe JAILLET <[email protected]> wrote:

...

Quoted 15 lines
Quoted 14 lines

Review

Quoted 6 lines
   static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
   {
(quoted diff) +3 -1
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);  

Not sure if the test and error handling should be added here. *If I'm correct*, functions related to debugfs already handle this case and just do nothing. And failure in debugfs related code is not considered as something that need to be reported and abort a probe function.

Maybe the same other (already existing) tests in this patch should be removed as well, in a separated patch.

Quoted 8 lines
Quoted 3 lines

Functions related to debugfs maybe do, but devm_ resource management functions may fail to allocate release structure, and those errors need to be handled, AFAIK.

I would say no.
If this memory allocation fails, then debugfs_create_dir() will not be called, but that's not a really big deal if the driver itself can still run normally without it.

debugfs_create_dir() will always be called. Resource allocation is done afterwards, and if it fails, then the created dir will be removed.

But now I don't know what to do, because yes, it seems that the debugfs errors are being ignored at many places...

Quoted 12 lines

Up to you to leave it as-is or remove what I think is a useless error handling.
At least, maybe it could be said in the commit log, so that maintainers can comment on it, if they don't spot the error handling you introduce.

CJ

Quoted 3 lines

Marek

#34 lore raw

Re: [PATCH v5 08/11] devm-helpers: Add resource managed version of debugfs directory create function

In reply to Christophe JAILLET
Quoted 8 lines · Christophe JAILLET

Review

Quoted 6 lines
  static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev)
  {
(quoted diff) +3 -1
-	pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
+	pvt->dbgfs_dir = devm_debugfs_create_dir(dev, dev_name(dev), NULL);
+	if (IS_ERR(pvt->dbgfs_dir))
+		return PTR_ERR(pvt->dbgfs_dir);

Not sure if the test and error handling should be added here.

Yep. debugfs_create_dir() is not supposed to be checked here. It breaks the driver if CONFIG_DEBUGFS is disabled. I have written a blog about this:

https://staticthinking.wordpress.com/2023/07/24/debugfs-functions-are-not-supposed-to-be-checked/

regards,
dan carpenter