Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Mar 2014 13:07:03 -0600
From:      Ian Lepore <ian@FreeBSD.org>
To:        freebsd-arch <freebsd-arch@FreeBSD.org>
Subject:   Supporting variable-frequency event timers
Message-ID:  <1395947223.81853.121.camel@revolution.hippie.lan>

next in thread | raw e-mail | index | archive | help

--=-6fkTI/i94V3xVMnPriRG
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

Increasingly, ARM systems are using techniques such as dynamic voltage
and frequency scaling (DVFS) to save power.  Sometimes the frequency
changes affect the clocks being used as event timers.  I'd like to
commit the attached patch which allows an event timer driver to call
et_change_frequency() to reconfigure the timer (if it's the active one)
on all CPUs when the frequency changes.

-- Ian


--=-6fkTI/i94V3xVMnPriRG
Content-Disposition: inline; filename="eventtimer_varfreq.diff"
Content-Type: text/x-patch; name="eventtimer_varfreq.diff"; charset="us-ascii"
Content-Transfer-Encoding: 7bit

Index: sys/sys/timeet.h
===================================================================
--- sys/sys/timeet.h	(revision 263112)
+++ sys/sys/timeet.h	(working copy)
@@ -89,6 +89,7 @@ extern struct mtx	et_eventtimers_mtx;
 /* Driver API */
 int	et_register(struct eventtimer *et);
 int	et_deregister(struct eventtimer *et);
+void	et_change_frequency(struct eventtimer *et, uint64_t newfreq);
 /* Consumer API  */
 struct eventtimer *et_find(const char *name, int check, int want);
 int	et_init(struct eventtimer *et, et_event_cb_t *event,
Index: sys/sys/systm.h
===================================================================
--- sys/sys/systm.h	(revision 263112)
+++ sys/sys/systm.h	(working copy)
@@ -168,6 +168,7 @@ struct ucred;
 struct uio;
 struct _jmp_buf;
 struct trapframe;
+struct eventtimer;
 
 int	setjmp(struct _jmp_buf *) __returns_twice;
 void	longjmp(struct _jmp_buf *, int) __dead2;
@@ -286,6 +287,7 @@ void	cpu_stopprofclock(void);
 sbintime_t 	cpu_idleclock(void);
 void	cpu_activeclock(void);
 void	cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt);
+void	cpu_et_frequency(struct eventtimer *et, uint64_t newfreq);
 extern int	cpu_can_deep_sleep;
 extern int	cpu_disable_deep_sleep;
 
Index: sys/kern/kern_et.c
===================================================================
--- sys/kern/kern_et.c	(revision 263112)
+++ sys/kern/kern_et.c	(working copy)
@@ -113,6 +113,18 @@ et_deregister(struct eventtimer *et)
 }
 
 /*
+ * Change the frequency of the given timer.  If it is the active timer,
+ * reconfigure it on all CPUs (reschedules all current events based on the new
+ * timer frequency).
+ */
+void
+et_change_frequency(struct eventtimer *et, uint64_t newfreq)
+{
+
+	cpu_et_frequency(et, newfreq);
+}
+
+/*
  * Find free event timer hardware with specified parameters.
  */
 struct eventtimer *
Index: sys/kern/kern_clocksource.c
===================================================================
--- sys/kern/kern_clocksource.c	(revision 263112)
+++ sys/kern/kern_clocksource.c	(working copy)
@@ -799,6 +799,25 @@ cpu_activeclock(void)
 	spinlock_exit();
 }
 
+/*
+ * Change the frequency of the given timer.  This changes et->et_frequency and
+ * if et is the active timer it reconfigures the timer on all CPUs.  This is
+ * intended to be a private interface for the use of et_change_frequency() only.
+ */
+void
+cpu_et_frequency(struct eventtimer *et, uint64_t newfreq)
+{
+
+	ET_LOCK();
+	if (et == timer) {
+		configtimer(0);
+		et->et_frequency = newfreq;
+		configtimer(1);
+	} else
+		et->et_frequency = newfreq;
+	ET_UNLOCK();
+}
+
 #ifdef KDTRACE_HOOKS
 void
 clocksource_cyc_set(const struct bintime *bt)

--=-6fkTI/i94V3xVMnPriRG--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1395947223.81853.121.camel>