#include <linux/interrupt.h>
#include <asm/mrst.h>
#include <asm/intel_scu_ipc.h>
+#include <linux/pm_qos_params.h>
/*
* IPC register summary
static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
+/* PM Qos struct */
+static struct pm_qos_request_list *qos;
+
/*
* Command Register (Write Only):
* A write to this register results in an interrupt to the SCU core processor
ipcdev.ioc = 0;
writel(cmd, ipcdev.ipc_base);
}
+
+ /* Prevent C-states beyond C6 */
+ pm_qos_update_request(qos, 150);
}
/*
static inline int ipc_wait_interrupt(void)
{
+ int ret = 0;
if (ipcdev.ioc) {
if (0 == wait_for_completion_timeout(
&ipcdev.cmd_complete, 3 * HZ)) {
dev_err(&ipcdev.pdev->dev, "IPC timed out, IPC_STS=0x%x",
ipc_read_status());
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto leave;
} else {
if ((ipcdev.status >> 1) & 1) {
dev_err(&ipcdev.pdev->dev, "IPC failed, IPC_STS=0x%x",
ipc_read_status());
- return -EIO;
+ ret = -EIO;
+ goto leave;
}
}
} else {
loop_count++;
if (loop_count > 3000000) {
dev_err(&ipcdev.pdev->dev, "IPC timed out");
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto leave;
}
}
if ((status >> 1) & 1)
- return -EIO;
+ ret = -EIO;
}
-
- return 0;
+leave:
+ /* Re-enable Deeper C-states beyond C6 */
+ pm_qos_update_request(qos, PM_QOS_DEFAULT_VALUE);
+ return ret;
}
/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
platform = mrst_identify_cpu();
if (platform == 0)
return -ENODEV;
+
+ qos = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
return pci_register_driver(&ipc_driver);
+
}
static void __exit intel_scu_ipc_exit(void)
{
+ pm_qos_remove_request(qos);
+
pci_unregister_driver(&ipc_driver);
}