Author: zbb
Date: Wed Jan  1 20:35:38 2014
New Revision: 260166
URL: http://svnweb.freebsd.org/changeset/base/260166

Log:
  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 <w...@semihalf.com>
  Obtained from:        Semihalf

Modified:
  head/sys/arm/versatile/sp804.c

Modified: head/sys/arm/versatile/sp804.c
==============================================================================
--- head/sys/arm/versatile/sp804.c      Wed Jan  1 20:26:08 2014        
(r260165)
+++ head/sys/arm/versatile/sp804.c      Wed Jan  1 20:35:38 2014        
(r260166)
@@ -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);
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to