root/drivers/misc/mic/cosm_client/cosm_scif_client.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cosm_reboot_event
  2. cosm_set_time
  3. cosm_client_recv
  4. cosm_scif_connect
  5. cosm_scif_connect_exit
  6. cosm_scif_client
  7. cosm_scif_probe
  8. cosm_scif_remove
  9. cosm_client_init
  10. cosm_client_exit

   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 
  20 static struct task_struct *client_thread;
  21 static scif_epd_t client_epd;
  22 static 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  */
  28 static 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 
  47 static struct notifier_block cosm_reboot = {
  48         .notifier_call  = cosm_reboot_event,
  49 };
  50 
  51 /* Set system time from timespec value received from the host */
  52 static 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 */
  66 static 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 */
 100 static 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 */
 133 static 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  */
 145 static 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 
 181 static 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;
 212 unreg_reboot:
 213         unregister_reboot_notifier(&cosm_reboot);
 214 connect_exit:
 215         cosm_scif_connect_exit();
 216 exit:
 217         client_spdev = NULL;
 218 }
 219 
 220 static 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 
 244 static struct scif_client scif_client_cosm = {
 245         .name = KBUILD_MODNAME,
 246         .probe = cosm_scif_probe,
 247         .remove = cosm_scif_remove,
 248 };
 249 
 250 static 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 
 259 static void __exit cosm_client_exit(void)
 260 {
 261         scif_client_unregister(&scif_client_cosm);
 262 }
 263 
 264 module_init(cosm_client_init);
 265 module_exit(cosm_client_exit);
 266 
 267 MODULE_AUTHOR("Intel Corporation");
 268 MODULE_DESCRIPTION("Intel(R) MIC card OS state management client driver");
 269 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */