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 80 ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); 81 82 if (ret < 0) { 83 dev_info(dev->dev, "wd: failed link client\n"); 84 return ret; 85 } 86 87 ret = mei_cl_connect(cl, NULL); 88 89 if (ret) { 90 dev_err(dev->dev, "wd: failed to connect = %d\n", ret); 91 mei_cl_unlink(cl); 92 return ret; 93 } 94 95 ret = mei_watchdog_register(dev); 96 if (ret) { 97 mei_cl_disconnect(cl); 98 mei_cl_unlink(cl); 99 } 100 return ret; 101} 102 103/** 104 * mei_wd_send - sends watch dog message to fw. 105 * 106 * @dev: the device structure 107 * 108 * Return: 0 if success, 109 * -EIO when message send fails 110 * -EINVAL when invalid message is to be sent 111 * -ENODEV on flow control failure 112 */ 113int mei_wd_send(struct mei_device *dev) 114{ 115 struct mei_cl *cl = &dev->wd_cl; 116 struct mei_msg_hdr hdr; 117 int ret; 118 119 hdr.host_addr = cl->host_client_id; 120 hdr.me_addr = cl->me_client_id; 121 hdr.msg_complete = 1; 122 hdr.reserved = 0; 123 hdr.internal = 0; 124 125 if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) 126 hdr.length = MEI_WD_START_MSG_SIZE; 127 else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE)) 128 hdr.length = MEI_WD_STOP_MSG_SIZE; 129 else { 130 dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n"); 131 return -EINVAL; 132 } 133 134 ret = mei_write_message(dev, &hdr, dev->wd_data); 135 if (ret) { 136 dev_err(dev->dev, "wd: write message failed\n"); 137 return ret; 138 } 139 140 ret = mei_cl_flow_ctrl_reduce(cl); 141 if (ret) { 142 dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n"); 143 return ret; 144 } 145 146 return 0; 147} 148 149/** 150 * mei_wd_stop - sends watchdog stop message to fw. 151 * 152 * @dev: the device structure 153 * 154 * Return: 0 if success 155 * on error: 156 * -EIO when message send fails 157 * -EINVAL when invalid message is to be sent 158 * -ETIME on message timeout 159 */ 160int mei_wd_stop(struct mei_device *dev) 161{ 162 int ret; 163 164 if (dev->wd_cl.state != MEI_FILE_CONNECTED || 165 dev->wd_state != MEI_WD_RUNNING) 166 return 0; 167 168 memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE); 169 170 dev->wd_state = MEI_WD_STOPPING; 171 172 ret = mei_cl_flow_ctrl_creds(&dev->wd_cl); 173 if (ret < 0) 174 goto err; 175 176 if (ret && mei_hbuf_acquire(dev)) { 177 ret = mei_wd_send(dev); 178 if (ret) 179 goto err; 180 dev->wd_pending = false; 181 } else { 182 dev->wd_pending = true; 183 } 184 185 mutex_unlock(&dev->device_lock); 186 187 ret = wait_event_timeout(dev->wait_stop_wd, 188 dev->wd_state == MEI_WD_IDLE, 189 msecs_to_jiffies(MEI_WD_STOP_TIMEOUT)); 190 mutex_lock(&dev->device_lock); 191 if (dev->wd_state != MEI_WD_IDLE) { 192 /* timeout */ 193 ret = -ETIME; 194 dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret); 195 goto err; 196 } 197 dev_dbg(dev->dev, "wd: stop completed after %u msec\n", 198 MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret)); 199 return 0; 200err: 201 return ret; 202} 203 204/* 205 * mei_wd_ops_start - wd start command from the watchdog core. 206 * 207 * @wd_dev - watchdog device struct 208 * 209 * Return: 0 if success, negative errno code for failure 210 */ 211static int mei_wd_ops_start(struct watchdog_device *wd_dev) 212{ 213 int err = -ENODEV; 214 struct mei_device *dev; 215 216 dev = watchdog_get_drvdata(wd_dev); 217 if (!dev) 218 return -ENODEV; 219 220 mutex_lock(&dev->device_lock); 221 222 if (dev->dev_state != MEI_DEV_ENABLED) { 223 dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n", 224 mei_dev_state_str(dev->dev_state)); 225 goto end_unlock; 226 } 227 228 if (dev->wd_cl.state != MEI_FILE_CONNECTED) { 229 dev_dbg(dev->dev, "MEI Driver is not connected to Watchdog Client\n"); 230 goto end_unlock; 231 } 232 233 mei_wd_set_start_timeout(dev, dev->wd_timeout); 234 235 err = 0; 236end_unlock: 237 mutex_unlock(&dev->device_lock); 238 return err; 239} 240 241/* 242 * mei_wd_ops_stop - wd stop command from the watchdog core. 243 * 244 * @wd_dev - watchdog device struct 245 * 246 * Return: 0 if success, negative errno code for failure 247 */ 248static int mei_wd_ops_stop(struct watchdog_device *wd_dev) 249{ 250 struct mei_device *dev; 251 252 dev = watchdog_get_drvdata(wd_dev); 253 if (!dev) 254 return -ENODEV; 255 256 mutex_lock(&dev->device_lock); 257 mei_wd_stop(dev); 258 mutex_unlock(&dev->device_lock); 259 260 return 0; 261} 262 263/* 264 * mei_wd_ops_ping - wd ping command from the watchdog core. 265 * 266 * @wd_dev - watchdog device struct 267 * 268 * Return: 0 if success, negative errno code for failure 269 */ 270static int mei_wd_ops_ping(struct watchdog_device *wd_dev) 271{ 272 struct mei_device *dev; 273 int ret; 274 275 dev = watchdog_get_drvdata(wd_dev); 276 if (!dev) 277 return -ENODEV; 278 279 mutex_lock(&dev->device_lock); 280 281 if (dev->wd_cl.state != MEI_FILE_CONNECTED) { 282 dev_err(dev->dev, "wd: not connected.\n"); 283 ret = -ENODEV; 284 goto end; 285 } 286 287 dev->wd_state = MEI_WD_RUNNING; 288 289 ret = mei_cl_flow_ctrl_creds(&dev->wd_cl); 290 if (ret < 0) 291 goto end; 292 /* Check if we can send the ping to HW*/ 293 if (ret && mei_hbuf_acquire(dev)) { 294 295 dev_dbg(dev->dev, "wd: sending ping\n"); 296 297 ret = mei_wd_send(dev); 298 if (ret) 299 goto end; 300 dev->wd_pending = false; 301 } else { 302 dev->wd_pending = true; 303 } 304 305end: 306 mutex_unlock(&dev->device_lock); 307 return ret; 308} 309 310/* 311 * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core. 312 * 313 * @wd_dev - watchdog device struct 314 * @timeout - timeout value to set 315 * 316 * Return: 0 if success, negative errno code for failure 317 */ 318static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, 319 unsigned int timeout) 320{ 321 struct mei_device *dev; 322 323 dev = watchdog_get_drvdata(wd_dev); 324 if (!dev) 325 return -ENODEV; 326 327 /* Check Timeout value */ 328 if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT) 329 return -EINVAL; 330 331 mutex_lock(&dev->device_lock); 332 333 dev->wd_timeout = timeout; 334 wd_dev->timeout = timeout; 335 mei_wd_set_start_timeout(dev, dev->wd_timeout); 336 337 mutex_unlock(&dev->device_lock); 338 339 return 0; 340} 341 342/* 343 * Watchdog Device structs 344 */ 345static const struct watchdog_ops wd_ops = { 346 .owner = THIS_MODULE, 347 .start = mei_wd_ops_start, 348 .stop = mei_wd_ops_stop, 349 .ping = mei_wd_ops_ping, 350 .set_timeout = mei_wd_ops_set_timeout, 351}; 352static const struct watchdog_info wd_info = { 353 .identity = INTEL_AMT_WATCHDOG_ID, 354 .options = WDIOF_KEEPALIVEPING | 355 WDIOF_SETTIMEOUT | 356 WDIOF_ALARMONLY, 357}; 358 359static struct watchdog_device amt_wd_dev = { 360 .info = &wd_info, 361 .ops = &wd_ops, 362 .timeout = MEI_WD_DEFAULT_TIMEOUT, 363 .min_timeout = MEI_WD_MIN_TIMEOUT, 364 .max_timeout = MEI_WD_MAX_TIMEOUT, 365}; 366 367 368int mei_watchdog_register(struct mei_device *dev) 369{ 370 371 int ret; 372 373 /* unlock to perserve correct locking order */ 374 mutex_unlock(&dev->device_lock); 375 ret = watchdog_register_device(&amt_wd_dev); 376 mutex_lock(&dev->device_lock); 377 if (ret) { 378 dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n", 379 ret); 380 return ret; 381 } 382 383 dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n"); 384 watchdog_set_drvdata(&amt_wd_dev, dev); 385 return 0; 386} 387 388void mei_watchdog_unregister(struct mei_device *dev) 389{ 390 if (watchdog_get_drvdata(&amt_wd_dev) == NULL) 391 return; 392 393 watchdog_set_drvdata(&amt_wd_dev, NULL); 394 watchdog_unregister_device(&amt_wd_dev); 395} 396 397