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

Commit fb1cd47a authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mhi_dev: add dma support for mhi"

parents 56a32ab1 eac790dd
Loading
Loading
Loading
Loading
+520 −90

File changed.

Preview size limit exceeded, changes collapsed.

+27 −50
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, 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
@@ -561,6 +561,9 @@ struct mhi_dev {
	/* Use IPA DMA for Software channel data transfer */
	bool				use_ipa;

	/* Use  PCI eDMA for data transfer */
	bool				use_edma;

	/* iATU is required to map control and data region */
	bool				config_iatu;

@@ -572,6 +575,22 @@ struct mhi_dev {
	bool				mhi_int_en;
	/* Registered client callback list */
	struct list_head		client_cb_list;
	/* Tx, Rx DMA channels */
	struct dma_chan			*tx_dma_chan;
	struct dma_chan			*rx_dma_chan;

	int (*device_to_host)(uint64_t dst_pa, void *src, uint32_t len,
				struct mhi_dev *mhi, struct mhi_req *req);

	int (*host_to_device)(void *device, uint64_t src_pa, uint32_t len,
				struct mhi_dev *mhi, struct mhi_req *mreq);

	void (*write_to_host)(struct mhi_dev *mhi,
			struct mhi_addr *mhi_transfer, struct event_req *ereq,
			enum mhi_dev_transfer_type type);

	void (*read_from_host)(struct mhi_dev *mhi,
				struct mhi_addr *mhi_transfer);

	struct kobj_uevent_env		kobj_env;
};
@@ -605,6 +624,8 @@ extern void *mhi_ipc_log;
/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 used for internal only */
#define MHI_DEV_UEVENT_CTRL	0

#define MHI_USE_DMA(mhi) (mhi->use_ipa || mhi->use_edma)

struct mhi_dev_uevent_info {
	enum mhi_client_channel	channel;
	enum mhi_ctrl_info	ctrl_info;
@@ -683,57 +704,13 @@ int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, uint32_t offset);
int mhi_dev_add_element(struct mhi_dev_ring *ring,
				union mhi_dev_ring_element_type *element,
				struct event_req *ereq, int evt_offset);
/**
 * mhi_transfer_device_to_host() - memcpy equivalent API to transfer data
 *		from device to the host.
 * @dst_pa:	Physical destination address.
 * @src:	Source virtual address.
 * @len:	Numer of bytes to be transferred.
 * @mhi:	MHI dev structure.
 * @req:        mhi_req structure
 */
int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len,
				struct mhi_dev *mhi, struct mhi_req *req);

/**
 * mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data
 *		from host to the device.
 * @dst:	Physical destination virtual address.
 * @src_pa:	Source physical address.
 * @len:	Numer of bytes to be transferred.
 * @mhi:	MHI dev structure.
 * @req:        mhi_req structure
 */
int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len,
				struct mhi_dev *mhi, struct mhi_req *mreq);

/**
 * mhi_dev_write_to_host() - Transfer data from device to host.
 *		Based on support available, either IPA DMA or memcpy is used.
 * @host:	Host and device address details.
 * @buf:	Data buffer that needs to be written to the host.
 * @size:	Data buffer size.
 */
void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer,
		struct event_req *ereq, enum mhi_dev_transfer_type type);
/**
 * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
 *		from host to device.
 * @host:	Host and device address details.
 * @buf:	Data buffer that needs to be read from the host.
 * @size:	Data buffer size.
 */
void mhi_dev_read_from_host(struct mhi_dev *mhi,
				struct mhi_addr *mhi_transfer);

/**
 * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
 *		from host to device.
 * @host:	Host and device address details.
 * @buf:	Data buffer that needs to be read from the host.
 * @size:	Data buffer size.
/*
 * mhi_ring_set_cb () - Call back function of the ring.
 *
 * @ring:	Ring for the respective context - Channel/Event/Command.
 * @ring_cb:	callback function.
 */

void mhi_ring_set_cb(struct mhi_dev_ring *ring,
			void (*ring_cb)(struct mhi_dev *dev,
			union mhi_dev_ring_element_type *el, void *ctx));
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, 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
@@ -175,7 +175,7 @@ static void mhi_dev_net_process_queue_packets(struct work_struct *work)
		wreq->buf = skb->data;
		wreq->len = skb->len;
		wreq->chan = client->in_chan;
		wreq->mode = IPA_DMA_ASYNC;
		wreq->mode = DMA_ASYNC;
		if (skb_queue_empty(&client->tx_buffers) ||
				list_empty(&client->wr_req_buffers)) {
			wreq->snd_cmpl = 1;
@@ -298,7 +298,7 @@ static ssize_t mhi_dev_net_client_read(struct mhi_dev_net_client *mhi_handle)
		req->buf = skb->data;
		req->len = MHI_NET_DEFAULT_MTU;
		req->context = skb;
		req->mode = IPA_DMA_ASYNC;
		req->mode = DMA_ASYNC;
		bytes_avail = mhi_dev_read_channel(req);

		if (bytes_avail < 0) {
+17 −11
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, 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
@@ -45,9 +45,12 @@ int mhi_dev_fetch_ring_elements(struct mhi_dev_ring *ring,
					uint32_t start, uint32_t end)
{
	struct mhi_addr host_addr;
	struct mhi_dev *mhi_ctx;

	mhi_ctx = ring->mhi_dev;

	/* fetch ring elements from start->end, take care of wrap-around case */
	if (ring->mhi_dev->use_ipa) {
	if (MHI_USE_DMA(mhi_ctx)) {
		host_addr.host_pa = ring->ring_shadow.host_pa
			+ sizeof(union mhi_dev_ring_element_type) * start;
		host_addr.phy_addr = ring->ring_cache_dma_handle +
@@ -59,12 +62,12 @@ int mhi_dev_fetch_ring_elements(struct mhi_dev_ring *ring,
	}
	host_addr.size = (end-start) * sizeof(union mhi_dev_ring_element_type);
	if (start < end) {
		mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
		mhi_ctx->read_from_host(ring->mhi_dev, &host_addr);
	} else if (start > end) {
		/* copy from 'start' to ring end, then ring start to 'end'*/
		host_addr.size = (ring->ring_size-start) *
					sizeof(union mhi_dev_ring_element_type);
		mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
		mhi_ctx->read_from_host(ring->mhi_dev, &host_addr);
		if (end) {
			/* wrapped around */
			host_addr.device_pa = ring->ring_shadow.device_pa;
@@ -74,7 +77,8 @@ int mhi_dev_fetch_ring_elements(struct mhi_dev_ring *ring,
			host_addr.phy_addr = ring->ring_cache_dma_handle;
			host_addr.size = (end *
				sizeof(union mhi_dev_ring_element_type));
			mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
			mhi_ctx->read_from_host(ring->mhi_dev,
							&host_addr);
		}
	}
	return 0;
@@ -276,9 +280,11 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
	struct mhi_addr host_addr;
	uint32_t num_elem = 1;
	uint32_t num_free_elem;
	struct mhi_dev *mhi_ctx;

	if (WARN_ON(!ring || !element))
		return -EINVAL;
	mhi_ctx = ring->mhi_dev;

	mhi_dev_update_wr_offset(ring);

@@ -314,7 +320,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
	 * iomap of the ring_base for memcpy
	 */

	if (ring->mhi_dev->use_ipa)
	if (MHI_USE_DMA(mhi_ctx))
		host_addr.host_pa = ring->ring_shadow.host_pa +
			sizeof(union mhi_dev_ring_element_type) * old_offset;
	else
@@ -331,7 +337,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
		mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset);
		mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type);

		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
		mhi_ctx->write_to_host(ring->mhi_dev, &host_addr,
			NULL, MHI_DEV_DMA_SYNC);
		return 0;
	}
@@ -341,25 +347,25 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
		/* No wrap-around case */
		host_addr.virt_addr = element;
		host_addr.size = size;
		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
		mhi_ctx->write_to_host(ring->mhi_dev, &host_addr,
			ereq, MHI_DEV_DMA_ASYNC);
	} else {
		/* Wrap-around case - first chunk uses dma sync */
		host_addr.virt_addr = element;
		host_addr.size = (ring->ring_size - old_offset) *
			sizeof(union mhi_dev_ring_element_type);
		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
		mhi_ctx->write_to_host(ring->mhi_dev, &host_addr,
			NULL, MHI_DEV_DMA_SYNC);

		/* Copy remaining elements */
		if (ring->mhi_dev->use_ipa)
		if (MHI_USE_DMA(mhi_ctx))
			host_addr.host_pa = ring->ring_shadow.host_pa;
		else
			host_addr.device_va = ring->ring_shadow.device_va;
		host_addr.virt_addr = element + (ring->ring_size - old_offset);
		host_addr.size = ring->rd_offset *
			sizeof(union mhi_dev_ring_element_type);
		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
		mhi_ctx->write_to_host(ring->mhi_dev, &host_addr,
			ereq, MHI_DEV_DMA_ASYNC);
	}
	return 0;
+21 −16
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, 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
@@ -445,36 +445,41 @@ static int mhi_sm_change_to_M0(void)

	old_state = mhi_sm_ctx->mhi_state;

	if (old_state == MHI_DEV_M0_STATE) {
	switch (old_state) {
	case MHI_DEV_M0_STATE:
		MHI_SM_DBG("Nothing to do, already in M0 state\n");
		res = 0;
		goto exit;
	} else if (old_state == MHI_DEV_M3_STATE ||
				old_state == MHI_DEV_READY_STATE) {
		/*  Retrieve MHI configuration*/
		res = mhi_dev_config_outbound_iatu(mhi_sm_ctx->mhi_dev);
		if (res) {
			MHI_SM_ERR("Fail to configure iATU, returned %d\n",
			res);
			goto exit;
		}
	case MHI_DEV_M3_STATE:
	case MHI_DEV_READY_STATE:
		res = ep_pcie_get_msi_config(mhi_sm_ctx->mhi_dev->phandle,
			&cfg);
		if (res) {
			MHI_SM_ERR("Error retrieving pcie msi logic\n");
			goto exit;
		}
		if (mhi_sm_ctx->mhi_dev->use_ipa) {
			/*  Retrieve MHI configuration*/
			res = mhi_dev_config_outbound_iatu(mhi_sm_ctx->mhi_dev);
			if (res) {
				MHI_SM_ERR("Fail to configure iATU, ret: %d\n",
									res);
				goto exit;
			}

			res = mhi_pcie_config_db_routing(mhi_sm_ctx->mhi_dev);
			if (res) {
				MHI_SM_ERR("Error configuring db routing\n");
				goto exit;

			}
	} else {
		}
		break;
	default:
		MHI_SM_ERR("unexpected old_state: %s\n",
			mhi_sm_mstate_str(old_state));
		goto exit;
	}

	mhi_sm_mmio_set_mhistatus(MHI_DEV_M0_STATE);

	/* Tell the host, device move to M0 */
Loading