Module Name:    src
Committed By:   dyoung
Date:           Tue Aug 18 17:47:46 UTC 2009

Modified Files:
        src/sys/arch/x86/pci: ichlpcib.c
        src/sys/dev/ic: acpipmtimer.c acpipmtimer.h

Log Message:
Let us detach ichlpcib(4) and its children.

XXX More testing is needed.  I've tested this on a Dell Dimension 3000,
XXX but that system does not attach every possible device that I try to
XXX detach with this code:

ichlpcib0 at pci0 dev 31 function 0
ichlpcib0: vendor 0x8086 product 0x24d0 (rev. 0x02)
timecounter: Timecounter "ichlpcib0" frequency 3579545 Hz quality 1000
ichlpcib0: 24-bit timer
ichlpcib0: TCO (watchdog) timer configured.
isa0 at ichlpcib0


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/x86/pci/ichlpcib.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/ic/acpipmtimer.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/ic/acpipmtimer.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/pci/ichlpcib.c
diff -u src/sys/arch/x86/pci/ichlpcib.c:1.18 src/sys/arch/x86/pci/ichlpcib.c:1.19
--- src/sys/arch/x86/pci/ichlpcib.c:1.18	Tue Aug 11 17:15:32 2009
+++ src/sys/arch/x86/pci/ichlpcib.c	Tue Aug 18 17:47:46 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: ichlpcib.c,v 1.18 2009/08/11 17:15:32 bouyer Exp $	*/
+/*	$NetBSD: ichlpcib.c,v 1.19 2009/08/18 17:47:46 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.18 2009/08/11 17:15:32 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.19 2009/08/18 17:47:46 dyoung Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -80,6 +80,7 @@
 	struct sysmon_wdog	sc_smw;
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
+	bus_size_t		sc_iosize;
 
 #if NHPET > 0
 	/* HPET variables. */
@@ -93,17 +94,29 @@
 	pcireg_t		sc_pirq[2];
 	pcireg_t		sc_pmcon;
 	pcireg_t		sc_fwhsel2;
+
+	/* Child devices */
+	device_t		sc_hpetbus;
+	acpipmtimer_t		sc_pmtimer;
+	pcireg_t		sc_acpi_cntl;
+
+	struct sysctllog	*sc_log;
 };
 
 static int lpcibmatch(device_t, cfdata_t, void *);
 static void lpcibattach(device_t, device_t, void *);
+static int lpcibdetach(device_t, int);
+static void lpcibchilddet(device_t, device_t);
+static int lpcibrescan(device_t, const char *, const int *);
 static bool lpcib_suspend(device_t PMF_FN_PROTO);
 static bool lpcib_resume(device_t PMF_FN_PROTO);
 static bool lpcib_shutdown(device_t, int);
 
 static void pmtimer_configure(device_t);
+static int pmtimer_unconfigure(device_t, int);
 
 static void tcotimer_configure(device_t);
+static int tcotimer_unconfigure(device_t, int);
 static int tcotimer_setmode(struct sysmon_wdog *);
 static int tcotimer_tickle(struct sysmon_wdog *);
 static void tcotimer_stop(struct lpcib_softc *);
@@ -112,16 +125,18 @@
 static int  tcotimer_disable_noreboot(device_t);
 
 static void speedstep_configure(device_t);
+static void speedstep_unconfigure(device_t);
 static int speedstep_sysctl_helper(SYSCTLFN_ARGS);
 
 #if NHPET > 0
 static void lpcib_hpet_configure(device_t);
+static int lpcib_hpet_unconfigure(device_t, int);
 #endif
 
 struct lpcib_softc *speedstep_cookie;	/* XXX */
 
-CFATTACH_DECL_NEW(ichlpcib, sizeof(struct lpcib_softc),
-    lpcibmatch, lpcibattach, NULL, NULL);
+CFATTACH_DECL2_NEW(ichlpcib, sizeof(struct lpcib_softc),
+    lpcibmatch, lpcibattach, lpcibdetach, NULL, lpcibrescan, lpcibchilddet);
 
 static struct lpcib_device {
 	pcireg_t vendor, product;
@@ -205,7 +220,7 @@
 	 * we do not have to bother bus_space I/O map confliction.
 	 */
 	if (pci_mapreg_map(pa, LPCIB_PCI_PMBASE, PCI_MAPREG_TYPE_IO, 0,
-			   &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
+			   &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) {
 		aprint_error_dev(self, "can't map power management i/o space");
 		return;
 	}
@@ -254,6 +269,102 @@
 		aprint_error_dev(self, "couldn't establish power handler\n");
 }
 
+static void
+lpcibchilddet(device_t self, device_t child)
+{
+	struct lpcib_softc *sc = device_private(self);
+	uint32_t val;
+
+	if (sc->sc_hpetbus != child) {
+		pcibchilddet(self, child);
+		return;
+	}
+	sc->sc_hpetbus = NULL;
+	if (sc->sc_has_ich5_hpet) {
+		val = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+		    LPCIB_PCI_GEN_CNTL);
+		switch (val & LPCIB_ICH5_HPTC_WIN_MASK) {
+		case LPCIB_ICH5_HPTC_0000:
+		case LPCIB_ICH5_HPTC_1000:
+		case LPCIB_ICH5_HPTC_2000:
+		case LPCIB_ICH5_HPTC_3000:
+			break;
+		default:
+			return;
+		}
+		val &= ~LPCIB_ICH5_HPTC_EN;
+		pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+		    LPCIB_PCI_GEN_CNTL, val);
+	} else if (sc->sc_has_rcba) {
+		val = bus_space_read_4(sc->sc_rcbat, sc->sc_rcbah,
+		    LPCIB_RCBA_HPTC);
+		switch (val & LPCIB_RCBA_HPTC_WIN_MASK) {
+		case LPCIB_RCBA_HPTC_0000:
+		case LPCIB_RCBA_HPTC_1000:
+		case LPCIB_RCBA_HPTC_2000:
+		case LPCIB_RCBA_HPTC_3000:
+			break;
+		default:
+			return;
+		}
+		val &= ~LPCIB_RCBA_HPTC_EN;
+		bus_space_write_4(sc->sc_rcbat, sc->sc_rcbah, LPCIB_RCBA_HPTC,
+		    val);
+	}
+}
+
+#if NHPET > 0
+/* XXX share this with sys/arch/i386/pci/elan520.c */
+static bool
+ifattr_match(const char *snull, const char *t)
+{
+	return (snull == NULL) || strcmp(snull, t) == 0;
+}
+#endif
+
+static int
+lpcibrescan(device_t self, const char *ifattr, const int *locators)
+{
+#if NHPET > 0
+	struct lpcib_softc *sc = device_private(self);
+
+	if (ifattr_match(ifattr, "hpetichbus") && sc->sc_hpetbus == NULL)
+		lpcib_hpet_configure(self);
+#endif
+
+	return pcibrescan(self, ifattr, locators);
+}
+
+static int
+lpcibdetach(device_t self, int flags)
+{
+	struct lpcib_softc *sc = device_private(self);
+	int rc;
+
+	pmf_device_deregister(self);
+
+#if NHPET > 0
+	if ((rc = lpcib_hpet_unconfigure(self, flags)) != 0)
+		return rc;
+#endif
+
+	/* Set up SpeedStep. */
+	speedstep_unconfigure(self);
+
+	if ((rc = tcotimer_unconfigure(self, flags)) != 0)
+		return rc;
+
+	if ((rc = pmtimer_unconfigure(self, flags)) != 0)
+		return rc;
+
+	if (sc->sc_has_rcba)
+		bus_space_unmap(sc->sc_rcbat, sc->sc_rcbah, LPCIB_RCBA_SIZE);
+
+	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+
+	return pcibdetach(self, flags);
+}
+
 static bool
 lpcib_shutdown(device_t dv, int howto)
 {
@@ -338,6 +449,7 @@
 	 */
 	control = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
 	    LPCIB_PCI_ACPI_CNTL);
+	sc->sc_acpi_cntl = control;
 	if ((control & LPCIB_PCI_ACPI_CNTL_EN) == 0) {
 		control |= LPCIB_PCI_ACPI_CNTL_EN;
 		pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
@@ -345,10 +457,26 @@
 	}
 
 	/* Attach our PM timer with the generic acpipmtimer function */
-	acpipmtimer_attach(self, sc->sc_iot, sc->sc_ioh,
+	sc->sc_pmtimer = acpipmtimer_attach(self, sc->sc_iot, sc->sc_ioh,
 	    LPCIB_PM1_TMR, 0);
 }
 
+static int
+pmtimer_unconfigure(device_t self, int flags)
+{
+	struct lpcib_softc *sc = device_private(self);
+	int rc;
+
+	if (sc->sc_pmtimer != NULL &&
+	    (rc = acpipmtimer_detach(sc->sc_pmtimer, flags)) != 0)
+		return rc;
+
+	pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+	    LPCIB_PCI_ACPI_CNTL, sc->sc_acpi_cntl);
+
+	return 0;
+}
+
 /*
  * Initialize the watchdog timer.
  */
@@ -405,6 +533,27 @@
 	aprint_verbose_dev(self, "TCO (watchdog) timer configured.\n");
 }
 
+static int
+tcotimer_unconfigure(device_t self, int flags)
+{
+	struct lpcib_softc *sc = device_private(self);
+	int rc;
+
+	if ((rc = sysmon_wdog_unregister(&sc->sc_smw)) != 0) {
+		if (rc == ERESTART)
+			rc = EINTR;
+		return rc;
+	}
+
+	/* Explicitly stop the TCO timer. */
+	tcotimer_stop(sc);
+
+	/* XXX Set No Reboot? */
+
+	return 0;
+}
+
+
 /*
  * Sysmon watchdog callbacks.
  */
@@ -592,7 +741,7 @@
 	    PCI_PRODUCT(sc->sc_pa.pa_id) == PCI_PRODUCT_INTEL_82801CAM_LPC ||
 	    (PCI_PRODUCT(sc->sc_pa.pa_id) == PCI_PRODUCT_INTEL_82801BAM_LPC &&
 	     pci_find_device(&sc->sc_pa, speedstep_bad_hb_check) == 0)) {
-		uint8_t pmcon;
+		pcireg_t pmcon;
 
 		/* Enable SpeedStep if it isn't already enabled. */
 		pmcon = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
@@ -603,13 +752,13 @@
 				       pmcon | LPCIB_PCI_GEN_PMCON_1_SS_EN);
 
 		/* Put in machdep.speedstep_state (0 for low, 1 for high). */
-		if ((rv = sysctl_createv(NULL, 0, NULL, &node,
+		if ((rv = sysctl_createv(&sc->sc_log, 0, NULL, &node,
 		    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
 		    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL)) != 0)
 			goto err;
 
 		/* CTLFLAG_ANYWRITE? kernel option like EST? */
-		if ((rv = sysctl_createv(NULL, 0, &node, &ssnode,
+		if ((rv = sysctl_createv(&sc->sc_log, 0, &node, &ssnode,
 		    CTLFLAG_READWRITE, CTLTYPE_INT, "speedstep_state", NULL,
 		    speedstep_sysctl_helper, 0, NULL, 0, CTL_CREATE,
 		    CTL_EOL)) != 0)
@@ -626,6 +775,18 @@
 	aprint_normal("%s: sysctl_createv failed (rv = %d)\n", __func__, rv);
 }
 
+static void
+speedstep_unconfigure(device_t self)
+{
+	struct lpcib_softc *sc = device_private(self);
+
+	sysctl_teardown(&sc->sc_log);
+	pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+	    LPCIB_PCI_GEN_PMCON_1, sc->sc_pmcon_orig);
+
+	speedstep_cookie = NULL;
+}
+
 /*
  * get/set the SpeedStep state: 0 == low power, 1 == high power.
  */
@@ -715,6 +876,20 @@
 	return 1;
 }
 
+static int
+lpcib_hpet_detach(device_t self, int flags)
+{
+	struct hpet_softc *sc = device_private(self);
+	int rc;
+
+	if ((rc = hpet_detach(self, flags)) != 0)
+		return rc;
+
+	bus_space_unmap(sc->sc_memt, sc->sc_memh, HPET_WINDOW_SIZE);
+
+	return 0;
+}
+
 static void
 lpcib_hpet_attach(device_t parent, device_t self, void *aux)
 {
@@ -737,7 +912,7 @@
 }
 
 CFATTACH_DECL_NEW(ichlpcib_hpet, sizeof(struct hpet_softc), lpcib_hpet_match,
-    lpcib_hpet_attach, NULL, NULL);
+    lpcib_hpet_attach, lpcib_hpet_detach, NULL);
 
 static void
 lpcib_hpet_configure(device_t self)
@@ -798,6 +973,19 @@
 	arg.hpet_mem_t = sc->sc_pa.pa_memt;
 	arg.hpet_reg = hpet_reg;
 
-	config_found_ia(self, "hpetichbus", &arg, NULL);
+	sc->sc_hpetbus = config_found_ia(self, "hpetichbus", &arg, NULL);
+}
+
+static int
+lpcib_hpet_unconfigure(device_t self, int flags)
+{
+	struct lpcib_softc *sc = device_private(self);
+	int rc;
+
+	if (sc->sc_hpetbus != NULL &&
+	    (rc = config_detach(sc->sc_hpetbus, flags)) != 0)
+		return rc;
+
+	return 0;
 }
 #endif

Index: src/sys/dev/ic/acpipmtimer.c
diff -u src/sys/dev/ic/acpipmtimer.c:1.7 src/sys/dev/ic/acpipmtimer.c:1.8
--- src/sys/dev/ic/acpipmtimer.c:1.7	Tue May 12 14:25:17 2009
+++ src/sys/dev/ic/acpipmtimer.c	Tue Aug 18 17:47:46 2009
@@ -1,7 +1,7 @@
-/* $NetBSD: acpipmtimer.c,v 1.7 2009/05/12 14:25:17 cegger Exp $ */
+/* $NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $ */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.7 2009/05/12 14:25:17 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $");
 
 #include <sys/types.h>
 
@@ -26,7 +26,7 @@
 static u_int acpihwtimer_read_safe(struct timecounter *);
 static u_int acpihwtimer_read_fast(struct timecounter *);
 
-int
+acpipmtimer_t
 acpipmtimer_attach(device_t dev,
 		   bus_space_tag_t t, bus_space_handle_t h, bus_size_t off,
 		   int flags)
@@ -34,8 +34,8 @@
 	struct hwtc *tc;
 
 	tc = malloc(sizeof(struct hwtc), M_DEVBUF, M_WAITOK|M_ZERO);
-	if (!tc)
-		return (-1);
+	if (tc == NULL)
+		return NULL;
 
 	tc->tc.tc_name = device_xname(dev);
 	tc->tc.tc_frequency = ACPI_PM_TIMER_FREQUENCY;
@@ -59,7 +59,15 @@
 	tc_init(&tc->tc);
 	aprint_normal("%s: %d-bit timer\n", tc->tc.tc_name,
 		      (flags & ACPIPMT_32BIT ? 32 : 24));
-	return (0);
+	return tc;
+}
+
+int
+acpipmtimer_detach(acpipmtimer_t timer, int flags)
+{
+	struct hwtc *tc = timer;
+
+	return tc_detach(&tc->tc);
 }
 
 #define r(h) bus_space_read_4(h->t, h->h, h->off)

Index: src/sys/dev/ic/acpipmtimer.h
diff -u src/sys/dev/ic/acpipmtimer.h:1.2 src/sys/dev/ic/acpipmtimer.h:1.3
--- src/sys/dev/ic/acpipmtimer.h:1.2	Tue May 12 14:25:17 2009
+++ src/sys/dev/ic/acpipmtimer.h	Tue Aug 18 17:47:46 2009
@@ -1,6 +1,9 @@
-/* $NetBSD: acpipmtimer.h,v 1.2 2009/05/12 14:25:17 cegger Exp $ */
+/* $NetBSD: acpipmtimer.h,v 1.3 2009/08/18 17:47:46 dyoung Exp $ */
 
-int acpipmtimer_attach(device_t,
+typedef void *acpipmtimer_t;
+
+acpipmtimer_t acpipmtimer_attach(device_t,
 		       bus_space_tag_t, bus_space_handle_t, bus_size_t, int);
+int acpipmtimer_detach(acpipmtimer_t, int);
 #define ACPIPMT_32BIT 1
 #define ACPIPMT_BADLATCH 2

Reply via email to