summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJinyoung Park <jinyoungp@nvidia.com>2018-09-14 09:24:19 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-18 02:41:31 -0400
commit4981200dfd24ef1f92cdc77f0641dec9b0f4e0b5 (patch)
tree68d3abe69007cf0aa74cc851e12cb556f0ef2080 /drivers
parent29065935d9e023891ec5664120f5ef753b0cfed3 (diff)
virt: tegra: tegra_hv_pm_ctl: Add dependency management on System suspend
For dependency management on System suspend, the privileged guest sends a guest suspend command to the listed guests from the "wait-for-guests" DT property and waits for the guests to be suspended. Jira STR-575 Change-Id: I47e7341bdc8b01a2ec3cb779184aa4477bc79931 Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1822897 GVS: Gerrit_Virtual_Submit Reviewed-by: Sang-Hun Lee <sanlee@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/virt/tegra/tegra_hv_pm_ctl.c127
1 files changed, 125 insertions, 2 deletions
diff --git a/drivers/virt/tegra/tegra_hv_pm_ctl.c b/drivers/virt/tegra/tegra_hv_pm_ctl.c
index 74458e9dc..82ffe994a 100644
--- a/drivers/virt/tegra/tegra_hv_pm_ctl.c
+++ b/drivers/virt/tegra/tegra_hv_pm_ctl.c
@@ -20,6 +20,7 @@
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/cdev.h> 21#include <linux/cdev.h>
22#include <linux/poll.h> 22#include <linux/poll.h>
23#include <linux/delay.h>
23 24
24#include <linux/tegra-ivc.h> 25#include <linux/tegra-ivc.h>
25#include <linux/tegra-ivc-instance.h> 26#include <linux/tegra-ivc-instance.h>
@@ -32,6 +33,7 @@
32 33
33#define DRV_NAME "tegra_hv_pm_ctl" 34#define DRV_NAME "tegra_hv_pm_ctl"
34#define CHAR_DEV_COUNT 1 35#define CHAR_DEV_COUNT 1
36#define MAX_GUESTS_NUM 8
35 37
36struct tegra_hv_pm_ctl { 38struct tegra_hv_pm_ctl {
37 struct device *dev; 39 struct device *dev;
@@ -43,6 +45,8 @@ struct tegra_hv_pm_ctl {
43 struct cdev cdev; 45 struct cdev cdev;
44 dev_t char_devt; 46 dev_t char_devt;
45 bool char_is_open; 47 bool char_is_open;
48 u32 wait_for_guests[MAX_GUESTS_NUM];
49 u32 wait_for_guests_size;
46 50
47 struct mutex mutex_lock; 51 struct mutex mutex_lock;
48 wait_queue_head_t wq; 52 wait_queue_head_t wq;
@@ -50,13 +54,72 @@ struct tegra_hv_pm_ctl {
50 54
51int (*tegra_hv_pm_ctl_prepare_shutdown)(void); 55int (*tegra_hv_pm_ctl_prepare_shutdown)(void);
52 56
57/* Global driver data */
58static struct tegra_hv_pm_ctl *tegra_hv_pm_ctl_data;
59
53/* Guest ID for state */ 60/* Guest ID for state */
54static u32 guest_id; 61static u32 guest_id;
55 62
63static int tegra_hv_pm_ctl_get_guest_state(u32 vmid, u32 *state);
64
65/*
66 * For dependency management on System suspend, if there are guests required
67 * to wait and the guests are not in suspended, the privileged guest sends
68 * a guest suspend command to the guests and waits for the guests to be
69 * suspended.
70 */
71static int do_wait_for_guests_suspended(void)
72{
73 bool sent_guest_suspend = false;
74 int i = 0;
75 int ret = 0;
76
77 while (i < tegra_hv_pm_ctl_data->wait_for_guests_size) {
78 u32 vmid = tegra_hv_pm_ctl_data->wait_for_guests[i];
79 u32 state;
80
81 ret = tegra_hv_pm_ctl_get_guest_state(vmid, &state);
82 if (ret < 0)
83 return ret;
84
85 if (state == VM_STATE_SUSPEND) {
86 sent_guest_suspend = false;
87 i++;
88 continue;
89 }
90
91 if (sent_guest_suspend == false) {
92 pr_debug("%s: Send a guest suspend command to guest%u\n",
93 __func__, vmid);
94 ret = tegra_hv_pm_ctl_trigger_guest_suspend(vmid);
95 if (ret < 0)
96 return ret;
97
98 sent_guest_suspend = true;
99 }
100 msleep(10);
101 }
102
103 return 0;
104}
105
56int tegra_hv_pm_ctl_trigger_sys_suspend(void) 106int tegra_hv_pm_ctl_trigger_sys_suspend(void)
57{ 107{
58 int ret; 108 int ret;
59 109
110 if (!tegra_hv_pm_ctl_data) {
111 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
112 __func__, -ENXIO);
113 return -ENXIO;
114 }
115
116 ret = do_wait_for_guests_suspended();
117 if (ret < 0) {
118 pr_err("%s: Failed to wait for guests suspended, %d\n",
119 __func__, ret);
120 return ret;
121 }
122
60 ret = hyp_guest_reset(SYS_SUSPEND_INIT_CMD, NULL); 123 ret = hyp_guest_reset(SYS_SUSPEND_INIT_CMD, NULL);
61 if (ret < 0) { 124 if (ret < 0) {
62 pr_err("%s: Failed to trigger system suspend, %d\n", 125 pr_err("%s: Failed to trigger system suspend, %d\n",
@@ -67,11 +130,16 @@ int tegra_hv_pm_ctl_trigger_sys_suspend(void)
67 return 0; 130 return 0;
68} 131}
69 132
70
71int tegra_hv_pm_ctl_trigger_sys_shutdown(void) 133int tegra_hv_pm_ctl_trigger_sys_shutdown(void)
72{ 134{
73 int ret; 135 int ret;
74 136
137 if (!tegra_hv_pm_ctl_data) {
138 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
139 __func__, -ENXIO);
140 return -ENXIO;
141 }
142
75 if (tegra_hv_pm_ctl_prepare_shutdown) { 143 if (tegra_hv_pm_ctl_prepare_shutdown) {
76 ret = tegra_hv_pm_ctl_prepare_shutdown(); 144 ret = tegra_hv_pm_ctl_prepare_shutdown();
77 if (ret < 0) { 145 if (ret < 0) {
@@ -95,6 +163,12 @@ int tegra_hv_pm_ctl_trigger_sys_reboot(void)
95{ 163{
96 int ret; 164 int ret;
97 165
166 if (!tegra_hv_pm_ctl_data) {
167 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
168 __func__, -ENXIO);
169 return -ENXIO;
170 }
171
98 ret = hyp_guest_reset(SYS_REBOOT_INIT_CMD, NULL); 172 ret = hyp_guest_reset(SYS_REBOOT_INIT_CMD, NULL);
99 if (ret < 0) { 173 if (ret < 0) {
100 pr_err("%s: Failed to trigger system reboot, %d\n", 174 pr_err("%s: Failed to trigger system reboot, %d\n",
@@ -109,6 +183,12 @@ int tegra_hv_pm_ctl_trigger_guest_suspend(u32 vmid)
109{ 183{
110 int ret; 184 int ret;
111 185
186 if (!tegra_hv_pm_ctl_data) {
187 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
188 __func__, -ENXIO);
189 return -ENXIO;
190 }
191
112 ret = hyp_guest_reset(GUEST_SUSPEND_REQ_CMD(vmid), NULL); 192 ret = hyp_guest_reset(GUEST_SUSPEND_REQ_CMD(vmid), NULL);
113 if (ret < 0) { 193 if (ret < 0) {
114 pr_err("%s: Failed to trigger guest%u suspend, %d\n", 194 pr_err("%s: Failed to trigger guest%u suspend, %d\n",
@@ -123,6 +203,12 @@ int tegra_hv_pm_ctl_trigger_guest_resume(u32 vmid)
123{ 203{
124 int ret; 204 int ret;
125 205
206 if (!tegra_hv_pm_ctl_data) {
207 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
208 __func__, -ENXIO);
209 return -ENXIO;
210 }
211
126 ret = hyp_guest_reset(GUEST_RESUME_INIT_CMD(vmid), NULL); 212 ret = hyp_guest_reset(GUEST_RESUME_INIT_CMD(vmid), NULL);
127 if (ret < 0) { 213 if (ret < 0) {
128 pr_err("%s: Failed to trigger guest%u resume, %d\n", 214 pr_err("%s: Failed to trigger guest%u resume, %d\n",
@@ -133,10 +219,18 @@ int tegra_hv_pm_ctl_trigger_guest_resume(u32 vmid)
133 return 0; 219 return 0;
134} 220}
135 221
136int tegra_hv_pm_ctl_get_guest_state(u32 vmid, u32 *state) 222static int tegra_hv_pm_ctl_get_guest_state(u32 vmid, u32 *state)
137{ 223{
138 int ret; 224 int ret;
139 225
226 if (!tegra_hv_pm_ctl_data) {
227 pr_err("%s: tegra_hv_pm_ctl driver is not probed, %d\n",
228 __func__, -ENXIO);
229 return -ENXIO;
230 }
231
232 /* guest state which can be returned:
233 * VM_STATE_BOOT, VM_STATE_HALT, VM_STATE_SUSPEND, VM_STATE_SHUTDOWN */
140 ret = hyp_read_guest_state(vmid, state); 234 ret = hyp_read_guest_state(vmid, state);
141 if (ret < 0) { 235 if (ret < 0) {
142 pr_err("%s: Failed to get guest%u state, %d\n", 236 pr_err("%s: Failed to get guest%u state, %d\n",
@@ -492,6 +586,22 @@ static ssize_t guest_state_store(struct device *dev,
492 return count; 586 return count;
493} 587}
494 588
589static ssize_t wait_for_guests_show(struct device *dev,
590 struct device_attribute *attr, char *buf)
591{
592 struct tegra_hv_pm_ctl *data = dev_get_drvdata(dev);
593 ssize_t count = 0;
594 int i;
595
596 for (i = 0; i < data->wait_for_guests_size; i++) {
597 count += snprintf(buf + count, PAGE_SIZE - count, "%u ",
598 data->wait_for_guests[i]);
599 }
600 count += snprintf(buf + count, PAGE_SIZE - count, "\n");
601
602 return count;
603}
604
495static DEVICE_ATTR_RO(ivc_id); 605static DEVICE_ATTR_RO(ivc_id);
496static DEVICE_ATTR_RO(ivc_frame_size); 606static DEVICE_ATTR_RO(ivc_frame_size);
497static DEVICE_ATTR_RO(ivc_nframes); 607static DEVICE_ATTR_RO(ivc_nframes);
@@ -502,6 +612,7 @@ static DEVICE_ATTR_WO(trigger_sys_reboot);
502static DEVICE_ATTR_WO(trigger_guest_suspend); 612static DEVICE_ATTR_WO(trigger_guest_suspend);
503static DEVICE_ATTR_WO(trigger_guest_resume); 613static DEVICE_ATTR_WO(trigger_guest_resume);
504static DEVICE_ATTR_RW(guest_state); 614static DEVICE_ATTR_RW(guest_state);
615static DEVICE_ATTR_RO(wait_for_guests);
505 616
506static struct attribute *tegra_hv_pm_ctl_attributes[] = { 617static struct attribute *tegra_hv_pm_ctl_attributes[] = {
507 &dev_attr_ivc_id.attr, 618 &dev_attr_ivc_id.attr,
@@ -514,6 +625,7 @@ static struct attribute *tegra_hv_pm_ctl_attributes[] = {
514 &dev_attr_trigger_guest_suspend.attr, 625 &dev_attr_trigger_guest_suspend.attr,
515 &dev_attr_trigger_guest_resume.attr, 626 &dev_attr_trigger_guest_resume.attr,
516 &dev_attr_guest_state.attr, 627 &dev_attr_guest_state.attr,
628 &dev_attr_wait_for_guests.attr,
517 NULL 629 NULL
518}; 630};
519 631
@@ -600,6 +712,7 @@ static void tegra_hv_pm_ctl_cleanup(struct tegra_hv_pm_ctl *data)
600static int tegra_hv_pm_ctl_parse_dt(struct tegra_hv_pm_ctl *data) 712static int tegra_hv_pm_ctl_parse_dt(struct tegra_hv_pm_ctl *data)
601{ 713{
602 struct device_node *np = data->dev->of_node; 714 struct device_node *np = data->dev->of_node;
715 int ret;
603 716
604 if (!np) { 717 if (!np) {
605 dev_err(data->dev, "%s: Failed to find device node\n", 718 dev_err(data->dev, "%s: Failed to find device node\n",
@@ -613,6 +726,13 @@ static int tegra_hv_pm_ctl_parse_dt(struct tegra_hv_pm_ctl *data)
613 return -EINVAL; 726 return -EINVAL;
614 } 727 }
615 728
729 /* List of guests to wait before sending a System suspend command for
730 * dependency management. */
731 ret = of_property_read_variable_u32_array(np, "wait-for-guests",
732 data->wait_for_guests, 1, MAX_GUESTS_NUM);
733 if (ret > 0)
734 data->wait_for_guests_size = ret;
735
616 return 0; 736 return 0;
617} 737}
618 738
@@ -669,6 +789,8 @@ static int tegra_hv_pm_ctl_probe(struct platform_device *pdev)
669 goto error_sysfs_remove_group; 789 goto error_sysfs_remove_group;
670 } 790 }
671 791
792 tegra_hv_pm_ctl_data = data;
793
672 dev_info(&pdev->dev, "%s: Probed\n", __func__); 794 dev_info(&pdev->dev, "%s: Probed\n", __func__);
673 795
674 return 0; 796 return 0;
@@ -685,6 +807,7 @@ static int tegra_hv_pm_ctl_remove(struct platform_device *pdev)
685{ 807{
686 struct tegra_hv_pm_ctl *data = platform_get_drvdata(pdev); 808 struct tegra_hv_pm_ctl *data = platform_get_drvdata(pdev);
687 809
810 tegra_hv_pm_ctl_data = NULL;
688 tegra_hv_pm_ctl_cleanup(data); 811 tegra_hv_pm_ctl_cleanup(data);
689 sysfs_remove_group(&pdev->dev.kobj, &tegra_hv_pm_ctl_attr_group); 812 sysfs_remove_group(&pdev->dev.kobj, &tegra_hv_pm_ctl_attr_group);
690 class_destroy(data->class); 813 class_destroy(data->class);