svn commit: r260166 - head/sys/arm/versatile

Zbigniew Bodek zbb at FreeBSD.org
Wed Jan 1 20:35:39 UTC 2014


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 <wma at 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);
 


More information about the svn-src-all mailing list