svn commit: r212323 - head/sys/dev/acpica

Alexander Motin mav at FreeBSD.org
Wed Sep 8 16:59:23 UTC 2010


Author: mav
Date: Wed Sep  8 16:59:22 2010
New Revision: 212323
URL: http://svn.freebsd.org/changeset/base/212323

Log:
  During SMP startup there is time window, when SMP started, but interrupts
  are still bound to BSP. It confuses timer management logic in per-CPU mode
  and may cause timer not being reloaded. Check such cases on interrupt
  arival and reload timer to give system some more time to manage proper
  binding.

Modified:
  head/sys/dev/acpica/acpi_hpet.c

Modified: head/sys/dev/acpica/acpi_hpet.c
==============================================================================
--- head/sys/dev/acpica/acpi_hpet.c	Wed Sep  8 16:58:06 2010	(r212322)
+++ head/sys/dev/acpica/acpi_hpet.c	Wed Sep  8 16:59:22 2010	(r212323)
@@ -89,6 +89,8 @@ struct hpet_softc {
 		int			mode;
 		int			intr_rid;
 		int			irq;
+		int			pcpu_cpu;
+		int			pcpu_misrouted;
 		int			pcpu_master;
 		int			pcpu_slaves[MAXCPU];
 		struct resource		*intr_res;
@@ -185,7 +187,7 @@ restart:
 	if (fdiv < 5000) {
 		bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
 		t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
-		if ((int32_t)(t->last - cmp) < 0) {
+		if ((int32_t)(t->last - cmp) >= 0) {
 			fdiv *= 2;
 			goto restart;
 		}
@@ -215,6 +217,26 @@ hpet_intr_single(void *arg)
 	struct hpet_softc *sc = t->sc;
 	uint32_t now;
 
+	/* Check that per-CPU timer interrupt reached right CPU. */
+	if (t->pcpu_cpu >= 0 && t->pcpu_cpu != curcpu) {
+		if ((++t->pcpu_misrouted) % 32 == 0) {
+			printf("HPET interrupt routed to the wrong CPU"
+			    " (timer %d CPU %d -> %d)!\n",
+			    t->num, t->pcpu_cpu, curcpu);
+		}
+
+		/*
+		 * Reload timer, hoping that next time may be more lucky
+		 * (system will manage proper interrupt binding).
+		 */
+		if ((t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) ||
+		    t->mode == 2) {
+			t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
+			bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
+			    t->last + sc->freq / 8);
+		}
+		return (FILTER_HANDLED);
+	}
 	if (t->mode == 1 &&
 	    (t->caps & HPET_TCAP_PER_INT) == 0) {
 		t->last += t->div;
@@ -394,6 +416,8 @@ hpet_attach(device_t dev)
 		t->mode = 0;
 		t->intr_rid = -1;
 		t->irq = -1;
+		t->pcpu_cpu = -1;
+		t->pcpu_misrouted = 0;
 		t->pcpu_master = -1;
 		t->caps = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i));
 		t->vectors = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i) + 4);
@@ -534,6 +558,7 @@ hpet_attach(device_t dev)
 		if (t->irq >= 0 && num_percpu_t > 0) {
 			if (cur_cpu == CPU_FIRST())
 				pcpu_master = i;
+			t->pcpu_cpu = cur_cpu;
 			t->pcpu_master = pcpu_master;
 			sc->t[pcpu_master].
 			    pcpu_slaves[cur_cpu] = i;


More information about the svn-src-all mailing list