diff options
Diffstat (limited to 'drivers/misc/mei/client.c')
| -rw-r--r-- | drivers/misc/mei/client.c | 128 | 
1 files changed, 80 insertions, 48 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 8d6197a88b54..4ab6251d418e 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -863,10 +863,12 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,  	int slots;  	int ret; -	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); +	msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request));  	slots = mei_hbuf_empty_slots(dev); +	if (slots < 0) +		return -EOVERFLOW; -	if (slots < msg_slots) +	if ((u32)slots < msg_slots)  		return -EMSGSIZE;  	ret = mei_cl_send_disconnect(cl, cb); @@ -1053,13 +1055,15 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,  	int slots;  	int rets; -	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); -	slots = mei_hbuf_empty_slots(dev); -  	if (mei_cl_is_other_connecting(cl))  		return 0; -	if (slots < msg_slots) +	msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request)); +	slots = mei_hbuf_empty_slots(dev); +	if (slots < 0) +		return -EOVERFLOW; + +	if ((u32)slots < msg_slots)  		return -EMSGSIZE;  	rets = mei_cl_send_connect(cl, cb); @@ -1294,10 +1298,12 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,  	int ret;  	bool request; -	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); +	msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request));  	slots = mei_hbuf_empty_slots(dev); +	if (slots < 0) +		return -EOVERFLOW; -	if (slots < msg_slots) +	if ((u32)slots < msg_slots)  		return -EMSGSIZE;  	request = mei_cl_notify_fop2req(cb->fop_type); @@ -1533,6 +1539,23 @@ nortpm:  }  /** + * mei_msg_hdr_init - initialize mei message header + * + * @mei_hdr: mei message header + * @cb: message callback structure + */ +static void mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *cb) +{ +	mei_hdr->host_addr = mei_cl_host_addr(cb->cl); +	mei_hdr->me_addr = mei_cl_me_id(cb->cl); +	mei_hdr->length = 0; +	mei_hdr->reserved = 0; +	mei_hdr->msg_complete = 0; +	mei_hdr->dma_ring = 0; +	mei_hdr->internal = cb->internal; +} + +/**   * mei_cl_irq_write - write a message to device   *	from the interrupt thread context   * @@ -1548,9 +1571,10 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,  	struct mei_device *dev;  	struct mei_msg_data *buf;  	struct mei_msg_hdr mei_hdr; +	size_t hdr_len = sizeof(mei_hdr);  	size_t len; -	u32 msg_slots; -	int slots; +	size_t hbuf_len; +	int hbuf_slots;  	int rets;  	bool first_chunk; @@ -1572,40 +1596,41 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,  		return 0;  	} -	slots = mei_hbuf_empty_slots(dev);  	len = buf->size - cb->buf_idx; -	msg_slots = mei_data2slots(len); +	hbuf_slots = mei_hbuf_empty_slots(dev); +	if (hbuf_slots < 0) { +		rets = -EOVERFLOW; +		goto err; +	} -	mei_hdr.host_addr = mei_cl_host_addr(cl); -	mei_hdr.me_addr = mei_cl_me_id(cl); -	mei_hdr.reserved = 0; -	mei_hdr.internal = cb->internal; +	hbuf_len = mei_slots2data(hbuf_slots); -	if (slots >= msg_slots) { +	mei_msg_hdr_init(&mei_hdr, cb); + +	/** +	 * Split the message only if we can write the whole host buffer +	 * otherwise wait for next time the host buffer is empty. +	 */ +	if (len + hdr_len <= hbuf_len) {  		mei_hdr.length = len;  		mei_hdr.msg_complete = 1; -	/* Split the message only if we can write the whole host buffer */ -	} else if (slots == dev->hbuf_depth) { -		msg_slots = slots; -		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); -		mei_hdr.length = len; -		mei_hdr.msg_complete = 0; +	} else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) { +		mei_hdr.length = hbuf_len - hdr_len;  	} else { -		/* wait for next time the host buffer is empty */  		return 0;  	}  	cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n",  			cb->buf.size, cb->buf_idx); -	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); +	rets = mei_write_message(dev, &mei_hdr, hdr_len, +				 buf->data + cb->buf_idx, mei_hdr.length);  	if (rets)  		goto err;  	cl->status = 0;  	cl->writing_state = MEI_WRITING;  	cb->buf_idx += mei_hdr.length; -	cb->completed = mei_hdr.msg_complete == 1;  	if (first_chunk) {  		if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { @@ -1634,13 +1659,16 @@ err:   *   * Return: number of bytes sent on success, <0 on failure.   */ -int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) +ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)  {  	struct mei_device *dev;  	struct mei_msg_data *buf;  	struct mei_msg_hdr mei_hdr; -	int size; -	int rets; +	size_t hdr_len = sizeof(mei_hdr); +	size_t len; +	size_t hbuf_len; +	int hbuf_slots; +	ssize_t rets;  	bool blocking;  	if (WARN_ON(!cl || !cl->dev)) @@ -1652,52 +1680,57 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)  	dev = cl->dev;  	buf = &cb->buf; -	size = buf->size; +	len = buf->size;  	blocking = cb->blocking; -	cl_dbg(dev, cl, "size=%d\n", size); +	cl_dbg(dev, cl, "len=%zd\n", len);  	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); +		cl_err(dev, cl, "rpm: get failed %zd\n", rets);  		goto free;  	}  	cb->buf_idx = 0;  	cl->writing_state = MEI_IDLE; -	mei_hdr.host_addr = mei_cl_host_addr(cl); -	mei_hdr.me_addr = mei_cl_me_id(cl); -	mei_hdr.reserved = 0; -	mei_hdr.msg_complete = 0; -	mei_hdr.internal = cb->internal;  	rets = mei_cl_tx_flow_ctrl_creds(cl);  	if (rets < 0)  		goto err; +	mei_msg_hdr_init(&mei_hdr, cb); +  	if (rets == 0) {  		cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); -		rets = size; +		rets = len;  		goto out;  	} +  	if (!mei_hbuf_acquire(dev)) {  		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); -		rets = size; +		rets = len;  		goto out;  	} -	/* Check for a maximum length */ -	if (size > mei_hbuf_max_len(dev)) { -		mei_hdr.length = mei_hbuf_max_len(dev); -		mei_hdr.msg_complete = 0; -	} else { -		mei_hdr.length = size; +	hbuf_slots = mei_hbuf_empty_slots(dev); +	if (hbuf_slots < 0) { +		rets = -EOVERFLOW; +		goto out; +	} + +	hbuf_len = mei_slots2data(hbuf_slots); + +	if (len + hdr_len <= hbuf_len) { +		mei_hdr.length = len;  		mei_hdr.msg_complete = 1; +	} else { +		mei_hdr.length = hbuf_len - hdr_len;  	} -	rets = mei_write_message(dev, &mei_hdr, buf->data); +	rets = mei_write_message(dev, &mei_hdr, hdr_len, +				 buf->data, mei_hdr.length);  	if (rets)  		goto err; @@ -1707,7 +1740,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)  	cl->writing_state = MEI_WRITING;  	cb->buf_idx = mei_hdr.length; -	cb->completed = mei_hdr.msg_complete == 1;  out:  	if (mei_hdr.msg_complete) @@ -1735,7 +1767,7 @@ out:  		}  	} -	rets = size; +	rets = buf->size;  err:  	cl_dbg(dev, cl, "rpm: autosuspend\n");  	pm_runtime_mark_last_busy(dev->dev);  |