diff mbox

[kvm-unit-tests,v8,03/10] arm/arm64: add some delay routines

Message ID 20161208175030.12269-4-drjones@redhat.com
State New
Headers show

Commit Message

Andrew Jones Dec. 8, 2016, 5:50 p.m. UTC
Allow a thread to wait some specified amount of time. Can
specify in cycles, usecs, and msecs.

Signed-off-by: Andrew Jones <drjones@redhat.com>


---
v8: rewrote basing on new sysreg framework. Also decided delay
    functions warrant their own files (delay.[ch])
---
 arm/Makefile.common       |  1 +
 lib/arm/asm/delay.h       | 14 ++++++++++++++
 lib/arm/asm/processor.h   | 15 +++++++++++++++
 lib/arm64/asm/delay.h     |  1 +
 lib/arm64/asm/processor.h | 12 ++++++++++++
 lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
 6 files changed, 72 insertions(+)
 create mode 100644 lib/arm/asm/delay.h
 create mode 100644 lib/arm64/asm/delay.h
 create mode 100644 lib/arm/delay.c

-- 
2.9.3

Comments

Andre Przywara Dec. 9, 2016, 11:41 a.m. UTC | #1
Hi,

On 08/12/16 17:50, Andrew Jones wrote:
> Allow a thread to wait some specified amount of time. Can

> specify in cycles, usecs, and msecs.

> 

> Signed-off-by: Andrew Jones <drjones@redhat.com>

> 

> ---

> v8: rewrote basing on new sysreg framework. Also decided delay

>     functions warrant their own files (delay.[ch])

> ---

>  arm/Makefile.common       |  1 +

>  lib/arm/asm/delay.h       | 14 ++++++++++++++

>  lib/arm/asm/processor.h   | 15 +++++++++++++++

>  lib/arm64/asm/delay.h     |  1 +

>  lib/arm64/asm/processor.h | 12 ++++++++++++

>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++

>  6 files changed, 72 insertions(+)

>  create mode 100644 lib/arm/asm/delay.h

>  create mode 100644 lib/arm64/asm/delay.h

>  create mode 100644 lib/arm/delay.c

> 

> diff --git a/arm/Makefile.common b/arm/Makefile.common

> index b2c0fc8a2fdc..89fe3f69eb44 100644

> --- a/arm/Makefile.common

> +++ b/arm/Makefile.common

> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o

>  cflatobjs += lib/arm/bitops.o

>  cflatobjs += lib/arm/psci.o

>  cflatobjs += lib/arm/smp.o

> +cflatobjs += lib/arm/delay.o

>  

>  libeabi = lib/arm/libeabi.a

>  eabiobjs = lib/arm/eabi_compat.o

> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h

> new file mode 100644

> index 000000000000..2436b28c77ae

> --- /dev/null

> +++ b/lib/arm/asm/delay.h

> @@ -0,0 +1,14 @@

> +#ifndef _ASMARM_DELAY_H_

> +#define _ASMARM_DELAY_H_

> +/*

> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> + *

> + * This work is licensed under the terms of the GNU LGPL, version 2.

> + */

> +#include <libcflat.h>

> +

> +extern void delay(u64 cycles);


Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
misleading, especially since this prototype is the only documentation on
this. You might just want to fix this when applying the patches.

That notwithstanding:
Reviewed-by: Andre Przywara <andre.przywara@arm.com>


Cheers,
Andre.

> +extern void udelay(unsigned long usecs);

> +extern void mdelay(unsigned long msecs);

> +

> +#endif /* _ASMARM_DELAY_H_ */

> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h

> index 6b0d36b87817..857bdd96a3cc 100644

> --- a/lib/arm/asm/processor.h

> +++ b/lib/arm/asm/processor.h

> @@ -7,6 +7,7 @@

>   */

>  #include <asm/ptrace.h>

>  #include <asm/sysreg.h>

> +#include <asm/barrier.h>

>  

>  enum vector {

>  	EXCPTN_RST,

> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);

>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);

>  extern bool is_user(void);

>  

> +#define CNTVCT		__ACCESS_CP15_64(1, c14)

> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)

> +

> +static inline u64 get_cntvct(void)

> +{

> +	isb();

> +	return read_sysreg(CNTVCT);

> +}

> +

> +static inline u32 get_cntfrq(void)

> +{

> +	return read_sysreg(CNTFRQ);

> +}

> +

>  #endif /* _ASMARM_PROCESSOR_H_ */

> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h

> new file mode 100644

> index 000000000000..288e4b3fe610

> --- /dev/null

> +++ b/lib/arm64/asm/delay.h

> @@ -0,0 +1 @@

> +#include "../../arm/asm/delay.h"

> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h

> index 48abf2c9e358..0898d89f9761 100644

> --- a/lib/arm64/asm/processor.h

> +++ b/lib/arm64/asm/processor.h

> @@ -20,6 +20,7 @@

>  #include <asm/ptrace.h>

>  #include <asm/esr.h>

>  #include <asm/sysreg.h>

> +#include <asm/barrier.h>

>  

>  enum vector {

>  	EL1T_SYNC,

> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t mpidr);

>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);

>  extern bool is_user(void);

>  

> +static inline u64 get_cntvct(void)

> +{

> +	isb();

> +	return read_sysreg(cntvct_el0);

> +}

> +

> +static inline u32 get_cntfrq(void)

> +{

> +	return read_sysreg(cntfrq_el0);

> +}

> +

>  #endif /* !__ASSEMBLY__ */

>  #endif /* _ASMARM64_PROCESSOR_H_ */

> diff --git a/lib/arm/delay.c b/lib/arm/delay.c

> new file mode 100644

> index 000000000000..fa65e2dc9e35

> --- /dev/null

> +++ b/lib/arm/delay.c

> @@ -0,0 +1,29 @@

> +/*

> + * Delay loops

> + *

> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> + *

> + * This work is licensed under the terms of the GNU LGPL, version 2.

> + */

> +#include <libcflat.h>

> +#include <asm/processor.h>

> +#include <asm/barrier.h>

> +

> +void delay(u64 cycles)

> +{

> +	u64 start = get_cntvct();

> +

> +	while ((get_cntvct() - start) < cycles)

> +		cpu_relax();

> +}

> +

> +void udelay(unsigned long usec)

> +{

> +	delay((u64)usec * get_cntfrq() / 1000000);

> +}

> +

> +void mdelay(unsigned long msecs)

> +{

> +	while (msecs--)

> +		udelay(1000);

> +}

>
Andrew Jones Dec. 9, 2016, 12:15 p.m. UTC | #2
On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:
> Hi,

> 

> On 08/12/16 17:50, Andrew Jones wrote:

> > Allow a thread to wait some specified amount of time. Can

> > specify in cycles, usecs, and msecs.

> > 

> > Signed-off-by: Andrew Jones <drjones@redhat.com>

> > 

> > ---

> > v8: rewrote basing on new sysreg framework. Also decided delay

> >     functions warrant their own files (delay.[ch])

> > ---

> >  arm/Makefile.common       |  1 +

> >  lib/arm/asm/delay.h       | 14 ++++++++++++++

> >  lib/arm/asm/processor.h   | 15 +++++++++++++++

> >  lib/arm64/asm/delay.h     |  1 +

> >  lib/arm64/asm/processor.h | 12 ++++++++++++

> >  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++

> >  6 files changed, 72 insertions(+)

> >  create mode 100644 lib/arm/asm/delay.h

> >  create mode 100644 lib/arm64/asm/delay.h

> >  create mode 100644 lib/arm/delay.c

> > 

> > diff --git a/arm/Makefile.common b/arm/Makefile.common

> > index b2c0fc8a2fdc..89fe3f69eb44 100644

> > --- a/arm/Makefile.common

> > +++ b/arm/Makefile.common

> > @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o

> >  cflatobjs += lib/arm/bitops.o

> >  cflatobjs += lib/arm/psci.o

> >  cflatobjs += lib/arm/smp.o

> > +cflatobjs += lib/arm/delay.o

> >  

> >  libeabi = lib/arm/libeabi.a

> >  eabiobjs = lib/arm/eabi_compat.o

> > diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h

> > new file mode 100644

> > index 000000000000..2436b28c77ae

> > --- /dev/null

> > +++ b/lib/arm/asm/delay.h

> > @@ -0,0 +1,14 @@

> > +#ifndef _ASMARM_DELAY_H_

> > +#define _ASMARM_DELAY_H_

> > +/*

> > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> > + *

> > + * This work is licensed under the terms of the GNU LGPL, version 2.

> > + */

> > +#include <libcflat.h>

> > +

> > +extern void delay(u64 cycles);

> 

> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit

> misleading, especially since this prototype is the only documentation on

> this. You might just want to fix this when applying the patches.


Right or wrong the kernel uses 'cycles' for this function, named
__timer_delay for arm and __delay for arm64. I guess I prefer
consistency here.

> 

> That notwithstanding:

> Reviewed-by: Andre Przywara <andre.przywara@arm.com>


Thanks!

drew
Alex Bennée Dec. 13, 2016, 4:41 p.m. UTC | #3
Andrew Jones <drjones@redhat.com> writes:

> Allow a thread to wait some specified amount of time. Can

> specify in cycles, usecs, and msecs.

>

> Signed-off-by: Andrew Jones <drjones@redhat.com>

>

> ---

> v8: rewrote basing on new sysreg framework. Also decided delay

>     functions warrant their own files (delay.[ch])

> ---

>  arm/Makefile.common       |  1 +

>  lib/arm/asm/delay.h       | 14 ++++++++++++++

>  lib/arm/asm/processor.h   | 15 +++++++++++++++

>  lib/arm64/asm/delay.h     |  1 +

>  lib/arm64/asm/processor.h | 12 ++++++++++++

>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++

>  6 files changed, 72 insertions(+)

>  create mode 100644 lib/arm/asm/delay.h

>  create mode 100644 lib/arm64/asm/delay.h

>  create mode 100644 lib/arm/delay.c

>

> diff --git a/arm/Makefile.common b/arm/Makefile.common

> index b2c0fc8a2fdc..89fe3f69eb44 100644

> --- a/arm/Makefile.common

> +++ b/arm/Makefile.common

> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o

>  cflatobjs += lib/arm/bitops.o

>  cflatobjs += lib/arm/psci.o

>  cflatobjs += lib/arm/smp.o

> +cflatobjs += lib/arm/delay.o

>

>  libeabi = lib/arm/libeabi.a

>  eabiobjs = lib/arm/eabi_compat.o

> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h

> new file mode 100644

> index 000000000000..2436b28c77ae

> --- /dev/null

> +++ b/lib/arm/asm/delay.h

> @@ -0,0 +1,14 @@

> +#ifndef _ASMARM_DELAY_H_

> +#define _ASMARM_DELAY_H_

> +/*

> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> + *

> + * This work is licensed under the terms of the GNU LGPL, version 2.

> + */

> +#include <libcflat.h>

> +

> +extern void delay(u64 cycles);

> +extern void udelay(unsigned long usecs);

> +extern void mdelay(unsigned long msecs);

> +

> +#endif /* _ASMARM_DELAY_H_ */

> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h

> index 6b0d36b87817..857bdd96a3cc 100644

> --- a/lib/arm/asm/processor.h

> +++ b/lib/arm/asm/processor.h

> @@ -7,6 +7,7 @@

>   */

>  #include <asm/ptrace.h>

>  #include <asm/sysreg.h>

> +#include <asm/barrier.h>


Hmm this fails to apply cleanly to master and doesn't build as sysreg.h
isn't in my tree. What happened to it?

>

>  enum vector {

>  	EXCPTN_RST,

> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);

>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);

>  extern bool is_user(void);

>

> +#define CNTVCT		__ACCESS_CP15_64(1, c14)

> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)

> +

> +static inline u64 get_cntvct(void)

> +{

> +	isb();

> +	return read_sysreg(CNTVCT);

> +}

> +

> +static inline u32 get_cntfrq(void)

> +{

> +	return read_sysreg(CNTFRQ);

> +}

> +

>  #endif /* _ASMARM_PROCESSOR_H_ */

> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h

> new file mode 100644

> index 000000000000..288e4b3fe610

> --- /dev/null

> +++ b/lib/arm64/asm/delay.h

> @@ -0,0 +1 @@

> +#include "../../arm/asm/delay.h"

> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h

> index 48abf2c9e358..0898d89f9761 100644

> --- a/lib/arm64/asm/processor.h

> +++ b/lib/arm64/asm/processor.h

> @@ -20,6 +20,7 @@

>  #include <asm/ptrace.h>

>  #include <asm/esr.h>

>  #include <asm/sysreg.h>

> +#include <asm/barrier.h>

>

>  enum vector {

>  	EL1T_SYNC,

> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t mpidr);

>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);

>  extern bool is_user(void);

>

> +static inline u64 get_cntvct(void)

> +{

> +	isb();

> +	return read_sysreg(cntvct_el0);

> +}

> +

> +static inline u32 get_cntfrq(void)

> +{

> +	return read_sysreg(cntfrq_el0);

> +}

> +

>  #endif /* !__ASSEMBLY__ */

>  #endif /* _ASMARM64_PROCESSOR_H_ */

> diff --git a/lib/arm/delay.c b/lib/arm/delay.c

> new file mode 100644

> index 000000000000..fa65e2dc9e35

> --- /dev/null

> +++ b/lib/arm/delay.c

> @@ -0,0 +1,29 @@

> +/*

> + * Delay loops

> + *

> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> + *

> + * This work is licensed under the terms of the GNU LGPL, version 2.

> + */

> +#include <libcflat.h>

> +#include <asm/processor.h>

> +#include <asm/barrier.h>

> +

> +void delay(u64 cycles)

> +{

> +	u64 start = get_cntvct();

> +

> +	while ((get_cntvct() - start) < cycles)

> +		cpu_relax();

> +}

> +

> +void udelay(unsigned long usec)

> +{

> +	delay((u64)usec * get_cntfrq() / 1000000);

> +}

> +

> +void mdelay(unsigned long msecs)

> +{

> +	while (msecs--)

> +		udelay(1000);

> +}



--
Alex Bennée
Alex Bennée Dec. 13, 2016, 5:09 p.m. UTC | #4
Alex Bennée <alex.bennee@linaro.org> writes:

> Andrew Jones <drjones@redhat.com> writes:

>

>> Allow a thread to wait some specified amount of time. Can

>> specify in cycles, usecs, and msecs.

<snip>
>> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h

>> index 6b0d36b87817..857bdd96a3cc 100644

>> --- a/lib/arm/asm/processor.h

>> +++ b/lib/arm/asm/processor.h

>> @@ -7,6 +7,7 @@

>>   */

>>  #include <asm/ptrace.h>

>>  #include <asm/sysreg.h>

>> +#include <asm/barrier.h>

>

> Hmm this fails to apply cleanly to master and doesn't build as sysreg.h

> isn't in my tree. What happened to it?

<snip>

Ahh I missed this is based on arm/next

--
Alex Bennée
Christopher Covington Dec. 27, 2016, 3:27 p.m. UTC | #5
On 12/09/2016 07:15 AM, Andrew Jones wrote:
> On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:

>> Hi,

>>

>> On 08/12/16 17:50, Andrew Jones wrote:

>>> Allow a thread to wait some specified amount of time. Can

>>> specify in cycles, usecs, and msecs.


>>> +++ b/lib/arm/asm/delay.h

>>> @@ -0,0 +1,14 @@

>>> +#ifndef _ASMARM_DELAY_H_

>>> +#define _ASMARM_DELAY_H_

>>> +/*

>>> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

>>> + *

>>> + * This work is licensed under the terms of the GNU LGPL, version 2.

>>> + */

>>> +#include <libcflat.h>

>>> +

>>> +extern void delay(u64 cycles);

>>

>> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit

>> misleading, especially since this prototype is the only documentation on

>> this. You might just want to fix this when applying the patches.

> 

> Right or wrong the kernel uses 'cycles' for this function, named

> __timer_delay for arm and __delay for arm64. I guess I prefer

> consistency here.


I too expect timers to tick and CPUs to cycle. The benefit of
parameter-name-precise consistency with the Linux source is not
obvious to me.

Cov

-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code
Aurora Forum, a Linux Foundation Collaborative Project.
Andrew Jones Dec. 27, 2016, 4:27 p.m. UTC | #6
On Tue, Dec 27, 2016 at 10:27:25AM -0500, Christopher Covington wrote:
> On 12/09/2016 07:15 AM, Andrew Jones wrote:

> > On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:

> >> Hi,

> >>

> >> On 08/12/16 17:50, Andrew Jones wrote:

> >>> Allow a thread to wait some specified amount of time. Can

> >>> specify in cycles, usecs, and msecs.

> 

> >>> +++ b/lib/arm/asm/delay.h

> >>> @@ -0,0 +1,14 @@

> >>> +#ifndef _ASMARM_DELAY_H_

> >>> +#define _ASMARM_DELAY_H_

> >>> +/*

> >>> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>

> >>> + *

> >>> + * This work is licensed under the terms of the GNU LGPL, version 2.

> >>> + */

> >>> +#include <libcflat.h>

> >>> +

> >>> +extern void delay(u64 cycles);

> >>

> >> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit

> >> misleading, especially since this prototype is the only documentation on

> >> this. You might just want to fix this when applying the patches.

> > 

> > Right or wrong the kernel uses 'cycles' for this function, named

> > __timer_delay for arm and __delay for arm64. I guess I prefer

> > consistency here.

> 

> I too expect timers to tick and CPUs to cycle. The benefit of

> parameter-name-precise consistency with the Linux source is not

> obvious to me.

>


I just didn't have a strong enough opinion on it to change it. It appears
I'm in a minority though. As this is in master already, patches welcome :)

Thanks,
drew
diff mbox

Patch

diff --git a/arm/Makefile.common b/arm/Makefile.common
index b2c0fc8a2fdc..89fe3f69eb44 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -48,6 +48,7 @@  cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/delay.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
new file mode 100644
index 000000000000..2436b28c77ae
--- /dev/null
+++ b/lib/arm/asm/delay.h
@@ -0,0 +1,14 @@ 
+#ifndef _ASMARM_DELAY_H_
+#define _ASMARM_DELAY_H_
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+extern void mdelay(unsigned long msecs);
+
+#endif /* _ASMARM_DELAY_H_ */
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index 6b0d36b87817..857bdd96a3cc 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -7,6 +7,7 @@ 
  */
 #include <asm/ptrace.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EXCPTN_RST,
@@ -51,4 +52,18 @@  extern int mpidr_to_cpu(uint64_t mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+#define CNTVCT		__ACCESS_CP15_64(1, c14)
+#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
+
+static inline u64 get_cntvct(void)
+{
+	isb();
+	return read_sysreg(CNTVCT);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(CNTFRQ);
+}
+
 #endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
new file mode 100644
index 000000000000..288e4b3fe610
--- /dev/null
+++ b/lib/arm64/asm/delay.h
@@ -0,0 +1 @@ 
+#include "../../arm/asm/delay.h"
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 48abf2c9e358..0898d89f9761 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -20,6 +20,7 @@ 
 #include <asm/ptrace.h>
 #include <asm/esr.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EL1T_SYNC,
@@ -83,5 +84,16 @@  extern int mpidr_to_cpu(uint64_t mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+static inline u64 get_cntvct(void)
+{
+	isb();
+	return read_sysreg(cntvct_el0);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(cntfrq_el0);
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm/delay.c b/lib/arm/delay.c
new file mode 100644
index 000000000000..fa65e2dc9e35
--- /dev/null
+++ b/lib/arm/delay.c
@@ -0,0 +1,29 @@ 
+/*
+ * Delay loops
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/processor.h>
+#include <asm/barrier.h>
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	delay((u64)usec * get_cntfrq() / 1000000);
+}
+
+void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}