summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0101-Add-poll-fops-in-eSPI-driver.patch
blob: 9c9704effb8126d1d241208eae2f64d52adb337b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
From 56ea1fc793c97232c12ddc3b4936081fe14c962f Mon Sep 17 00:00:00 2001
From: "Arun P. Mohanan" <arun.p.m@linux.intel.com>
Date: Wed, 18 Mar 2020 08:34:43 +0530
Subject: [PATCH] Add poll fops in eSPI driver

Modify eSPI driver to support poll fops.

Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
---
 drivers/misc/aspeed-espi-slave.c | 83 +++++++++++++++++++++++---------
 1 file changed, 59 insertions(+), 24 deletions(-)

diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c
index 87bc81948694..f4a0d7528414 100644
--- a/drivers/misc/aspeed-espi-slave.c
+++ b/drivers/misc/aspeed-espi-slave.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/poll.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/sched/signal.h>
@@ -95,6 +96,7 @@ struct aspeed_espi {
 	spinlock_t		pltrstn_lock; /* for PLTRST_N signal sampling */
 	wait_queue_head_t	pltrstn_waitq;
 	char			pltrstn;
+	bool			pltrstn_in_avail;
 };
 
 static void aspeed_espi_sys_event(struct aspeed_espi *priv)
@@ -127,7 +129,10 @@ static void aspeed_espi_sys_event(struct aspeed_espi *priv)
 		dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n");
 	}
 	if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') {
+		spin_lock(&priv->pltrstn_lock);
 		priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0';
+		priv->pltrstn_in_avail = true;
+		spin_unlock(&priv->pltrstn_lock);
 		wake_up_interruptible(&priv->pltrstn_waitq);
 		dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn);
 	}
@@ -284,41 +289,71 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
 
 	spin_lock_irqsave(&priv->pltrstn_lock, flags);
 
-	add_wait_queue(&priv->pltrstn_waitq, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
-
-	old_sample = priv->pltrstn;
-
-	do {
-		char new_sample = priv->pltrstn;
-
-		if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) {
-			ret = put_user(new_sample, (unsigned long __user *)buf);
-			if (!ret)
-				ret = sizeof(new_sample);
-		} else if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
+	if (filp->f_flags & O_NONBLOCK) {
+		if (!priv->pltrstn_in_avail) {
+			ret = -EAGAIN;
+			goto out_unlock;
 		}
-
-		if (!ret) {
-			spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
-			schedule();
-			spin_lock_irqsave(&priv->pltrstn_lock, flags);
+		char data = priv->pltrstn;
+		ret = put_user(data, (unsigned long __user *)buf);
+		if (!ret){
+			ret = sizeof(data);
+		} else{
+			ret = -EAGAIN;
 		}
-	} while (!ret);
-
-	remove_wait_queue(&priv->pltrstn_waitq, &wait);
-	set_current_state(TASK_RUNNING);
-
+		priv->pltrstn_in_avail = false;
+	} else {
+		add_wait_queue(&priv->pltrstn_waitq, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		old_sample = priv->pltrstn;
+
+		do {
+			char new_sample = priv->pltrstn;
+
+			if (old_sample != new_sample) {
+				ret = put_user(new_sample,
+						 (unsigned long __user *)buf);
+				if (!ret)
+					ret = sizeof(new_sample);
+			} else if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+			}
+
+			if (!ret) {
+				spin_unlock_irqrestore(&priv->pltrstn_lock,
+							 flags);
+				schedule();
+				spin_lock_irqsave(&priv->pltrstn_lock, flags);
+			}
+		} while (!ret);
+
+		remove_wait_queue(&priv->pltrstn_waitq, &wait);
+		set_current_state(TASK_RUNNING);
+	}
+out_unlock:
 	spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
 
 	return ret;
 }
 
+static unsigned int aspeed_espi_pltrstn_poll(struct file *file,
+						 poll_table *wait)
+{
+	struct aspeed_espi *priv = to_aspeed_espi(file);
+	unsigned int mask = 0;
+	poll_wait(file, &priv->pltrstn_waitq, wait);
+
+	if (priv->pltrstn_in_avail)
+		mask |= POLLIN;
+	return mask;
+}
+
 static const struct file_operations aspeed_espi_pltrstn_fops = {
 	.owner	= THIS_MODULE,
 	.open	= aspeed_espi_pltrstn_open,
 	.read	= aspeed_espi_pltrstn_read,
+	.poll	= aspeed_espi_pltrstn_poll,
 };
 
 static const struct regmap_config aspeed_espi_regmap_cfg = {
-- 
2.17.1