summaryrefslogtreecommitdiffstats
path: root/sys/dev/cpufreq/ichss.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-03-10 22:18:07 +0000
committerjhb <jhb@FreeBSD.org>2008-03-10 22:18:07 +0000
commit18300325cbb0d05941fff043af793858b4aef3dd (patch)
tree9434f84ce46229a380631770a44da3d379da5c99 /sys/dev/cpufreq/ichss.c
parente0c2a8245edf31dd9da5a9938c1ab8be11802de9 (diff)
downloadFreeBSD-src-18300325cbb0d05941fff043af793858b4aef3dd.zip
FreeBSD-src-18300325cbb0d05941fff043af793858b4aef3dd.tar.gz
Probe CPUs after the PCI hierarchy on i386, amd64, and ia64. This allows
the cpufreq drivers to reliably use properties of PCI devices for quirks, etc. - For the legacy drivers, add CPU devices via an identify routine in the CPU driver itself rather than in the legacy driver's attach routine. - Add CPU devices after Host-PCI bridges in the acpi bus driver. - Change the ichss(4) driver to use pci_find_bsf() to locate the ICH and check its device ID rather than having a bogus PCI attachment that only checked for the ID in probe and always failed. As a side effect, you can now kldload ichss after boot. - Fix the ichss(4) driver to use the correct device_t for the ICH (and not for ichss0) when doing PCI config space operations to enable SpeedStep. MFC after: 2 weeks Reviewed by: njl, Andriy Gapon avg of icyb.net.ua
Diffstat (limited to 'sys/dev/cpufreq/ichss.c')
-rw-r--r--sys/dev/cpufreq/ichss.c111
1 files changed, 50 insertions, 61 deletions
diff --git a/sys/dev/cpufreq/ichss.c b/sys/dev/cpufreq/ichss.c
index 13d004d..179886e 100644
--- a/sys/dev/cpufreq/ichss.c
+++ b/sys/dev/cpufreq/ichss.c
@@ -91,7 +91,7 @@ struct ichss_softc {
(bus_space_write_1(rman_get_bustag((reg)), \
rman_get_bushandle((reg)), 0, (val)))
-static int ichss_pci_probe(device_t dev);
+static void ichss_identify(driver_t *driver, device_t parent);
static int ichss_probe(device_t dev);
static int ichss_attach(device_t dev);
static int ichss_detach(device_t dev);
@@ -103,6 +103,7 @@ static int ichss_type(device_t dev, int *type);
static device_method_t ichss_methods[] = {
/* Device interface */
+ DEVMETHOD(device_identify, ichss_identify),
DEVMETHOD(device_probe, ichss_probe),
DEVMETHOD(device_attach, ichss_attach),
DEVMETHOD(device_detach, ichss_detach),
@@ -120,15 +121,7 @@ static driver_t ichss_driver = {
static devclass_t ichss_devclass;
DRIVER_MODULE(ichss, cpu, ichss_driver, ichss_devclass, 0, 0);
-static device_method_t ichss_pci_methods[] = {
- DEVMETHOD(device_probe, ichss_pci_probe),
- {0, 0}
-};
-static driver_t ichss_pci_driver = {
- "ichss_pci", ichss_pci_methods, 0
-};
-static devclass_t ichss_pci_devclass;
-DRIVER_MODULE(ichss_pci, pci, ichss_pci_driver, ichss_pci_devclass, 0, 0);
+static device_t ich_device;
#if 0
#define DPRINT(x...) printf(x)
@@ -136,70 +129,69 @@ DRIVER_MODULE(ichss_pci, pci, ichss_pci_driver, ichss_pci_devclass, 0, 0);
#define DPRINT(x...)
#endif
-/*
- * We detect the chipset by looking for its LPC bus ID during the PCI
- * scan and reading its config registers during the probe. However,
- * we add the ichss child under the cpu device since even though the
- * chipset provides the control, it really affects the cpu only.
- *
- * XXX This approach does not work if the module is loaded after boot.
- */
-static int
-ichss_pci_probe(device_t dev)
+static void
+ichss_identify(driver_t *driver, device_t parent)
{
- device_t child, parent;
+ device_t child;
uint32_t pmbase;
+ if (resource_disabled("ichss", 0))
+ return;
+
/*
- * TODO: add a quirk to disable if we see the 82815_MC along
- * with the 82801BA and revision < 5.
+ * It appears that ICH SpeedStep only requires a single CPU to
+ * set the value (since the chipset is shared by all CPUs.)
+ * Thus, we only add a child to cpu 0.
*/
- if (pci_get_vendor(dev) != PCI_VENDOR_INTEL ||
- (pci_get_device(dev) != PCI_DEV_82801BA &&
- pci_get_device(dev) != PCI_DEV_82801CA &&
- pci_get_device(dev) != PCI_DEV_82801DB))
- return (ENXIO);
+ if (device_get_unit(parent) != 0)
+ return;
- /* Only one CPU is supported for this hardware. */
- if (devclass_get_device(ichss_devclass, 0))
- return (ENXIO);
+ /* Avoid duplicates. */
+ if (device_find_child(parent, "ichss", -1))
+ return;
/*
- * Add a child under the CPU parent. It appears that ICH SpeedStep
- * only requires a single CPU to set the value (since the chipset
- * is shared by all CPUs.) Thus, we only add a child to cpu 0.
+ * ICH2/3/4-M I/O Controller Hub is at bus 0, slot 1F, function 0.
+ * E.g. see Section 6.1 "PCI Devices and Functions" and table 6.1 of
+ * Intel(r) 82801BA I/O Controller Hub 2 (ICH2) and Intel(r) 82801BAM
+ * I/O Controller Hub 2 Mobile (ICH2-M).
+ *
+ * TODO: add a quirk to disable if we see the 82815_MC along
+ * with the 82801BA and revision < 5.
*/
- parent = devclass_get_device(devclass_find("cpu"), 0);
- KASSERT(parent != NULL, ("cpu parent is NULL"));
- child = BUS_ADD_CHILD(parent, 0, "ichss", 0);
- if (child == NULL) {
- device_printf(parent, "add SpeedStep child failed\n");
- return (ENXIO);
- }
+ ich_device = pci_find_bsf(0, 0x1f, 0);
+ if (ich_device == NULL ||
+ pci_get_vendor(ich_device) != PCI_VENDOR_INTEL ||
+ (pci_get_device(ich_device) != PCI_DEV_82801BA &&
+ pci_get_device(ich_device) != PCI_DEV_82801CA &&
+ pci_get_device(ich_device) != PCI_DEV_82801DB))
+ return;
/* Find the PMBASE register from our PCI config header. */
- pmbase = pci_read_config(dev, ICHSS_PMBASE_OFFSET, sizeof(pmbase));
+ pmbase = pci_read_config(ich_device, ICHSS_PMBASE_OFFSET,
+ sizeof(pmbase));
if ((pmbase & ICHSS_IO_REG) == 0) {
printf("ichss: invalid PMBASE memory type\n");
- return (ENXIO);
+ return;
}
pmbase &= ICHSS_PMBASE_MASK;
if (pmbase == 0) {
printf("ichss: invalid zero PMBASE address\n");
- return (ENXIO);
+ return;
}
DPRINT("ichss: PMBASE is %#x\n", pmbase);
+ child = BUS_ADD_CHILD(parent, 0, "ichss", 0);
+ if (child == NULL) {
+ device_printf(parent, "add SpeedStep child failed\n");
+ return;
+ }
+
/* Add the bus master arbitration and control registers. */
bus_set_resource(child, SYS_RES_IOPORT, 0, pmbase + ICHSS_BM_OFFSET,
1);
bus_set_resource(child, SYS_RES_IOPORT, 1, pmbase + ICHSS_CTRL_OFFSET,
1);
-
- /* Attach the new CPU child now. */
- device_probe_and_attach(child);
-
- return (ENXIO);
}
static int
@@ -207,10 +199,6 @@ ichss_probe(device_t dev)
{
device_t est_dev, perf_dev;
int error, type;
- uint16_t ss_en;
-
- if (resource_disabled("ichss", 0))
- return (ENXIO);
/*
* If the ACPI perf driver has attached and is not just offering
@@ -227,14 +215,6 @@ ichss_probe(device_t dev)
if (est_dev && device_is_attached(est_dev))
return (ENXIO);
- /* Activate SpeedStep control if not already enabled. */
- ss_en = pci_read_config(dev, ICHSS_PMCFG_OFFSET, sizeof(ss_en));
- if ((ss_en & ICHSS_ENABLE) == 0) {
- printf("ichss: enabling SpeedStep support\n");
- pci_write_config(dev, ICHSS_PMCFG_OFFSET,
- ss_en | ICHSS_ENABLE, sizeof(ss_en));
- }
-
device_set_desc(dev, "SpeedStep ICH");
return (-1000);
}
@@ -243,6 +223,7 @@ static int
ichss_attach(device_t dev)
{
struct ichss_softc *sc;
+ uint16_t ss_en;
sc = device_get_softc(dev);
sc->dev = dev;
@@ -264,6 +245,14 @@ ichss_attach(device_t dev)
return (ENXIO);
}
+ /* Activate SpeedStep control if not already enabled. */
+ ss_en = pci_read_config(ich_device, ICHSS_PMCFG_OFFSET, sizeof(ss_en));
+ if ((ss_en & ICHSS_ENABLE) == 0) {
+ device_printf(dev, "enabling SpeedStep support\n");
+ pci_write_config(ich_device, ICHSS_PMCFG_OFFSET,
+ ss_en | ICHSS_ENABLE, sizeof(ss_en));
+ }
+
/* Setup some defaults for our exported settings. */
sc->sets[0].freq = CPUFREQ_VAL_UNKNOWN;
sc->sets[0].volts = CPUFREQ_VAL_UNKNOWN;
OpenPOWER on IntegriCloud