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

Commit 6a66016f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: core: Enable queueing of virtual buffers"

parents ea1825c2 59e76cd8
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -546,7 +546,8 @@ void reset_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
	mhi_log(MHI_MSG_VERBOSE, "Exited\n");
}

static enum MHI_STATUS mhi_queue_xfer(struct mhi_client_handle *client_handle,
static enum MHI_STATUS mhi_queue_dma_xfer(
		struct mhi_client_handle *client_handle,
		dma_addr_t buf, size_t buf_len, enum MHI_FLAGS mhi_flags)
{
	union mhi_xfer_pkt *pkt_loc;
@@ -609,9 +610,8 @@ error:
	pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->plat_dev->dev);
	return ret_val;
}
EXPORT_SYMBOL(mhi_queue_xfer);

int mhi_queue_virt_xfer(struct mhi_client_handle *client_handle,
int mhi_queue_xfer(struct mhi_client_handle *client_handle,
		void *buf, size_t buf_len, enum MHI_FLAGS mhi_flags)
{
	int r;
@@ -640,18 +640,20 @@ int mhi_queue_virt_xfer(struct mhi_client_handle *client_handle,
	   "Queueing to HW: Client Buf 0x%p, size 0x%zx, DMA %llx, chan %d\n",
			buf, buf_len, (u64)bb->bb_p_addr,
			client_handle->chan_info.chan_nr);
	r = mhi_queue_xfer(client_handle,
	r = mhi_queue_dma_xfer(client_handle,
				bb->bb_p_addr,
				bb->buf_len,
				mhi_flags);

	/* Assumption: If create_bb did not fail, we do not
	 * expect mhi_queue_xfer to fail, if it does, the bb list will be
	/*
	 * Assumption: If create_bounce_buffer did not fail, we do not
	 * expect mhi_queue_dma_xfer to fail, if it does, the bb list will be
	 * out of sync with the descriptor list which is problematic.
	 */
	BUG_ON(r);
	return r;
}
EXPORT_SYMBOL(mhi_queue_xfer);

enum MHI_STATUS mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
			enum MHI_COMMAND cmd, u32 chan)
+23 −67
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,6 @@
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/ipc_logging.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>

#define MHI_DEV_NODE_NAME_LEN 13
@@ -115,7 +114,7 @@ struct uci_client {
	int mhi_status;
	void *pkt_loc;
	size_t pkt_size;
	dma_addr_t *in_buf_list;
	void **in_buf_list;
	atomic_t out_pkt_pend_ack;
	atomic_t mhi_disabled;
	struct mhi_uci_ctxt_t *uci_ctxt;
@@ -256,7 +255,6 @@ static enum MHI_STATUS mhi_init_inbound(struct uci_client *client_handle,
{
	enum MHI_STATUS ret_val = MHI_STATUS_SUCCESS;
	u32 i = 0;
	dma_addr_t dma_addr = 0;
	struct chan_attr *chan_attributes =
		&uci_ctxt.chan_attrib[chan];
	void *data_loc = NULL;
@@ -269,7 +267,7 @@ static enum MHI_STATUS mhi_init_inbound(struct uci_client *client_handle,
	chan_attributes->nr_trbs =
			mhi_get_free_desc(client_handle->in_handle);
	client_handle->in_buf_list =
			kmalloc(sizeof(dma_addr_t) * chan_attributes->nr_trbs,
			kmalloc(sizeof(void *) * chan_attributes->nr_trbs,
			GFP_KERNEL);
	if (!client_handle->in_buf_list)
		return MHI_STATUS_ERROR;
@@ -282,18 +280,10 @@ static enum MHI_STATUS mhi_init_inbound(struct uci_client *client_handle,
			data_loc, buf_size);
		if (data_loc == NULL)
			return -ENOMEM;
		dma_addr = dma_map_single(NULL, data_loc,
					buf_size, DMA_FROM_DEVICE);
		if (dma_mapping_error(NULL, dma_addr)) {
			uci_log(UCI_DBG_ERROR, "Failed to Map DMA\n");
			return -ENOMEM;
		}
		client_handle->in_buf_list[i] = dma_addr;
		client_handle->in_buf_list[i] = data_loc;
		ret_val = mhi_queue_xfer(client_handle->in_handle,
					  dma_addr, buf_size, MHI_EOT);
					  data_loc, buf_size, MHI_EOT);
		if (MHI_STATUS_SUCCESS != ret_val) {
			dma_unmap_single(NULL, dma_addr,
					 buf_size, DMA_FROM_DEVICE);
			kfree(data_loc);
			uci_log(UCI_DBG_ERROR,
				"Failed insertion for chan %d, ret %d\n",
@@ -314,7 +304,6 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle,
	int data_left_to_insert = 0;
	size_t data_to_insert_now = 0;
	u32 data_inserted_so_far = 0;
	dma_addr_t dma_addr = 0;
	int ret_val = 0;
	enum MHI_FLAGS flags;
	struct uci_client *uci_handle;
@@ -353,27 +342,19 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle,
			data_loc = buf;
		}

		dma_addr = dma_map_single(NULL, data_loc,
					data_to_insert_now, DMA_TO_DEVICE);
		if (dma_mapping_error(NULL, dma_addr)) {
			uci_log(UCI_DBG_ERROR,
					"Failed to Map DMA 0x%x\n", size);
			data_inserted_so_far = -ENOMEM;
			goto error_memcpy;
		}

		flags = MHI_EOT;
		if (data_left_to_insert - data_to_insert_now > 0)
			flags |= MHI_CHAIN | MHI_EOB;
		uci_log(UCI_DBG_VERBOSE,
			    "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%lx chan %d\n",
			    "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%p chan %d\n",
				i, nr_avail_trbs,
				flags & MHI_CHAIN,
				flags & MHI_EOB,
				(uintptr_t)dma_addr,
				data_loc,
				uci_handle->out_chan);
		ret_val = mhi_queue_xfer(*client_handle, dma_addr,
		ret_val = mhi_queue_xfer(*client_handle, data_loc,
					data_to_insert_now, flags);

		if (0 != ret_val) {
			goto error_queue;
		} else {
@@ -387,10 +368,6 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle,
	return data_inserted_so_far;

error_queue:
	dma_unmap_single(NULL,
		(dma_addr_t)dma_addr,
		data_to_insert_now,
		DMA_TO_DEVICE);
error_memcpy:
	kfree(data_loc);
	return data_inserted_so_far;
@@ -676,10 +653,6 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
		uci_handle->in_chan_state = 0;
		atomic_set(&uci_handle->out_pkt_pend_ack, 0);
		for (i = 0; i < nr_in_bufs; ++i) {
			dma_unmap_single(NULL,
					uci_handle->in_buf_list[i],
					buf_size,
					DMA_FROM_DEVICE);
			kfree((void *)uci_handle->in_buf_list[i]);
		}
		kfree(uci_handle->in_buf_list);
@@ -697,7 +670,6 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
		size_t uspace_buf_size, loff_t *bytes_pending)
{
	struct uci_client *uci_handle = NULL;
	uintptr_t phy_buf = 0;
	struct mhi_client_handle *client_handle = NULL;
	int ret_val = 0;
	size_t buf_size = 0;
@@ -728,19 +700,16 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
				"Failed to poll inbound ret %d avail pkt %d\n",
				ret_val, atomic_read(&uci_handle->avail_pkts));
			}
			phy_buf = result.payload_buf;
			if (phy_buf != 0)
				uci_handle->pkt_loc = (void *)phy_buf;
			if (result.buf_addr)
				uci_handle->pkt_loc = result.buf_addr;
			else
				uci_handle->pkt_loc = 0;
			uci_handle->pkt_size = result.bytes_xferd;
			*bytes_pending = uci_handle->pkt_size;
			uci_log(UCI_DBG_VERBOSE,
				"Got pkt of size 0x%zx at addr 0x%lx, chan %d\n",
				uci_handle->pkt_size, (uintptr_t)phy_buf, chan);
			dma_unmap_single(NULL, (dma_addr_t)phy_buf,
					 buf_size,
					 DMA_FROM_DEVICE);
				"Got pkt size 0x%zx at addr 0x%lx, chan %d\n",
				uci_handle->pkt_size,
				(uintptr_t)result.buf_addr, chan);
		}
		if ((*bytes_pending == 0 || uci_handle->pkt_loc == 0) &&
				(atomic_read(&uci_handle->avail_pkts) <= 0)) {
@@ -774,9 +743,9 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
			   uci_handle->pkt_size != 0 &&
			   uci_handle->pkt_loc != 0) {
			uci_log(UCI_DBG_VERBOSE,
			"Got packet: avail pkts %d phy_adr 0x%lx, chan %d\n",
			"Got packet: avail pkts %d phy_adr 0x%p, chan %d\n",
					atomic_read(&uci_handle->avail_pkts),
					phy_buf,
					result.buf_addr,
					chan);
			break;
			/*
@@ -785,10 +754,10 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
			 */
		} else {
			uci_log(UCI_DBG_CRITICAL,
			"chan %d err: avail pkts %d phy_adr 0x%lx mhi_stat%d\n",
			"chan %d err: avail pkts %d phy_adr 0x%p mhi_stat%d\n",
					chan,
					atomic_read(&uci_handle->avail_pkts),
					phy_buf,
					result.buf_addr,
					uci_handle->mhi_status);
			return -EIO;
		}
@@ -830,16 +799,12 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
		uci_log(UCI_DBG_VERBOSE, "Pkt loc %p ,chan %d\n",
					uci_handle->pkt_loc, chan);
		memset(uci_handle->pkt_loc, 0, buf_size);
		phy_buf = dma_map_single(NULL, uci_handle->pkt_loc,
				buf_size, DMA_FROM_DEVICE);
		atomic_dec(&uci_handle->avail_pkts);
		uci_log(UCI_DBG_VERBOSE,
				"Decremented avail pkts avail 0x%x\n",
				atomic_read(&uci_handle->avail_pkts));

		ret_val = mhi_queue_xfer(client_handle, phy_buf,
		ret_val = mhi_queue_xfer(client_handle, uci_handle->pkt_loc,
					 buf_size, MHI_EOT);

		if (MHI_STATUS_SUCCESS != ret_val) {
			uci_log(UCI_DBG_ERROR,
					"Failed to recycle element\n");
@@ -987,13 +952,11 @@ static void process_rs232_state(struct mhi_result *result)
	}
	if (result->bytes_xferd != sizeof(struct rs232_ctrl_msg)) {
		uci_log(UCI_DBG_ERROR,
		"Buffer is of wrong size is: 0x%x: expected 0x%zx\n",
		"Buffer is of wrong size is: 0x%zx: expected 0x%zx\n",
		result->bytes_xferd, sizeof(struct rs232_ctrl_msg));
		goto error_size;
	}
	dma_unmap_single(NULL, result->payload_buf,
			result->bytes_xferd, DMA_FROM_DEVICE);
	rs232_pkt = (void *)result->payload_buf;
	rs232_pkt = result->buf_addr;
	MHI_GET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, chan);
	client = &uci_ctxt.client_handles[chan / 2];

@@ -1014,11 +977,8 @@ static void process_rs232_state(struct mhi_result *result)
error_bad_xfer:
error_size:
	memset(rs232_pkt, 0, sizeof(struct rs232_ctrl_msg));
	dma_map_single(NULL, rs232_pkt,
			sizeof(struct rs232_ctrl_msg),
			DMA_FROM_DEVICE);
	ret_val = mhi_queue_xfer(client->in_handle,
			result->payload_buf,
			result->buf_addr,
			result->bytes_xferd,
			result->flags);
	if (MHI_STATUS_SUCCESS != ret_val) {
@@ -1044,11 +1004,7 @@ static void parse_inbound_ack(struct uci_client *uci_handle,
static void parse_outbound_ack(struct uci_client *uci_handle,
			struct mhi_result *result)
{
	dma_unmap_single(NULL,
			result->payload_buf,
			result->bytes_xferd,
			DMA_TO_DEVICE);
	kfree((void *) result->payload_buf);
	kfree(result->buf_addr);
	uci_log(UCI_DBG_VERBOSE,
		"Received ack on chan %d, pending acks: 0x%x\n",
		uci_handle->out_chan,
+7 −5
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -113,8 +113,8 @@ enum MHI_FLAGS {

struct mhi_result {
	void *user_data;
	dma_addr_t payload_buf;
	u32 bytes_xferd;
	void *buf_addr;
	size_t bytes_xferd;
	enum MHI_STATUS transaction_status;
	enum MHI_FLAGS flags;
};
@@ -180,12 +180,14 @@ enum MHI_STATUS mhi_open_channel(struct mhi_client_handle *client_handle);
 *  @chain          Specify whether to set the chain bit on this buffer
 *  @eob            Specify whether this buffer should trigger EOB interrupt
 *
 *  NOTE:
 *  Not thread safe, caller must ensure concurrency protection.
 *  User buffer must be physically contiguous.
 *
 * @Return MHI_STATUS
 */
enum MHI_STATUS mhi_queue_xfer(struct mhi_client_handle *client_handle,
		dma_addr_t buf, size_t buf_len, enum MHI_FLAGS flags);
int mhi_queue_xfer(struct mhi_client_handle *client_handle,
		void *buf, size_t buf_len, enum MHI_FLAGS mhi_flags);

/**
 * mhi_close_channel - Client can request channel to be closed and handle freed