diff options
author | zbb <zbb@FreeBSD.org> | 2014-01-01 20:35:38 +0000 |
---|---|---|
committer | zbb <zbb@FreeBSD.org> | 2014-01-01 20:35:38 +0000 |
commit | 50beff885041a37b080791dd3eb2998f5bf8523c (patch) | |
tree | 4c0df8fbcff4ba70549fc0d02092f316e87a105f /sys/arm/versatile/sp804.c | |
parent | 9c9582b4299491121b66e205cf3572cf24e39447 (diff) | |
download | FreeBSD-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.c | 27 |
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); |