summaryrefslogtreecommitdiffstats
path: root/sys/arm/versatile/sp804.c
diff options
context:
space:
mode:
authorzbb <zbb@FreeBSD.org>2014-01-01 20:35:38 +0000
committerzbb <zbb@FreeBSD.org>2014-01-01 20:35:38 +0000
commit50beff885041a37b080791dd3eb2998f5bf8523c (patch)
tree4c0df8fbcff4ba70549fc0d02092f316e87a105f /sys/arm/versatile/sp804.c
parent9c9582b4299491121b66e205cf3572cf24e39447 (diff)
downloadFreeBSD-src-50beff885041a37b080791dd3eb2998f5bf8523c.zip
FreeBSD-src-50beff885041a37b080791dd3eb2998f5bf8523c.tar.gz
Fix race condition in DELAY for SP804 timer.
Fix race condition in DELAY function: sc->tc was not initialized yet when time_counter pointer was set, what resulted in NULL pointer dereference. Export sysfreq to dts. Submitted by: Wojciech Macek <wma@semihalf.com> Obtained from: Semihalf
Diffstat (limited to 'sys/arm/versatile/sp804.c')
-rw-r--r--sys/arm/versatile/sp804.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/sys/arm/versatile/sp804.c b/sys/arm/versatile/sp804.c
index 395d70a..16db30d 100644
--- a/sys/arm/versatile/sp804.c
+++ b/sys/arm/versatile/sp804.c
@@ -100,6 +100,7 @@ struct sp804_timer_softc {
struct timecounter tc;
bool et_enabled;
struct eventtimer et;
+ int timer_initialized;
};
/* Read/Write macros for Timer used as timecounter */
@@ -198,6 +199,8 @@ sp804_timer_attach(device_t dev)
int rid = 0;
int i;
uint32_t id, reg;
+ phandle_t node;
+ pcell_t clock;
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->mem_res == NULL) {
@@ -215,8 +218,12 @@ sp804_timer_attach(device_t dev)
return (ENXIO);
}
- /* TODO: get frequency from FDT */
sc->sysclk_freq = DEFAULT_FREQUENCY;
+ /* Get the base clock frequency */
+ node = ofw_bus_get_node(dev);
+ if ((OF_getprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) {
+ sc->sysclk_freq = fdt32_to_cpu(clock);
+ }
/* Setup and enable the timer */
if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK,
@@ -234,8 +241,8 @@ sp804_timer_attach(device_t dev)
/*
* Timer 1, timecounter
*/
- sc->tc.tc_frequency = DEFAULT_FREQUENCY;
- sc->tc.tc_name = "SP804 Timecouter";
+ sc->tc.tc_frequency = sc->sysclk_freq;
+ sc->tc.tc_name = "SP804 Time Counter";
sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount;
sc->tc.tc_poll_pps = NULL;
sc->tc.tc_counter_mask = ~0u;
@@ -283,6 +290,8 @@ sp804_timer_attach(device_t dev)
device_printf(dev, "PrimeCell ID: %08x\n", id);
+ sc->timer_initialized = 1;
+
return (0);
}
@@ -309,10 +318,18 @@ DELAY(int usec)
uint32_t first, last;
device_t timer_dev;
struct sp804_timer_softc *sc;
+ int timer_initialized = 0;
timer_dev = devclass_get_device(sp804_timer_devclass, 0);
- if (timer_dev == NULL) {
+ if (timer_dev) {
+ sc = device_get_softc(timer_dev);
+
+ if (sc)
+ timer_initialized = sc->timer_initialized;
+ }
+
+ if (!timer_initialized) {
/*
* Timer is not initialized yet
*/
@@ -323,8 +340,6 @@ DELAY(int usec)
return;
}
- sc = device_get_softc(timer_dev);
-
/* Get the number of times to count */
counts = usec * ((sc->tc.tc_frequency / 1000000) + 1);
OpenPOWER on IntegriCloud