From owner-p4-projects@FreeBSD.ORG Tue Jan 23 21:58:37 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 8F40B16A405; Tue, 23 Jan 2007 21:58:37 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 656A416A403 for ; Tue, 23 Jan 2007 21:58:37 +0000 (UTC) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 57B2413C442 for ; Tue, 23 Jan 2007 21:58:37 +0000 (UTC) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id l0NLwbPv053033 for ; Tue, 23 Jan 2007 21:58:37 GMT (envelope-from mjacob@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id l0NLwaUX053030 for perforce@freebsd.org; Tue, 23 Jan 2007 21:58:36 GMT (envelope-from mjacob@freebsd.org) Date: Tue, 23 Jan 2007 21:58:36 GMT Message-Id: <200701232158.l0NLwaUX053030@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to mjacob@freebsd.org using -f From: Matt Jacob To: Perforce Change Reviews Cc: Subject: PERFORCE change 113465 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Jan 2007 21:58:37 -0000 http://perforce.freebsd.org/chv.cgi?CH=113465 Change 113465 by mjacob@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 -__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 #include #include +#ifdef __amd64__ +#include +#include +#else #include #include +#endif #include /* 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 -__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 @@ -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 -__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 @@ -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 -__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 #include @@ -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 -__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 @@ -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 -__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 @@ -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) <<<