PERFORCE change 113465 for review
Matt Jacob
mjacob at FreeBSD.org
Tue Jan 23 21:58:37 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=113465
Change 113465 by mjacob at mjexp_6 on 2007/01/23 21:58:23
Integrate from vendor branch.
Affected files ...
.. //depot/projects/mjexp_6/sys/dev/aac/aac_linux.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpi.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpi_cpu.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpi_package.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpi_perf.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpi_throttle.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/acpica/acpivar.h#2 integrate
.. //depot/projects/mjexp_6/sys/dev/usb/ums.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/usb/usb_quirks.c#2 integrate
.. //depot/projects/mjexp_6/sys/dev/usb/usbdevs#3 integrate
.. //depot/projects/mjexp_6/sys/net/bridgestp.c#2 integrate
.. //depot/projects/mjexp_6/sys/net/bridgestp.h#1 branch
.. //depot/projects/mjexp_6/sys/net/if_bridge.c#3 integrate
.. //depot/projects/mjexp_6/sys/net/if_bridgevar.h#3 integrate
.. //depot/projects/mjexp_6/sys/netinet6/icmp6.c#2 integrate
Differences ...
==== //depot/projects/mjexp_6/sys/dev/aac/aac_linux.c#2 (text+ko) ====
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/aac/aac_linux.c,v 1.3 2004/05/30 20:08:23 phk Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/aac/aac_linux.c,v 1.3.8.1 2007/01/20 07:05:55 delphij Exp $");
/*
* Linux ioctl handler for the aac device driver
@@ -38,8 +38,13 @@
#include <sys/module.h>
#include <sys/file.h>
#include <sys/proc.h>
+#ifdef __amd64__
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
+#endif
#include <compat/linux/linux_ioctl.h>
/* There are multiple ioctl number ranges that need to be handled */
==== //depot/projects/mjexp_6/sys/dev/acpica/acpi.c#2 (text+ko) ====
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi.c,v 1.214.2.8 2006/10/04 19:08:23 jhb Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi.c,v 1.214.2.9 2007/01/23 07:21:23 njl Exp $");
#include "opt_acpi.h"
#include <sys/param.h>
@@ -1110,7 +1110,7 @@
/* Allocate an IO port or memory resource, given its GAS. */
int
acpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas,
- struct resource **res)
+ struct resource **res, u_int flags)
{
int error, res_type;
@@ -1143,7 +1143,7 @@
bus_set_resource(dev, res_type, *rid, gas->Address,
gas->RegisterBitWidth / 8);
- *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE);
+ *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE | flags);
if (*res != NULL) {
*type = res_type;
error = 0;
==== //depot/projects/mjexp_6/sys/dev/acpica/acpi_cpu.c#2 (text+ko) ====
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.57.2.1 2005/11/05 23:49:39 njl Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.57.2.2 2007/01/23 07:21:23 njl Exp $");
#include "opt_acpi.h"
#include <sys/param.h>
@@ -51,9 +51,6 @@
/*
* Support for ACPI Processor devices, including C[1-3] sleep states.
- *
- * TODO: implement scans of all CPUs to be sure all Cx states are
- * equivalent.
*/
/* Hooks for the ACPI CA debugging infrastructure */
@@ -80,10 +77,20 @@
int cpu_cx_count; /* Number of valid Cx states. */
int cpu_prev_sleep;/* Last idle sleep duration. */
int cpu_features; /* Child driver supported features. */
+ /* Runtime state. */
+ int cpu_non_c3; /* Index of lowest non-C3 state. */
+ int cpu_short_slp; /* Count of < 1us sleeps. */
+ u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
+ /* Values for sysctl. */
+ struct sysctl_ctx_list cpu_sysctl_ctx;
+ struct sysctl_oid *cpu_sysctl_tree;
+ int cpu_cx_lowest;
+ char cpu_cx_supported[64];
+ int cpu_rid;
};
struct acpi_cpu_device {
- struct resource_list ad_rl;
+ struct resource_list ad_rl;
};
#define CPU_GET_REG(reg, width) \
@@ -110,20 +117,17 @@
/* Platform hardware resource information. */
static uint32_t cpu_smi_cmd; /* Value to write to SMI_CMD. */
static uint8_t cpu_cst_cnt; /* Indicate we are _CST aware. */
-static int cpu_rid; /* Driver-wide resource id. */
static int cpu_quirks; /* Indicate any hardware bugs. */
/* Runtime state. */
-static int cpu_cx_count; /* Number of valid states */
-static int cpu_non_c3; /* Index of lowest non-C3 state. */
-static int cpu_short_slp; /* Count of < 1us sleeps. */
-static u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
+static int cpu_disable_idle; /* Disable entry to idle function */
+static int cpu_cx_count; /* Number of valid Cx states */
/* Values for sysctl. */
-static struct sysctl_ctx_list acpi_cpu_sysctl_ctx;
-static struct sysctl_oid *acpi_cpu_sysctl_tree;
+static struct sysctl_ctx_list cpu_sysctl_ctx;
+static struct sysctl_oid *cpu_sysctl_tree;
+static int cpu_cx_generic;
static int cpu_cx_lowest;
-static char cpu_cx_supported[64];
static device_t *cpu_devices;
static int cpu_ndevices;
@@ -140,15 +144,17 @@
static int acpi_cpu_read_ivar(device_t dev, device_t child, int index,
uintptr_t *result);
static int acpi_cpu_shutdown(device_t dev);
-static int acpi_cpu_cx_probe(struct acpi_cpu_softc *sc);
+static void acpi_cpu_cx_probe(struct acpi_cpu_softc *sc);
+static void acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc);
static int acpi_cpu_cx_cst(struct acpi_cpu_softc *sc);
static void acpi_cpu_startup(void *arg);
-static void acpi_cpu_startup_cx(void);
+static void acpi_cpu_startup_cx(struct acpi_cpu_softc *sc);
static void acpi_cpu_idle(void);
static void acpi_cpu_notify(ACPI_HANDLE h, UINT32 notify, void *context);
-static int acpi_cpu_quirks(struct acpi_cpu_softc *sc);
+static int acpi_cpu_quirks(void);
static int acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARGS);
static int acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_cpu_global_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS);
static device_method_t acpi_cpu_methods[] = {
/* Device interface */
@@ -288,11 +294,24 @@
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: P_BLK at %#x/%d\n",
device_get_unit(dev), sc->cpu_p_blk, sc->cpu_p_blk_len));
- acpi_sc = acpi_device_get_parent_softc(dev);
- sysctl_ctx_init(&acpi_cpu_sysctl_ctx);
- acpi_cpu_sysctl_tree = SYSCTL_ADD_NODE(&acpi_cpu_sysctl_ctx,
- SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "cpu",
- CTLFLAG_RD, 0, "");
+ /*
+ * If this is the first cpu we attach, create and initialize the generic
+ * resources that will be used by all acpi cpu devices.
+ */
+ if (device_get_unit(dev) == 0) {
+ /* Assume we won't be using generic Cx mode by default */
+ cpu_cx_generic = FALSE;
+
+ /* Install hw.acpi.cpu sysctl tree */
+ acpi_sc = acpi_device_get_parent_softc(dev);
+ sysctl_ctx_init(&cpu_sysctl_ctx);
+ cpu_sysctl_tree = SYSCTL_ADD_NODE(&cpu_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "cpu",
+ CTLFLAG_RD, 0, "node for CPU children");
+
+ /* Queue post cpu-probing task handler */
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cpu_startup, NULL);
+ }
/*
* Before calling any CPU methods, collect child driver feature hints
@@ -327,17 +346,8 @@
AcpiEvaluateObject(sc->cpu_handle, "_PDC", &arglist, NULL);
}
- /*
- * Probe for Cx state support. If it isn't present, free up unused
- * resources.
- */
- if (acpi_cpu_cx_probe(sc) == 0) {
- status = AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY,
- acpi_cpu_notify, sc);
- if (device_get_unit(dev) == 0)
- AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cpu_startup, NULL);
- } else
- sysctl_ctx_free(&acpi_cpu_sysctl_ctx);
+ /* Probe for Cx state support. */
+ acpi_cpu_cx_probe(sc);
/* Finally, call identify and probe/attach for child devices. */
bus_generic_probe(dev);
@@ -371,7 +381,7 @@
* return the pc_cpuid to reference this processor.
*/
if (pcpu_data->pc_acpi_id == 0xffffffff)
- pcpu_data->pc_acpi_id = *acpi_id;
+ pcpu_data->pc_acpi_id = *acpi_id;
else if (pcpu_data->pc_acpi_id != *acpi_id)
*acpi_id = pcpu_data->pc_acpi_id;
*cpu_id = pcpu_data->pc_cpuid;
@@ -396,17 +406,17 @@
static device_t
acpi_cpu_add_child(device_t dev, int order, const char *name, int unit)
{
- struct acpi_cpu_device *ad;
- device_t child;
+ struct acpi_cpu_device *ad;
+ device_t child;
if ((ad = malloc(sizeof(*ad), M_TEMP, M_NOWAIT | M_ZERO)) == NULL)
- return (NULL);
+ return (NULL);
resource_list_init(&ad->ad_rl);
child = device_add_child_ordered(dev, order, name, unit);
if (child != NULL)
- device_set_ivars(child, ad);
+ device_set_ivars(child, ad);
else
free(ad, M_TEMP);
return (child);
@@ -440,7 +450,7 @@
bus_generic_shutdown(dev);
/* Disable any entry to the idle function. */
- cpu_cx_count = 0;
+ cpu_disable_idle = TRUE;
/* Signal and wait for all processors to exit acpi_cpu_idle(). */
smp_rendezvous(NULL, NULL, NULL, NULL);
@@ -448,105 +458,100 @@
return_VALUE (0);
}
-static int
+static void
acpi_cpu_cx_probe(struct acpi_cpu_softc *sc)
{
- ACPI_GENERIC_ADDRESS gas;
- struct acpi_cx *cx_ptr;
- int error;
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ /* Use initial sleep value of 1 sec. to start with lowest idle state. */
+ sc->cpu_prev_sleep = 1000000;
+ sc->cpu_cx_lowest = 0;
/*
- * Bus mastering arbitration control is needed to keep caches coherent
- * while sleeping in C3. If it's not present but a working flush cache
- * instruction is present, flush the caches before entering C3 instead.
- * Otherwise, just disable C3 completely.
+ * Check for the ACPI 2.0 _CST sleep states object. If we can't find
+ * any, we'll revert to generic FADT/P_BLK Cx control method which will
+ * be handled by acpi_cpu_startup. We need to defer to after having
+ * probed all the cpus in the system before probing for generic Cx
+ * states as we may already have found cpus with valid _CST packages
*/
- if (AcpiGbl_FADT->V1_Pm2CntBlk == 0 || AcpiGbl_FADT->Pm2CntLen == 0) {
- if (AcpiGbl_FADT->WbInvd && AcpiGbl_FADT->WbInvdFlush == 0) {
- cpu_quirks |= CPU_QUIRK_NO_BM_CTRL;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "acpi_cpu%d: no BM control, using flush cache method\n",
- device_get_unit(sc->cpu_dev)));
- } else {
- cpu_quirks |= CPU_QUIRK_NO_C3;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "acpi_cpu%d: no BM control, C3 not available\n",
- device_get_unit(sc->cpu_dev)));
- }
+ if (!cpu_cx_generic && acpi_cpu_cx_cst(sc) != 0) {
+ /*
+ * We were unable to find a _CST package for this cpu or there
+ * was an error parsing it. Switch back to generic mode.
+ */
+ cpu_cx_generic = TRUE;
+ if (bootverbose)
+ device_printf(sc->cpu_dev, "switching to generic Cx mode\n");
}
/*
- * First, check for the ACPI 2.0 _CST sleep states object.
- * If not usable, fall back to the P_BLK's P_LVL2 and P_LVL3.
+ * TODO: _CSD Package should be checked here.
*/
+}
+
+static void
+acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
+{
+ ACPI_GENERIC_ADDRESS gas;
+ struct acpi_cx *cx_ptr;
+
sc->cpu_cx_count = 0;
- error = acpi_cpu_cx_cst(sc);
- if (error != 0) {
- cx_ptr = sc->cpu_cx_states;
+ cx_ptr = sc->cpu_cx_states;
+
+ /* Use initial sleep value of 1 sec. to start with lowest idle state. */
+ sc->cpu_prev_sleep = 1000000;
- /* C1 has been required since just after ACPI 1.0 */
- cx_ptr->type = ACPI_STATE_C1;
- cx_ptr->trans_lat = 0;
- cpu_non_c3 = 0;
- cx_ptr++;
- sc->cpu_cx_count++;
+ /* C1 has been required since just after ACPI 1.0 */
+ cx_ptr->type = ACPI_STATE_C1;
+ cx_ptr->trans_lat = 0;
+ cx_ptr++;
+ sc->cpu_cx_count++;
- /*
- * The spec says P_BLK must be 6 bytes long. However, some systems
- * use it to indicate a fractional set of features present so we
- * take 5 as C2. Some may also have a value of 7 to indicate
- * another C3 but most use _CST for this (as required) and having
- * "only" C1-C3 is not a hardship.
- */
- if (sc->cpu_p_blk_len < 5)
- goto done;
+ /*
+ * The spec says P_BLK must be 6 bytes long. However, some systems
+ * use it to indicate a fractional set of features present so we
+ * take 5 as C2. Some may also have a value of 7 to indicate
+ * another C3 but most use _CST for this (as required) and having
+ * "only" C1-C3 is not a hardship.
+ */
+ if (sc->cpu_p_blk_len < 5)
+ return;
- /* Validate and allocate resources for C2 (P_LVL2). */
- gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
- gas.RegisterBitWidth = 8;
- if (AcpiGbl_FADT->Plvl2Lat <= 100) {
- gas.Address = sc->cpu_p_blk + 4;
- acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->res_type, &cpu_rid, &gas,
- &cx_ptr->p_lvlx);
- if (cx_ptr->p_lvlx != NULL) {
- cpu_rid++;
- cx_ptr->type = ACPI_STATE_C2;
- cx_ptr->trans_lat = AcpiGbl_FADT->Plvl2Lat;
- cpu_non_c3 = 1;
- cx_ptr++;
- sc->cpu_cx_count++;
- }
+ /* Validate and allocate resources for C2 (P_LVL2). */
+ gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
+ gas.RegisterBitWidth = 8;
+ if (AcpiGbl_FADT->Plvl2Lat <= 100) {
+ gas.Address = sc->cpu_p_blk + 4;
+ acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->res_type, &sc->cpu_rid,
+ &gas, &cx_ptr->p_lvlx, RF_SHAREABLE);
+ if (cx_ptr->p_lvlx != NULL) {
+ sc->cpu_rid++;
+ cx_ptr->type = ACPI_STATE_C2;
+ cx_ptr->trans_lat = AcpiGbl_FADT->Plvl2Lat;
+ cx_ptr++;
+ sc->cpu_cx_count++;
}
- if (sc->cpu_p_blk_len < 6)
- goto done;
+ }
+ if (sc->cpu_p_blk_len < 6)
+ return;
- /* Validate and allocate resources for C3 (P_LVL3). */
- if (AcpiGbl_FADT->Plvl3Lat <= 1000 &&
- (cpu_quirks & CPU_QUIRK_NO_C3) == 0) {
- gas.Address = sc->cpu_p_blk + 5;
- acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->res_type, &cpu_rid, &gas,
- &cx_ptr->p_lvlx);
- if (cx_ptr->p_lvlx != NULL) {
- cpu_rid++;
- cx_ptr->type = ACPI_STATE_C3;
- cx_ptr->trans_lat = AcpiGbl_FADT->Plvl3Lat;
- cx_ptr++;
- sc->cpu_cx_count++;
- }
+ /* Validate and allocate resources for C3 (P_LVL3). */
+ if (AcpiGbl_FADT->Plvl3Lat <= 1000) {
+ gas.Address = sc->cpu_p_blk + 5;
+ acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->res_type, &sc->cpu_rid, &gas,
+ &cx_ptr->p_lvlx, RF_SHAREABLE);
+ if (cx_ptr->p_lvlx != NULL) {
+ sc->cpu_rid++;
+ cx_ptr->type = ACPI_STATE_C3;
+ cx_ptr->trans_lat = AcpiGbl_FADT->Plvl3Lat;
+ cx_ptr++;
+ sc->cpu_cx_count++;
}
}
-done:
- /* If no valid registers were found, don't attach. */
- if (sc->cpu_cx_count == 0)
- return (ENXIO);
-
- /* Use initial sleep value of 1 sec. to start with lowest idle state. */
- sc->cpu_prev_sleep = 1000000;
-
- return (0);
+ /* Update the largest cx_count seen so far */
+ if (sc->cpu_cx_count > cpu_cx_count)
+ cpu_cx_count = sc->cpu_cx_count;
}
/*
@@ -576,12 +581,12 @@
/* _CST is a package with a count and at least one Cx package. */
top = (ACPI_OBJECT *)buf.Pointer;
if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) {
- device_printf(sc->cpu_dev, "Invalid _CST package\n");
+ device_printf(sc->cpu_dev, "invalid _CST package\n");
AcpiOsFree(buf.Pointer);
return (ENXIO);
}
if (count != top->Package.Count - 1) {
- device_printf(sc->cpu_dev, "Invalid _CST state count (%d != %d)\n",
+ device_printf(sc->cpu_dev, "invalid _CST state count (%d != %d)\n",
count, top->Package.Count - 1);
count = top->Package.Count - 1;
}
@@ -607,7 +612,7 @@
/* Validate the state to see if we should use it. */
switch (cx_ptr->type) {
case ACPI_STATE_C1:
- cpu_non_c3 = i;
+ sc->cpu_non_c3 = i;
cx_ptr++;
sc->cpu_cx_count++;
continue;
@@ -618,7 +623,7 @@
device_get_unit(sc->cpu_dev), i));
continue;
}
- cpu_non_c3 = i;
+ sc->cpu_non_c3 = i;
break;
case ACPI_STATE_C3:
default:
@@ -642,10 +647,10 @@
#endif
/* Allocate the control register for C2 or C3. */
- acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->res_type, &cpu_rid,
- &cx_ptr->p_lvlx);
+ acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->res_type, &sc->cpu_rid,
+ &cx_ptr->p_lvlx, RF_SHAREABLE);
if (cx_ptr->p_lvlx) {
- cpu_rid++;
+ sc->cpu_rid++;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"acpi_cpu%d: Got C%d - %d latency\n",
device_get_unit(sc->cpu_dev), cx_ptr->type,
@@ -666,81 +671,119 @@
acpi_cpu_startup(void *arg)
{
struct acpi_cpu_softc *sc;
- int count, i;
+ int i;
/* Get set of CPU devices */
devclass_get_devices(acpi_cpu_devclass, &cpu_devices, &cpu_ndevices);
- /* Check for quirks via the first CPU device. */
- sc = device_get_softc(cpu_devices[0]);
- acpi_cpu_quirks(sc);
-
/*
- * Make sure all the processors' Cx counts match. We should probably
- * also check the contents of each. However, no known systems have
- * non-matching Cx counts so we'll deal with this later.
+ * Setup any quirks that might necessary now that we have probed
+ * all the CPUs
*/
- count = MAX_CX_STATES;
+ acpi_cpu_quirks();
+
+ cpu_cx_count = 0;
+ if (cpu_cx_generic) {
+ /*
+ * We are using generic Cx mode, probe for available Cx states
+ * for all processors.
+ */
+ for (i = 0; i < cpu_ndevices; i++) {
+ sc = device_get_softc(cpu_devices[i]);
+ acpi_cpu_generic_cx_probe(sc);
+ }
+
+ /*
+ * Find the highest Cx state common to all CPUs
+ * in the system, taking quirks into account.
+ */
+ for (i = 0; i < cpu_ndevices; i++) {
+ sc = device_get_softc(cpu_devices[i]);
+ if (sc->cpu_cx_count < cpu_cx_count)
+ cpu_cx_count = sc->cpu_cx_count;
+ }
+ } else {
+ /*
+ * We are using _CST mode, remove C3 state if necessary.
+ * Update the largest Cx state supported in the global cpu_cx_count.
+ * It will be used in the global Cx sysctl handler.
+ * As we now know for sure that we will be using _CST mode
+ * install our notify handler.
+ */
+ for (i = 0; i < cpu_ndevices; i++) {
+ sc = device_get_softc(cpu_devices[i]);
+ if (cpu_quirks && CPU_QUIRK_NO_C3) {
+ sc->cpu_cx_count = sc->cpu_non_c3 + 1;
+ }
+ if (sc->cpu_cx_count > cpu_cx_count)
+ cpu_cx_count = sc->cpu_cx_count;
+ AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY,
+ acpi_cpu_notify, sc);
+ }
+ }
+
+ /* Perform Cx final initialization. */
for (i = 0; i < cpu_ndevices; i++) {
sc = device_get_softc(cpu_devices[i]);
- count = min(sc->cpu_cx_count, count);
+ acpi_cpu_startup_cx(sc);
}
- cpu_cx_count = count;
+
+ /* Add a sysctl handler to handle global Cx lowest setting */
+ SYSCTL_ADD_PROC(&cpu_sysctl_ctx, SYSCTL_CHILDREN(cpu_sysctl_tree),
+ OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW,
+ NULL, 0, acpi_cpu_global_cx_lowest_sysctl, "A",
+ "Global lowest Cx sleep state to use");
- /* Perform Cx final initialization. */
- sc = device_get_softc(cpu_devices[0]);
- if (cpu_cx_count > 0)
- acpi_cpu_startup_cx();
+ /* Take over idling from cpu_idle_default(). */
+ cpu_cx_lowest = 0;
+ cpu_disable_idle = FALSE;
+ cpu_idle_hook = acpi_cpu_idle;
}
static void
-acpi_cpu_startup_cx()
+acpi_cpu_startup_cx(struct acpi_cpu_softc *sc)
{
- struct acpi_cpu_softc *sc;
struct sbuf sb;
int i;
/*
- * Set up the list of Cx states, eliminating C3 states by truncating
- * cpu_cx_count if quirks indicate C3 is not usable.
+ * Set up the list of Cx states
*/
- sc = device_get_softc(cpu_devices[0]);
- sbuf_new(&sb, cpu_cx_supported, sizeof(cpu_cx_supported), SBUF_FIXEDLEN);
- for (i = 0; i < cpu_cx_count; i++) {
- if ((cpu_quirks & CPU_QUIRK_NO_C3) == 0 ||
- sc->cpu_cx_states[i].type != ACPI_STATE_C3)
- sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cpu_cx_states[i].trans_lat);
- else
- cpu_cx_count = i;
+ sc->cpu_non_c3 = 0;
+ sbuf_new(&sb, sc->cpu_cx_supported, sizeof(sc->cpu_cx_supported),
+ SBUF_FIXEDLEN);
+ for (i = 0; i < sc->cpu_cx_count; i++) {
+ sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cpu_cx_states[i].trans_lat);
+ if (sc->cpu_cx_states[i].type < ACPI_STATE_C3)
+ sc->cpu_non_c3 = i;
}
sbuf_trim(&sb);
sbuf_finish(&sb);
- SYSCTL_ADD_STRING(&acpi_cpu_sysctl_ctx,
- SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
- OID_AUTO, "cx_supported", CTLFLAG_RD, cpu_cx_supported,
- 0, "Cx/microsecond values for supported Cx states");
- SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx,
- SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+
+ SYSCTL_ADD_STRING(&sc->cpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
+ OID_AUTO, "cx_supported", CTLFLAG_RD,
+ sc->cpu_cx_supported, 0,
+ "Cx/microsecond values for supported Cx states");
+ SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW,
- NULL, 0, acpi_cpu_cx_lowest_sysctl, "A",
+ (void *)sc, 0, acpi_cpu_cx_lowest_sysctl, "A",
"lowest Cx sleep state to use");
- SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx,
- SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+ SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
OID_AUTO, "cx_usage", CTLTYPE_STRING | CTLFLAG_RD,
- NULL, 0, acpi_cpu_usage_sysctl, "A",
+ (void *)sc, 0, acpi_cpu_usage_sysctl, "A",
"percent usage for each Cx state");
#ifdef notyet
/* Signal platform that we can handle _CST notification. */
- if (cpu_cst_cnt != 0) {
+ if (!cpu_cx_generic && cpu_cst_cnt != 0) {
ACPI_LOCK(acpi);
AcpiOsWritePort(cpu_smi_cmd, cpu_cst_cnt, 8);
ACPI_UNLOCK(acpi);
}
#endif
-
- /* Take over idling from cpu_idle_default(). */
- cpu_idle_hook = acpi_cpu_idle;
}
/*
@@ -758,7 +801,7 @@
int bm_active, cx_next_idx, i;
/* If disabled, return immediately. */
- if (cpu_cx_count == 0) {
+ if (cpu_disable_idle) {
ACPI_ENABLE_IRQS();
return;
}
@@ -779,28 +822,34 @@
* find the lowest state that has a latency less than or equal to
* the length of our last sleep.
*/
- cx_next_idx = cpu_cx_lowest;
+ cx_next_idx = sc->cpu_cx_lowest;
if (sc->cpu_prev_sleep < 100) {
/*
* If we sleep too short all the time, this system may not implement
* C2/3 correctly (i.e. reads return immediately). In this case,
* back off and use the next higher level.
+ * It seems that when you have a dual core cpu (like the Intel Core Duo)
+ * that both cores will get out of C3 state as soon as one of them
+ * requires it. This breaks the sleep detection logic as the sleep
+ * counter is local to each cpu. Disable the sleep logic for now as a
+ * workaround if there's more than one CPU. The right fix would probably
+ * be to add quirks for system that don't really support C3 state.
*/
- if (sc->cpu_prev_sleep <= 1) {
- cpu_short_slp++;
- if (cpu_short_slp == 1000 && cpu_cx_lowest != 0) {
- if (cpu_non_c3 == cpu_cx_lowest && cpu_non_c3 != 0)
- cpu_non_c3--;
- cpu_cx_lowest--;
- cpu_short_slp = 0;
+ if (mp_ncpus < 2 && sc->cpu_prev_sleep <= 1) {
+ sc->cpu_short_slp++;
+ if (sc->cpu_short_slp == 1000 && sc->cpu_cx_lowest != 0) {
+ if (sc->cpu_non_c3 == sc->cpu_cx_lowest && sc->cpu_non_c3 != 0)
+ sc->cpu_non_c3--;
+ sc->cpu_cx_lowest--;
+ sc->cpu_short_slp = 0;
device_printf(sc->cpu_dev,
"too many short sleeps, backing off to C%d\n",
- cpu_cx_lowest + 1);
+ sc->cpu_cx_lowest + 1);
}
} else
- cpu_short_slp = 0;
+ sc->cpu_short_slp = 0;
- for (i = cpu_cx_lowest; i >= 0; i--)
+ for (i = sc->cpu_cx_lowest; i >= 0; i--)
if (sc->cpu_cx_states[i].trans_lat <= sc->cpu_prev_sleep) {
cx_next_idx = i;
break;
@@ -819,13 +868,13 @@
if (bm_active != 0) {
AcpiSetRegister(ACPI_BITREG_BUS_MASTER_STATUS, 1,
ACPI_MTX_DO_NOT_LOCK);
- cx_next_idx = min(cx_next_idx, cpu_non_c3);
+ cx_next_idx = min(cx_next_idx, sc->cpu_non_c3);
}
}
/* Select the next state and update statistics. */
cx_next = &sc->cpu_cx_states[cx_next_idx];
- cpu_cx_stats[cx_next_idx]++;
+ sc->cpu_cx_stats[cx_next_idx]++;
KASSERT(cx_next->type != ACPI_STATE_C0, ("acpi_cpu_idle: C0 sleep"));
/*
@@ -901,16 +950,39 @@
}
static int
-acpi_cpu_quirks(struct acpi_cpu_softc *sc)
+acpi_cpu_quirks(void)
{
device_t acpi_dev;
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+ /*
+ * Bus mastering arbitration control is needed to keep caches coherent
+ * while sleeping in C3. If it's not present but a working flush cache
+ * instruction is present, flush the caches before entering C3 instead.
+ * Otherwise, just disable C3 completely.
+ */
+ if (AcpiGbl_FADT->V1_Pm2CntBlk == 0 || AcpiGbl_FADT->Pm2CntLen == 0) {
+ if (AcpiGbl_FADT->WbInvd && AcpiGbl_FADT->WbInvdFlush == 0) {
+ cpu_quirks |= CPU_QUIRK_NO_BM_CTRL;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "acpi_cpu: no BM control, using flush cache method\n"));
+ } else {
+ cpu_quirks |= CPU_QUIRK_NO_C3;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "acpi_cpu: no BM control, C3 not available\n"));
+ }
+ }
+
/*
- * C3 on multiple CPUs requires using the expensive flush cache
- * instruction.
+ * If we are using generic Cx mode, C3 on multiple CPUs requires using
+ * the expensive flush cache instruction.
*/
- if (mp_ncpus > 1)
+ if (cpu_cx_generic && mp_ncpus > 1) {
cpu_quirks |= CPU_QUIRK_NO_BM_CTRL;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "acpi_cpu: SMP, using flush cache mode for C3\n"));
+ }
/* Look for various quirks of the PIIX4 part. */
acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
@@ -931,6 +1003,8 @@
case PCI_REVISION_4E:
case PCI_REVISION_4M:
cpu_quirks |= CPU_QUIRK_NO_C3;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "acpi_cpu: working around PIIX4 bug, disabling C3\n"));
break;
default:
break;
@@ -943,18 +1017,20 @@
static int
acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARGS)
{
+ struct acpi_cpu_softc *sc;
struct sbuf sb;
char buf[128];
int i;
uintmax_t fract, sum, whole;
+ sc = (struct acpi_cpu_softc *) arg1;
sum = 0;
- for (i = 0; i < cpu_cx_count; i++)
- sum += cpu_cx_stats[i];
+ for (i = 0; i < sc->cpu_cx_count; i++)
+ sum += sc->cpu_cx_stats[i];
sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
- for (i = 0; i < cpu_cx_count; i++) {
+ for (i = 0; i < sc->cpu_cx_count; i++) {
if (sum > 0) {
- whole = (uintmax_t)cpu_cx_stats[i] * 100;
+ whole = (uintmax_t)sc->cpu_cx_stats[i] * 100;
fract = (whole % sum) * 100;
sbuf_printf(&sb, "%u.%02u%% ", (u_int)(whole / sum),
(u_int)(fract / sum));
@@ -976,31 +1052,73 @@
char state[8];
int val, error, i;
- sc = device_get_softc(cpu_devices[0]);
- snprintf(state, sizeof(state), "C%d", cpu_cx_lowest + 1);
+ sc = (struct acpi_cpu_softc *) arg1;
+ snprintf(state, sizeof(state), "C%d", sc->cpu_cx_lowest + 1);
error = sysctl_handle_string(oidp, state, sizeof(state), req);
if (error != 0 || req->newptr == NULL)
return (error);
if (strlen(state) < 2 || toupper(state[0]) != 'C')
return (EINVAL);
val = (int) strtol(state + 1, NULL, 10) - 1;
- if (val < 0 || val > cpu_cx_count - 1)
+ if (val < 0 || val > sc->cpu_cx_count - 1)
return (EINVAL);
ACPI_SERIAL_BEGIN(cpu);
- cpu_cx_lowest = val;
+ sc->cpu_cx_lowest = val;
/* If not disabling, cache the new lowest non-C3 state. */
- cpu_non_c3 = 0;
- for (i = cpu_cx_lowest; i >= 0; i--) {
+ sc->cpu_non_c3 = 0;
+ for (i = sc->cpu_cx_lowest; i >= 0; i--) {
if (sc->cpu_cx_states[i].type < ACPI_STATE_C3) {
- cpu_non_c3 = i;
+ sc->cpu_non_c3 = i;
break;
}
}
/* Reset the statistics counters. */
- bzero(cpu_cx_stats, sizeof(cpu_cx_stats));
+ bzero(sc->cpu_cx_stats, sizeof(sc->cpu_cx_stats));
+ ACPI_SERIAL_END(cpu);
+
+ return (0);
+}
+
+static int
+acpi_cpu_global_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct acpi_cpu_softc *sc;
+ char state[8];
+ int val, error, i, j;
+
+ snprintf(state, sizeof(state), "C%d", cpu_cx_lowest + 1);
+ error = sysctl_handle_string(oidp, state, sizeof(state), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (strlen(state) < 2 || toupper(state[0]) != 'C')
+ return (EINVAL);
+ val = (int) strtol(state + 1, NULL, 10) - 1;
+ if (val < 0 || val > cpu_cx_count - 1)
+ return (EINVAL);
+
+ cpu_cx_lowest = val;
+
+ /*
+ * Update the new lowest useable Cx state for all CPUs
+ */
+ ACPI_SERIAL_BEGIN(cpu);
+ for (i = 0; i < cpu_ndevices; i++) {
+ sc = device_get_softc(cpu_devices[i]);
+ sc->cpu_cx_lowest = cpu_cx_lowest;
+ sc->cpu_non_c3 = 0;
+ for (j = sc->cpu_cx_lowest; j >= 0; j++) {
+ if (sc->cpu_cx_states[i].type < ACPI_STATE_C3) {
+ sc->cpu_non_c3 = i;
+ break;
+ }
+ }
+
+ /* Reset the statistics counters. */
+ bzero(sc->cpu_cx_stats, sizeof(sc->cpu_cx_stats));
+ }
ACPI_SERIAL_END(cpu);
return (0);
==== //depot/projects/mjexp_6/sys/dev/acpica/acpi_package.c#2 (text+ko) ====
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_package.c,v 1.6.2.2 2005/11/07 09:53:22 obrien Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_package.c,v 1.6.2.3 2007/01/23 07:21:23 njl Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -104,7 +104,7 @@
int
acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
- struct resource **dst)
+ struct resource **dst, u_int flags)
{
ACPI_GENERIC_ADDRESS gas;
ACPI_OBJECT *obj;
@@ -116,7 +116,7 @@
memcpy(&gas, obj->Buffer.Pointer + 3, sizeof(gas));
- return (acpi_bus_alloc_gas(dev, type, rid, &gas, dst));
+ return (acpi_bus_alloc_gas(dev, type, rid, &gas, dst, flags));
}
ACPI_HANDLE
==== //depot/projects/mjexp_6/sys/dev/acpica/acpi_perf.c#2 (text+ko) ====
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_perf.c,v 1.21.2.3 2006/07/18 14:15:04 bruno Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_perf.c,v 1.21.2.4 2007/01/23 07:21:23 njl Exp $");
#include "opt_acpi.h"
#include <sys/param.h>
@@ -191,7 +191,7 @@
pkg = (ACPI_OBJECT *)buf.Pointer;
if (ACPI_PKG_VALID(pkg, 2)) {
rid = 0;
- error = acpi_PkgGas(dev, pkg, 0, &type, &rid, &res);
+ error = acpi_PkgGas(dev, pkg, 0, &type, &rid, &res, 0);
switch (error) {
case 0:
bus_release_resource(dev, type, rid, res);
@@ -329,7 +329,7 @@
}
error = acpi_PkgGas(sc->dev, pkg, 0, &sc->perf_ctrl_type, &sc->px_rid,
- &sc->perf_ctrl);
+ &sc->perf_ctrl, 0);
if (error) {
/*
* If the register is of type FFixedHW, we can only return
@@ -345,7 +345,7 @@
sc->px_rid++;
error = acpi_PkgGas(sc->dev, pkg, 1, &sc->perf_sts_type, &sc->px_rid,
- &sc->perf_status);
+ &sc->perf_status, 0);
if (error) {
if (error == EOPNOTSUPP) {
sc->info_only = TRUE;
==== //depot/projects/mjexp_6/sys/dev/acpica/acpi_throttle.c#2 (text+ko) ====
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_throttle.c,v 1.7.2.2 2006/05/11 17:41:00 njl Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_throttle.c,v 1.7.2.3 2007/01/23 07:21:23 njl Exp $");
#include "opt_acpi.h"
#include <sys/param.h>
@@ -278,7 +278,7 @@
}
memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
- &gas, &sc->cpu_p_cnt);
+ &gas, &sc->cpu_p_cnt, 0);
if (sc->cpu_p_cnt != NULL && bootverbose) {
device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n",
gas.Address);
@@ -298,7 +298,7 @@
gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
gas.RegisterBitWidth = 32;
acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
- &gas, &sc->cpu_p_cnt);
+ &gas, &sc->cpu_p_cnt, 0);
if (sc->cpu_p_cnt != NULL) {
if (bootverbose)
device_printf(sc->cpu_dev,
==== //depot/projects/mjexp_6/sys/dev/acpica/acpivar.h#2 (text+ko) ====
@@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/acpica/acpivar.h,v 1.95.2.4 2006/08/02 07:21:24 njl Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpivar.h,v 1.95.2.5 2007/01/23 07:21:23 njl Exp $
*/
#ifndef _ACPIVAR_H_
@@ -312,7 +312,8 @@
void acpi_UserNotify(const char *subsystem, ACPI_HANDLE h,
uint8_t notify);
int acpi_bus_alloc_gas(device_t dev, int *type, int *rid,
- ACPI_GENERIC_ADDRESS *gas, struct resource **res);
+ ACPI_GENERIC_ADDRESS *gas, struct resource **res,
+ u_int flags);
struct acpi_parse_resource_set {
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list