return -EBUSY;
}
+static int _pmu2_wait_not_busy_yield(void)
+{
+ int pmu_busy_retry = 20;
+
+ /* wait 10ms that the latest pmu command finished */
+ do {
+ usleep_range(10, 500);
+
+ if (!_pmu_read_status(PMU_BUSY_STATUS))
+ return 0;
+ } while (--pmu_busy_retry);
+
+ WARN(1, "pmu2 busy!");
+
+ return -EBUSY;
+}
+
static void pmu_write_subsys_config(struct pmu_ss_states *pm_ssc)
{
/* South complex in Penwell has multiple registers for
int pmu_num;
struct pmu_ss_states cur_pmssc;
int status = 0;
+ int retry_count = 3;
/* Ignore callback from devices until we have initialized */
if (unlikely((!pmu_initialized)))
if (unlikely(mid_pmu_cxt->shutdown_started))
goto unlock;
- mid_pmu_cxt->interactive_cmd_sent = true;
-
/*get LSS index corresponding to pdev, its position in
*32 bit register and its register numer*/
status =
cur_pmssc.pmu2_states[2] &= ~IGNORE_SSS2;
cur_pmssc.pmu2_states[3] &= ~IGNORE_SSS3;
- /* Issue the pmu command to PMU 2
- * flag is needed to distinguish between
- * S0ix vs interactive command in pmu_sc_irq()
- */
- status = pmu_issue_interactive_command(&cur_pmssc, true);
+ do {
+ /* Issue the pmu command to PMU 2
+ * flag is needed to distinguish between
+ * S0ix vs interactive command in pmu_sc_irq()
+ */
+ status = pmu_issue_interactive_command(&cur_pmssc, false);
- if (unlikely(status != PMU_SUCCESS)) {
- dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
- "Failed to Issue a PM command to PMU2\n");
- goto unlock;
- }
+ if (unlikely(status != PMU_SUCCESS)) {
+ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
+ "Failed to Issue a PM command to PMU2\n");
+ goto unlock;
+ }
- /*
- * Wait for interactive command to complete.
- * If we dont wait, there is a possibility that
- * the driver may access the device before its
- * powered on in SCU.
- *
- */
- if (!wait_for_completion_timeout(
- &mid_pmu_cxt->set_mode_complete, 2 * HZ)) {
+ /*
+ * Wait for interactive command to complete.
+ * If we dont wait, there is a possibility that
+ * the driver may access the device before its
+ * powered on in SCU.
+ *
+ */
+ status = _pmu2_wait_not_busy_yield();
+
+ if (likely(!status))
+ break;
- /* Since we didn't receive the completion
- * interrupt, check if the power transition
+ printk(KERN_CRIT "%s: D0ix transition failure:"
+ " %04x %04X %s %20s:\n", __func__,
+ pdev->vendor, pdev->device,
+ dev_name(&pdev->dev),
+ dev_driver_string(&pdev->dev));
+ printk(KERN_CRIT "pmu_busy_status = %d\n",
+ _pmu_read_status(PMU_BUSY_STATUS));
+ printk(KERN_CRIT "suspend_started = %d\n",
+ mid_pmu_cxt->suspend_started);
+ printk(KERN_CRIT "shutdown_started = %d\n",
+ mid_pmu_cxt->shutdown_started);
+ printk(KERN_CRIT "Retrying... attempt(%d):\n",
+ retry_count);
+ } while (--retry_count);
+
+ if (unlikely(status)) {
+ struct pmu_ss_states new_pmsss;
+ u32 post_transition_val;
+
+ /*
+ * Check if the power transition
* indeed happend, if yes continue, else BUG
*/
- struct pmu_ss_states new_pmsss;
+ new_value &=
+ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
pmu_read_sss(&new_pmsss);
-
- if (new_value == new_pmsss.pmu2_states[sub_sys_index]) {
- WARN(1,
- "%s: completion timed out.\n", __func__);
- init_completion
- (&mid_pmu_cxt->set_mode_complete);
- } else {
- printk(KERN_CRIT "%s: completion timeout:"
- " %04x %04X %s %20s:\n", __func__,
- pdev->vendor, pdev->device,
- dev_name(&pdev->dev),
- dev_driver_string(&pdev->dev));
- printk(KERN_CRIT "interrupt pending = %d\n",
- pmu_interrupt_pending());
- printk(KERN_CRIT "pmu_busy_status = %d\n",
- _pmu_read_status(PMU_BUSY_STATUS));
- printk(KERN_CRIT "suspend_started = %d\n",
- mid_pmu_cxt->suspend_started);
- printk(KERN_CRIT "shutdown_started = %d\n",
- mid_pmu_cxt->shutdown_started);
- printk(KERN_CRIT "interactive_cmd_sent = %d\n",
- (int)mid_pmu_cxt->interactive_cmd_sent);
- printk(KERN_CRIT "camera_off = %d"
- " display_off = %d\n", mid_pmu_cxt->camera_off,
- mid_pmu_cxt->display_off);
- printk(KERN_CRIT "s0ix_possible = 0x%x\n",
- mid_pmu_cxt->s0ix_possible);
- printk(KERN_CRIT "s0ix_entered = 0x%x\n",
- mid_pmu_cxt->s0ix_entered);
- printk(KERN_CRIT "pmu_current_state = %d\n",
- mid_pmu_cxt->pmu_current_state);
- pmu_dump_logs();
-
- BUG();
+ post_transition_val =
+ (new_pmsss.pmu2_states[sub_sys_index] &
+ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS)));
+
+ if (new_value != post_transition_val) {
+ printk(KERN_CRIT "%s: D0ix transition failure:"
+ " %04x %04X %s %20s:\n", __func__,
+ pdev->vendor, pdev->device,
+ dev_name(&pdev->dev),
+ dev_driver_string(&pdev->dev));
+ printk(KERN_CRIT "interrupt pending = %d\n",
+ pmu_interrupt_pending());
+ printk(KERN_CRIT "pmu_busy_status = %d\n",
+ _pmu_read_status(PMU_BUSY_STATUS));
+ printk(KERN_CRIT "suspend_started = %d\n",
+ mid_pmu_cxt->suspend_started);
+ printk(KERN_CRIT "shutdown_started = %d\n",
+ mid_pmu_cxt->shutdown_started);
+ printk(KERN_CRIT "interactive_cmd_sent = %d\n",
+ (int)mid_pmu_cxt->interactive_cmd_sent);
+ printk(KERN_CRIT "camera_off = %d"
+ " display_off = %d\n", mid_pmu_cxt->camera_off,
+ mid_pmu_cxt->display_off);
+ printk(KERN_CRIT "s0ix_possible = 0x%x\n",
+ mid_pmu_cxt->s0ix_possible);
+ printk(KERN_CRIT "s0ix_entered = 0x%x\n",
+ mid_pmu_cxt->s0ix_entered);
+ printk(KERN_CRIT "pmu_current_state = %d\n",
+ mid_pmu_cxt->pmu_current_state);
+ pmu_dump_logs();
+
+ BUG();
}
}
pci_to_platform_state(state));
unlock:
- mid_pmu_cxt->interactive_cmd_sent = false;
up(&mid_pmu_cxt->scu_ready_sem);
/*
return status;
}
-
pci_power_t platfrom_pmu_choose_state(int lss)
{
pci_power_t state = PCI_D3hot;