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

Commit e3b090ea authored by Rui Miguel Silva's avatar Rui Miguel Silva Committed by Greg Kroah-Hartman
Browse files

greybus: sdio: avoid extra memory operation at data transfer



Right now greybus sdio uses the greybus operation_sync to transfer data,
this will imply an extra memcpy at greybus core that we can avoid.

Also with this change we remove the need for an extra buffer to store
intermediate copy.

So, let us create the operation and do the memory operations in the sdio
driver.

Signed-off-by: default avatarRui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 0698be02
Loading
Loading
Loading
Loading
+45 −35
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ struct gb_sdio_host {
	struct mmc_request	*mrq;
	struct mutex		lock;	/* lock for this host */
	size_t			data_max;
	void			*xfer_buffer;
	spinlock_t		xfer;	/* lock to cancel ongoing transfer */
	bool			xfer_stop;
	struct workqueue_struct	*mrq_workqueue;
@@ -245,7 +244,8 @@ static int _gb_sdio_send(struct gb_sdio_host *host, struct mmc_data *data,
			 size_t len, u16 nblocks, off_t skip)
{
	struct gb_sdio_transfer_request *request;
	struct gb_sdio_transfer_response response;
	struct gb_sdio_transfer_response *response;
	struct gb_operation *operation;
	struct scatterlist *sg = data->sg;
	unsigned int sg_len = data->sg_len;
	size_t copied;
@@ -255,39 +255,51 @@ static int _gb_sdio_send(struct gb_sdio_host *host, struct mmc_data *data,

	WARN_ON(len > host->data_max);

	request = host->xfer_buffer;
	operation = gb_operation_create(host->connection, GB_SDIO_TYPE_TRANSFER,
					len + sizeof(*request),
					sizeof(*response), GFP_KERNEL);
	if (!operation)
		return -ENOMEM;

	request = operation->request->payload;
	request->data_flags = (data->flags >> 8);
	request->data_blocks = cpu_to_le16(nblocks);
	request->data_blksz = cpu_to_le16(data->blksz);

	copied = sg_pcopy_to_buffer(sg, sg_len, &request->data[0], len, skip);

	if (copied != len)
		return -EINVAL;
	if (copied != len) {
		ret = -EINVAL;
		goto err_put_operation;
	}

	ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_TRANSFER,
				request, len + sizeof(*request),
				&response, sizeof(response));
	ret = gb_operation_request_send_sync(operation);
	if (ret < 0)
		return ret;
		goto err_put_operation;

	send_blocks = le16_to_cpu(response.data_blocks);
	send_blksz = le16_to_cpu(response.data_blksz);
	response = operation->response->payload;

	send_blocks = le16_to_cpu(response->data_blocks);
	send_blksz = le16_to_cpu(response->data_blksz);

	if (len != send_blksz * send_blocks) {
		dev_err(mmc_dev(host->mmc), "send: size received: %zu != %d\n",
			len, send_blksz * send_blocks);
		return -EINVAL;
		ret = -EINVAL;
	}

err_put_operation:
	gb_operation_put(operation);

	return ret;
}

static int _gb_sdio_recv(struct gb_sdio_host *host, struct mmc_data *data,
			 size_t len, u16 nblocks, off_t skip)
{
	struct gb_sdio_transfer_request request;
	struct gb_sdio_transfer_request *request;
	struct gb_sdio_transfer_response *response;
	struct gb_operation *operation;
	struct scatterlist *sg = data->sg;
	unsigned int sg_len = data->sg_len;
	size_t copied;
@@ -297,33 +309,41 @@ static int _gb_sdio_recv(struct gb_sdio_host *host, struct mmc_data *data,

	WARN_ON(len > host->data_max);

	request.data_flags = (data->flags >> 8);
	request.data_blocks = cpu_to_le16(nblocks);
	request.data_blksz = cpu_to_le16(data->blksz);
	operation = gb_operation_create(host->connection, GB_SDIO_TYPE_TRANSFER,
					sizeof(*request),
					len + sizeof(*response), GFP_KERNEL);
	if (!operation)
		return -ENOMEM;

	response = host->xfer_buffer;
	request = operation->request->payload;
	request->data_flags = (data->flags >> 8);
	request->data_blocks = cpu_to_le16(nblocks);
	request->data_blksz = cpu_to_le16(data->blksz);

	ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_TRANSFER,
				&request, sizeof(request), response, len +
				sizeof(*response));
	ret = gb_operation_request_send_sync(operation);
	if (ret < 0)
		return ret;
		goto err_put_operation;

	response = operation->response->payload;
	recv_blocks = le16_to_cpu(response->data_blocks);
	recv_blksz = le16_to_cpu(response->data_blksz);

	if (len != recv_blksz * recv_blocks) {
		dev_err(mmc_dev(host->mmc), "recv: size received: %d != %zu\n",
			recv_blksz * recv_blocks, len);
		return -EINVAL;
		ret = -EINVAL;
		goto err_put_operation;
	}

	copied = sg_pcopy_from_buffer(sg, sg_len, &response->data[0], len,
				      skip);
	if (copied != len)
		return -EINVAL;
		ret = -EINVAL;

	return 0;
err_put_operation:
	gb_operation_put(operation);

	return ret;
}

static int gb_sdio_transfer(struct gb_sdio_host *host, struct mmc_data *data)
@@ -720,7 +740,6 @@ static int gb_sdio_probe(struct gbphy_device *gbphy_dev,
	struct gb_connection *connection;
	struct mmc_host *mmc;
	struct gb_sdio_host *host;
	size_t max_buffer;
	int ret = 0;

	mmc = mmc_alloc_host(sizeof(*host), &gbphy_dev->dev);
@@ -760,19 +779,13 @@ static int gb_sdio_probe(struct gbphy_device *gbphy_dev,

	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

	max_buffer = gb_operation_get_payload_size_max(host->connection);
	host->xfer_buffer = kzalloc(max_buffer, GFP_KERNEL);
	if (!host->xfer_buffer) {
		ret = -ENOMEM;
		goto exit_connection_disable;
	}
	mutex_init(&host->lock);
	spin_lock_init(&host->xfer);
	host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1,
					      dev_name(&gbphy_dev->dev));
	if (!host->mrq_workqueue) {
		ret = -ENOMEM;
		goto exit_buf_free;
		goto exit_connection_disable;
	}
	INIT_WORK(&host->mrqwork, gb_sdio_mrq_work);

@@ -791,8 +804,6 @@ static int gb_sdio_probe(struct gbphy_device *gbphy_dev,

exit_wq_destroy:
	destroy_workqueue(host->mrq_workqueue);
exit_buf_free:
	kfree(host->xfer_buffer);
exit_connection_disable:
	gb_connection_disable(connection);
exit_connection_destroy:
@@ -821,7 +832,6 @@ static void gb_sdio_remove(struct gbphy_device *gbphy_dev)
	mmc_remove_host(mmc);
	gb_connection_disable(connection);
	gb_connection_destroy(connection);
	kfree(host->xfer_buffer);
	mmc_free_host(mmc);
}