adsp: fix the race between mmc0 and gpio-hogs - #3462
Conversation
Add a generic function to allow creation of groups and functions at runtime based on devicetree content, before setting up mux mappings. It works similarly to pinconf_generic_dt_node_to_map(), and therefore parses pinconf properties and maps those too, allowing it to be used as the dt_node_to_map member of the pinctrl_ops struct. Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Signed-off-by: Linus Walleij <linusw@kernel.org> [alvin: upstream commit 4372257 applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Rename the temporary devm_mux_state_get_optional function to avoid conflict with upcoming implementation in multiplexer subsystem. Signed-off-by: Josua Mayer <josua@solid-run.com> Acked-by: Vinod Koul <vkoul@kernel.org> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> [alvin: upstream commit b6376cc applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
In-tree phy-can-transceiver and phy_rcar_gen3_usb2 have already implemented local versions of devm_mux_state_get_optional. The omap-i2c driver gets and selects an optional mux in its probe function without using any helper. Add new helper functions covering both aforementioned use-cases: - mux_control_get_optional: Get a mux-control if specified in dt, return NULL otherwise. - devm_mux_state_get_optional: Get a mux-state if specified in dt, return NULL otherwise. - devm_mux_state_get_selected: Get and select a mux-state specified in dt, return error otherwise. - devm_mux_state_get_optional_selected: Get and select a mux-state if specified in dt, return error or NULL. Existing mux_get helper function is changed to take an extra argument indicating whether the mux is optional. In this case no error is printed, and NULL returned in case of ENOENT. Calling code is adapted to handle NULL return case, and to pass optional argument as required. To support automatic deselect for _selected helper, a new structure is created storing an exit pointer similar to clock core which is called on release. To facilitate code sharing between optional/mandatory/selected helpers, a new internal helper function is added to handle quiet (optional) and verbose (mandatory) errors, as well as storing the correct callback for devm release: __devm_mux_state_get Due to this structure devm_mux_state_get_*_selected can no longer print a useful error message when select fails. Instead callers should print errors where needed. Commit e153fde ("phy: can-transceiver: Re-instate "mux-states" property presence check") noted that "mux_get() always prints an error message in case of an error, including when the property is not present, confusing the user." The first error message covers the case that a mux name is not matched in dt. The second error message is based on of_parse_phandle_with_args return value. In optional case no error is printed and NULL is returned. This ensures that the new helper functions will not confuse the user either. With the addition of optional helper functions it became clear that drivers should compile and link even if CONFIG_MULTIPLEXER was not enabled. Add stubs for all symbols exported by mux core. Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Josua Mayer <josua@solid-run.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> [alvin: upstream commit 993bcaf applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Multiplexer subsystem has now added helpers for getting managed optional mux-state. Switch to the new devm_mux_state_get_optional helper. This change is only compile-tested. Acked-by: Vinod Koul <vkoul@kernel.org> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Josua Mayer <josua@solid-run.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> [alvin: upstream commit d76e0c5 applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Add new API devm_mux_state_get_from_np() to retrieve a mux control from
a specified child device node.
Make devm_mux_state_get() call devm_mux_state_get_from_np() with a NULL
node parameter, which defaults to using the device's own of_node.
Support the following DT schema:
pinctrl@0 {
uart-func {
mux-state = <&mux_chip 0>;
};
spi-func {
mux-state = <&mux_chip 1>;
};
};
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
[alvin: upstream commit 05e58da applied with no conflicts]
Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Add a generic pinctrl binding for board-level pinmux chips that are controlled through the multiplexer subsystem. On some boards, especially development boards, external mux chips are used to switch SoC signals between different peripherals (e.g. MMC and UART). The mux select lines are often driven by a GPIO expander over I2C, as illustrated below: ┌──────┐ ┌─────┐ │ SOC │ │ │ ┌───────┐ │ │ │ │───►│ MMC │ │ │ │ MUX │ └───────┘ │ ├─────►│ │ ┌───────┐ │ │ │ │───►│ UART │ │ │ └─────┘ └───────┘ │ │ ▲ │ │ ┌────┴──────────────┐ │ I2C ├───►│ GPIO Expander │ └──────┘ └───────────────────┘ Traditionally, gpio-hog is used to configure the onboard mux at boot. However, the GPIO expander may probe later than consumer devices such as MMC. As a result, the MUX might not be configured when the peripheral driver probes, leading to initialization failures or data transfer errors. Introduce a generic pinctrl binding that models the board-level MUX as a pin control provider and builds proper device links between the MUX, its GPIO controller, and peripheral devices. This ensures correct probe ordering and reliable mux configuration. The implementation leverages the standard multiplexer subsystem, which provides broad support for onboard mux controllers and avoids the need for per-driver custom MUX handling. Allow pinctrl-* pattern as node name because this pinctrl device have not reg property. Reviewed-by: Linus Walleij <linusw@kernel.org> Reviewed-by: Rob Herring (Arm) <robh@kernel.org> Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Linus Walleij <linusw@kernel.org> [alvin: upstream commit 9e5e1de applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
…unction_dt_node_to_map() Refactor pinctrl_generic_pins_function_dt_subnode_to_map() by separating DT parsing logic from map creation. Introduce a new helper pinctrl_generic_to_map() to handle mapping to kernel data structures, while keeping DT property parsing in the subnode function. Improve code structure and enables easier reuse for platforms using different DT properties (e.g. pinmux) without modifying the dt_node_to_map-style callback API. Avoid unnecessary coupling to pinctrl_generic_pins_function_dt_node_to_map(), which provides functionality not needed when the phandle target is unambiguous. Maximize code reuse and provide a cleaner extension point for future pinctrl drivers. Suggested-by: Conor Dooley <conor.dooley@microchip.com> Acked-by: Conor Dooley <conor.dooley@microchip.com> Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Linus Walleij <linusw@kernel.org> [alvin: upstream commit aaaf31b applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Add an optional .release_mux() callback to struct pinmux_ops. Some drivers acquire additional resources in .set_mux(), such as software locks. These resources may need to be released when the mux function is no longer active. Introducing a dedicated .release_mux() callback allows drivers to clean up such resources. The callback is optional and does not affect existing drivers. Commit 2243a87 ("pinctrl: avoid duplicated calling enable_pinmux_setting for a pin") removed the .disable() callback to resolve two issues: 1. desc->mux_usecount increasing monotonically 2. Hardware glitches caused by repeated .disable()/.enable() calls Adding .release_mux() does not reintroduce those problems. The callback is intended only for releasing driver-side resources (e.g. locks) and must not modify hardware registers. Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Linus Walleij <linusw@kernel.org> [alvin: upstream commit 418a2bb applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Many boards use on-board mux chips (often controlled by GPIOs from an I2C expander) to switch shared signals between peripherals. Add a generic pinctrl driver built on top of the mux framework to centralize mux handling and avoid probe ordering issues. Keep board-level routing out of individual drivers and supports boot-time only mux selection. Ensure correct probe ordering, especially when the GPIO expander is probed later. Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Linus Walleij <linusw@kernel.org> [alvin: upstream commit 34acc5a applied with no conflicts] Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
CONFIG_MULTIPLEXER can only be enabled indirectly. If it's not already enabled, then CONFIG_PINCTRL_GENERIC_MUX cannot be selected at all in menuconfig. That's because it depends on MULTIPLEXER. Follow similar consumers of the multiplexer core and select MULTIPLEXER instead. This way the driver will be visible in menuconfig as long as PINCTRL is selected. Fixes: 34acc5a ("pinctrl: add generic board-level pinctrl driver using mux framework") [alvin: submitted upstream, see Link] Link: https://lore.kernel.org/all/20260727-pinctrl-generic-mux-fix-kconfig-v1-1-5abebd6f1a8d@analog.com/ Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Just like on EZKIT, it's using the SoM's eMMC which is non-removable. Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
Since the consumers of the SoM's dtsi are the ones describing how the interface is set up (eMMC or SD card), they ought to enable explicitly. For HTOL it's then already disabled, so the lines can just be dropped. Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
The EV-SC598-SOM has several switches controlled by the MMC_EN* and MMC_SOM_EN* signals and through which the SoC's MSI0 pins are routed. This "soft config" allows for the signals either to be terminated, routed to the on-SoM eMMC, or routed through the SoM board-to-board connector into the carrier board. The whole network is essentially a mux. Describe it as such, with states 0, 1, and 2 respectively. Since this is not only a mux, but a pin mux, the generic pinctrl multiplexer can also be employed to expose the valid states (1 and 2) as consumable pinctrl groups. Define the two groups, mmc_som_grp and mmc_carrier_grp, meaning "route the MMC pins to the SoM (resp. carrier board)". Doing so allows for a race-free initialization of the pins before the MMC is probed. For each use-case in the downstream device trees for EZKIT and EZLITE, select the appropriate pinctrl group in &mmc0's pinctrl-0. In turn, drop the racy gpio-hogs. Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
b239c1a to
56cf224
Compare
|
Hmm, @gastmaier could you give me any pointers in how to fix this CI build failure? I don't understand the error, it seems spurious to me. The last time I looked into the CI build, it seemed it was using a different defconfig (#3409 (comment)) But that doesn't make sense to me for this either... do you know what the actual defconfig is that it's using? |
|
Hi @sipraga , I couldn't immediately replicate except this hint: oddly, the missing symbol is from core.c, a I believe you can safely ignore, and the fix would be pre-enabling the PINCTRL in the adi_ci_defconfig. |
@gastmaier thanks a lot for taking a look. I still don't understand what the CI is actually running/building in order to produce this error (and the other). How did you reproduce it on your end? |
nunojsa
left a comment
There was a problem hiding this comment.
Naturally there are some backports and an increase of the adsp patchset but I'm not going to debate on that :)! To me, the whole thing makes sense.
| CONFIG_USB_EHCI_HCD_PLATFORM=y | ||
| CONFIG_USB_OHCI_HCD=y | ||
| CONFIG_USB_OHCI_HCD_PLATFORM=y | ||
| CONFIG_USB_STORAGE=y |
There was a problem hiding this comment.
I'm seeing some unrelated stuff being enabled and changed! I might guess the reason for it but mentioning in the commit message would still make sense.
There was a problem hiding this comment.
Yikes! No, that was just a stupid mistake. Thanks for catching it! I have pushed the original commit now.
56cf224 to
a3043f7
Compare
|
Thanks @nunojsa for the review. I still don't want to merge until I have figured out the CI stuff though |
I'm sure Jorge will follow-up, but in case it helps you should be able to reproduce it locally as follows: https://analogdevicesinc.github.io/linux/ci.html#build-the-container-image Also a good opportunity to check the documentation and see if anything can be made more clear. 😄 |
|
@sipraga all ci/cd steps are reproducible locally with a little of bootstrapping |
|
Thanks, I was able to get into that same shell after building the CI container and running it with the container-run.sh script (I failed to make sense of how to run it manually). I then ran a few times and understand now that the build failure is the result of a kconfig misconfiguration. I eventually gave up trying to figure out how that config is actually assembled though... In general it shouldn't be possible to select GENERIC_PINCTRL if it has unmet dependencies, so I agree with you Jorge that the failure can be ignored. :-) Maybe the fix is indeed to add CONFIG_PINCTRL to the adi_ci_defconfig, but I still do not understand really how this works, so I am reluctant to make changes I don't understand. Anyway thanx for the pointers, will help me in future! |
They are needed to control the SoM's MMC mux. Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
They're needed to control the SoM's MMC mux. Signed-off-by: Alvin Šipraga <alvin.sipraga@analog.com>
a3043f7 to
f26e2be
Compare
|
Tested on sc598-som-ezkit, both eMMC and SD-card device trees. Verified also the consumer/supplier dependency chain, and that mmc returns -EPROBE_DEFER if the mux isn't available yet (e.g. CONFIG_MUX_GPIO=n ;-)). Ignoring CI per above discussion. |
PR Description
This is the second, more proper attempt to fix the issue originally identified in #3420 - namely, that the initialization of the MMC signal muxes can race with the actual probing of MMC. I noticed it when I was making unrelated changes in the kernel which likely triggered some different timings.
This time I have described the hardware properly, using gpio-mux and pinctrl-multiplexer. A more precise explanation of the changes can be found in the commit
arm64: dts: adi: sc598-som: describe the MMC muxes faithfully.You will notice a ton of seemingly unrelated commits. This is because our kernel doesn't have pinctrl-multiplexer. I chose to simply backport the required patches. They are not many, and all apply cleanly without any conflicts, meaning that a later rebase of the patch stack should make them disappear. I have annotated each commit with a small
[alvin: upstream commit xxxx]just in case. I could have cherry-picked fewer patches if I were to edit the pinctrl-multiplexer driver, but that would make it both harder to rebase and introduce possible bugs. And there'd still be quite a few patches anyway.Another alternative which would produce fewer patches is to modify the mmc driver to accept a
mux-statesDT property. But I wouldn't choose this path if our kernel were newer, so I elected not to do that, as it will just make more work for us in the future after updating the kernel.One thing I don't like about these changes is that I had to basically copy-paste the same stuff into som-revD and som-revE. Any suggestions for a better approach here are welcome. I know I could sneak it into the som.dtsi only once and it would still compile, but I dislike the idea of referencing the non-existent
som_gpio_expanderlabel in that file.PR Type
PR Checklist