x86: initializes the LPC
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 2 Sep 2014 18:48:58 +0000 (11:48 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 10 Sep 2014 03:15:27 +0000 (20:15 -0700)
If your machine has an LPC, part of the PCH or maybe the southbridge, then this
will do very basic initialization.  It'll just disable one of the timers that
triggers SMIs on one of my machines.

kern/arch/x86/Kbuild
kern/arch/x86/init.c
kern/arch/x86/init.h
kern/arch/x86/intel.c [new file with mode: 0644]
kern/arch/x86/pci.h

index bf44a8b..b732241 100644 (file)
@@ -7,6 +7,7 @@ obj-y                                           += devarch.o
 obj-y                                          += entry$(BITS).o
 obj-y                                          += frontend.o
 obj-y                                          += init.o
+obj-y                                          += intel.o
 obj-y                                          += ioapic.o
 obj-y                                          += kclock.o
 obj-y                                          += kdebug.o
index fe9f7dd..e143cc9 100644 (file)
@@ -93,6 +93,7 @@ void arch_init()
 
        perfmon_init();
        cons_irq_init();
+       intel_lpc_init();
        usb_disable_legacy();
        check_timing_stability();
 }
index 57ad0bc..7f38043 100644 (file)
@@ -6,5 +6,7 @@
 void arch_init();
 bool check_timing_stability(void);     /* in rdtsc_test.c */
 
+void intel_lpc_init();
+
 #endif // !ROS_ARCH_INIT_H
 
diff --git a/kern/arch/x86/intel.c b/kern/arch/x86/intel.c
new file mode 100644 (file)
index 0000000..da6d120
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * See LICENSE for details.
+ *
+ * Barret Rhoden <brho@cs.berkeley.edu> */
+
+#include <arch/x86.h>
+#include <arch/pci.h>
+#include <trap.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <kmalloc.h>
+#include <time.h>
+#include <mm.h>
+
+/* super-shoddy LPC chip initialization.
+ *
+ * the PCH (old southbridge) is a c602, TBDF x:1f:00 LPC controller
+ * - PMBASE is the mnemonic for "ACPI Base Address"
+ * - TCO is 0x60 off in the PMBASE space
+ * - PMBASE + 0x30 is an SMI control reg
+ *
+ * TODO:
+ * - why don't we find the other functions (1f.2 and 1f.3, in linux)?
+ */
+static void lpc_init_pci(struct pci_device *pcidev)
+{
+       uint32_t pmbase = pcidev_read32(pcidev, 0x40);
+
+       pmbase &= ~1; /* clear bit 0 */
+       uint32_t smi_ctl = inl(pmbase + 0x30);
+       #if 0
+       /* halt the tco timer: this busts things, and won't work with the lock on */
+       uint16_t tco1 = inw(pmbase + 0x60 + 0x08);
+       if (tco1 & (1 << 12)) {
+               printk("\t\tTCO_LOCK is on!\n");
+       } else {
+               outw(pmbase + 0x60 + 0x08, tco1 & ~(1 << 11));
+               tco1 = inw(pmbase + 0x60 + 0x08);
+       }
+       #endif
+       /* bit 6 is another timer, one that messes up c89. */
+       outl(pmbase + 0x30, smi_ctl & ~(1 << 6));
+       smi_ctl = inl(pmbase + 0x30);
+}
+
+void intel_lpc_init()
+{
+       struct pci_device *i;
+       STAILQ_FOREACH(i, &pci_devices, all_dev) {
+               if ((i->dev == 0x1f) && (i->func == 0x00))
+                       lpc_init_pci(i);
+       }
+}
index 36275ca..beb8b05 100644 (file)
@@ -362,7 +362,6 @@ struct msix_irq_vector {
 
 /* List of all discovered devices */
 STAILQ_HEAD(pcidev_stailq, pci_device);
-SLIST_HEAD(pcidev_slist, pci_device);
 extern struct pcidev_stailq pci_devices;
 
 /* Sync rules for PCI: once a device is added to the list, it is never removed,