| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Intel Management Engine Interface (Intel MEI) Linux driver | 
					
						
							| 
									
										
										
										
											2012-02-09 19:25:53 +02:00
										 |  |  |  * Copyright (c) 2003-2012, Intel Corporation. | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify it | 
					
						
							|  |  |  |  * under the terms and conditions of the GNU General Public License, | 
					
						
							|  |  |  |  * version 2, as published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope it will be useful, but WITHOUT | 
					
						
							|  |  |  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
					
						
							|  |  |  |  * more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-27 16:58:30 +02:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/wait.h>
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-25 19:06:03 +02:00
										 |  |  | #include <linux/mei.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | #include "mei_dev.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-11 18:27:03 +02:00
										 |  |  | #include "hbm.h"
 | 
					
						
							| 
									
										
										
										
											2013-01-08 23:07:14 +02:00
										 |  |  | #include "client.h"
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 00:03:56 +03:00
										 |  |  | const char *mei_dev_state_str(int state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
 | 
					
						
							|  |  |  | 	switch (state) { | 
					
						
							|  |  |  | 	MEI_DEV_STATE(INITIALIZING); | 
					
						
							|  |  |  | 	MEI_DEV_STATE(INIT_CLIENTS); | 
					
						
							|  |  |  | 	MEI_DEV_STATE(ENABLED); | 
					
						
							| 
									
										
										
										
											2013-04-19 22:01:36 +03:00
										 |  |  | 	MEI_DEV_STATE(RESETTING); | 
					
						
							| 
									
										
										
										
											2012-08-07 00:03:56 +03:00
										 |  |  | 	MEI_DEV_STATE(DISABLED); | 
					
						
							|  |  |  | 	MEI_DEV_STATE(POWER_DOWN); | 
					
						
							|  |  |  | 	MEI_DEV_STATE(POWER_UP); | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2013-05-21 23:13:12 +09:00
										 |  |  | 		return "unknown"; | 
					
						
							| 
									
										
										
										
											2012-08-07 00:03:56 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | #undef MEI_DEV_STATE
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * mei_cancel_work. Cancel mei background jobs | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @dev: the device structure | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * returns 0 on success or < 0 if the reset hasn't succeeded | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2013-11-11 13:26:06 +02:00
										 |  |  | void mei_cancel_work(struct mei_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	cancel_work_sync(&dev->init_work); | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 	cancel_work_sync(&dev->reset_work); | 
					
						
							| 
									
										
										
										
											2013-11-11 13:26:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cancel_delayed_work(&dev->timer_work); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(mei_cancel_work); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * mei_reset - resets host and fw. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @dev: the device structure | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | int mei_reset(struct mei_device *dev) | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	enum mei_dev_state state = dev->dev_state; | 
					
						
							|  |  |  | 	bool interrupts_enabled; | 
					
						
							| 
									
										
										
										
											2013-06-23 10:42:49 +03:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	if (state != MEI_DEV_INITIALIZING && | 
					
						
							|  |  |  | 	    state != MEI_DEV_DISABLED && | 
					
						
							|  |  |  | 	    state != MEI_DEV_POWER_DOWN && | 
					
						
							|  |  |  | 	    state != MEI_DEV_POWER_UP) | 
					
						
							| 
									
										
										
										
											2013-10-21 22:05:43 +03:00
										 |  |  | 		dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 			 mei_dev_state_str(state)); | 
					
						
							| 
									
										
										
										
											2013-10-21 22:05:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:22 +02:00
										 |  |  | 	/* we're already in reset, cancel the init timer
 | 
					
						
							|  |  |  | 	 * if the reset was called due the hbm protocol error | 
					
						
							|  |  |  | 	 * we need to call it before hw start | 
					
						
							|  |  |  | 	 * so the hbm watchdog won't kick in | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	mei_hbm_idle(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	/* enter reset flow */ | 
					
						
							|  |  |  | 	interrupts_enabled = state != MEI_DEV_POWER_DOWN; | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_RESETTING; | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:10 +02:00
										 |  |  | 	dev->reset_count++; | 
					
						
							|  |  |  | 	if (dev->reset_count > MEI_MAX_CONSEC_RESET) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); | 
					
						
							|  |  |  | 		dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	ret = mei_hw_reset(dev, interrupts_enabled); | 
					
						
							|  |  |  | 	/* fall through and remove the sw state even if hw reset has failed */ | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	/* no need to clean up software state in case of power up */ | 
					
						
							|  |  |  | 	if (state != MEI_DEV_INITIALIZING && | 
					
						
							|  |  |  | 	    state != MEI_DEV_POWER_UP) { | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-25 20:15:53 +03:00
										 |  |  | 		/* remove all waiting requests */ | 
					
						
							|  |  |  | 		mei_cl_all_write_clear(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-06 14:06:44 +02:00
										 |  |  | 		mei_cl_all_disconnect(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		/* wake up all readers and writers so they can be interrupted */ | 
					
						
							| 
									
										
										
										
											2013-07-25 20:15:53 +03:00
										 |  |  | 		mei_cl_all_wakeup(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 		/* remove entry if already in list */ | 
					
						
							| 
									
										
										
										
											2012-11-11 17:38:03 +02:00
										 |  |  | 		dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); | 
					
						
							| 
									
										
										
										
											2013-01-08 23:07:14 +02:00
										 |  |  | 		mei_cl_unlink(&dev->wd_cl); | 
					
						
							|  |  |  | 		mei_cl_unlink(&dev->iamthif_cl); | 
					
						
							| 
									
										
										
										
											2012-11-01 21:17:15 +02:00
										 |  |  | 		mei_amthif_reset_params(dev); | 
					
						
							| 
									
										
										
										
											2012-11-18 15:13:15 +02:00
										 |  |  | 		memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-02 13:29:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 10:44:33 +03:00
										 |  |  | 	dev->me_clients_num = 0; | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 	dev->rd_msg_hdr = 0; | 
					
						
							| 
									
										
										
										
											2011-05-25 17:28:22 +03:00
										 |  |  | 	dev->wd_pending = false; | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret); | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:22 +02:00
										 |  |  | 		dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (state == MEI_DEV_POWER_DOWN) { | 
					
						
							|  |  |  | 		dev_dbg(&dev->pdev->dev, "powering down: end of reset\n"); | 
					
						
							|  |  |  | 		dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2013-03-11 18:27:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-23 22:49:04 +03:00
										 |  |  | 	ret = mei_hw_start(dev); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret); | 
					
						
							| 
									
										
										
										
											2013-06-23 22:49:04 +03:00
										 |  |  | 		dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2013-06-23 22:49:04 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-03-11 18:27:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_INIT_CLIENTS; | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 	ret = mei_hbm_start_req(dev); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret); | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 		dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-03-27 16:58:30 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(mei_reset); | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * mei_start - initializes host and fw to start work. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @dev: the device structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * returns 0 on success, <0 on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int mei_start(struct mei_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	mutex_lock(&dev->device_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* acknowledge interrupt and stop interrupts */ | 
					
						
							|  |  |  | 	mei_clear_interrupts(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mei_hw_config(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_INITIALIZING; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:10 +02:00
										 |  |  | 	dev->reset_count = 0; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	mei_reset(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dev->dev_state == MEI_DEV_DISABLED) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "reset failed"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mei_hbm_start_wait(dev)) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "HBM haven't started"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!mei_host_is_ready(dev)) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "host is not ready.\n"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!mei_hw_is_ready(dev)) { | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "ME is not ready.\n"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!mei_hbm_version_is_supported(dev)) { | 
					
						
							|  |  |  | 		dev_dbg(&dev->pdev->dev, "MEI start failed.\n"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&dev->device_lock); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  | 	dev_err(&dev->pdev->dev, "link layer initialization failed.\n"); | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_DISABLED; | 
					
						
							|  |  |  | 	mutex_unlock(&dev->device_lock); | 
					
						
							|  |  |  | 	return -ENODEV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(mei_start); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * mei_restart - restart device after suspend | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @dev: the device structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * returns 0 on success or -ENODEV if the restart hasn't succeeded | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int mei_restart(struct mei_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&dev->device_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mei_clear_interrupts(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_POWER_UP; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:10 +02:00
										 |  |  | 	dev->reset_count = 0; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	err = mei_reset(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&dev->device_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (err || dev->dev_state == MEI_DEV_DISABLED) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(mei_restart); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | static void mei_reset_work(struct work_struct *work) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct mei_device *dev = | 
					
						
							|  |  |  | 		container_of(work, struct mei_device,  reset_work); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&dev->device_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	mei_reset(dev); | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&dev->device_lock); | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dev->dev_state == MEI_DEV_DISABLED) | 
					
						
							|  |  |  | 		dev_err(&dev->pdev->dev, "reset failed"); | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-10 13:56:08 +02:00
										 |  |  | void mei_stop(struct mei_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dev_dbg(&dev->pdev->dev, "stopping the device.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-11 13:26:06 +02:00
										 |  |  | 	mei_cancel_work(dev); | 
					
						
							| 
									
										
										
										
											2013-06-10 10:10:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-11 13:26:06 +02:00
										 |  |  | 	mei_nfc_host_exit(dev); | 
					
						
							| 
									
										
										
										
											2013-03-10 13:56:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-11 13:26:06 +02:00
										 |  |  | 	mutex_lock(&dev->device_lock); | 
					
						
							| 
									
										
										
										
											2013-03-10 13:56:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mei_wd_stop(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_POWER_DOWN; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:09 +02:00
										 |  |  | 	mei_reset(dev); | 
					
						
							| 
									
										
										
										
											2013-03-10 13:56:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&dev->device_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-27 16:58:26 +02:00
										 |  |  | 	mei_watchdog_unregister(dev); | 
					
						
							| 
									
										
										
										
											2013-03-10 13:56:08 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-03-27 16:58:30 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(mei_stop); | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-18 15:13:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-15 13:43:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | void mei_device_init(struct mei_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* setup our list array */ | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&dev->file_list); | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&dev->device_list); | 
					
						
							|  |  |  | 	mutex_init(&dev->device_lock); | 
					
						
							|  |  |  | 	init_waitqueue_head(&dev->wait_hw_ready); | 
					
						
							|  |  |  | 	init_waitqueue_head(&dev->wait_recvd_msg); | 
					
						
							|  |  |  | 	init_waitqueue_head(&dev->wait_stop_wd); | 
					
						
							|  |  |  | 	dev->dev_state = MEI_DEV_INITIALIZING; | 
					
						
							| 
									
										
										
										
											2014-01-12 00:36:10 +02:00
										 |  |  | 	dev->reset_count = 0; | 
					
						
							| 
									
										
										
										
											2014-01-08 20:19:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->read_list); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->write_list); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->write_waiting_list); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->ctrl_wr_list); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->ctrl_rd_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | 
					
						
							|  |  |  | 	INIT_WORK(&dev->init_work, mei_host_client_init); | 
					
						
							|  |  |  | 	INIT_WORK(&dev->reset_work, mei_reset_work); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&dev->wd_cl.link); | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&dev->iamthif_cl.link); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->amthif_cmd_list); | 
					
						
							|  |  |  | 	mei_io_list_init(&dev->amthif_rd_complete_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | 
					
						
							|  |  |  | 	dev->open_handle_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Reserving the first client ID | 
					
						
							|  |  |  | 	 * 0: Reserved for MEI Bus Message communications | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	bitmap_set(dev->host_clients_map, 0, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(mei_device_init); | 
					
						
							|  |  |  | 
 |