Ejemplo n.º 1
0
/**
 * mei_wd_ops_start - wd start command from the watchdog core.
 *
 * @wd_dev: watchdog device struct
 *
 * Return: 0 if success, negative errno code for failure
 */
static int mei_wd_ops_start(struct watchdog_device *wd_dev)
{
	struct mei_device *dev;
	struct mei_cl *cl;
	int err = -ENODEV;

	dev = watchdog_get_drvdata(wd_dev);
	if (!dev)
		return -ENODEV;

	cl = &dev->wd_cl;

	mutex_lock(&dev->device_lock);

	if (dev->dev_state != MEI_DEV_ENABLED) {
		dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
			mei_dev_state_str(dev->dev_state));
		goto end_unlock;
	}

	if (!mei_cl_is_connected(cl)) {
		cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n");
		goto end_unlock;
	}

	mei_wd_set_start_timeout(dev, dev->wd_timeout);

	err = 0;
end_unlock:
	mutex_unlock(&dev->device_lock);
	return err;
}
Ejemplo n.º 2
0
/**
 * mei_open - the open function
 *
 * @inode: pointer to inode structure
 * @file: pointer to file structure
 e
 * returns 0 on success, <0 on error
 */
static int mei_open(struct inode *inode, struct file *file)
{
	struct miscdevice *misc = file->private_data;
	struct pci_dev *pdev;
	struct mei_cl *cl;
	struct mei_device *dev;

	int err;

	err = -ENODEV;
	if (!misc->parent)
		goto out;

	pdev = container_of(misc->parent, struct pci_dev, dev);

	dev = pci_get_drvdata(pdev);
	if (!dev)
		goto out;

	mutex_lock(&dev->device_lock);
	err = -ENOMEM;
	cl = mei_cl_allocate(dev);
	if (!cl)
		goto out_unlock;

	err = -ENODEV;
	if (dev->dev_state != MEI_DEV_ENABLED) {
		dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
		    mei_dev_state_str(dev->dev_state));
		goto out_unlock;
	}
	err = -EMFILE;
	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
		dev_err(&dev->pdev->dev, "open_handle_count exceded %d",
			MEI_MAX_OPEN_HANDLE_COUNT);
		goto out_unlock;
	}

	err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
	if (err)
		goto out_unlock;

	file->private_data = cl;
	mutex_unlock(&dev->device_lock);

	return nonseekable_open(inode, file);

out_unlock:
	mutex_unlock(&dev->device_lock);
	kfree(cl);
out:
	return err;
}
Ejemplo n.º 3
0
Archivo: main.c Proyecto: 7799/linux
/**
 * mei_open - the open function
 *
 * @inode: pointer to inode structure
 * @file: pointer to file structure
 *
 * returns 0 on success, <0 on error
 */
static int mei_open(struct inode *inode, struct file *file)
{
	struct miscdevice *misc = file->private_data;
	struct pci_dev *pdev;
	struct mei_cl *cl;
	struct mei_device *dev;

	int err;

	if (!misc->parent)
		return -ENODEV;

	pdev = container_of(misc->parent, struct pci_dev, dev);

	dev = pci_get_drvdata(pdev);
	if (!dev)
		return -ENODEV;

	mutex_lock(&dev->device_lock);

	cl = NULL;

	err = -ENODEV;
	if (dev->dev_state != MEI_DEV_ENABLED) {
		dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
		    mei_dev_state_str(dev->dev_state));
		goto err_unlock;
	}

	err = -ENOMEM;
	cl = mei_cl_allocate(dev);
	if (!cl)
		goto err_unlock;

	/* open_handle_count check is handled in the mei_cl_link */
	err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
	if (err)
		goto err_unlock;

	file->private_data = cl;

	mutex_unlock(&dev->device_lock);

	return nonseekable_open(inode, file);

err_unlock:
	mutex_unlock(&dev->device_lock);
	kfree(cl);
	return err;
}
Ejemplo n.º 4
0
/**
 * mei_reset - resets host and fw.
 *
 * @dev: the device structure
 * @interrupts_enabled: if interrupt should be enabled after reset.
 */
void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
	bool unexpected;

	if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
		return;

	unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
			dev->dev_state != MEI_DEV_DISABLED &&
			dev->dev_state != MEI_DEV_POWER_DOWN &&
			dev->dev_state != MEI_DEV_POWER_UP);

	mei_hw_reset(dev, interrupts_enabled);


	if (dev->dev_state != MEI_DEV_INITIALIZING) {
		if (dev->dev_state != MEI_DEV_DISABLED &&
		    dev->dev_state != MEI_DEV_POWER_DOWN)
			dev->dev_state = MEI_DEV_RESETING;

		mei_cl_all_disconnect(dev);

		/* remove entry if already in list */
		dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
		mei_cl_unlink(&dev->wd_cl);
		if (dev->open_handle_count > 0)
			dev->open_handle_count--;
		mei_cl_unlink(&dev->iamthif_cl);
		if (dev->open_handle_count > 0)
			dev->open_handle_count--;

		mei_amthif_reset_params(dev);
		memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
	}

	dev->me_clients_num = 0;
	dev->rd_msg_hdr = 0;
	dev->wd_pending = false;

	if (unexpected)
		dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
			 mei_dev_state_str(dev->dev_state));

	/* wake up all readings so they can be interrupted */
	mei_cl_all_read_wakeup(dev);

	/* remove all waiting requests */
	mei_cl_all_write_clear(dev);
}
Ejemplo n.º 5
0
/**
 * mei_write_is_idle - check if there is pending write transaction
 *
 * @dev: the device structure
 * returns true if the writ queues are empty
 */
bool mei_write_is_idle(struct mei_device *dev)
{
	bool idle = (dev->dev_state == MEI_DEV_ENABLED &&
		dev->wr_ext_msg.hdr.length == 0  &&
		list_empty(&dev->ctrl_wr_list.list) &&
		list_empty(&dev->write_list.list));

	dev_dbg(&dev->pdev->dev, "pm: is idle[%d] state=%s extra=%d, ctrl=%d write=%d\n",
		idle,
		mei_dev_state_str(dev->dev_state),
		dev->wr_ext_msg.hdr.length == 0,
		list_empty(&dev->ctrl_wr_list.list),
		list_empty(&dev->write_list.list));

	return idle;
}
Ejemplo n.º 6
0
/**
 * mei_write_is_idle - check if the write queues are idle
 *
 * @dev: the device structure
 *
 * Return: true of there is no pending write
 */
bool mei_write_is_idle(struct mei_device *dev)
{
	bool idle = (dev->dev_state == MEI_DEV_ENABLED &&
		list_empty(&dev->ctrl_wr_list) &&
		list_empty(&dev->write_list)   &&
		list_empty(&dev->write_waiting_list));

	dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n",
		idle,
		mei_dev_state_str(dev->dev_state),
		list_empty(&dev->ctrl_wr_list),
		list_empty(&dev->write_list),
		list_empty(&dev->write_waiting_list));

	return idle;
}
Ejemplo n.º 7
0
static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
					size_t cnt, loff_t *ppos)
{
	struct mei_device *dev = fp->private_data;
	const size_t bufsz = 1024;
	char *buf = kzalloc(bufsz, GFP_KERNEL);
	int pos = 0;
	int ret;

	if  (!buf)
		return -ENOMEM;

	pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
			mei_dev_state_str(dev->dev_state));
	ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
	kfree(buf);
	return ret;
}
Ejemplo n.º 8
0
/**
 * mei_open - the open function
 *
 * @inode: pointer to inode structure
 * @file: pointer to file structure
 *
 * Return: 0 on success, <0 on error
 */
static int mei_open(struct inode *inode, struct file *file)
{
	struct mei_device *dev;
	struct mei_cl *cl;

	int err;

	dev = container_of(inode->i_cdev, struct mei_device, cdev);
	if (!dev)
		return -ENODEV;

	mutex_lock(&dev->device_lock);

	if (dev->dev_state != MEI_DEV_ENABLED) {
		dev_dbg(dev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
		    mei_dev_state_str(dev->dev_state));
		err = -ENODEV;
		goto err_unlock;
	}

	cl = mei_cl_alloc_linked(dev);
	if (IS_ERR(cl)) {
		err = PTR_ERR(cl);
		goto err_unlock;
	}

	cl->fp = file;
	file->private_data = cl;

	mutex_unlock(&dev->device_lock);

	return nonseekable_open(inode, file);

err_unlock:
	mutex_unlock(&dev->device_lock);
	return err;
}
Ejemplo n.º 9
0
/**
 * mei_reset - resets host and fw.
 *
 * @dev: the device structure
 */
int mei_reset(struct mei_device *dev)
{
	enum mei_dev_state state = dev->dev_state;
	bool interrupts_enabled;
	int ret;

	if (state != MEI_DEV_INITIALIZING &&
	    state != MEI_DEV_DISABLED &&
	    state != MEI_DEV_POWER_DOWN &&
	    state != MEI_DEV_POWER_UP)
		dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
			 mei_dev_state_str(state));

	/* 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);

	/* enter reset flow */
	interrupts_enabled = state != MEI_DEV_POWER_DOWN;
	dev->dev_state = MEI_DEV_RESETTING;

	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;
	}

	ret = mei_hw_reset(dev, interrupts_enabled);
	/* fall through and remove the sw state even if hw reset has failed */

	/* no need to clean up software state in case of power up */
	if (state != MEI_DEV_INITIALIZING &&
	    state != MEI_DEV_POWER_UP) {

		/* remove all waiting requests */
		mei_cl_all_write_clear(dev);

		mei_cl_all_disconnect(dev);

		/* wake up all readers and writers so they can be interrupted */
		mei_cl_all_wakeup(dev);

		/* remove entry if already in list */
		dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
		mei_cl_unlink(&dev->wd_cl);
		mei_cl_unlink(&dev->iamthif_cl);
		mei_amthif_reset_params(dev);
	}


	dev->me_clients_num = 0;
	dev->rd_msg_hdr = 0;
	dev->wd_pending = false;

	if (ret) {
		dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
		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;
	}

	ret = mei_hw_start(dev);
	if (ret) {
		dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
		return ret;
	}

	dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");

	dev->dev_state = MEI_DEV_INIT_CLIENTS;
	ret = mei_hbm_start_req(dev);
	if (ret) {
		dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
		dev->dev_state = MEI_DEV_RESETTING;
		return ret;
	}

	return 0;
}
Ejemplo n.º 10
0
/**
 * mei_reset - resets host and fw.
 *
 * @dev: the device structure
 * @interrupts_enabled: if interrupt should be enabled after reset.
 */
void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
	bool unexpected;

	unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
			dev->dev_state != MEI_DEV_DISABLED &&
			dev->dev_state != MEI_DEV_POWER_DOWN &&
			dev->dev_state != MEI_DEV_POWER_UP);

	mei_hw_reset(dev, interrupts_enabled);

	dev->hbm_state = MEI_HBM_IDLE;

	if (dev->dev_state != MEI_DEV_INITIALIZING &&
	    dev->dev_state != MEI_DEV_POWER_UP) {
		if (dev->dev_state != MEI_DEV_DISABLED &&
		    dev->dev_state != MEI_DEV_POWER_DOWN)
			dev->dev_state = MEI_DEV_RESETTING;

		mei_cl_all_disconnect(dev);

		/* remove entry if already in list */
		dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
		mei_cl_unlink(&dev->wd_cl);
		if (dev->open_handle_count > 0)
			dev->open_handle_count--;
		mei_cl_unlink(&dev->iamthif_cl);
		if (dev->open_handle_count > 0)
			dev->open_handle_count--;

		mei_amthif_reset_params(dev);
		memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
	}

	dev->me_clients_num = 0;
	dev->rd_msg_hdr = 0;
	dev->wd_pending = false;

	if (unexpected)
		dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
			 mei_dev_state_str(dev->dev_state));

	if (!interrupts_enabled) {
		dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
		return;
	}

	mei_hw_start(dev);

	dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
	/* link is established * start sending messages.  */

	dev->dev_state = MEI_DEV_INIT_CLIENTS;

	mei_hbm_start_req(dev);

	/* wake up all readings so they can be interrupted */
	mei_cl_all_read_wakeup(dev);

	/* remove all waiting requests */
	mei_cl_all_write_clear(dev);
}
Ejemplo n.º 11
0
/**
 * mei_reset - resets host and fw.
 *
 * @dev: the device structure
 *
 * Return: 0 on success or < 0 if the reset hasn't succeeded
 */
int mei_reset(struct mei_device *dev)
{
	enum mei_dev_state state = dev->dev_state;
	bool interrupts_enabled;
	int ret;

	if (state != MEI_DEV_INITIALIZING &&
	    state != MEI_DEV_DISABLED &&
	    state != MEI_DEV_POWER_DOWN &&
	    state != MEI_DEV_POWER_UP) {
		char fw_sts_str[MEI_FW_STATUS_STR_SZ];

		mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ);
		dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
			 mei_dev_state_str(state), fw_sts_str);
	}

	mei_clear_interrupts(dev);

	/* 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);

	/* enter reset flow */
	interrupts_enabled = state != MEI_DEV_POWER_DOWN;
	dev->dev_state = MEI_DEV_RESETTING;

	dev->reset_count++;
	if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
		dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
		dev->dev_state = MEI_DEV_DISABLED;
		return -ENODEV;
	}

	ret = mei_hw_reset(dev, interrupts_enabled);
	/* fall through and remove the sw state even if hw reset has failed */

	/* no need to clean up software state in case of power up */
	if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_POWER_UP)
		mei_cl_all_disconnect(dev);

	mei_hbm_reset(dev);

	memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));

	if (ret) {
		dev_err(dev->dev, "hw_reset failed ret = %d\n", ret);
		return ret;
	}

	if (state == MEI_DEV_POWER_DOWN) {
		dev_dbg(dev->dev, "powering down: end of reset\n");
		dev->dev_state = MEI_DEV_DISABLED;
		return 0;
	}

	ret = mei_hw_start(dev);
	if (ret) {
		dev_err(dev->dev, "hw_start failed ret = %d\n", ret);
		return ret;
	}

	dev_dbg(dev->dev, "link is established start sending messages.\n");

	dev->dev_state = MEI_DEV_INIT_CLIENTS;
	ret = mei_hbm_start_req(dev);
	if (ret) {
		dev_err(dev->dev, "hbm_start failed ret = %d\n", ret);
		dev->dev_state = MEI_DEV_RESETTING;
		return ret;
	}

	return 0;
}