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 v5.8-rc7 269 lines 6.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel MIC Platform Software Stack (MPSS) 4 * 5 * Copyright(c) 2015 Intel Corporation. 6 * 7 * Intel MIC COSM Client Driver 8 */ 9#include <linux/module.h> 10#include <linux/delay.h> 11#include <linux/reboot.h> 12#include <linux/kthread.h> 13#include <linux/sched/signal.h> 14 15#include "../cosm/cosm_main.h" 16 17#define COSM_SCIF_MAX_RETRIES 10 18#define COSM_HEARTBEAT_SEND_MSEC (COSM_HEARTBEAT_SEND_SEC * MSEC_PER_SEC) 19 20static struct task_struct *client_thread; 21static scif_epd_t client_epd; 22static struct scif_peer_dev *client_spdev; 23 24/* 25 * Reboot notifier: receives shutdown status from the OS and communicates it 26 * back to the COSM process on the host 27 */ 28static int cosm_reboot_event(struct notifier_block *this, unsigned long event, 29 void *ptr) 30{ 31 struct cosm_msg msg = { .id = COSM_MSG_SHUTDOWN_STATUS }; 32 int rc; 33 34 event = (event == SYS_RESTART) ? SYSTEM_RESTART : event; 35 dev_info(&client_spdev->dev, "%s %d received event %ld\n", 36 __func__, __LINE__, event); 37 38 msg.shutdown_status = event; 39 rc = scif_send(client_epd, &msg, sizeof(msg), SCIF_SEND_BLOCK); 40 if (rc < 0) 41 dev_err(&client_spdev->dev, "%s %d scif_send rc %d\n", 42 __func__, __LINE__, rc); 43 44 return NOTIFY_DONE; 45} 46 47static struct notifier_block cosm_reboot = { 48 .notifier_call = cosm_reboot_event, 49}; 50 51/* Set system time from timespec value received from the host */ 52static void cosm_set_time(struct cosm_msg *msg) 53{ 54 struct timespec64 ts = { 55 .tv_sec = msg->timespec.tv_sec, 56 .tv_nsec = msg->timespec.tv_nsec, 57 }; 58 int rc = do_settimeofday64(&ts); 59 60 if (rc) 61 dev_err(&client_spdev->dev, "%s: %d settimeofday rc %d\n", 62 __func__, __LINE__, rc); 63} 64 65/* COSM client receive message processing */ 66static void cosm_client_recv(void) 67{ 68 struct cosm_msg msg; 69 int rc; 70 71 while (1) { 72 rc = scif_recv(client_epd, &msg, sizeof(msg), 0); 73 if (!rc) { 74 return; 75 } else if (rc < 0) { 76 dev_err(&client_spdev->dev, "%s: %d rc %d\n", 77 __func__, __LINE__, rc); 78 return; 79 } 80 81 dev_dbg(&client_spdev->dev, "%s: %d rc %d id 0x%llx\n", 82 __func__, __LINE__, rc, msg.id); 83 84 switch (msg.id) { 85 case COSM_MSG_SYNC_TIME: 86 cosm_set_time(&msg); 87 break; 88 case COSM_MSG_SHUTDOWN: 89 orderly_poweroff(true); 90 break; 91 default: 92 dev_err(&client_spdev->dev, "%s: %d unknown id %lld\n", 93 __func__, __LINE__, msg.id); 94 break; 95 } 96 } 97} 98 99/* Initiate connection to the COSM server on the host */ 100static int cosm_scif_connect(void) 101{ 102 struct scif_port_id port_id; 103 int i, rc; 104 105 client_epd = scif_open(); 106 if (!client_epd) { 107 dev_err(&client_spdev->dev, "%s %d scif_open failed\n", 108 __func__, __LINE__); 109 return -ENOMEM; 110 } 111 112 port_id.node = 0; 113 port_id.port = SCIF_COSM_LISTEN_PORT; 114 115 for (i = 0; i < COSM_SCIF_MAX_RETRIES; i++) { 116 rc = scif_connect(client_epd, &port_id); 117 if (rc < 0) 118 msleep(1000); 119 else 120 break; 121 } 122 123 if (rc < 0) { 124 dev_err(&client_spdev->dev, "%s %d scif_connect rc %d\n", 125 __func__, __LINE__, rc); 126 scif_close(client_epd); 127 client_epd = NULL; 128 } 129 return rc < 0 ? rc : 0; 130} 131 132/* Close host SCIF connection */ 133static void cosm_scif_connect_exit(void) 134{ 135 if (client_epd) { 136 scif_close(client_epd); 137 client_epd = NULL; 138 } 139} 140 141/* 142 * COSM SCIF client thread function: waits for messages from the host and sends 143 * a heartbeat to the host 144 */ 145static int cosm_scif_client(void *unused) 146{ 147 struct cosm_msg msg = { .id = COSM_MSG_HEARTBEAT }; 148 struct scif_pollepd pollepd; 149 int rc; 150 151 allow_signal(SIGKILL); 152 153 while (!kthread_should_stop()) { 154 pollepd.epd = client_epd; 155 pollepd.events = EPOLLIN; 156 157 rc = scif_poll(&pollepd, 1, COSM_HEARTBEAT_SEND_MSEC); 158 if (rc < 0) { 159 if (-EINTR != rc) 160 dev_err(&client_spdev->dev, 161 "%s %d scif_poll rc %d\n", 162 __func__, __LINE__, rc); 163 continue; 164 } 165 166 if (pollepd.revents & EPOLLIN) 167 cosm_client_recv(); 168 169 msg.id = COSM_MSG_HEARTBEAT; 170 rc = scif_send(client_epd, &msg, sizeof(msg), SCIF_SEND_BLOCK); 171 if (rc < 0) 172 dev_err(&client_spdev->dev, "%s %d scif_send rc %d\n", 173 __func__, __LINE__, rc); 174 } 175 176 dev_dbg(&client_spdev->dev, "%s %d Client thread stopped\n", 177 __func__, __LINE__); 178 return 0; 179} 180 181static void cosm_scif_probe(struct scif_peer_dev *spdev) 182{ 183 int rc; 184 185 dev_dbg(&spdev->dev, "%s %d: dnode %d\n", 186 __func__, __LINE__, spdev->dnode); 187 188 /* We are only interested in the host with spdev->dnode == 0 */ 189 if (spdev->dnode) 190 return; 191 192 client_spdev = spdev; 193 rc = cosm_scif_connect(); 194 if (rc) 195 goto exit; 196 197 rc = register_reboot_notifier(&cosm_reboot); 198 if (rc) { 199 dev_err(&spdev->dev, 200 "reboot notifier registration failed rc %d\n", rc); 201 goto connect_exit; 202 } 203 204 client_thread = kthread_run(cosm_scif_client, NULL, "cosm_client"); 205 if (IS_ERR(client_thread)) { 206 rc = PTR_ERR(client_thread); 207 dev_err(&spdev->dev, "%s %d kthread_run rc %d\n", 208 __func__, __LINE__, rc); 209 goto unreg_reboot; 210 } 211 return; 212unreg_reboot: 213 unregister_reboot_notifier(&cosm_reboot); 214connect_exit: 215 cosm_scif_connect_exit(); 216exit: 217 client_spdev = NULL; 218} 219 220static void cosm_scif_remove(struct scif_peer_dev *spdev) 221{ 222 int rc; 223 224 dev_dbg(&spdev->dev, "%s %d: dnode %d\n", 225 __func__, __LINE__, spdev->dnode); 226 227 if (spdev->dnode) 228 return; 229 230 if (!IS_ERR_OR_NULL(client_thread)) { 231 rc = send_sig(SIGKILL, client_thread, 0); 232 if (rc) { 233 pr_err("%s %d send_sig rc %d\n", 234 __func__, __LINE__, rc); 235 return; 236 } 237 kthread_stop(client_thread); 238 } 239 unregister_reboot_notifier(&cosm_reboot); 240 cosm_scif_connect_exit(); 241 client_spdev = NULL; 242} 243 244static struct scif_client scif_client_cosm = { 245 .name = KBUILD_MODNAME, 246 .probe = cosm_scif_probe, 247 .remove = cosm_scif_remove, 248}; 249 250static int __init cosm_client_init(void) 251{ 252 int rc = scif_client_register(&scif_client_cosm); 253 254 if (rc) 255 pr_err("scif_client_register failed rc %d\n", rc); 256 return rc; 257} 258 259static void __exit cosm_client_exit(void) 260{ 261 scif_client_unregister(&scif_client_cosm); 262} 263 264module_init(cosm_client_init); 265module_exit(cosm_client_exit); 266 267MODULE_AUTHOR("Intel Corporation"); 268MODULE_DESCRIPTION("Intel(R) MIC card OS state management client driver"); 269MODULE_LICENSE("GPL v2");