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