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