diff options
| author | Miguel Ojeda <ojeda@kernel.org> | 2026-08-16 15:32:33 +0200 |
|---|---|---|
| committer | Miguel Ojeda <ojeda@kernel.org> | 2026-08-23 21:27:17 +0200 |
| commit | 5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch) | |
| tree | 93a1ed1d337bc53adf1e572c2586d347703b286e /drivers/reset/reset-ath79.c | |
| download | linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip | |
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit
`objtool` errors such as:
vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a:
can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd
The reason is that in such builds, the Clang invocation that compiles
the combined Rust plus helpers bitcode emits LLVM bitcode (again) --
the final code generation happens in the linker's LTO step, which the
`-mllvm` trap options passed to Clang do not reach.
This, in turn, means that unreachable traps are missing, and the
impossible paths do not merely fallthrough to the next symbol, but past
the end of their own section, since LTO builds place each function in
its own section.
Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always
emits machine code directly, with the traps in place.
Assisted-by: LLM
Cc: Gary Guo <gary@garyguo.net>
Cc: Boqun Feng <boqun@kernel.org>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust")
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'drivers/reset/reset-ath79.c')
| -rw-r--r-- | drivers/reset/reset-ath79.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c new file mode 100644 index 000000000..1a2c0f8a5 --- /dev/null +++ b/drivers/reset/reset-ath79.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AR71xx Reset Controller Driver + * Author: Alban Bedel + * + * Copyright (C) 2015 Alban Bedel <albeu@free.fr> + */ + +#include <linux/io.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/reboot.h> + +struct ath79_reset { + struct reset_controller_dev rcdev; + void __iomem *base; + spinlock_t lock; +}; + +#define FULL_CHIP_RESET 24 + +static int ath79_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ath79_reset->lock, flags); + val = readl(ath79_reset->base); + if (assert) + val |= BIT(id); + else + val &= ~BIT(id); + writel(val, ath79_reset->base); + spin_unlock_irqrestore(&ath79_reset->lock, flags); + + return 0; +} + +static int ath79_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, true); +} + +static int ath79_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, false); +} + +static int ath79_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + u32 val; + + val = readl(ath79_reset->base); + + return !!(val & BIT(id)); +} + +static const struct reset_control_ops ath79_reset_ops = { + .assert = ath79_reset_assert, + .deassert = ath79_reset_deassert, + .status = ath79_reset_status, +}; + +static int ath79_reset_restart_handler(struct sys_off_data *data) +{ + struct ath79_reset *ath79_reset = data->cb_data; + + ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET); + + return NOTIFY_DONE; +} + +static int ath79_reset_probe(struct platform_device *pdev) +{ + struct ath79_reset *ath79_reset; + int err; + + ath79_reset = devm_kzalloc(&pdev->dev, + sizeof(*ath79_reset), GFP_KERNEL); + if (!ath79_reset) + return -ENOMEM; + + ath79_reset->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ath79_reset->base)) + return PTR_ERR(ath79_reset->base); + + spin_lock_init(&ath79_reset->lock); + ath79_reset->rcdev.ops = &ath79_reset_ops; + ath79_reset->rcdev.owner = THIS_MODULE; + ath79_reset->rcdev.of_node = pdev->dev.of_node; + ath79_reset->rcdev.of_reset_n_cells = 1; + ath79_reset->rcdev.nr_resets = 32; + + err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev); + if (err) + return err; + + err = devm_register_restart_handler(&pdev->dev, ath79_reset_restart_handler, ath79_reset); + if (err) + dev_warn(&pdev->dev, "Failed to register restart handler\n"); + + return 0; +} + +static const struct of_device_id ath79_reset_dt_ids[] = { + { .compatible = "qca,ar7100-reset", }, + { }, +}; + +static struct platform_driver ath79_reset_driver = { + .probe = ath79_reset_probe, + .driver = { + .name = "ath79-reset", + .of_match_table = ath79_reset_dt_ids, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(ath79_reset_driver); |
