aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic
diff options
context:
space:
mode:
authorAshutosh Dixit <ashutosh.dixit@intel.com>2015-09-29 21:13:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-10-04 07:46:06 -0400
commit7cb46d9bffd949244f4ac784c94f4caae1ac206c (patch)
tree801c1ec37d1dfe97fd30e5669e8c5f90f57ecb52 /drivers/misc/mic
parent6727b613573f9902e6f0fc60abf6289f5e7f4593 (diff)
misc: mic: COSM client driver
The COSM client driver running on the MIC cards is implemented as a kernel mode SCIF client. It responds to a "shutdown" message from the host by triggering a card shutdown and also communicates the shutdown or reboot status back the host. It is also responsible for syncing the card time to that of the host. Because SCIF messaging cannot be used in a panic context, the COSM client driver also periodically sends a heartbeat SCIF message to the host thereby enabling the host to detect card crashes. Reviewed-by: Nikhil Rao <nikhil.rao@intel.com> Reviewed-by: Sudeep Dutt <sudeep.dutt@intel.com> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mic')
-rw-r--r--drivers/misc/mic/cosm_client/Makefile7
-rw-r--r--drivers/misc/mic/cosm_client/cosm_scif_client.c275
2 files changed, 282 insertions, 0 deletions
diff --git a/drivers/misc/mic/cosm_client/Makefile b/drivers/misc/mic/cosm_client/Makefile
new file mode 100644
index 000000000000..6f751a519a09
--- /dev/null
+++ b/drivers/misc/mic/cosm_client/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile - Intel MIC COSM Client Driver
3# Copyright(c) 2015, Intel Corporation.
4#
5obj-$(CONFIG_MIC_COSM) += cosm_client.o
6
7cosm_client-objs += cosm_scif_client.o
diff --git a/drivers/misc/mic/cosm_client/cosm_scif_client.c b/drivers/misc/mic/cosm_client/cosm_scif_client.c
new file mode 100644
index 000000000000..03e98bf1ac15
--- /dev/null
+++ b/drivers/misc/mic/cosm_client/cosm_scif_client.c
@@ -0,0 +1,275 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2015 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC COSM Client Driver
19 *
20 */
21#include <linux/module.h>
22#include <linux/delay.h>
23#include <linux/reboot.h>
24#include <linux/kthread.h>
25#include "../cosm/cosm_main.h"
26
27#define COSM_SCIF_MAX_RETRIES 10
28#define COSM_HEARTBEAT_SEND_MSEC (COSM_HEARTBEAT_SEND_SEC * MSEC_PER_SEC)
29
30static struct task_struct *client_thread;
31static scif_epd_t client_epd;
32static struct scif_peer_dev *client_spdev;
33
34/*
35 * Reboot notifier: receives shutdown status from the OS and communicates it
36 * back to the COSM process on the host
37 */
38static int cosm_reboot_event(struct notifier_block *this, unsigned long event,
39 void *ptr)
40{
41 struct cosm_msg msg = { .id = COSM_MSG_SHUTDOWN_STATUS };
42 int rc;
43
44 event = (event == SYS_RESTART) ? SYSTEM_RESTART : event;
45 dev_info(&client_spdev->dev, "%s %d received event %ld\n",
46 __func__, __LINE__, event);
47
48 msg.shutdown_status = event;
49 rc = scif_send(client_epd, &msg, sizeof(msg), SCIF_SEND_BLOCK);
50 if (rc < 0)
51 dev_err(&client_spdev->dev, "%s %d scif_send rc %d\n",
52 __func__, __LINE__, rc);
53
54 return NOTIFY_DONE;
55}
56
57static struct notifier_block cosm_reboot = {
58 .notifier_call = cosm_reboot_event,
59};
60
61/* Set system time from timespec value received from the host */
62static void cosm_set_time(struct cosm_msg *msg)
63{
64 int rc = do_settimeofday64(&msg->timespec);
65
66 if (rc)
67 dev_err(&client_spdev->dev, "%s: %d settimeofday rc %d\n",
68 __func__, __LINE__, rc);
69}
70
71/* COSM client receive message processing */
72static void cosm_client_recv(void)
73{
74 struct cosm_msg msg;
75 int rc;
76
77 while (1) {
78 rc = scif_recv(client_epd, &msg, sizeof(msg), 0);
79 if (!rc) {
80 return;
81 } else if (rc < 0) {
82 dev_err(&client_spdev->dev, "%s: %d rc %d\n",
83 __func__, __LINE__, rc);
84 return;
85 }
86
87 dev_dbg(&client_spdev->dev, "%s: %d rc %d id 0x%llx\n",
88 __func__, __LINE__, rc, msg.id);
89
90 switch (msg.id) {
91 case COSM_MSG_SYNC_TIME:
92 cosm_set_time(&msg);
93 break;
94 case COSM_MSG_SHUTDOWN:
95 orderly_poweroff(true);
96 break;
97 default:
98 dev_err(&client_spdev->dev, "%s: %d unknown id %lld\n",
99 __func__, __LINE__, msg.id);
100 break;
101 }
102 }
103}
104
105/* Initiate connection to the COSM server on the host */
106static int cosm_scif_connect(void)
107{
108 struct scif_port_id port_id;
109 int i, rc;
110
111 client_epd = scif_open();
112 if (!client_epd) {
113 dev_err(&client_spdev->dev, "%s %d scif_open failed\n",
114 __func__, __LINE__);
115 return -ENOMEM;
116 }
117
118 port_id.node = 0;
119 port_id.port = SCIF_COSM_LISTEN_PORT;
120
121 for (i = 0; i < COSM_SCIF_MAX_RETRIES; i++) {
122 rc = scif_connect(client_epd, &port_id);
123 if (rc < 0)
124 msleep(1000);
125 else
126 break;
127 }
128
129 if (rc < 0) {
130 dev_err(&client_spdev->dev, "%s %d scif_connect rc %d\n",
131 __func__, __LINE__, rc);
132 scif_close(client_epd);
133 client_epd = NULL;
134 }
135 return rc < 0 ? rc : 0;
136}
137
138/* Close host SCIF connection */
139static void cosm_scif_connect_exit(void)
140{
141 if (client_epd) {
142 scif_close(client_epd);
143 client_epd = NULL;
144 }
145}
146
147/*
148 * COSM SCIF client thread function: waits for messages from the host and sends
149 * a heartbeat to the host
150 */
151static int cosm_scif_client(void *unused)
152{
153 struct cosm_msg msg = { .id = COSM_MSG_HEARTBEAT };
154 struct scif_pollepd pollepd;
155 int rc;
156
157 allow_signal(SIGKILL);
158
159 while (!kthread_should_stop()) {
160 pollepd.epd = client_epd;
161 pollepd.events = POLLIN;
162
163 rc = scif_poll(&pollepd, 1, COSM_HEARTBEAT_SEND_MSEC);
164 if (rc < 0) {
165 if (-EINTR != rc)
166 dev_err(&client_spdev->dev,
167 "%s %d scif_poll rc %d\n",
168 __func__, __LINE__, rc);
169 continue;
170 }
171
172 if (pollepd.revents & POLLIN)
173 cosm_client_recv();
174
175 msg.id = COSM_MSG_HEARTBEAT;
176 rc = scif_send(client_epd, &msg, sizeof(msg), SCIF_SEND_BLOCK);
177 if (rc < 0)
178 dev_err(&client_spdev->dev, "%s %d scif_send rc %d\n",
179 __func__, __LINE__, rc);
180 }
181
182 dev_dbg(&client_spdev->dev, "%s %d Client thread stopped\n",
183 __func__, __LINE__);
184 return 0;
185}
186
187static void cosm_scif_probe(struct scif_peer_dev *spdev)
188{
189 int rc;
190
191 dev_dbg(&spdev->dev, "%s %d: dnode %d\n",
192 __func__, __LINE__, spdev->dnode);
193
194 /* We are only interested in the host with spdev->dnode == 0 */
195 if (spdev->dnode)
196 return;
197
198 client_spdev = spdev;
199 rc = cosm_scif_connect();
200 if (rc)
201 goto exit;
202
203 rc = register_reboot_notifier(&cosm_reboot);
204 if (rc) {
205 dev_err(&spdev->dev,
206 "reboot notifier registration failed rc %d\n", rc);
207 goto connect_exit;
208 }
209
210 client_thread = kthread_run(cosm_scif_client, NULL, "cosm_client");
211 if (IS_ERR(client_thread)) {
212 rc = PTR_ERR(client_thread);
213 dev_err(&spdev->dev, "%s %d kthread_run rc %d\n",
214 __func__, __LINE__, rc);
215 goto unreg_reboot;
216 }
217 return;
218unreg_reboot:
219 unregister_reboot_notifier(&cosm_reboot);
220connect_exit:
221 cosm_scif_connect_exit();
222exit:
223 client_spdev = NULL;
224}
225
226static void cosm_scif_remove(struct scif_peer_dev *spdev)
227{
228 int rc;
229
230 dev_dbg(&spdev->dev, "%s %d: dnode %d\n",
231 __func__, __LINE__, spdev->dnode);
232
233 if (spdev->dnode)
234 return;
235
236 if (!IS_ERR_OR_NULL(client_thread)) {
237 rc = send_sig(SIGKILL, client_thread, 0);
238 if (rc) {
239 pr_err("%s %d send_sig rc %d\n",
240 __func__, __LINE__, rc);
241 return;
242 }
243 kthread_stop(client_thread);
244 }
245 unregister_reboot_notifier(&cosm_reboot);
246 cosm_scif_connect_exit();
247 client_spdev = NULL;
248}
249
250static struct scif_client scif_client_cosm = {
251 .name = KBUILD_MODNAME,
252 .probe = cosm_scif_probe,
253 .remove = cosm_scif_remove,
254};
255
256static int __init cosm_client_init(void)
257{
258 int rc = scif_client_register(&scif_client_cosm);
259
260 if (rc)
261 pr_err("scif_client_register failed rc %d\n", rc);
262 return rc;
263}
264
265static void __exit cosm_client_exit(void)
266{
267 scif_client_unregister(&scif_client_cosm);
268}
269
270module_init(cosm_client_init);
271module_exit(cosm_client_exit);
272
273MODULE_AUTHOR("Intel Corporation");
274MODULE_DESCRIPTION("Intel(R) MIC card OS state management client driver");
275MODULE_LICENSE("GPL v2");