diff options
Diffstat (limited to 'drivers/misc/mei/wd.c')
| -rw-r--r-- | drivers/misc/mei/wd.c | 147 | 
1 files changed, 81 insertions, 66 deletions
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index b8921432e89..a84a664dfcc 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -25,7 +25,6 @@  #include "mei_dev.h"  #include "hbm.h" -#include "hw-me.h"  #include "client.h"  static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; @@ -53,14 +52,14 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)   *   * @dev: the device structure   * - * returns -ENENT if wd client cannot be found + * returns -ENOTTY if wd client cannot be found   *         -EIO if write has failed   *         0 on success   */  int mei_wd_host_init(struct mei_device *dev)  {  	struct mei_cl *cl = &dev->wd_cl; -	int i; +	int id;  	int ret;  	mei_cl_init(cl, dev); @@ -70,32 +69,35 @@ int mei_wd_host_init(struct mei_device *dev)  	/* check for valid client id */ -	i = mei_me_cl_by_uuid(dev, &mei_wd_guid); -	if (i < 0) { +	id = mei_me_cl_by_uuid(dev, &mei_wd_guid); +	if (id < 0) {  		dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); -		return -ENOENT; +		return -ENOTTY;  	} -	cl->me_client_id = dev->me_clients[i].client_id; +	cl->me_client_id = dev->me_clients[id].client_id;  	ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);  	if (ret < 0) {  		dev_info(&dev->pdev->dev, "wd: failed link client\n"); -		return -ENOENT; +		return ret;  	} -	cl->state = MEI_FILE_CONNECTING; +	ret = mei_cl_connect(cl, NULL); -	if (mei_hbm_cl_connect_req(dev, cl)) { -		dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n"); -		cl->state = MEI_FILE_DISCONNECTED; -		cl->host_client_id = 0; -		return -EIO; +	if (ret) { +		dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret); +		mei_cl_unlink(cl); +		return ret;  	} -	cl->timer_count = MEI_CONNECT_TIMEOUT; -	return 0; +	ret = mei_watchdog_register(dev); +	if (ret) { +		mei_cl_disconnect(cl); +		mei_cl_unlink(cl); +	} +	return ret;  }  /** @@ -106,24 +108,42 @@ int mei_wd_host_init(struct mei_device *dev)   * returns 0 if success,   *	-EIO when message send fails   *	-EINVAL when invalid message is to be sent + *	-ENODEV on flow control failure   */  int mei_wd_send(struct mei_device *dev)  { +	struct mei_cl *cl = &dev->wd_cl;  	struct mei_msg_hdr hdr; +	int ret; -	hdr.host_addr = dev->wd_cl.host_client_id; -	hdr.me_addr = dev->wd_cl.me_client_id; +	hdr.host_addr = cl->host_client_id; +	hdr.me_addr = cl->me_client_id;  	hdr.msg_complete = 1;  	hdr.reserved = 0; +	hdr.internal = 0;  	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))  		hdr.length = MEI_WD_START_MSG_SIZE;  	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))  		hdr.length = MEI_WD_STOP_MSG_SIZE; -	else +	else { +		dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");  		return -EINVAL; +	} + +	ret = mei_write_message(dev, &hdr, dev->wd_data); +	if (ret) { +		dev_err(&dev->pdev->dev, "wd: write message failed\n"); +		return ret; +	} -	return mei_write_message(dev, &hdr, dev->wd_data); +	ret = mei_cl_flow_ctrl_reduce(cl); +	if (ret) { +		dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n"); +		return ret; +	} + +	return 0;  }  /** @@ -132,9 +152,11 @@ int mei_wd_send(struct mei_device *dev)   * @dev: the device structure   * @preserve: indicate if to keep the timeout value   * - * returns 0 if success, - *	-EIO when message send fails + * returns 0 if success + * on error: + *	-EIO    when message send fails   *	-EINVAL when invalid message is to be sent + *	-ETIME  on message timeout   */  int mei_wd_stop(struct mei_device *dev)  { @@ -150,20 +172,12 @@ int mei_wd_stop(struct mei_device *dev)  	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);  	if (ret < 0) -		goto out; - -	if (ret && dev->hbuf_is_ready) { -		ret = 0; -		dev->hbuf_is_ready = false; - -		if (!mei_wd_send(dev)) { -			ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl); -			if (ret) -				goto out; -		} else { -			dev_err(&dev->pdev->dev, "wd: send stop failed\n"); -		} +		goto err; +	if (ret && mei_hbuf_acquire(dev)) { +		ret = mei_wd_send(dev); +		if (ret) +			goto err;  		dev->wd_pending = false;  	} else {  		dev->wd_pending = true; @@ -171,21 +185,21 @@ int mei_wd_stop(struct mei_device *dev)  	mutex_unlock(&dev->device_lock); -	ret = wait_event_interruptible_timeout(dev->wait_stop_wd, -					dev->wd_state == MEI_WD_IDLE, -					msecs_to_jiffies(MEI_WD_STOP_TIMEOUT)); +	ret = wait_event_timeout(dev->wait_stop_wd, +				dev->wd_state == MEI_WD_IDLE, +				msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));  	mutex_lock(&dev->device_lock); -	if (dev->wd_state == MEI_WD_IDLE) { -		dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret); -		ret = 0; -	} else { -		if (!ret) -			ret = -ETIMEDOUT; +	if (dev->wd_state != MEI_WD_IDLE) { +		/* timeout */ +		ret = -ETIME;  		dev_warn(&dev->pdev->dev,  			"wd: stop failed to complete ret=%d.\n", ret); +		goto err;  	} - -out: +	dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n", +			MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret)); +	return 0; +err:  	return ret;  } @@ -259,8 +273,8 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)   */  static int mei_wd_ops_ping(struct watchdog_device *wd_dev)  { -	int ret = 0;  	struct mei_device *dev; +	int ret;  	dev = watchdog_get_drvdata(wd_dev);  	if (!dev) @@ -276,25 +290,18 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)  	dev->wd_state = MEI_WD_RUNNING; +	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl); +	if (ret < 0) +		goto end;  	/* Check if we can send the ping to HW*/ -	if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) { +	if (ret && mei_hbuf_acquire(dev)) { -		dev->hbuf_is_ready = false;  		dev_dbg(&dev->pdev->dev, "wd: sending ping\n"); -		if (mei_wd_send(dev)) { -			dev_err(&dev->pdev->dev, "wd: send failed.\n"); -			ret = -EIO; -			goto end; -		} - -		if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) { -			dev_err(&dev->pdev->dev, -				"wd: mei_cl_flow_ctrl_reduce() failed.\n"); -			ret = -EIO; +		ret = mei_wd_send(dev); +		if (ret)  			goto end; -		} - +		dev->wd_pending = false;  	} else {  		dev->wd_pending = true;  	} @@ -362,17 +369,25 @@ static struct watchdog_device amt_wd_dev = {  }; -void mei_watchdog_register(struct mei_device *dev) +int mei_watchdog_register(struct mei_device *dev)  { -	if (watchdog_register_device(&amt_wd_dev)) { -		dev_err(&dev->pdev->dev, -			"wd: unable to register watchdog device.\n"); -		return; + +	int ret; + +	/* unlock to perserve correct locking order */ +	mutex_unlock(&dev->device_lock); +	ret = watchdog_register_device(&amt_wd_dev); +	mutex_lock(&dev->device_lock); +	if (ret) { +		dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n", +			ret); +		return ret;  	}  	dev_dbg(&dev->pdev->dev,  		"wd: successfully register watchdog interface.\n");  	watchdog_set_drvdata(&amt_wd_dev, dev); +	return 0;  }  void mei_watchdog_unregister(struct mei_device *dev)  | 
