On Wed, 5 Oct 2022 at 11:08, Akhil P Oommen <quic_akhilpo@xxxxxxxxxxx> wrote: > > Add a reset op compatible function to poll for gdsc collapse. This is > required because: > 1. We don't wait for it to turn OFF at hardware for VOTABLE GDSCs. > 2. There is no way for client drivers (eg. gpu driver) to do > put-with-wait for these gdscs which is required in some scenarios > (eg. GPU recovery). What puzzles me a bit, who is the typical consumer of the reset. I looked at patch4 and tried to figure it out, but let's discuss that in that thread instead. Some more comments, see below. > > Signed-off-by: Akhil P Oommen <quic_akhilpo@xxxxxxxxxxx> > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> > --- > > Changes in v7: > - Update commit message (Bjorn) > > Changes in v2: > - Minor update to function prototype > > drivers/clk/qcom/gdsc.c | 23 +++++++++++++++++++---- > drivers/clk/qcom/gdsc.h | 7 +++++++ > 2 files changed, 26 insertions(+), 4 deletions(-) > > diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c > index 7cf5e13..ccef742 100644 > --- a/drivers/clk/qcom/gdsc.c > +++ b/drivers/clk/qcom/gdsc.c > @@ -17,6 +17,7 @@ > #include <linux/reset-controller.h> > #include <linux/slab.h> > #include "gdsc.h" > +#include "reset.h" > > #define PWR_ON_MASK BIT(31) > #define EN_REST_WAIT_MASK GENMASK_ULL(23, 20) > @@ -116,7 +117,8 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en) > return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val); > } > > -static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status) > +static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status, > + s64 timeout_us, unsigned int interval_ms) > { > ktime_t start; > > @@ -124,7 +126,9 @@ static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status) > do { > if (gdsc_check_status(sc, status)) > return 0; > - } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); > + if (interval_ms) > + msleep(interval_ms); > + } while (ktime_us_delta(ktime_get(), start) < timeout_us); Rather than continue to open code this polling loop, would it not make sense to convert the code into using readx_poll_timeout() (or some of its friends). Down the road, this leads to that the msleep() above should become usleep_range() instead, which seems more correct to me. > > if (gdsc_check_status(sc, status)) > return 0; > @@ -189,7 +193,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status) > udelay(1); > } > > - ret = gdsc_poll_status(sc, status); > + ret = gdsc_poll_status(sc, status, TIMEOUT_US, 0); > WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n"); > > if (!ret && status == GDSC_OFF && sc->rsupply) { > @@ -360,7 +364,7 @@ static int _gdsc_disable(struct gdsc *sc) > */ > udelay(1); > > - ret = gdsc_poll_status(sc, GDSC_ON); > + ret = gdsc_poll_status(sc, GDSC_ON, TIMEOUT_US, 0); > if (ret) > return ret; > } > @@ -608,3 +612,14 @@ int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain) > return 0; > } > EXPORT_SYMBOL_GPL(gdsc_gx_do_nothing_enable); > + > +int gdsc_wait_for_collapse(void *priv) > +{ > + struct gdsc *sc = priv; > + int ret; > + > + ret = gdsc_poll_status(sc, GDSC_OFF, 500000, 5); > + WARN(ret, "%s status stuck at 'on'", sc->pd.name); > + return ret; > +} > +EXPORT_SYMBOL_GPL(gdsc_wait_for_collapse); > diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h > index 981a12c..5395f69 100644 > --- a/drivers/clk/qcom/gdsc.h > +++ b/drivers/clk/qcom/gdsc.h > @@ -12,6 +12,7 @@ > struct regmap; > struct regulator; > struct reset_controller_dev; > +struct qcom_reset_map; > > /** > * struct gdsc - Globally Distributed Switch Controller > @@ -88,6 +89,7 @@ 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); > +int gdsc_wait_for_collapse(void *priv); > #else > static inline int gdsc_register(struct gdsc_desc *desc, > struct reset_controller_dev *rcdev, > @@ -97,5 +99,10 @@ static inline int gdsc_register(struct gdsc_desc *desc, > } > > static inline void gdsc_unregister(struct gdsc_desc *desc) {}; > + > +static int gdsc_wait_for_collapse(void *priv) > +{ > + return -ENOSYS; > +} > #endif /* CONFIG_QCOM_GDSC */ > #endif /* __QCOM_GDSC_H__ */ Kind regards Uffe