Date: Sat, 01 Mar 2008 10:49:59 +0200 From: Andriy Gapon <avg@icyb.net.ua> To: John Baldwin <jhb@freebsd.org> Cc: freebsd-acpi@freebsd.org Subject: Re: acpi_throttle: quirk based on pci info Message-ID: <47C918B7.9040504@icyb.net.ua> In-Reply-To: <200802280856.31548.jhb@freebsd.org> References: <47B96989.6070008@icyb.net.ua> <200802271126.30132.jhb@freebsd.org> <47C5E0A6.5030102@icyb.net.ua> <200802280856.31548.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------000002010403000307090000 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit on 28/02/2008 15:56 John Baldwin said the following: > On Wednesday 27 February 2008 05:13:58 pm Andriy Gapon wrote: >> on 27/02/2008 18:26 John Baldwin said the following: >>> On Wednesday 27 February 2008 02:54:38 am Andriy Gapon wrote: >> [snip] >> John, >> >> thank you for this detailed reply! >> I looked through the code and I think that ichss is the only device that >> explicitly requires cpu and pci buses to be "configured". acpi_throttle >> is another one that implicitly requires that. >> My personal preference is to probe/attach pci first and then go with >> cpu. This is mostly because pci can provide a lot of useful information >> and resources to various devices. On the other hand, cpu mostly exists >> so that others could attach to it (it does provide a little bit, but >> it's a very little bit). So, in my opinion, it is more likely that a >> child of cpu would need something from pci than vice versa. >> >> If we agree on this order and implement it, then I agree with you that >> it would be quite easy to modify ichss to be a "normal" child of cpu and >> use pci_find_device to find a proper pci device. And the rest of the >> code that uses pci_read_config, bus_set_resource and >> bus_alloc_resource_any would remain practically the same. >> I'd even say that this would be a trivial change. >> And I'd even say that this would be a change in right direction, because >> ichss would lose most of its 'specialness'. > > Actually, we can make ichss rather simple w/o changing it much by having it > just set a global variable in its PCI probe routine and checking that global > when attaching to the CPU. > > One other thing that concerns me is that cpufreq drivers want to know about > each other (e.g. smist checks for ichss0, etc.). I'd rather that if we have > multiple drivers controlling the same back-end hardware (via difference > interfaces) they all use the same driver name (e.g. speedstep0) and use probe > priority to decide which driver wins if both ichss0 and smist0 can handle a > CPU for example. > > Here is a patch to make CPUs come after PCI and an attempt to fix ICH. Note > that if we made ichss_identify() manually look for the PCI device by bsf > instead of using a probe routine to find it we could remove the pci "driver" > completely and make it work on kldload. It also fixes a bug that the attempt > to enable SS via a PCI config register write could never work as it passed a > cpu0 device_t to pci_read_config/pci_write_config in ichss_probe() > previously. I moved this to attach() (where it belongs) and used the right > device_t so this should work now. I have no hardware to test it on though. > Here is a patch that implements find by bsf idea in ichss that we also discussed. I don't own the actual hardware but I "tested" the patch by temporarily changing some ids and adding printfs instead of some actions. Another little difference that I've added (just in case) a protection against double-adding. I also tested acpi part of your patch - works great! Here's one strange thing - in your patch you accidentally have parameters of device_identify switched, I initially inherited that bug too. I got no error/warning from compiler whatsoever. It wasn't until I saw that device_get_unit(parent) returned garbage that I my untrained eye noticed the mistake. -- Andriy Gapon --------------000002010403000307090000 Content-Type: text/x-patch; name="ichss.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ichss.patch" --- ichss.c.orig 2006-05-16 17:36:24.000000000 +0300 +++ ichss.c 2008-03-01 01:37:53.000000000 +0200 @@ -91,7 +91,7 @@ (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 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 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,66 @@ #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). */ - 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 +196,6 @@ { 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 +212,6 @@ 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 +220,7 @@ ichss_attach(device_t dev) { struct ichss_softc *sc; + uint16_t ss_en; sc = device_get_softc(dev); sc->dev = dev; @@ -264,6 +242,14 @@ 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; --------------000002010403000307090000--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?47C918B7.9040504>