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