- struct per_proc_info *pp;
- uint32_t nstate;
- int dir;
-
- pp = getPerProc(); /* Get our per_proc */
-
- if(!pmsInstalled || pp->pms.pmsState == pmsParked) return; /* No stepping if parked or not installed */
-
- nstate = pmsCtls.pmsDefs[pp->pms.pmsState]->pmsNext; /* Assume a normal step */
- dir = 1; /* A normal step is a step up */
-
- if(timer && (pmsCtls.pmsDefs[pp->pms.pmsState]->pmsSetCmd == pmsDelay)) { /* If the timer expired and we are in a delay step, use the delay branch */
- nstate = pmsCtls.pmsDefs[pp->pms.pmsState]->pmsTDelay; /* Get the delayed step */
- dir = 0; /* Delayed steps are a step down for accounting purposes. */
+int pmsStepIdleSneaks;
+int pmsStepIdleTries;
+
+void
+pmsStep(int timer)
+{
+ PER_PROC_INFO *pp;
+ uint32_t nstate;
+ uint32_t tstate;
+ uint32_t pkgstate;
+ int dir;
+ int i;
+
+ pp = GET_PER_PROC_INFO(); /* Get our per_proc */
+
+ if(!pmsInstalled || pp->pms.pmsState == pmsParked)
+ return; /* No stepping if parked or not installed */
+
+ /*
+ * Assume a normal step.
+ */
+ nstate = pmsCtls.pmsDefs[pp->pms.pmsState]->pmsNext;
+
+ /*
+ * If we are idling and being asked to step up, check to see whether
+ * the package we're in is already at a non-idle power state. If so,
+ * attempt to work out what state that is, and go there directly to
+ * avoid wasting time ramping up.
+ */
+ if ((pp->pms.pmsState == pmsIdle)
+ && ((pkgstate = pmsCPUPackageQuery()) != ~(uint32_t)0)) {
+ /*
+ * Search forward through the stepper program,
+ * avoid looping for too long.
+ */
+ tstate = nstate;
+ pmsStepIdleTries++;
+ for (i = 0; i < 32; i++) {
+ /*
+ * Compare command with current package state
+ */
+ if ((pmsCtls.pmsDefs[tstate]->pmsSetCmd & pmsCPU) == pkgstate) {
+ nstate = tstate;
+ pmsStepIdleSneaks++;
+ break;
+ }
+
+ /*
+ * Advance to the next step in the program.
+ */
+ if (pmsCtls.pmsDefs[tstate]->pmsNext == tstate)
+ break; /* infinite loop */
+ tstate = pmsCtls.pmsDefs[tstate]->pmsNext;
+ }
+ }
+
+ /*
+ * Default to a step up.
+ */
+ dir = 1;
+
+ /*
+ * If we are stepping as a consequence of timer expiry, select the
+ * alternate exit path and note this as downward step for accounting
+ * purposes.
+ */
+ if (timer
+ && (pmsCtls.pmsDefs[pp->pms.pmsState]->pmsSetCmd == pmsDelay)) {
+ nstate = pmsCtls.pmsDefs[pp->pms.pmsState]->pmsTDelay;
+
+ /*
+ * Delayed steps are a step down for accounting purposes.
+ */
+ dir = 0;