Linux Audio

Check our new training course

Loading...
v4.10.11
  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");
v4.6
  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");