summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2010-05-05 20:13:02 -0700
committerGary King <gking@nvidia.com>2010-05-28 17:51:03 -0700
commit7aefa6254a6cd672c962c4ff5e6f37874aef0109 (patch)
treee8f6771c9d7d337f5045c53cd613b54d378927ee
parent78edd4a2d67fdd8907afdb596fc9993356668512 (diff)
tegra RM: Expanded CPU power off (LP2) policies.
Expanded CPU power off (LP2 state) policies as follows: (a) "Enter in Low Corner" - LP2 is entered and DVFS tick interrupt is masked only when DVFS is in low corner. (b) "Mask in Low Corner" - LP2 is entered independently of DVFS, but DVFS tick interrupt is masked only when low corner is hit (c) "Ignore Low Corner" - LP2 is entered and DVFS tick interrupt is masked independently of DVFS low corner. Set default policy to (a), which is the same as current kernel behavior. Thus, no immediate changes in power or performance numbers is expected. Added sysfs node to change and evaluate new policies. Change-Id: I7c52e87daa5128976337220422d79924a16e442e Reviewed-on: http://git-master/r/1660 Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/idle-t2.c9
-rw-r--r--arch/arm/mach-tegra/include/nvrm_power_private.h28
-rw-r--r--arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c25
-rw-r--r--arch/arm/mach-tegra/nvrm_user.c29
-rw-r--r--arch/arm/mach-tegra/power-t2.c10
5 files changed, 89 insertions, 12 deletions
diff --git a/arch/arm/mach-tegra/idle-t2.c b/arch/arm/mach-tegra/idle-t2.c
index 1e80c34cc342..78183ca7a589 100644
--- a/arch/arm/mach-tegra/idle-t2.c
+++ b/arch/arm/mach-tegra/idle-t2.c
@@ -322,9 +322,16 @@ void mach_tegra_idle(void)
#endif
if (!s_pFlowCtrl || num_online_cpus()>1 || !s_hRmGlobal ||
- !(NvRmPrivGetDfsFlags(s_hRmGlobal) & NvRmDfsStatusFlags_Pause))
+ (g_Lp2Policy == NvRmLp2Policy_Disabled))
lp2_ok = false;
+ if (lp2_ok && (g_Lp2Policy == NvRmLp2Policy_EnterInLowCorner)) {
+ bool dfs_paused = NvRmPrivGetDfsFlags(s_hRmGlobal) &
+ NvRmDfsStatusFlags_Pause;
+ if (!dfs_paused)
+ lp2_ok = false;
+ }
+
if (lp2_ok) {
struct tick_sched *ts =
tick_get_tick_sched(smp_processor_id());
diff --git a/arch/arm/mach-tegra/include/nvrm_power_private.h b/arch/arm/mach-tegra/include/nvrm_power_private.h
index f4adaa0c64ca..7ad22814fb1b 100644
--- a/arch/arm/mach-tegra/include/nvrm_power_private.h
+++ b/arch/arm/mach-tegra/include/nvrm_power_private.h
@@ -104,6 +104,34 @@ typedef enum
} NvRmPmRequest;
/**
+ * Defines RM power manager policies for turning CPU power Off
+ * when it is idle (LP2 state)
+ */
+typedef enum
+{
+ // LP2 entry is disabled
+ NvRmLp2Policy_Disabled = 0,
+
+ // LP2 is entered and DVFS tick interrupt is masked only when DVFS
+ // is in low corner
+ NvRmLp2Policy_EnterInLowCorner,
+
+ // LP2 is entered independently of DVFS low corner, but DVFS tick
+ // interrupt is masked only in low corner
+ NvRmLp2Policy_MaskInLowCorner,
+
+ // LP2 is entered and DVFS tick interrupt is masked independently
+ // of DVFS low corner
+ NvRmLp2Policy_IgnoreLowCorner,
+
+ NvRmLp2Policy_Num,
+ NvRmLp2Policy_Force32 = 0x7FFFFFFF
+} NvRmLp2Policy;
+
+#define NVRM_DEFAULT_LP2POLICY (NvRmLp2Policy_EnterInLowCorner)
+extern NvRmLp2Policy g_Lp2Policy;
+
+/**
* NVRM PM function called within OS shim high priority thread
*/
NvRmPmRequest NvRmPrivPmThread(void);
diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
index 0f25159a15f6..a75d7b04a084 100644
--- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
+++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power_dfs.c
@@ -288,6 +288,9 @@ do\
/*****************************************************************************/
+// LP2 entry policy
+NvRmLp2Policy g_Lp2Policy = NVRM_DEFAULT_LP2POLICY;
+
// DFS object
static NvRmDfs s_Dfs;
@@ -1210,19 +1213,23 @@ DfsGetTargetFrequencies(
/*
* Determine if low corner is hit in this domain - clear hit indicator
- * if new target domain frequency is above low limit (with hysteresis)
- * For platform with dedicated CPU partition do not include activity
- * margin when there is no busy or starvation requirements
+ * if new target domain frequency is above low limit (with hysteresis).
+ * For platform with dedicated CPU partition adjust low corner threshold
+ * when no starvation is detected: if target frequency is limited by
+ * activity, include activity margin in the threshold; otherwise set
+ * low corner at busy hint level per LP2 policy
*/
if (NvRmPrivIsCpuRailDedicated(pDfs->hRm) &&
- (DomainBusyKHz <= LowCornerDomainKHz) &&
- ((*pDomainKHz) == pDomainSampler->BumpedAverageKHz))
+ (!pDomainSampler->RtStarveBoostKHz) &&
+ (!pDomainSampler->NrtStarveBoostKHz))
{
- // Multiplying threshold has the same effect as dividing target
- // to reduce margin
- LowCornerDomainKHz +=
- (LowCornerDomainKHz >> pDomainParam->RelAdjustBits);
+ if ((*pDomainKHz) == pDomainSampler->BumpedAverageKHz)
+ LowCornerDomainKHz +=
+ (LowCornerDomainKHz >> pDomainParam->RelAdjustBits);
+ else if (g_Lp2Policy != NvRmLp2Policy_EnterInLowCorner)
+ LowCornerDomainKHz = NV_MAX(DomainBusyKHz, LowCornerDomainKHz);
}
+
if ( ((*pDomainKHz) >
(LowCornerDomainKHz + pDomainParam->NrtStarveParam.BoostStepKHz))
|| (((*pDomainKHz) > LowCornerDomainKHz) && (!pDfs->LowCornerHit))
diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c
index d8e5f94502fc..12fc1edb5ac8 100644
--- a/arch/arm/mach-tegra/nvrm_user.c
+++ b/arch/arm/mach-tegra/nvrm_user.c
@@ -724,6 +724,34 @@ static struct early_suspend tegra_display_power =
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB
};
#endif
+
+/*
+ * NVRM CPU power gating (LP2) policy
+ */
+static ssize_t
+nvrm_lp2policy_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", g_Lp2Policy);
+}
+
+static ssize_t
+nvrm_lp2policy_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int n, policy;
+
+ n = sscanf(buf, "%u", &policy);
+ if ((n != 1) || (policy >= NvRmLp2Policy_Num))
+ return -1;
+
+ g_Lp2Policy = policy;
+ return count;
+}
+
+static struct kobj_attribute nvrm_lp2policy_attribute =
+ __ATTR(lp2policy, 0644, nvrm_lp2policy_show, nvrm_lp2policy_store);
+
#endif
static int __init nvrm_init(void)
@@ -743,6 +771,7 @@ static int __init nvrm_init(void)
// Create /sys/power/nvrm/notifier.
nvrm_kobj = kobject_create_and_add("nvrm", power_kobj);
+ sysfs_create_file(nvrm_kobj, &nvrm_lp2policy_attribute.attr);
sysfs_create_file(nvrm_kobj, &nvrm_notifier_attribute.attr);
sys_nvrm_notifier = NULL;
init_waitqueue_head(&sys_nvrm_notifier_wait);
diff --git a/arch/arm/mach-tegra/power-t2.c b/arch/arm/mach-tegra/power-t2.c
index d9235a8ca1ac..71885eda5422 100644
--- a/arch/arm/mach-tegra/power-t2.c
+++ b/arch/arm/mach-tegra/power-t2.c
@@ -227,6 +227,7 @@ void cpu_ap20_do_lp1(void)
void cpu_ap20_do_lp2(void)
{
+ bool dfs_stop = NV_TRUE;
unsigned int proc_id = smp_processor_id();
//Save our context ptrs to scratch regs
@@ -240,7 +241,11 @@ void cpu_ap20_do_lp2(void)
if (!proc_id)
{
//Disable the Statistics interrupt
- disable_irq(INT_SYS_STATS_MON);
+ if (g_Lp2Policy == NvRmLp2Policy_MaskInLowCorner)
+ dfs_stop = (NvRmPrivGetDfsFlags(s_hRmGlobal) &
+ NvRmDfsStatusFlags_Pause);
+ if (dfs_stop)
+ disable_irq(INT_SYS_STATS_MON);
do_suspend_prep();
// Save/clear CPU clock divider ("voltage-safe", as scaling is
@@ -257,7 +262,8 @@ void cpu_ap20_do_lp2(void)
if (!proc_id)
{
//We're back
- enable_irq(INT_SYS_STATS_MON);
+ if (dfs_stop)
+ enable_irq(INT_SYS_STATS_MON);
//Delay if needed