summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-03-15 21:47:34 +0000
committerphk <phk@FreeBSD.org>2004-03-15 21:47:34 +0000
commit6c8e5c543fa1cfd6b4fe816257f119f51eacb285 (patch)
tree049e81a809cd5a7ba0e7f2bcbd26cb9022281f80
parent31018190bc305e0ec98cb075da3faab9a68625a6 (diff)
downloadFreeBSD-src-6c8e5c543fa1cfd6b4fe816257f119f51eacb285.zip
FreeBSD-src-6c8e5c543fa1cfd6b4fe816257f119f51eacb285.tar.gz
The PPS code needs to be much more brutal to avoid synchronism on
hardware with non-sucky clocks.
-rw-r--r--sys/i386/i386/elan-mmcr.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/sys/i386/i386/elan-mmcr.c b/sys/i386/i386/elan-mmcr.c
index 518f342..5ffb41b 100644
--- a/sys/i386/i386/elan-mmcr.c
+++ b/sys/i386/i386/elan-mmcr.c
@@ -68,16 +68,18 @@ __FBSDID("$FreeBSD$");
static char gpio_config[33];
static volatile uint16_t *mmcrptr;
-volatile struct elan_mmcr * elan_mmcr;
+volatile struct elan_mmcr *elan_mmcr;
#ifdef CPU_ELAN_PPS
static struct pps_state elan_pps;
-u_int pps_a, pps_d;
-u_int echo_a, echo_d;
+static volatile uint16_t *pps_ap[3];
+static u_int pps_a, pps_d;
+static u_int echo_a, echo_d;
#endif /* CPU_ELAN_PPS */
+
#ifdef CPU_SOEKRIS
-u_int led_cookie[32];
-dev_t led_dev[32];
+static u_int led_cookie[32];
+static dev_t led_dev[32];
static void
gpio_led(void *cookie, int state)
@@ -158,6 +160,9 @@ sysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS)
case 'P':
pps_d = u;
pps_a = 0xc30 + v;
+ pps_ap[0] = &mmcrptr[pps_a / 2];
+ pps_ap[1] = &elan_mmcr->GPTMR2CNT;
+ pps_ap[2] = &elan_mmcr->GPTMR1CNT;
mmcrptr[(0xc2a + v) / 2] &= ~u;
gpio_config[i] = buf[i];
break;
@@ -208,7 +213,20 @@ elan_poll_pps(struct timecounter *tc)
{
static int state;
int i;
- u_int u;
+ uint16_t u, x, y, z;
+ u_long eflags;
+
+ /*
+ * Grab the HW state as quickly and compactly as we can. Disable
+ * interrupts to avoid measuring our interrupt service time on
+ * hw with quality clock sources.
+ */
+ eflags = read_eflags();
+ disable_intr();
+ x = *pps_ap[0]; /* state, must be first, see below */
+ y = *pps_ap[1]; /* timer2 */
+ z = *pps_ap[2]; /* timer1 */
+ write_eflags(eflags);
/*
* Order is important here. We need to check the state of the GPIO
@@ -217,13 +235,8 @@ elan_poll_pps(struct timecounter *tc)
* harmlessly read the REVID register and the contents of pps_d is
* of no concern.
*/
- i = mmcrptr[pps_a / 2] & pps_d;
- /*
- * Subtract timer1 from timer2 to compensate for time from the
- * edge until now.
- */
- u = elan_mmcr->GPTMR2CNT - elan_mmcr->GPTMR1CNT;
+ i = x & pps_d;
/* If state did not change or we don't have a GPIO pin, return */
if (i == state || pps_a == 0)
@@ -238,9 +251,14 @@ elan_poll_pps(struct timecounter *tc)
return;
}
- /* State is "high", record the pps data */
+ /*
+ * Subtract timer1 from timer2 to compensate for time from the
+ * edge until we read the counters.
+ */
+ u = y - z;
+
pps_capture(&elan_pps);
- elan_pps.capcount = u & 0xffff;
+ elan_pps.capcount = u;
pps_event(&elan_pps, PPS_CAPTUREASSERT);
/* Twiddle echo bit */
OpenPOWER on IntegriCloud