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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to