0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/slab.h>
0009 #include <linux/interrupt.h>
0010 #include <linux/debugfs.h>
0011 #include <linux/completion.h>
0012 #include <linux/watchdog.h>
0013
0014 #include <linux/uuid.h>
0015 #include <linux/mei_cl_bus.h>
0016
0017
0018
0019
0020 #define INTEL_AMT_WATCHDOG_ID "iamt_wdt"
0021
0022 #define MEI_WDT_DEFAULT_TIMEOUT 120
0023 #define MEI_WDT_MIN_TIMEOUT 120
0024 #define MEI_WDT_MAX_TIMEOUT 65535
0025
0026
0027 #define MEI_MANAGEMENT_CONTROL 0x02
0028
0029
0030 #define MEI_MC_VERSION_NUMBER 0x10
0031
0032
0033 #define MEI_MC_START_WD_TIMER_REQ 0x13
0034 #define MEI_MC_START_WD_TIMER_RES 0x83
0035 #define MEI_WDT_STATUS_SUCCESS 0
0036 #define MEI_WDT_WDSTATE_NOT_REQUIRED 0x1
0037 #define MEI_MC_STOP_WD_TIMER_REQ 0x14
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 enum mei_wdt_state {
0050 MEI_WDT_PROBE,
0051 MEI_WDT_IDLE,
0052 MEI_WDT_START,
0053 MEI_WDT_RUNNING,
0054 MEI_WDT_STOPPING,
0055 MEI_WDT_NOT_REQUIRED,
0056 };
0057
0058 static const char *mei_wdt_state_str(enum mei_wdt_state state)
0059 {
0060 switch (state) {
0061 case MEI_WDT_PROBE:
0062 return "PROBE";
0063 case MEI_WDT_IDLE:
0064 return "IDLE";
0065 case MEI_WDT_START:
0066 return "START";
0067 case MEI_WDT_RUNNING:
0068 return "RUNNING";
0069 case MEI_WDT_STOPPING:
0070 return "STOPPING";
0071 case MEI_WDT_NOT_REQUIRED:
0072 return "NOT_REQUIRED";
0073 default:
0074 return "unknown";
0075 }
0076 }
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 struct mei_wdt {
0093 struct watchdog_device wdd;
0094
0095 struct mei_cl_device *cldev;
0096 enum mei_wdt_state state;
0097 bool resp_required;
0098 struct completion response;
0099 struct work_struct unregister;
0100 struct mutex reg_lock;
0101 u16 timeout;
0102
0103 #if IS_ENABLED(CONFIG_DEBUG_FS)
0104 struct dentry *dbgfs_dir;
0105 #endif
0106 };
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116 struct mei_mc_hdr {
0117 u8 command;
0118 u8 bytecount;
0119 u8 subcommand;
0120 u8 versionnumber;
0121 };
0122
0123
0124
0125
0126
0127
0128
0129
0130 struct mei_wdt_start_request {
0131 struct mei_mc_hdr hdr;
0132 u16 timeout;
0133 u8 reserved[17];
0134 } __packed;
0135
0136
0137
0138
0139
0140
0141
0142
0143 struct mei_wdt_start_response {
0144 struct mei_mc_hdr hdr;
0145 u8 status;
0146 u8 wdstate;
0147 } __packed;
0148
0149
0150
0151
0152
0153
0154 struct mei_wdt_stop_request {
0155 struct mei_mc_hdr hdr;
0156 } __packed;
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 static int mei_wdt_ping(struct mei_wdt *wdt)
0167 {
0168 struct mei_wdt_start_request req;
0169 const size_t req_len = sizeof(req);
0170 int ret;
0171
0172 memset(&req, 0, req_len);
0173 req.hdr.command = MEI_MANAGEMENT_CONTROL;
0174 req.hdr.bytecount = req_len - offsetof(struct mei_mc_hdr, subcommand);
0175 req.hdr.subcommand = MEI_MC_START_WD_TIMER_REQ;
0176 req.hdr.versionnumber = MEI_MC_VERSION_NUMBER;
0177 req.timeout = wdt->timeout;
0178
0179 ret = mei_cldev_send(wdt->cldev, (u8 *)&req, req_len);
0180 if (ret < 0)
0181 return ret;
0182
0183 return 0;
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 static int mei_wdt_stop(struct mei_wdt *wdt)
0195 {
0196 struct mei_wdt_stop_request req;
0197 const size_t req_len = sizeof(req);
0198 int ret;
0199
0200 memset(&req, 0, req_len);
0201 req.hdr.command = MEI_MANAGEMENT_CONTROL;
0202 req.hdr.bytecount = req_len - offsetof(struct mei_mc_hdr, subcommand);
0203 req.hdr.subcommand = MEI_MC_STOP_WD_TIMER_REQ;
0204 req.hdr.versionnumber = MEI_MC_VERSION_NUMBER;
0205
0206 ret = mei_cldev_send(wdt->cldev, (u8 *)&req, req_len);
0207 if (ret < 0)
0208 return ret;
0209
0210 return 0;
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220 static int mei_wdt_ops_start(struct watchdog_device *wdd)
0221 {
0222 struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
0223
0224 wdt->state = MEI_WDT_START;
0225 wdd->timeout = wdt->timeout;
0226 return 0;
0227 }
0228
0229
0230
0231
0232
0233
0234
0235
0236 static int mei_wdt_ops_stop(struct watchdog_device *wdd)
0237 {
0238 struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
0239 int ret;
0240
0241 if (wdt->state != MEI_WDT_RUNNING)
0242 return 0;
0243
0244 wdt->state = MEI_WDT_STOPPING;
0245
0246 ret = mei_wdt_stop(wdt);
0247 if (ret)
0248 return ret;
0249
0250 wdt->state = MEI_WDT_IDLE;
0251
0252 return 0;
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262 static int mei_wdt_ops_ping(struct watchdog_device *wdd)
0263 {
0264 struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
0265 int ret;
0266
0267 if (wdt->state != MEI_WDT_START && wdt->state != MEI_WDT_RUNNING)
0268 return 0;
0269
0270 if (wdt->resp_required)
0271 init_completion(&wdt->response);
0272
0273 wdt->state = MEI_WDT_RUNNING;
0274 ret = mei_wdt_ping(wdt);
0275 if (ret)
0276 return ret;
0277
0278 if (wdt->resp_required)
0279 ret = wait_for_completion_killable(&wdt->response);
0280
0281 return ret;
0282 }
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292 static int mei_wdt_ops_set_timeout(struct watchdog_device *wdd,
0293 unsigned int timeout)
0294 {
0295
0296 struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
0297
0298
0299 wdt->timeout = timeout;
0300 wdd->timeout = timeout;
0301
0302 return 0;
0303 }
0304
0305 static const struct watchdog_ops wd_ops = {
0306 .owner = THIS_MODULE,
0307 .start = mei_wdt_ops_start,
0308 .stop = mei_wdt_ops_stop,
0309 .ping = mei_wdt_ops_ping,
0310 .set_timeout = mei_wdt_ops_set_timeout,
0311 };
0312
0313
0314 static struct watchdog_info wd_info = {
0315 .identity = INTEL_AMT_WATCHDOG_ID,
0316 .options = WDIOF_KEEPALIVEPING |
0317 WDIOF_SETTIMEOUT |
0318 WDIOF_ALARMONLY,
0319 };
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329 static inline bool __mei_wdt_is_registered(struct mei_wdt *wdt)
0330 {
0331 return !!watchdog_get_drvdata(&wdt->wdd);
0332 }
0333
0334
0335
0336
0337
0338
0339 static void mei_wdt_unregister(struct mei_wdt *wdt)
0340 {
0341 mutex_lock(&wdt->reg_lock);
0342
0343 if (__mei_wdt_is_registered(wdt)) {
0344 watchdog_unregister_device(&wdt->wdd);
0345 watchdog_set_drvdata(&wdt->wdd, NULL);
0346 memset(&wdt->wdd, 0, sizeof(wdt->wdd));
0347 }
0348
0349 mutex_unlock(&wdt->reg_lock);
0350 }
0351
0352
0353
0354
0355
0356
0357
0358
0359 static int mei_wdt_register(struct mei_wdt *wdt)
0360 {
0361 struct device *dev;
0362 int ret;
0363
0364 if (!wdt || !wdt->cldev)
0365 return -EINVAL;
0366
0367 dev = &wdt->cldev->dev;
0368
0369 mutex_lock(&wdt->reg_lock);
0370
0371 if (__mei_wdt_is_registered(wdt)) {
0372 ret = 0;
0373 goto out;
0374 }
0375
0376 wdt->wdd.info = &wd_info;
0377 wdt->wdd.ops = &wd_ops;
0378 wdt->wdd.parent = dev;
0379 wdt->wdd.timeout = MEI_WDT_DEFAULT_TIMEOUT;
0380 wdt->wdd.min_timeout = MEI_WDT_MIN_TIMEOUT;
0381 wdt->wdd.max_timeout = MEI_WDT_MAX_TIMEOUT;
0382
0383 watchdog_set_drvdata(&wdt->wdd, wdt);
0384 watchdog_stop_on_reboot(&wdt->wdd);
0385 watchdog_stop_on_unregister(&wdt->wdd);
0386
0387 ret = watchdog_register_device(&wdt->wdd);
0388 if (ret)
0389 watchdog_set_drvdata(&wdt->wdd, NULL);
0390
0391 wdt->state = MEI_WDT_IDLE;
0392
0393 out:
0394 mutex_unlock(&wdt->reg_lock);
0395 return ret;
0396 }
0397
0398 static void mei_wdt_unregister_work(struct work_struct *work)
0399 {
0400 struct mei_wdt *wdt = container_of(work, struct mei_wdt, unregister);
0401
0402 mei_wdt_unregister(wdt);
0403 }
0404
0405
0406
0407
0408
0409
0410 static void mei_wdt_rx(struct mei_cl_device *cldev)
0411 {
0412 struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
0413 struct mei_wdt_start_response res;
0414 const size_t res_len = sizeof(res);
0415 int ret;
0416
0417 ret = mei_cldev_recv(wdt->cldev, (u8 *)&res, res_len);
0418 if (ret < 0) {
0419 dev_err(&cldev->dev, "failure in recv %d\n", ret);
0420 return;
0421 }
0422
0423
0424 if (ret == 0)
0425 return;
0426
0427 if (ret < sizeof(struct mei_mc_hdr)) {
0428 dev_err(&cldev->dev, "recv small data %d\n", ret);
0429 return;
0430 }
0431
0432 if (res.hdr.command != MEI_MANAGEMENT_CONTROL ||
0433 res.hdr.versionnumber != MEI_MC_VERSION_NUMBER) {
0434 dev_err(&cldev->dev, "wrong command received\n");
0435 return;
0436 }
0437
0438 if (res.hdr.subcommand != MEI_MC_START_WD_TIMER_RES) {
0439 dev_warn(&cldev->dev, "unsupported command %d :%s[%d]\n",
0440 res.hdr.subcommand,
0441 mei_wdt_state_str(wdt->state),
0442 wdt->state);
0443 return;
0444 }
0445
0446
0447
0448
0449
0450 if (wdt->state == MEI_WDT_RUNNING) {
0451 if (res.wdstate & MEI_WDT_WDSTATE_NOT_REQUIRED) {
0452 wdt->state = MEI_WDT_NOT_REQUIRED;
0453 schedule_work(&wdt->unregister);
0454 }
0455 goto out;
0456 }
0457
0458 if (wdt->state == MEI_WDT_PROBE) {
0459 if (res.wdstate & MEI_WDT_WDSTATE_NOT_REQUIRED) {
0460 wdt->state = MEI_WDT_NOT_REQUIRED;
0461 } else {
0462
0463 mei_wdt_stop(wdt);
0464 mei_wdt_register(wdt);
0465 }
0466 return;
0467 }
0468
0469 dev_warn(&cldev->dev, "not in correct state %s[%d]\n",
0470 mei_wdt_state_str(wdt->state), wdt->state);
0471
0472 out:
0473 if (!completion_done(&wdt->response))
0474 complete(&wdt->response);
0475 }
0476
0477
0478
0479
0480
0481
0482 static void mei_wdt_notif(struct mei_cl_device *cldev)
0483 {
0484 struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
0485
0486 if (wdt->state != MEI_WDT_NOT_REQUIRED)
0487 return;
0488
0489 mei_wdt_register(wdt);
0490 }
0491
0492 #if IS_ENABLED(CONFIG_DEBUG_FS)
0493
0494 static ssize_t mei_dbgfs_read_activation(struct file *file, char __user *ubuf,
0495 size_t cnt, loff_t *ppos)
0496 {
0497 struct mei_wdt *wdt = file->private_data;
0498 const size_t bufsz = 32;
0499 char buf[32];
0500 ssize_t pos;
0501
0502 mutex_lock(&wdt->reg_lock);
0503 pos = scnprintf(buf, bufsz, "%s\n",
0504 __mei_wdt_is_registered(wdt) ? "activated" : "deactivated");
0505 mutex_unlock(&wdt->reg_lock);
0506
0507 return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
0508 }
0509
0510 static const struct file_operations dbgfs_fops_activation = {
0511 .open = simple_open,
0512 .read = mei_dbgfs_read_activation,
0513 .llseek = generic_file_llseek,
0514 };
0515
0516 static ssize_t mei_dbgfs_read_state(struct file *file, char __user *ubuf,
0517 size_t cnt, loff_t *ppos)
0518 {
0519 struct mei_wdt *wdt = file->private_data;
0520 char buf[32];
0521 ssize_t pos;
0522
0523 pos = scnprintf(buf, sizeof(buf), "state: %s\n",
0524 mei_wdt_state_str(wdt->state));
0525
0526 return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
0527 }
0528
0529 static const struct file_operations dbgfs_fops_state = {
0530 .open = simple_open,
0531 .read = mei_dbgfs_read_state,
0532 .llseek = generic_file_llseek,
0533 };
0534
0535 static void dbgfs_unregister(struct mei_wdt *wdt)
0536 {
0537 debugfs_remove_recursive(wdt->dbgfs_dir);
0538 wdt->dbgfs_dir = NULL;
0539 }
0540
0541 static void dbgfs_register(struct mei_wdt *wdt)
0542 {
0543 struct dentry *dir;
0544
0545 dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
0546 wdt->dbgfs_dir = dir;
0547
0548 debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
0549
0550 debugfs_create_file("activation", S_IRUSR, dir, wdt,
0551 &dbgfs_fops_activation);
0552 }
0553
0554 #else
0555
0556 static inline void dbgfs_unregister(struct mei_wdt *wdt) {}
0557 static inline void dbgfs_register(struct mei_wdt *wdt) {}
0558 #endif
0559
0560 static int mei_wdt_probe(struct mei_cl_device *cldev,
0561 const struct mei_cl_device_id *id)
0562 {
0563 struct mei_wdt *wdt;
0564 int ret;
0565
0566 wdt = kzalloc(sizeof(struct mei_wdt), GFP_KERNEL);
0567 if (!wdt)
0568 return -ENOMEM;
0569
0570 wdt->timeout = MEI_WDT_DEFAULT_TIMEOUT;
0571 wdt->state = MEI_WDT_PROBE;
0572 wdt->cldev = cldev;
0573 wdt->resp_required = mei_cldev_ver(cldev) > 0x1;
0574 mutex_init(&wdt->reg_lock);
0575 init_completion(&wdt->response);
0576 INIT_WORK(&wdt->unregister, mei_wdt_unregister_work);
0577
0578 mei_cldev_set_drvdata(cldev, wdt);
0579
0580 ret = mei_cldev_enable(cldev);
0581 if (ret < 0) {
0582 dev_err(&cldev->dev, "Could not enable cl device\n");
0583 goto err_out;
0584 }
0585
0586 ret = mei_cldev_register_rx_cb(wdt->cldev, mei_wdt_rx);
0587 if (ret) {
0588 dev_err(&cldev->dev, "Could not reg rx event ret=%d\n", ret);
0589 goto err_disable;
0590 }
0591
0592 ret = mei_cldev_register_notif_cb(wdt->cldev, mei_wdt_notif);
0593
0594
0595 if (ret && ret != -EOPNOTSUPP) {
0596 dev_err(&cldev->dev, "Could not reg notif event ret=%d\n", ret);
0597 goto err_disable;
0598 }
0599
0600 wd_info.firmware_version = mei_cldev_ver(cldev);
0601
0602 if (wdt->resp_required)
0603 ret = mei_wdt_ping(wdt);
0604 else
0605 ret = mei_wdt_register(wdt);
0606
0607 if (ret)
0608 goto err_disable;
0609
0610 dbgfs_register(wdt);
0611
0612 return 0;
0613
0614 err_disable:
0615 mei_cldev_disable(cldev);
0616
0617 err_out:
0618 kfree(wdt);
0619
0620 return ret;
0621 }
0622
0623 static void mei_wdt_remove(struct mei_cl_device *cldev)
0624 {
0625 struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
0626
0627
0628 if (!completion_done(&wdt->response))
0629 complete(&wdt->response);
0630
0631 cancel_work_sync(&wdt->unregister);
0632
0633 mei_wdt_unregister(wdt);
0634
0635 mei_cldev_disable(cldev);
0636
0637 dbgfs_unregister(wdt);
0638
0639 kfree(wdt);
0640 }
0641
0642 #define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
0643 0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
0644
0645 static const struct mei_cl_device_id mei_wdt_tbl[] = {
0646 { .uuid = MEI_UUID_WD, .version = MEI_CL_VERSION_ANY },
0647
0648 { }
0649 };
0650 MODULE_DEVICE_TABLE(mei, mei_wdt_tbl);
0651
0652 static struct mei_cl_driver mei_wdt_driver = {
0653 .id_table = mei_wdt_tbl,
0654 .name = KBUILD_MODNAME,
0655
0656 .probe = mei_wdt_probe,
0657 .remove = mei_wdt_remove,
0658 };
0659
0660 module_mei_cl_driver(mei_wdt_driver);
0661
0662 MODULE_AUTHOR("Intel Corporation");
0663 MODULE_LICENSE("GPL v2");
0664 MODULE_DESCRIPTION("Device driver for Intel MEI iAMT watchdog");