diff options
| author | Kumar Kartikeya Dwivedi <memxor@gmail.com> | 2026-09-04 10:43:19 +0200 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-09-04 07:58:36 -0700 |
| commit | 6668ed271eaefaa63e686bdfbedaeb7b8e492722 (patch) | |
| tree | 58e8288fead484f6755ad0815fc74c3742663761 /drivers/clk/qcom/gdsc.h | |
| download | linux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.tar.gz linux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.zip | |
selftests/bpf: Reject graph kptr use after RCU unlockgrafted
Add a sleepable verifier test that loads a graph-node local kptr in an
explicit RCU read-side critical section, then passes its node to
bpf_rbtree_remove() after the section ends.
Before the verifier fix, the stale NON_OWN_REF flag makes the node look like
a live borrowed reference and the program is accepted. After the fix, the
pointer is demoted without NON_OWN_REF and the graph kfunc argument is
rejected.
Also exercise a graph kptr loaded while a spin lock provides implicit RCU
protection. The pointer must be invalidated when the lock is released, which
guards the required ordering between non-owning-reference invalidation and
RCU demotion.
Update the existing fault-protected load test state description. The
post-unlock pointer no longer carries NON_OWN_REF, but remains readable
because the load is rewritten to use BPF_PROBE_MEM.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260904084325.52250-7-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'drivers/clk/qcom/gdsc.h')
| -rw-r--r-- | drivers/clk/qcom/gdsc.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h new file mode 100644 index 000000000..92ff6bcce --- /dev/null +++ b/drivers/clk/qcom/gdsc.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved. + */ + +#ifndef __QCOM_GDSC_H__ +#define __QCOM_GDSC_H__ + +#include <linux/err.h> +#include <linux/pm_domain.h> + +struct icc_path; +struct regmap; +struct regulator; +struct reset_controller_dev; + +/** + * struct gdsc - Globally Distributed Switch Controller + * @pd: generic power domain + * @regmap: regmap for MMIO accesses + * @gdscr: gsdc control register + * @collapse_ctrl: APCS collapse-vote register + * @collapse_mask: APCS collapse-vote mask + * @gds_hw_ctrl: gds_hw_ctrl register + * @cxcs: offsets of branch registers to toggle mem/periph bits in + * @cxc_count: number of @cxcs + * @pwrsts: Possible powerdomain power states + * @en_rest_wait_val: transition delay value for receiving enr ack signal + * @en_few_wait_val: transition delay value for receiving enf ack signal + * @clk_dis_wait_val: transition delay value for halting clock + * @resets: ids of resets associated with this gdsc + * @reset_count: number of @resets + * @rcdev: reset controller + */ +struct gdsc { + struct generic_pm_domain pd; + struct generic_pm_domain *parent; + struct regmap *regmap; + unsigned int gdscr; + unsigned int collapse_ctrl; + unsigned int collapse_mask; + unsigned int gds_hw_ctrl; + unsigned int clamp_io_ctrl; + unsigned int *cxcs; + unsigned int cxc_count; + unsigned int en_rest_wait_val; + unsigned int en_few_wait_val; + unsigned int clk_dis_wait_val; + const u8 pwrsts; +/* Powerdomain allowable state bitfields */ +#define PWRSTS_OFF BIT(0) +/* + * There is no SW control to transition a GDSC into + * PWRSTS_RET. This happens in HW when the parent + * domain goes down to a low power state + */ +#define PWRSTS_RET BIT(1) +#define PWRSTS_ON BIT(2) +#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) +#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) + const u16 flags; +#define VOTABLE BIT(0) +#define CLAMP_IO BIT(1) +#define HW_CTRL BIT(2) +#define SW_RESET BIT(3) +#define AON_RESET BIT(4) +#define POLL_CFG_GDSCR BIT(5) +#define ALWAYS_ON BIT(6) +#define RETAIN_FF_ENABLE BIT(7) +#define NO_RET_PERIPH BIT(8) +#define HW_CTRL_TRIGGER BIT(9) + struct reset_controller_dev *rcdev; + unsigned int *resets; + unsigned int reset_count; + + const char *supply; + struct regulator *rsupply; + + bool needs_icc; + unsigned int icc_path_index; + struct icc_path *icc_path; +}; + +struct gdsc_desc { + struct device *dev; + struct gdsc **scs; + size_t num; + struct dev_pm_domain_list *pd_list; +}; + +#ifdef CONFIG_QCOM_GDSC +int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *, + struct regmap *); +void gdsc_unregister(struct gdsc_desc *desc); +int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain); +#else +static inline int gdsc_register(struct gdsc_desc *desc, + struct reset_controller_dev *rcdev, + struct regmap *r) +{ + return -ENOSYS; +} + +static inline void gdsc_unregister(struct gdsc_desc *desc) {}; +#endif /* CONFIG_QCOM_GDSC */ +#endif /* __QCOM_GDSC_H__ */ |
