Subject: amd8111 LPC watchdog support
To: None <port-amd64@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: port-amd64
Date: 11/24/2007 18:55:35
--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hi all,
I hope someone here has a AMD8111 LPC bridge to test the attached patch.
E.g. pcictl pci0 list will tell you. If you have, please apply the patch
to -current, uncomment the amdpcib* entry in GENERIC and run
wdogctl -k -p1 amdpcib0
after reboot. System should continue to run. Now enter DDB and after a
second, the system should reboot.
Joerg
--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="amdpcib.c.diff"
Index: amdpcib.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/x86/pci/amdpcib.c,v
retrieving revision 1.1
diff -u -p -r1.1 amdpcib.c
--- amdpcib.c 26 Oct 2007 22:17:14 -0000 1.1
+++ amdpcib.c 23 Nov 2007 00:35:06 -0000
@@ -31,6 +31,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: amdpcib.c,v 1.1 2007/10/26 22:17:14 xtraeme Exp $");
+#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/device.h>
@@ -38,17 +39,27 @@ __KERNEL_RCSID(0, "$NetBSD: amdpcib.c,v
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
+#include <dev/sysmon/sysmonvar.h>
+
struct amdpcib_softc {
struct device sc_dev;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_memh;
+
+ struct sysmon_wdog sc_smw;
+ bus_space_tag_t sc_wdog_tag;
+ bus_space_handle_t sc_wdog_handle;
};
static int amdpcib_match(struct device *, struct cfdata *, void *);
static void amdpcib_attach(struct device *, struct device *, void *);
static int amdpcib_search(device_t, cfdata_t, const int *, void *);
+static void amdpcib_wdog_stop(struct amdpcib_softc *);
+static int amdpcib_wdog_setmode(struct sysmon_wdog *);
+static int amdpcib_wdog_tickle(struct sysmon_wdog *);
+
extern void pcibattach(struct device *, struct device *, void *);
@@ -72,6 +83,8 @@ amdpcib_attach(struct device *parent, st
{
struct amdpcib_softc *sc;
struct pci_attach_args *pa;
+ bus_addr_t wdog_addr;
+ pcireg_t reg;
sc = (struct amdpcib_softc *)self;
pa = (struct pci_attach_args *)aux;
@@ -79,6 +92,31 @@ amdpcib_attach(struct device *parent, st
pcibattach(parent, self, aux);
config_search_loc(amdpcib_search, &sc->sc_dev, "amdpcib", NULL, pa);
+
+ sc->sc_wdog_tag = X86_BUS_SPACE_MEM;
+ /* Map 32 byte below 4GB */
+ bus_space_alloc(sc->sc_wdog_tag, 0, 0xffffffff, 32, 32, 0, 0,
+ &wdog_addr, &sc->sc_wdog_handle);
+
+ /* Enable address range decoding with disabled watchdog first */
+ reg = (uint32_t)wdog_addr | 1;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, 0xa8, reg | 2);
+ /* Ensure that the watchdog is stopped */
+ amdpcib_wdog_stop(sc);
+ /* ...and enable the watchdog processing */
+ pci_conf_write(pa->pa_pc, pa->pa_tag, 0xa8, reg);
+
+ sc->sc_smw.smw_name = device_xname(self);
+ sc->sc_smw.smw_cookie = sc;
+ sc->sc_smw.smw_setmode = amdpcib_wdog_setmode;
+ sc->sc_smw.smw_tickle = amdpcib_wdog_tickle;
+ sc->sc_smw.smw_period = 0xffff;
+
+ if (sysmon_wdog_register(&sc->sc_smw)) {
+ aprint_error_dev(self, "unable to watchdog timer.\n");
+ return;
+ }
+
}
static int
@@ -90,3 +128,37 @@ amdpcib_search(device_t parent, cfdata_t
return 0;
}
+
+static void
+amdpcib_wdog_stop(struct amdpcib_softc *sc)
+{
+ bus_space_write_4(sc->sc_wdog_tag, sc->sc_wdog_handle, 8, 0);
+}
+
+static int
+amdpcib_wdog_setmode(struct sysmon_wdog *smw)
+{
+ struct amdpcib_softc *sc = smw->smw_cookie;
+
+ if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
+ amdpcib_wdog_stop(sc);
+ return 0;
+ }
+
+ if (smw->smw_period > 0xffff)
+ return EINVAL;
+
+ amdpcib_wdog_stop(sc);
+ bus_space_write_4(sc->sc_wdog_tag, sc->sc_wdog_handle, 0, smw->smw_period);
+ amdpcib_wdog_tickle(smw);
+ return 0;
+}
+
+static int
+amdpcib_wdog_tickle(struct sysmon_wdog *smw)
+{
+ struct amdpcib_softc *sc = smw->smw_cookie;
+
+ bus_space_write_4(sc->sc_wdog_tag, sc->sc_wdog_handle, 8, 0x81);
+ return 0;
+}
--FCuugMFkClbJLl1L--