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

Commit 10711435 authored by Jack Pham's avatar Jack Pham Committed by Gerrit - the friendly Code Review server
Browse files

sound: usb: Use IOMMU_CACHE mapping if USB controller is dma-coherent



If IO coherency for the USB controller is enabled, the shared buffers
need to be remapped with the cached attribute set so that the
controller HW can properly access the memory coherently. Otherwise,
the HW could end up reading stale data from cache.

While at it, remove the dma_sync_* calls, as they were previously
added with the misunderstanding that the APPS needs to force an
invalidation before passing it to the ADSP. This is not required
as long as the coherency settings are matched as there is no need
to manually perform cache maintenance when handing off the buffers.

Change-Id: I3a7ecbd7b7f1c264c64e9f5f82c9d4ec27848dc0
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 613aaf12
Loading
Loading
Loading
Loading
+18 −16
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/soc/qcom/qmi.h>
#include <linux/soc/qcom/qmi.h>
#include <linux/iommu.h>
#include <linux/iommu.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/dma-noncoherent.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/usb/audio-v3.h>
#include <linux/usb/audio-v3.h>
#include <linux/usb/xhci-sec.h>
#include <linux/usb/xhci-sec.h>
@@ -288,8 +289,8 @@ static unsigned long uaudio_get_iova(unsigned long *curr_iova,
	return va;
	return va;
}
}


static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent,
		size_t size, struct sg_table *sgt)
		phys_addr_t pa, size_t size, struct sg_table *sgt)
{
{
	unsigned long va_sg, va = 0;
	unsigned long va_sg, va = 0;
	bool map = true;
	bool map = true;
@@ -299,6 +300,9 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
	phys_addr_t pa_sg;
	phys_addr_t pa_sg;
	int prot = IOMMU_READ | IOMMU_WRITE;
	int prot = IOMMU_READ | IOMMU_WRITE;


	if (dma_coherent)
		prot |= IOMMU_CACHE;

	switch (mtype) {
	switch (mtype) {
	case MEM_EVENT_RING:
	case MEM_EVENT_RING:
		va = IOVA_BASE;
		va = IOVA_BASE;
@@ -342,9 +346,6 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
		}
		}
		uaudio_dbg("memtype %d:map pa:%pK to iova:%lu len:%zu\n", mtype,
		uaudio_dbg("memtype %d:map pa:%pK to iova:%lu len:%zu\n", mtype,
				&pa_sg, va_sg, sg_len);
				&pa_sg, va_sg, sg_len);
		/* Invalidate cpu cache for device to access shared memory */
		dma_sync_single_for_device(uaudio_qdev->dev, va_sg, sg_len,
							DMA_TO_DEVICE);
		va_sg += sg_len;
		va_sg += sg_len;
		total_len += sg_len;
		total_len += sg_len;
	}
	}
@@ -362,14 +363,9 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
			va, size);
			va, size);


	ret = iommu_map(uaudio_qdev->domain, va, pa, size, prot);
	ret = iommu_map(uaudio_qdev->domain, va, pa, size, prot);
	if (ret) {
	if (ret)
		uaudio_err("failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
		uaudio_err("failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
				&pa, va, mtype, ret);
				&pa, va, mtype, ret);
		goto done;
	}

	/* Invalidate cpu cache for device to access shared memory */
	dma_sync_single_for_device(uaudio_qdev->dev, va, size, DMA_TO_DEVICE);
done:
done:
	return va;
	return va;
}
}
@@ -503,6 +499,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
	dma_addr_t dma;
	dma_addr_t dma;
	struct sg_table sgt;
	struct sg_table sgt;
	bool dma_coherent;


	iface = usb_ifnum_to_if(subs->dev, subs->interface);
	iface = usb_ifnum_to_if(subs->dev, subs->interface);
	if (!iface) {
	if (!iface) {
@@ -670,6 +667,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	}
	}


	/* map xhci data structures PA memory to iova */
	/* map xhci data structures PA memory to iova */
	dma_coherent = dev_is_dma_coherent(subs->dev->bus->sysdev);


	/* event ring */
	/* event ring */
	ret = xhci_sec_event_ring_setup(subs->dev, resp->interrupter_num);
	ret = xhci_sec_event_ring_setup(subs->dev, resp->interrupter_num);
@@ -686,7 +684,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
		goto err;
		goto err;
	}
	}


	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, xhci_pa, PAGE_SIZE,
			NULL);
	if (!va) {
	if (!va) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto err;
		goto err;
@@ -707,7 +706,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	resp->speed_info_valid = 1;
	resp->speed_info_valid = 1;


	/* data transfer ring */
	/* data transfer ring */
	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_data_pa,
			PAGE_SIZE, NULL);
	if (!va) {
	if (!va) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto unmap_er;
		goto unmap_er;
@@ -723,7 +723,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
		goto skip_sync;
		goto skip_sync;


	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_sync_pa,
			PAGE_SIZE, NULL);
	if (!va) {
	if (!va) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto unmap_data;
		goto unmap_data;
@@ -758,7 +759,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,


	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
			len);
			len);
	va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
	va = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent, xfer_buf_pa, len,
			&sgt);
	if (!va) {
	if (!va) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto unmap_sync;
		goto unmap_sync;