[RFC PATCH 13/15] drivers/acrn: add service to obtain Power data transition

From: Zhao Yakui
Date: Thu Aug 15 2019 - 22:33:24 EST


The px/cx data is critical to support the power transition. DM will get
these data to build DSDT for UOS. With this DSDT, UOS would have the
capability on power control if acpi-cpufreq/idle driver is enabled in
kernel.
Add the PM ioctl that is used to obtain the info of power state
so that the DM can construct the DSDT with Power frequence/C-state idle
for guest system.

Co-developed-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx>
Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx>
Co-developed-by: Victor Sun <victor.sun@xxxxxxxxx>
Signed-off-by: Victor Sun <victor.sun@xxxxxxxxx>
Signed-off-by: Zhao Yakui <yakui.zhao@xxxxxxxxx>
---
drivers/staging/acrn/acrn_dev.c | 75 +++++++++++++++++++++++++++++++
include/uapi/linux/acrn/acrn_ioctl_defs.h | 36 +++++++++++++++
2 files changed, 111 insertions(+)

diff --git a/drivers/staging/acrn/acrn_dev.c b/drivers/staging/acrn/acrn_dev.c
index 93f45e3..ef0ec50 100644
--- a/drivers/staging/acrn/acrn_dev.c
+++ b/drivers/staging/acrn/acrn_dev.c
@@ -432,6 +432,81 @@ long acrn_dev_ioctl(struct file *filep,
break;
}

+ case IC_PM_GET_CPU_STATE: {
+ u64 cmd;
+
+ if (copy_from_user(&cmd, (void *)ioctl_param, sizeof(cmd)))
+ return -EFAULT;
+
+ switch (cmd & PMCMD_TYPE_MASK) {
+ case PMCMD_GET_PX_CNT:
+ case PMCMD_GET_CX_CNT: {
+ u64 *pm_info;
+
+ pm_info = kmalloc(sizeof(u64), GFP_KERNEL);
+ if (!pm_info)
+ return -ENOMEM;
+
+ ret = hcall_get_cpu_state(cmd, virt_to_phys(pm_info));
+ if (ret < 0) {
+ kfree(pm_info);
+ return -EFAULT;
+ }
+
+ if (copy_to_user((void *)ioctl_param,
+ pm_info, sizeof(u64)))
+ ret = -EFAULT;
+
+ kfree(pm_info);
+ break;
+ }
+ case PMCMD_GET_PX_DATA: {
+ struct cpu_px_data *px_data;
+
+ px_data = kmalloc(sizeof(*px_data), GFP_KERNEL);
+ if (!px_data)
+ return -ENOMEM;
+
+ ret = hcall_get_cpu_state(cmd, virt_to_phys(px_data));
+ if (ret < 0) {
+ kfree(px_data);
+ return -EFAULT;
+ }
+
+ if (copy_to_user((void *)ioctl_param,
+ px_data, sizeof(*px_data)))
+ ret = -EFAULT;
+
+ kfree(px_data);
+ break;
+ }
+ case PMCMD_GET_CX_DATA: {
+ struct cpu_cx_data *cx_data;
+
+ cx_data = kmalloc(sizeof(*cx_data), GFP_KERNEL);
+ if (!cx_data)
+ return -ENOMEM;
+
+ ret = hcall_get_cpu_state(cmd, virt_to_phys(cx_data));
+ if (ret < 0) {
+ kfree(cx_data);
+ return -EFAULT;
+ }
+
+ if (copy_to_user((void *)ioctl_param,
+ cx_data, sizeof(*cx_data)))
+ ret = -EFAULT;
+ kfree(cx_data);
+ break;
+ }
+ default:
+ ret = -EFAULT;
+ break;
+ }
+
+ break;
+ }
+
default:
pr_warn("Unknown IOCTL 0x%x\n", ioctl_num);
ret = -EFAULT;
diff --git a/include/uapi/linux/acrn/acrn_ioctl_defs.h b/include/uapi/linux/acrn/acrn_ioctl_defs.h
index c3c4f98..c762bd2 100644
--- a/include/uapi/linux/acrn/acrn_ioctl_defs.h
+++ b/include/uapi/linux/acrn/acrn_ioctl_defs.h
@@ -234,6 +234,39 @@ struct ioreq_notify {
uint32_t vcpu;
};

+struct acrn_generic_address {
+ uint8_t space_id;
+ uint8_t bit_width;
+ uint8_t bit_offset;
+ uint8_t access_size;
+ uint64_t address;
+};
+
+struct cpu_cx_data {
+ struct acrn_generic_address cx_reg;
+ uint8_t type;
+ uint32_t latency;
+ uint64_t power;
+};
+
+struct cpu_px_data {
+ uint64_t core_frequency; /* megahertz */
+ uint64_t power; /* milliWatts */
+ uint64_t transition_latency; /* microseconds */
+ uint64_t bus_master_latency; /* microseconds */
+ uint64_t control; /* control value */
+ uint64_t status; /* success indicator */
+};
+
+#define PMCMD_TYPE_MASK 0x000000ff
+
+enum pm_cmd_type {
+ PMCMD_GET_PX_CNT,
+ PMCMD_GET_PX_DATA,
+ PMCMD_GET_CX_CNT,
+ PMCMD_GET_CX_DATA,
+};
+
/*
* Common IOCTL ID definition for DM
*/
@@ -281,4 +314,7 @@ struct ioreq_notify {
#define IC_SET_PTDEV_INTR_INFO _IC_ID(IC_ID, IC_ID_PCI_BASE + 0x03)
#define IC_RESET_PTDEV_INTR_INFO _IC_ID(IC_ID, IC_ID_PCI_BASE + 0x04)

+/* Power management */
+#define IC_ID_PM_BASE 0x60UL
+#define IC_PM_GET_CPU_STATE _IC_ID(IC_ID, IC_ID_PM_BASE + 0x00)
#endif /* __ACRN_IOCTL_DEFS_H__ */
--
2.7.4