Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Let us detach ichlpcib(4) and its children.
details: https://anonhg.NetBSD.org/src/rev/9233f8a232c9
branches: trunk
changeset: 746712:9233f8a232c9
user: dyoung <dyoung%NetBSD.org@localhost>
date: Tue Aug 18 17:47:46 2009 +0000
description:
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
diffstat:
sys/arch/x86/pci/ichlpcib.c | 210 +++++++++++++++++++++++++++++++++++++++++--
sys/dev/ic/acpipmtimer.c | 20 ++-
sys/dev/ic/acpipmtimer.h | 7 +-
3 files changed, 218 insertions(+), 19 deletions(-)
diffs (truncated from 413 to 300 lines):
diff -r 60e27bd23aec -r 9233f8a232c9 sys/arch/x86/pci/ichlpcib.c
--- a/sys/arch/x86/pci/ichlpcib.c Tue Aug 18 17:40:39 2009 +0000
+++ b/sys/arch/x86/pci/ichlpcib.c Tue Aug 18 17:47:46 2009 +0000
@@ -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;
}
Home |
Main Index |
Thread Index |
Old Index