Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18901357 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman
Browse files

mei: disconnect on connection request timeout



For the FW with  HBM version >= 2.0 we don't need to reset the whole
device in case of a particular client failing to connect, it is enough
to send disconnect a request to bring the device to the stable state.

Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 70ef835c
Loading
Loading
Loading
Loading
+59 −26
Original line number Diff line number Diff line
@@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
	return ret;
}



/**
 * mei_cl_disconnect - disconnect host client from the me one
 * __mei_cl_disconnect - disconnect host client from the me one
 *     internal function runtime pm has to be already acquired
 *
 * @cl: host client
 *
 * Locking: called under "dev->device_lock" lock
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_cl_disconnect(struct mei_cl *cl)
static int __mei_cl_disconnect(struct mei_cl *cl)
{
	struct mei_device *dev;
	struct mei_cl_cb *cb;
	int rets;

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	cl_dbg(dev, cl, "disconnecting");

	if (!mei_cl_is_connected(cl))
		return 0;

	if (mei_cl_is_fixed_address(cl)) {
		mei_cl_set_disconnected(cl);
		return 0;
	}

	rets = pm_runtime_get(dev->dev);
	if (rets < 0 && rets != -EINPROGRESS) {
		pm_runtime_put_noidle(dev->dev);
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}
	if (WARN_ON(!pm_runtime_active(dev->dev)))
		return -EFAULT;

	cl->state = MEI_FILE_DISCONNECTING;

@@ -910,11 +890,52 @@ int mei_cl_disconnect(struct mei_cl *cl)
	if (!rets)
		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");

	mei_io_cb_free(cb);
	return rets;
}

/**
 * mei_cl_disconnect - disconnect host client from the me one
 *
 * @cl: host client
 *
 * Locking: called under "dev->device_lock" lock
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_cl_disconnect(struct mei_cl *cl)
{
	struct mei_device *dev;
	int rets;

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	cl_dbg(dev, cl, "disconnecting");

	if (!mei_cl_is_connected(cl))
		return 0;

	if (mei_cl_is_fixed_address(cl)) {
		mei_cl_set_disconnected(cl);
		return 0;
	}

	rets = pm_runtime_get(dev->dev);
	if (rets < 0 && rets != -EINPROGRESS) {
		pm_runtime_put_noidle(dev->dev);
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

	rets = __mei_cl_disconnect(cl);

	cl_dbg(dev, cl, "rpm: autosuspend\n");
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);

	mei_io_cb_free(cb);
	return rets;
}

@@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
	mutex_unlock(&dev->device_lock);
	wait_event_timeout(cl->wait,
			(cl->state == MEI_FILE_CONNECTED ||
			 cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
			 cl->state == MEI_FILE_DISCONNECT_REPLY),
			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
	mutex_lock(&dev->device_lock);

	if (!mei_cl_is_connected(cl)) {
		if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) {
			mei_io_list_flush(&dev->ctrl_rd_list, cl);
			mei_io_list_flush(&dev->ctrl_wr_list, cl);
			 /* ignore disconnect return valuue;
			  * in case of failure reset will be invoked
			  */
			__mei_cl_disconnect(cl);
			rets = -EFAULT;
			goto out;
		}

		/* timeout or something went really wrong */
		if (!cl->status)
			cl->status = -EFAULT;
+2 −0
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
				 dev->hbm_f_pg_supported);
		pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
				 dev->hbm_f_dc_supported);
		pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
				 dev->hbm_f_dot_supported);
	}

	pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",
+4 −0
Original line number Diff line number Diff line
@@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev)

	if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
		dev->hbm_f_dc_supported = 1;

	/* disconnect on connect timeout instead of link reset */
	if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
		dev->hbm_f_dot_supported = 1;
}

/**
+6 −0
Original line number Diff line number Diff line
@@ -52,6 +52,12 @@
#define HBM_MINOR_VERSION_DC               0
#define HBM_MAJOR_VERSION_DC               2

/*
 * MEI version with disconnect on connection timeout support
 */
#define HBM_MINOR_VERSION_DOT              0
#define HBM_MAJOR_VERSION_DOT              2

/* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK                  0x7f
/* Host bus message command RESPONSE */
+19 −1
Original line number Diff line number Diff line
@@ -424,6 +424,24 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
EXPORT_SYMBOL_GPL(mei_irq_write_handler);


/**
 * mei_connect_timeout  - connect/disconnect timeouts
 *
 * @cl: host client
 */
static void mei_connect_timeout(struct mei_cl *cl)
{
	struct mei_device *dev = cl->dev;

	if (cl->state == MEI_FILE_CONNECTING) {
		if (dev->hbm_f_dot_supported) {
			cl->state = MEI_FILE_DISCONNECT_REQUIRED;
			wake_up(&cl->wait);
			return;
		}
	}
	mei_reset(dev);
}

/**
 * mei_timer - timer function.
@@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work)
		if (cl->timer_count) {
			if (--cl->timer_count == 0) {
				dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
				mei_reset(dev);
				mei_connect_timeout(cl);
				goto out;
			}
		}
Loading