Disables the HPET
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 9 Sep 2014 21:26:09 +0000 (14:26 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 10 Sep 2014 03:23:37 +0000 (20:23 -0700)
If the system has an HPET, ACPI will tell us.  In lieu of properly setting it
up, I just make sure it is disabled.

Long range plan is for a #T timer device or something, which would use the HPET
if available.

The HPET is pretty straightforward btw, just not a priority.

kern/arch/x86/x86.h
kern/drivers/Kbuild
kern/drivers/dev/acpi.c
kern/drivers/timers/Kbuild [new file with mode: 0644]
kern/drivers/timers/hpet.c [new file with mode: 0644]
kern/drivers/timers/hpet.h [new file with mode: 0644]
kern/include/acpi.h
kern/src/printfmt.c

index ff71352..6009ecf 100644 (file)
@@ -191,6 +191,7 @@ static inline uint32_t cpuid_ecx(int op) __attribute__((always_inline));
 static inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
 static inline void write_msr(uint32_t reg, uint64_t val)
               __attribute__((always_inline));
+/* if we have mm64s, change the hpet helpers */
 static inline void write_mmreg32(uintptr_t reg, uint32_t val)
               __attribute__((always_inline));
 static inline uint32_t read_mmreg32(uintptr_t reg)
index b896147..86e9b80 100644 (file)
@@ -1,2 +1,3 @@
 obj-y                                          += net/
 obj-y                                          += dev/
+obj-y                                          += timers/
index a9173f0..daa8362 100644 (file)
@@ -21,6 +21,9 @@
 #include <smp.h>
 #include <ip.h>
 #include <acpi.h>
+
+#include "../timers/hpet.h"
+
 #ifdef CONFIG_X86
 #include <arch/pci.h>
 #endif
@@ -74,6 +77,7 @@ static struct Parse ptables[] = {
        {"SLIT", acpislit,},
        {"MSCT", acpimsct,},
        {"SSDT", acpitable,},
+       {"HPET", acpihpet,},
 };
 
 static struct Facs *facs;              /* Firmware ACPI control structure */
@@ -365,7 +369,7 @@ static long regio(struct Reg *r, void *p, uint32_t len, uintptr_t off, int iswr)
        return len;
 }
 
-static struct Atable *newtable(uint8_t * p)
+struct Atable *new_acpi_table(uint8_t * p)
 {
        struct Atable *t;
        struct Sdthdr *h;
@@ -1067,7 +1071,7 @@ static struct Atable *acpitable(uint8_t * p, int len)
        if (len < Sdthdrsz) {
                return NULL;
        }
-       return newtable(p);
+       return new_acpi_table(p);
 }
 
 static char *dumptable(char *start, char *end, char *sig, uint8_t * p, int l)
diff --git a/kern/drivers/timers/Kbuild b/kern/drivers/timers/Kbuild
new file mode 100644 (file)
index 0000000..2c95da0
--- /dev/null
@@ -0,0 +1,3 @@
+# if we make this conditional, we'll need to change ACPI or else have a weak
+# alias for aciphpet().  don't forget to keep at least one obj file building.
+obj-y                                                  += hpet.o
diff --git a/kern/drivers/timers/hpet.c b/kern/drivers/timers/hpet.c
new file mode 100644 (file)
index 0000000..386a014
--- /dev/null
@@ -0,0 +1,77 @@
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <endian.h>
+#include <pmap.h>
+#include <acpi.h>
+
+#include "hpet.h"
+
+/* The HPET likes 64bit mmreg reads and writes.  If the arch doesn't support
+ * them, then things are a little trickier.  Probably just replace these with
+ * mm64 ops, and quit supporting 32 bit. */
+static inline void hpet_w64(uintptr_t reg, uint64_t val)
+{
+       *((volatile uint64_t*)reg) = val;
+}
+
+static inline uint64_t hpet_r64(uintptr_t reg)
+{
+       return *((volatile uint64_t*)reg);
+}
+
+struct Atable *acpihpet(uint8_t * p, int len)
+{
+       /* Do we want to keep this table around?  if so, we can use newtable, which
+        * allocs an Atable and puts it on a global stailq.  then we return that
+        * pointer, not as an addr, but as a signal to parse code about whether or
+        * not it is safe to unmap (which we don't do anymore). */
+       struct Atable *hpet = new_acpi_table(p);
+       unsigned long hp_addr;
+       uint32_t evt_blk_id;
+       int nr_timers;
+
+       assert(hpet);
+       printk("HPET table detected at %p, for %d bytes\n", p, len);
+
+       evt_blk_id = l32get(p + 36);
+       printd("EV BID 0x%08x\n", evt_blk_id);
+
+       hp_addr = (unsigned long)KADDR_NOCHECK(l64get(p + 44));
+
+       printd("cap/ip %p\n", hpet_r64(hp_addr + 0x00));
+       printd("config %p\n", hpet_r64(hp_addr + 0x10));
+       printd("irqsts %p\n", hpet_r64(hp_addr + 0x20));
+
+       nr_timers = ((hpet_r64(hp_addr) >> 8) & 0xf) + 1;
+       for (int i = 0; i < nr_timers; i++)
+               printd("Timer %d, config reg %p\n", i,
+                      hpet_r64(hp_addr + 0x100 + 0x20 * i));
+       /* 0x10, general config register.  bottom two bits are legacy mode and
+        * global enable.  turning them both off.  need to do read-modify-writes to
+        * HPET registers with reserved fields.*/
+       hpet_w64(hp_addr + 0x10, hpet_r64(hp_addr + 0x10) & ~0x3);
+       printk("Disabled the HPET timer\n");
+       return hpet;
+}
+
+void cmos_dumping_ground()
+{
+       uint8_t cmos_b;
+
+       /* this stuff tries to turn off various cmos / RTC timer bits.  keeping
+        * around if we need to disable the RTC alarm.  note that the HPET replaces
+        * the RTC periodic function (where available), and in those cases the RTC
+        * alarm function is implemented with SMM. */
+       outb(0x70, 0xb);
+       cmos_b = inb(0x71);
+       printk("cmos b 0x%02x\n", cmos_b);
+
+       cmos_b &= ~((1 << 5) | (1 << 6));
+       outb(0x70, 0xb);
+       outb(0x71, cmos_b);
+
+       outb(0x70, 0xb);
+       cmos_b = inb(0x71);
+       printk("cmos b 0x%02x\n", cmos_b);
+}
diff --git a/kern/drivers/timers/hpet.h b/kern/drivers/timers/hpet.h
new file mode 100644 (file)
index 0000000..dc1c2fc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef ROS_DRIVERS_TIMERS_HPET_H
+#define ROS_DRIVERS_TIMERS_HPET_H
+
+#include <acpi.h>
+
+struct Atable *acpihpet(uint8_t *p, int len);
+
+#endif /* ROS_DRIVERS_TIMERS_HPET_H */
index f336c9d..62e138d 100644 (file)
@@ -386,6 +386,7 @@ struct Xsdt {
 extern uintptr_t acpimblocksize(uintptr_t, int *);
 
 int acpiinit(void);
+struct Atable *new_acpi_table(uint8_t *p);
 extern struct Madt *apics;
 
 #endif /* ROS_KERN_ACPI_H */
index 48258c6..d999339 100644 (file)
@@ -13,7 +13,6 @@
 #include <stdarg.h>
 #include <kthread.h>
 #include <ns.h>
-#include <acpi.h>
 
 /* Print a number (base <= 16) in reverse order,
  * using specified putch function and associated pointer putdat. */