📄 prpower.c
字号:
* * PARAMETERS: * * RETURN: * * DESCRIPTION: Sets the default Cx state policy (OS idle handler). Our * scheme is to promote quickly to C2 but more conservatively * to C3. We're favoring C2 for its characteristics of low * latency (quick response), good power savings, and ability * to allow bus mastering activity. * * Note that Cx state policy is completely customizable, with * the goal of having heuristics to alter policy dynamically. * ****************************************************************************/acpi_statuspr_power_set_default_policy ( PR_CONTEXT *processor){ FUNCTION_TRACE("pr_power_set_default_policy"); if (!processor) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* * Busy Metric: * ------------ * Used to determine when the OS has been busy and thus when * policy should return to using the default Cx state (e.g. C1). * On Linux we use the number of jiffies (scheduler quantums) * that transpire between calls to the idle handler. * * TBD: Linux-specific. */ processor->power.busy_metric = 2; /* * C1: * --- * C1 serves as our default state. It must be valid. */ if (processor->power.state[PR_C1].is_valid) { processor->power.active_state = processor->power.default_state = PR_C1; } else { processor->power.active_state = processor->power.default_state = PR_C0; return_ACPI_STATUS(AE_OK); } /* * C2: * --- * Set default C1 promotion and C2 demotion policies. */ if (processor->power.state[PR_C2].is_valid) { /* * Promote from C1 to C2 anytime we're asleep in C1 for * longer than two times the C2 latency (to amortize cost * of transition). Demote from C2 to C1 anytime we're * asleep in C2 for less than this time. */ processor->power.state[PR_C1].promotion.count_threshold = 10; processor->power.state[PR_C1].promotion.time_threshold = 2 * processor->power.state[PR_C2].latency; processor->power.state[PR_C1].promotion.target_state = PR_C2; processor->power.state[PR_C2].demotion.count_threshold = 1; processor->power.state[PR_C2].demotion.time_threshold = 2 * processor->power.state[PR_C2].latency; processor->power.state[PR_C2].demotion.target_state = PR_C1; } /* * C3: * --- * Set default C2 promotion and C3 demotion policies. */ if ((processor->power.state[PR_C2].is_valid) && (processor->power.state[PR_C3].is_valid)) { /* * Promote from C2 to C3 after 4 cycles of no bus * mastering activity (while maintaining sleep time * criteria). Demote immediately on a short or * whenever bus mastering activity occurs. */ processor->power.state[PR_C2].promotion.count_threshold = 1; processor->power.state[PR_C2].promotion.time_threshold = 2 * processor->power.state[PR_C3].latency; processor->power.state[PR_C2].promotion.bm_threshold = 0x0000000F; processor->power.state[PR_C2].promotion.target_state = PR_C3; processor->power.state[PR_C3].demotion.count_threshold = 1; processor->power.state[PR_C3].demotion.time_threshold = 2 * processor->power.state[PR_C3].latency; processor->power.state[PR_C3].demotion.bm_threshold = 0x0000000F; processor->power.state[PR_C3].demotion.target_state = PR_C2; } return_ACPI_STATUS(AE_OK);}/***************************************************************************** * * FUNCTION: pr_power_add_device * * PARAMETERS: <none> * * RETURN: * * DESCRIPTION: * ****************************************************************************//* * TBD: 1. PROC_C1 support. * 2. Symmetric Cx state support (different Cx states supported * by different CPUs results in lowest common denominator). */acpi_statuspr_power_add_device ( PR_CONTEXT *processor){ FUNCTION_TRACE("pr_power_add_device"); if (!processor) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* * State Count: * ------------ * Fixed at four (C0-C3). We use is_valid to determine whether or * not a state actually gets used. */ processor->power.state_count = PR_MAX_POWER_STATES; /* * C0: * --- * C0 exists only as filler in our array. (Let's assume its valid!) */ processor->power.state[PR_C0].is_valid = TRUE; /* * C1: * --- * ACPI states that C1 must be supported by all processors * with a latency so small that it can be ignored. * * TBD: What about PROC_C1 support? */ processor->power.state[PR_C1].is_valid = TRUE; /* * C2: * --- * We're only supporting C2 on UP systems with latencies <= 100us. * * TBD: Support for C2 on MP (P_LVL2_UP) -- I'm taking the * conservative approach for now. */ processor->power.state[PR_C2].latency = acpi_fadt.plvl2_lat;#ifdef CONFIG_SMP if (smp_num_cpus == 1) {#endif /*CONFIG_SMP*/ if (acpi_fadt.plvl2_lat <= PR_MAX_C2_LATENCY) { processor->power.state[PR_C2].is_valid = TRUE; processor->power.p_lvl2 = processor->pblk.address + 4; }#ifdef CONFIG_SMP }#endif /*CONFIG_SMP*/ /* * C3: * --- * We're only supporting C3 on UP systems with latencies <= 1000us, * and that include the ability to disable bus mastering while in * C3 (ARB_DIS) but allows bus mastering requests to wake the system * from C3 (BM_RLD). Note his method of maintaining cache coherency * (disabling of bus mastering) cannot be used on SMP systems, and * flushing caches (e.g. WBINVD) is simply too costly at this time. * * TBD: Support for C3 on MP -- I'm taking the conservative * approach for now. */ processor->power.state[PR_C3].latency = acpi_fadt.plvl3_lat;#ifdef CONFIG_SMP if (smp_num_cpus == 1) {#endif /*CONFIG_SMP*/ if ((acpi_fadt.plvl3_lat <= PR_MAX_C3_LATENCY) && bm_control) { processor->power.state[PR_C3].is_valid = TRUE; processor->power.p_lvl3 = processor->pblk.address + 5; }#ifdef CONFIG_SMP }#endif /*CONFIG_SMP*/ /* * Set Default Policy: * ------------------- * Now that we know which state are supported, set the default * policy. Note that this policy can be changed dynamically * (e.g. encourage deeper sleeps to conserve battery life when * not on AC). */ pr_power_set_default_policy(processor); /* * Save Processor Context: * ----------------------- * TBD: Enhance Linux idle handler to take processor context * parameter. */ processor_list[processor->uid] = processor; return_ACPI_STATUS(AE_OK);}/**************************************************************************** * * FUNCTION: pr_power_remove_device * * PARAMETERS: * * RETURN: * * DESCRIPTION: * ****************************************************************************/acpi_statuspr_power_remove_device ( PR_CONTEXT *processor){ acpi_status status = AE_OK; FUNCTION_TRACE("pr_power_remove_device"); if (!processor) { return_ACPI_STATUS(AE_BAD_PARAMETER); } MEMSET(&(processor->power), 0, sizeof(PR_POWER)); processor_list[processor->uid] = NULL; return_ACPI_STATUS(status);}/**************************************************************************** * * FUNCTION: pr_power_initialize * * PARAMETERS: <none> * * RETURN: * * DESCRIPTION: * ****************************************************************************/acpi_statuspr_power_initialize (void){ u32 i = 0; FUNCTION_TRACE("pr_power_initialize"); /* TBD: Linux-specific. */ for (i=0; i<NR_CPUS; i++) { processor_list[i] = NULL; } ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Max CPUs[%d], this CPU[%d].\n", NR_CPUS, smp_processor_id())); /* Only use C3 if we can control bus mastering. */ if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) bm_control = 1; /* * Install idle handler. * * TBD: Linux-specific (need OSL function). */ pr_pm_idle_save = pm_idle; pm_idle = pr_power_idle; return_ACPI_STATUS(AE_OK);}/**************************************************************************** * * FUNCTION: pr_power_terminate * * PARAMETERS: <none> * * RETURN: * * DESCRIPTION: * ****************************************************************************/acpi_statuspr_power_terminate (void){ FUNCTION_TRACE("pr_power_terminate"); /* * Remove idle handler. * * TBD: Linux-specific (need OSL function). */ pm_idle = pr_pm_idle_save; return_ACPI_STATUS(AE_OK);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -