1/* 2 * 3 * Intel Management Engine Interface (Intel MEI) Linux driver 4 * Copyright (c) 2003-2012, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 */ 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/moduleparam.h> 19#include <linux/device.h> 20#include <linux/sched.h> 21#include <linux/watchdog.h> 22 23#include <linux/mei.h> 24 25#include "mei_dev.h" 26#include "hbm.h" 27#include "client.h" 28 29static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; 30static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 }; 31 32/* 33 * AMT Watchdog Device 34 */ 35#define INTEL_AMT_WATCHDOG_ID "INTCAMT" 36 37/* UUIDs for AMT F/W clients */ 38const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89, 39 0x9D, 0xA9, 0x15, 0x14, 0xCB, 40 0x32, 0xAB); 41 42static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) 43{ 44 dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout); 45 memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE); 46 memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16)); 47} 48 49/** 50 * mei_wd_host_init - connect to the watchdog client 51 * 52 * @dev: the device structure 53 * 54 * Return: -ENOTTY if wd client cannot be found 55 * -EIO if write has failed 56 * 0 on success 57 */ 58int mei_wd_host_init(struct mei_device *dev) 59{ 60 struct mei_cl *cl = &dev->wd_cl; 61 struct mei_me_client *me_cl; 62 int ret; 63 64 mei_cl_init(cl, dev); 65 66 dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; 67 dev->wd_state = MEI_WD_IDLE; 68 69 70 /* check for valid client id */ 71 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid); 72 if (!me_cl) { 73 dev_info(dev->dev, "wd: failed to find the client\n"); 74 return -ENOTTY; 75 } 76 77 cl->me_client_id = me_cl->client_id; 78 cl->cl_uuid = me_cl->props.protocol_name; 79 mei_me_cl_put(me_cl); 80 81 ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); 82 83 if (ret < 0) { 84 dev_info(dev->dev, "wd: failed link client\n"); 85 return ret; 86 } 87 88 ret = mei_cl_connect(cl, NULL); 89 90 if (ret) { 91 dev_err(dev->dev, "wd: failed to connect = %d\n", ret); 92 mei_cl_unlink(cl); 93 return ret; 94 } 95 96 ret = mei_watchdog_register(dev); 97 if (ret) { 98 mei_cl_disconnect(cl); 99 mei_cl_unlink(cl); 100 } 101 return ret; 102} 103 104/** 105 * mei_wd_send - sends watch dog message to fw. 106 * 107 * @dev: the device structure 108 * 109 * Return: 0 if success, 110 * -EIO when message send fails 111 * -EINVAL when invalid message is to be sent 112 * -ENODEV on flow control failure 113 */ 114int mei_wd_send(struct mei_device *dev) 115{ 116 struct mei_cl *cl = &dev->wd_cl; 117 struct mei_msg_hdr hdr; 118 int ret; 119 120 hdr.host_addr = cl->host_client_id; 121 hdr.me_addr = cl->me_client_id; 122 hdr.msg_complete = 1; 123 hdr.reserved = 0; 124 hdr.internal = 0; 125 126 if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) 127 hdr.length = MEI_WD_START_MSG_SIZE; 128 else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE)) 129 hdr.length = MEI_WD_STOP_MSG_SIZE; 130 else { 131 dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n"); 132 return -EINVAL; 133 } 134 135 ret = mei_write_message(dev, &hdr, dev->wd_data); 136 if (ret) { 137 dev_err(dev->dev, "wd: write message failed\n"); 138 return ret; 139 } 140 141 ret = mei_cl_flow_ctrl_reduce(cl); 142 if (ret) { 143 dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n"); 144 return ret; 145 } 146 147 return 0; 148} 149 150/** 151 * mei_wd_stop - sends watchdog stop message to fw. 152 * 153 * @dev: the device structure 154 * 155 * Return: 0 if success 156 * on error: 157 * -EIO when message send fails 158 * -EINVAL when invalid message is to be sent 159 * -ETIME on message timeout 160 */ 161int mei_wd_stop(struct mei_device *dev) 162{ 163 struct mei_cl *cl = &dev->wd_cl; 164 int ret; 165 166 if (!mei_cl_is_connected(cl) || 167 dev->wd_state != MEI_WD_RUNNING) 168 return 0; 169 170 memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE); 171 172 dev->wd_state = MEI_WD_STOPPING; 173 174 ret = mei_cl_flow_ctrl_creds(cl); 175 if (ret < 0) 176 goto err; 177 178 if (ret && mei_hbuf_acquire(dev)) { 179 ret = mei_wd_send(dev); 180 if (ret) 181 goto err; 182 dev->wd_pending = false; 183 } else { 184 dev->wd_pending = true; 185 } 186 187 mutex_unlock(&dev->device_lock); 188 189 ret = wait_event_timeout(dev->wait_stop_wd, 190 dev->wd_state == MEI_WD_IDLE, 191 msecs_to_jiffies(MEI_WD_STOP_TIMEOUT)); 192 mutex_lock(&dev->device_lock); 193 if (dev->wd_state != MEI_WD_IDLE) { 194 /* timeout */ 195 ret = -ETIME; 196 dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret); 197 goto err; 198 } 199 dev_dbg(dev->dev, "wd: stop completed after %u msec\n", 200 MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret)); 201 return 0; 202err: 203 return ret; 204} 205 206/** 207 * mei_wd_ops_start - wd start command from the watchdog core. 208 * 209 * @wd_dev: watchdog device struct 210 * 211 * Return: 0 if success, negative errno code for failure 212 */ 213static int mei_wd_ops_start(struct watchdog_device *wd_dev) 214{ 215 struct mei_device *dev; 216 struct mei_cl *cl; 217 int err = -ENODEV; 218 219 dev = watchdog_get_drvdata(wd_dev); 220 if (!dev) 221 return -ENODEV; 222 223 cl = &dev->wd_cl; 224 225 mutex_lock(&dev->device_lock); 226 227 if (dev->dev_state != MEI_DEV_ENABLED) { 228 dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n", 229 mei_dev_state_str(dev->dev_state)); 230 goto end_unlock; 231 } 232 233 if (!mei_cl_is_connected(cl)) { 234 cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n"); 235 goto end_unlock; 236 } 237 238 mei_wd_set_start_timeout(dev, dev->wd_timeout); 239 240 err = 0; 241end_unlock: 242 mutex_unlock(&dev->device_lock); 243 return err; 244} 245 246/** 247 * mei_wd_ops_stop - wd stop command from the watchdog core. 248 * 249 * @wd_dev: watchdog device struct 250 * 251 * Return: 0 if success, negative errno code for failure 252 */ 253static int mei_wd_ops_stop(struct watchdog_device *wd_dev) 254{ 255 struct mei_device *dev; 256 257 dev = watchdog_get_drvdata(wd_dev); 258 if (!dev) 259 return -ENODEV; 260 261 mutex_lock(&dev->device_lock); 262 mei_wd_stop(dev); 263 mutex_unlock(&dev->device_lock); 264 265 return 0; 266} 267 268/** 269 * mei_wd_ops_ping - wd ping command from the watchdog core. 270 * 271 * @wd_dev: watchdog device struct 272 * 273 * Return: 0 if success, negative errno code for failure 274 */ 275static int mei_wd_ops_ping(struct watchdog_device *wd_dev) 276{ 277 struct mei_device *dev; 278 struct mei_cl *cl; 279 int ret; 280 281 dev = watchdog_get_drvdata(wd_dev); 282 if (!dev) 283 return -ENODEV; 284 285 cl = &dev->wd_cl; 286 287 mutex_lock(&dev->device_lock); 288 289 if (!mei_cl_is_connected(cl)) { 290 cl_err(dev, cl, "wd: not connected.\n"); 291 ret = -ENODEV; 292 goto end; 293 } 294 295 dev->wd_state = MEI_WD_RUNNING; 296 297 ret = mei_cl_flow_ctrl_creds(cl); 298 if (ret < 0) 299 goto end; 300 301 /* Check if we can send the ping to HW*/ 302 if (ret && mei_hbuf_acquire(dev)) { 303 dev_dbg(dev->dev, "wd: sending ping\n"); 304 305 ret = mei_wd_send(dev); 306 if (ret) 307 goto end; 308 dev->wd_pending = false; 309 } else { 310 dev->wd_pending = true; 311 } 312 313end: 314 mutex_unlock(&dev->device_lock); 315 return ret; 316} 317 318/** 319 * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core. 320 * 321 * @wd_dev: watchdog device struct 322 * @timeout: timeout value to set 323 * 324 * Return: 0 if success, negative errno code for failure 325 */ 326static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, 327 unsigned int timeout) 328{ 329 struct mei_device *dev; 330 331 dev = watchdog_get_drvdata(wd_dev); 332 if (!dev) 333 return -ENODEV; 334 335 /* Check Timeout value */ 336 if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT) 337 return -EINVAL; 338 339 mutex_lock(&dev->device_lock); 340 341 dev->wd_timeout = timeout; 342 wd_dev->timeout = timeout; 343 mei_wd_set_start_timeout(dev, dev->wd_timeout); 344 345 mutex_unlock(&dev->device_lock); 346 347 return 0; 348} 349 350/* 351 * Watchdog Device structs 352 */ 353static const struct watchdog_ops wd_ops = { 354 .owner = THIS_MODULE, 355 .start = mei_wd_ops_start, 356 .stop = mei_wd_ops_stop, 357 .ping = mei_wd_ops_ping, 358 .set_timeout = mei_wd_ops_set_timeout, 359}; 360static const struct watchdog_info wd_info = { 361 .identity = INTEL_AMT_WATCHDOG_ID, 362 .options = WDIOF_KEEPALIVEPING | 363 WDIOF_SETTIMEOUT | 364 WDIOF_ALARMONLY, 365}; 366 367static struct watchdog_device amt_wd_dev = { 368 .info = &wd_info, 369 .ops = &wd_ops, 370 .timeout = MEI_WD_DEFAULT_TIMEOUT, 371 .min_timeout = MEI_WD_MIN_TIMEOUT, 372 .max_timeout = MEI_WD_MAX_TIMEOUT, 373}; 374 375 376int mei_watchdog_register(struct mei_device *dev) 377{ 378 379 int ret; 380 381 /* unlock to perserve correct locking order */ 382 mutex_unlock(&dev->device_lock); 383 ret = watchdog_register_device(&amt_wd_dev); 384 mutex_lock(&dev->device_lock); 385 if (ret) { 386 dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n", 387 ret); 388 return ret; 389 } 390 391 dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n"); 392 watchdog_set_drvdata(&amt_wd_dev, dev); 393 return 0; 394} 395 396void mei_watchdog_unregister(struct mei_device *dev) 397{ 398 if (watchdog_get_drvdata(&amt_wd_dev) == NULL) 399 return; 400 401 watchdog_set_drvdata(&amt_wd_dev, NULL); 402 watchdog_unregister_device(&amt_wd_dev); 403} 404 405