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

Commit dcd97508 authored by Udaya Bhaskara Reddy Mallavarapu's avatar Udaya Bhaskara Reddy Mallavarapu
Browse files

media: broadcast: tspp: Add SMMU translation for ION buffers



Add SMMU translation for ION buffers to fix the kernel crash observed
while TSPP driver configuring ion buffers to BAM for DMA.

Change-Id: I228701894b3895a06844ef6b0e2bfc8e260ebe13
Signed-off-by: default avatarUdaya Bhaskara Reddy Mallavarapu <udaym@codeaurora.org>
parent 089d1cb5
Loading
Loading
Loading
Loading
+126 −17
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#include <linux/msm-bus.h>
#include <linux/interrupt.h>	/* tasklet */
#include <asm/arch_timer.h> /* Timer */
#include <linux/dma-buf.h>

/*
 * General defines
@@ -495,7 +496,6 @@ struct tspp_device {
	struct tspp_pinctrl pinctrl;
	unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */
	struct dma_iommu_mapping *iommu_mapping;
	bool bypass_s1_smmu;

	struct dentry *dent;
	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
@@ -1068,7 +1068,6 @@ static void tspp_free_key_entry(int entry)
static int tspp_iommu_init(struct tspp_device *device)
{
	struct dma_iommu_mapping *iommu_map;
	int s1_bypass = 1;

	iommu_map = arm_iommu_create_mapping(&platform_bus_type,
						TSPP_SMMU_IOVA_START,
@@ -1077,12 +1076,6 @@ static int tspp_iommu_init(struct tspp_device *device)
		dev_err(&device->pdev->dev, "iommu_create_mapping failure\n");
		return PTR_ERR(iommu_map);
	}
	if (iommu_domain_set_attr(iommu_map->domain,
				  DOMAIN_ATTR_S1_BYPASS, &s1_bypass)) {
		dev_err(&device->pdev->dev, "Can't bypass s1 translation\n");
		arm_iommu_release_mapping(iommu_map);
		return -EIO;
	}
	if (arm_iommu_attach_device(&device->pdev->dev, iommu_map)) {
		dev_err(&device->pdev->dev, "can't arm_iommu_attach_device\n");
		arm_iommu_release_mapping(iommu_map);
@@ -1095,7 +1088,7 @@ static int tspp_iommu_init(struct tspp_device *device)

static void tspp_iommu_release_iomapping(struct tspp_device *device)
{
	if (device->bypass_s1_smmu && device->iommu_mapping)
	if (device->iommu_mapping)
		arm_iommu_release_mapping(device->iommu_mapping);

	device->iommu_mapping = NULL;
@@ -1113,7 +1106,7 @@ static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
	if (alloc) {
		TSPP_DEBUG("tspp using alloc function");
		desc->virt_base = alloc(channel_id, size,
			&desc->phys_base, user);
			&desc->phys_base, &desc->dma_base, user);
	} else {
		if (!dma_pool)
			desc->virt_base = dma_alloc_coherent(NULL, size,
@@ -2605,7 +2598,8 @@ int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
		desc->next = channel->data;

		/* prepare the sps descriptor */
		desc->sps.phys_base = desc->desc.phys_base;
		desc->sps.phys_base = ((alloc != NULL) ? desc->desc.dma_base :
				       desc->desc.phys_base);
		desc->sps.base = desc->desc.virt_base;
		desc->sps.size = desc->desc.size;

@@ -2643,6 +2637,121 @@ int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
}
EXPORT_SYMBOL(tspp_allocate_buffers);

/**
 * tspp_attach_ion_dma_buff- attach ion dma buffer to TSPP device
 * It will attach the DMA buffer to TSPP device to go through SMMU.
 *
 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
 * @ion_dma_buf: It contains required members for ION buffer dma mapping.
 *
 * Return  error status
 *
 */
int tspp_attach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
{
	struct tspp_device *pdev;
	int dir = DMA_FROM_DEVICE;
	int ret = -1;

	if (NULL == ion_dma_buf || NULL == ion_dma_buf->dbuf) {
		pr_err("tspp: invalid input argument");
		return -EINVAL;
	}

	if (dev >= TSPP_MAX_DEVICES) {
		pr_err("tspp: device id out of range");
		return -ENODEV;
	}

	pdev = tspp_find_by_id(dev);
	if (!pdev) {
		pr_err("tspp: can't find device %i", dev);
		return -ENODEV;
	}

	ion_dma_buf->attach = dma_buf_attach(ion_dma_buf->dbuf,
					&pdev->pdev->dev);
	if (IS_ERR_OR_NULL(ion_dma_buf->attach)) {
		dev_err(&pdev->pdev->dev, "%s: dma_buf_attach fail", __func__);
		return -ENODEV;
	}
	ion_dma_buf->table = dma_buf_map_attachment(ion_dma_buf->attach, dir);
	if (IS_ERR_OR_NULL(ion_dma_buf->table)) {
		dev_err(&pdev->pdev->dev, "dma_buf_map_attachment fail");
		dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
		return -ENODEV;
	}
	ret = dma_map_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
				ion_dma_buf->table->nents, dir);
	if (ret <= 0) {
		dev_err(&pdev->pdev->dev, "dma_map_sg failed! ret=%d\n", ret);
		goto unmap_attachment;
	}
	if (ion_dma_buf->table->nents > 1) {
		dev_err(&pdev->pdev->dev, "no of sg table entries %d > 1\n",
			ion_dma_buf->table->nents);
		goto unmap_attachment;
	}

	ion_dma_buf->dma_map_base = sg_dma_address(ion_dma_buf->table->sgl);
	ion_dma_buf->smmu_map = true;
	return 0;

unmap_attachment:
	dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
	dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
	dma_buf_put(ion_dma_buf->dbuf);

	return ret;
}
EXPORT_SYMBOL(tspp_attach_ion_dma_buff);

/**
 * tspp_detach_ion_dma_buff - detach the mapped ion dma buffer from TSPP device
 * It will detach previously mapped DMA buffer from TSPP device.
 *
 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
 * @ion_dma_buf: It contains required members for ION buffer dma mapping.
 *
 * Return  error status
 *
 */
int tspp_detach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
{
	struct tspp_device *pdev;
	int dir = DMA_FROM_DEVICE;

	if (ion_dma_buf == NULL || ion_dma_buf->dbuf == NULL ||
	    ion_dma_buf->table == NULL || ion_dma_buf->table->sgl == NULL ||
	    ion_dma_buf->smmu_map == false) {
		pr_err("tspp: invalid input argument");
		return -EINVAL;
	}

	if (dev >= TSPP_MAX_DEVICES) {
		pr_err("tspp: device id out of range");
		return -ENODEV;
	}

	pdev = tspp_find_by_id(dev);
	if (!pdev) {
		pr_err("tspp: can't find device %i", dev);
		return -ENODEV;
	}


	dma_unmap_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
			ion_dma_buf->table->nents, dir);
	dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
	dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
	dma_buf_put(ion_dma_buf->dbuf);

	ion_dma_buf->smmu_map = false;
	return 0;
}
EXPORT_SYMBOL(tspp_detach_ion_dma_buff);


/*** debugfs ***/
static int debugfs_iomem_x32_set(void *data, u64 val)
{
@@ -3002,13 +3111,10 @@ static int msm_tspp_probe(struct platform_device *pdev)
		goto err_irq;
	device->req_irqs = false;

	if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass")) {
		device->bypass_s1_smmu = true;
	if (tspp_iommu_init(device)) {
		dev_err(&pdev->dev, "iommu init failed");
		goto err_iommu;
	}
	}

	device->tts_source = TSIF_TTS_TCR;
	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
@@ -3152,6 +3258,9 @@ static int msm_tspp_remove(struct platform_device *pdev)
	if (device->tsif_vreg)
		regulator_disable(device->tsif_vreg);

	tspp_iommu_release_iomapping(device);
	arm_iommu_detach_device(&pdev->dev);

	pm_runtime_disable(&pdev->dev);

	kfree(device);
+32 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
#include <linux/dma-buf.h>
#include <linux/qcom_tspp.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
@@ -189,6 +190,10 @@ static struct

		/* Mutex protecting the data-structure */
		struct mutex mutex;

		/* ion dma buffer mapping structure */
		struct tspp_ion_dma_buf_info ch_ion_dma_buf;

	} tsif[TSIF_COUNT];

	/* ION client used for TSPP data buffer allocation */
@@ -196,7 +201,8 @@ static struct
} mpq_dmx_tspp_info;

static void *tspp_mem_allocator(int channel_id, u32 size,
				phys_addr_t *phys_base, void *user)
				phys_addr_t *phys_base, dma_addr_t *dma_base,
				void *user)
{
	void *virt_addr = NULL;
	int i = TSPP_GET_TSIF_NUM(channel_id);
@@ -213,6 +219,10 @@ static void *tspp_mem_allocator(int channel_id, u32 size,
		(mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base +
		(mpq_dmx_tspp_info.tsif[i].buff_index * size));

	*dma_base =
		(mpq_dmx_tspp_info.tsif[i].ch_ion_dma_buf.dma_map_base +
		(mpq_dmx_tspp_info.tsif[i].buff_index * size));

	mpq_dmx_tspp_info.tsif[i].buff_index++;

	return virt_addr;
@@ -539,6 +549,9 @@ static void mpq_dmx_channel_mem_free(int tsif)

	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL;
	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL;

	tspp_detach_ion_dma_buff(0,
		&mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
}

/**
@@ -589,6 +602,24 @@ static int mpq_dmx_channel_mem_alloc(int tsif)
		return -ENOMEM;
	}

	mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf = ion_share_dma_buf(
			mpq_dmx_tspp_info.ion_client,
			mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle);
	if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf)) {
		MPQ_DVB_ERR_PRINT("%s: ion_share_dma_buf failed\n", __func__);
		mpq_dmx_channel_mem_free(tsif);
		return -ENOMEM;
	}

	result = tspp_attach_ion_dma_buff(0,
				&mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
	if (result) {
		MPQ_DVB_ERR_PRINT("%s: tspp_attach_ion_dma_buff failed\n",
					 __func__);
		mpq_dmx_channel_mem_free(tsif);
		return result;
	}

	return 0;
}

+15 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
struct tspp_data_descriptor {
	void *virt_base;   /* logical address of the actual data */
	phys_addr_t phys_base; /* physical address of the actual data */
	dma_addr_t dma_base; /* DMA address of the actual data */
	u32 size;          /* size of buffer in bytes */
	int id;            /* unique identifier */
	void *user;        /* user-defined data */
@@ -75,9 +76,17 @@ enum tsif_tts_source {
	TSIF_TTS_LPASS_TIMER	/* Time stamps from AV/Qtimer Timer  */
};

struct tspp_ion_dma_buf_info {
	struct dma_buf *dbuf;
	struct dma_buf_attachment *attach;
	struct sg_table *table;
	bool smmu_map;
	dma_addr_t dma_map_base;
};

typedef void (tspp_notifier)(int channel_id, void *user);
typedef void* (tspp_allocator)(int channel_id, u32 size,
	phys_addr_t *phys_base, void *user);
	      phys_addr_t *phys_base, dma_addr_t *dma_base, void *user);
typedef void (tspp_memfree)(int channel_id, u32 size,
	void *virt_base, phys_addr_t phys_base, void *user);

@@ -105,4 +114,9 @@ int tspp_get_tts_source(u32 dev, int *tts_source);
int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
			u64 *lpass_time_counter);

int tspp_attach_ion_dma_buff(u32 dev,
	struct tspp_ion_dma_buf_info *ion_dma_buf);

int tspp_detach_ion_dma_buff(u32 dev,
	struct tspp_ion_dma_buf_info *ion_dma_buf);
#endif /* _MSM_TSPP_H_ */