[v2] regmap: add iopoll-like atomic polling macro
diff mbox series

Message ID 1578546077-764-1-git-send-email-spujar@nvidia.com
State Changes Requested
Headers show
Series
  • [v2] regmap: add iopoll-like atomic polling macro
Related show

Commit Message

Sameer Pujar Jan. 9, 2020, 5:01 a.m. UTC
This patch adds a macro 'regmap_read_poll_timeout_atomic' that works
similar to 'readx_poll_timeout_atomic' defined in linux/iopoll.h; This
is atomic version of already available 'regmap_read_poll_timeout' macro.

It should be noted that above atomic macro cannot be used by all regmaps.
If the regmap is set up for atomic use (flat or no cache and MMIO) then
only it can use.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/linux/regmap.h | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

Comments

Sameer Pujar Jan. 9, 2020, 5:05 a.m. UTC | #1
On 1/9/2020 10:31 AM, Sameer Pujar wrote:
> This patch adds a macro 'regmap_read_poll_timeout_atomic' that works
> similar to 'readx_poll_timeout_atomic' defined in linux/iopoll.h; This
> is atomic version of already available 'regmap_read_poll_timeout' macro.
>
> It should be noted that above atomic macro cannot be used by all regmaps.
> If the regmap is set up for atomic use (flat or no cache and MMIO) then
> only it can use.
>
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
>   include/linux/regmap.h | 45 +++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 45 insertions(+)
>
> diff --git a/include/linux/regmap.h b/include/linux/regmap.h
> index dfe493a..aaf0ed1 100644
> --- a/include/linux/regmap.h
> +++ b/include/linux/regmap.h
> @@ -119,6 +119,10 @@ struct reg_sequence {
>    * from atomic context if sleep_us or timeout_us are used.
>    *
>    * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
> + *
> + * Note: In general regmap cannot be used in atomic context. If you want to use
> + * this macro then first setup your regmap for atomic use (flat or no cache
> + * and MMIO regmap).

oops! Sorry!
Wrong place, will fix in next revision.

>    */
>   #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
>   ({ \
> @@ -145,6 +149,47 @@ struct reg_sequence {
>   })
>   
>   /**
> + * regmap_read_poll_timeout_atomic - Poll until a condition is met or a timeout occurs
> + *
> + * @map: Regmap to read from
> + * @addr: Address to poll
> + * @val: Unsigned integer variable to read the value into
> + * @cond: Break condition (usually involving @val)
> + * @delay_us: Time to udelay between reads in us (0 tight-loops).
> + *            Should be less than ~10us since udelay is used
> + *            (see Documentation/timers/timers-howto.rst).
> + * @timeout_us: Timeout in us, 0 means never timeout
> + *
> + * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read
> + * error return value in case of a error read. In the two former cases,
> + * the last read value at @addr is stored in @val.
> + *
> + * This is modelled after the readx_poll_timeout_atomic macros in linux/iopoll.h.
> + */
> +#define regmap_read_poll_timeout_atomic(map, addr, val, cond, delay_us, timeout_us) \
> +({ \
> +	u64 __timeout_us = (timeout_us); \
> +	unsigned long __delay_us = (delay_us); \
> +	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
> +	int __ret; \
> +	for (;;) { \
> +		__ret = regmap_read((map), (addr), &(val)); \
> +		if (__ret) \
> +			break; \
> +		if (cond) \
> +			break; \
> +		if ((__timeout_us) && \
> +		    ktime_compare(ktime_get(), __timeout) > 0) { \
> +			__ret = regmap_read((map), (addr), &(val)); \
> +			break; \
> +		} \
> +		if (__delay_us) \
> +			udelay(__delay_us); \
> +	} \
> +	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
> +})
> +
> +/**
>    * regmap_field_read_poll_timeout - Poll until a condition is met or timeout
>    *
>    * @field: Regmap field to read from

Patch
diff mbox series

diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index dfe493a..aaf0ed1 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -119,6 +119,10 @@  struct reg_sequence {
  * from atomic context if sleep_us or timeout_us are used.
  *
  * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
+ *
+ * Note: In general regmap cannot be used in atomic context. If you want to use
+ * this macro then first setup your regmap for atomic use (flat or no cache
+ * and MMIO regmap).
  */
 #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
 ({ \
@@ -145,6 +149,47 @@  struct reg_sequence {
 })
 
 /**
+ * regmap_read_poll_timeout_atomic - Poll until a condition is met or a timeout occurs
+ *
+ * @map: Regmap to read from
+ * @addr: Address to poll
+ * @val: Unsigned integer variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @delay_us: Time to udelay between reads in us (0 tight-loops).
+ *            Should be less than ~10us since udelay is used
+ *            (see Documentation/timers/timers-howto.rst).
+ * @timeout_us: Timeout in us, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val.
+ *
+ * This is modelled after the readx_poll_timeout_atomic macros in linux/iopoll.h.
+ */
+#define regmap_read_poll_timeout_atomic(map, addr, val, cond, delay_us, timeout_us) \
+({ \
+	u64 __timeout_us = (timeout_us); \
+	unsigned long __delay_us = (delay_us); \
+	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
+	int __ret; \
+	for (;;) { \
+		__ret = regmap_read((map), (addr), &(val)); \
+		if (__ret) \
+			break; \
+		if (cond) \
+			break; \
+		if ((__timeout_us) && \
+		    ktime_compare(ktime_get(), __timeout) > 0) { \
+			__ret = regmap_read((map), (addr), &(val)); \
+			break; \
+		} \
+		if (__delay_us) \
+			udelay(__delay_us); \
+	} \
+	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/**
  * regmap_field_read_poll_timeout - Poll until a condition is met or timeout
  *
  * @field: Regmap field to read from