Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.4-rc6 275 lines 6.4 kB view raw
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");