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

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

Merge "msm: kgsl: Refactor MMU/IOMMU support"

parents 3d58bb66 a8d79f9c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -40,3 +40,7 @@ config MSM_ADRENO_DEFAULT_GOVERNOR
	default "msm-adreno-tz" if DEVFREQ_GOV_MSM_ADRENO_TZ
	default "simple_ondemand"
	depends on MSM_KGSL

config MSM_KGSL_IOMMU
	bool
	default y if MSM_KGSL && (MSM_IOMMU || ARM_SMMU)
+2 −2
Original line number Diff line number Diff line
@@ -9,10 +9,10 @@ msm_kgsl_core-y = \
	kgsl_pwrctrl.o \
	kgsl_pwrscale.o \
	kgsl_mmu.o \
	kgsl_iommu.o \
	kgsl_snapshot.o \
	kgsl_events.o

msm_kgsl_core-$(CONFIG_MSM_KGSL_IOMMU) += kgsl_iommu.o
msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
@@ -35,9 +35,9 @@ msm_adreno-y += \
	adreno_sysfs.o \
	adreno.o \
	adreno_cp_parser.o \
	adreno_iommu.o \
	adreno_perfcounter.o

msm_adreno-$(CONFIG_MSM_KGSL_IOMMU) += adreno_iommu.o
msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o adreno_profile.o
msm_adreno-$(CONFIG_COMPAT) += adreno_compat.o

+8 −200
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include "kgsl_trace.h"

#include "adreno.h"
#include "adreno_iommu.h"
#include "adreno_compat.h"
#include "adreno_pm4types.h"
#include "adreno_trace.h"
@@ -69,8 +70,6 @@ static struct devfreq_msm_adreno_tz_data adreno_tz_data = {

static const struct kgsl_functable adreno_functable;

static struct kgsl_iommu device_3d0_iommu;

static struct adreno_device device_3d0 = {
	.dev = {
		KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
@@ -236,164 +235,6 @@ int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset,
	return 0;
}

/*
 * adreno_iommu_cb_probe() - Adreno iommu context bank probe
 *
 * Iommu context bank probe function.
 */
static int adreno_iommu_cb_probe(struct platform_device *pdev)
{
	struct kgsl_iommu_context *ctx = NULL;
	struct device_node *node = pdev->dev.of_node;
	struct kgsl_iommu *iommu = &device_3d0_iommu;
	int ret = 0;

	/* Map context names from dt to id's */
	if (!strcmp("gfx3d_user", node->name)) {
		ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
		ctx->id = KGSL_IOMMU_CONTEXT_USER;
		ctx->cb_num = -1;
	} else if (!strcmp("gfx3d_secure", node->name)) {
		ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE];
		ctx->id = KGSL_IOMMU_CONTEXT_SECURE;
		ctx->cb_num = -1;
		device_3d0.dev.mmu.secured = true;
	} else {
		KGSL_CORE_ERR("dt: Unknown context label %s\n", node->name);
		return -EINVAL;
	}

	if (ctx->name != NULL) {
		KGSL_CORE_ERR("dt: %s appears multiple times\n", node->name);
		return -EINVAL;
	}
	ctx->name = node->name;

	/* this property won't be found for all context banks */
	if (of_property_read_u32(node, "qcom,gpu-offset",
				&ctx->gpu_offset))
		ctx->gpu_offset = UINT_MAX;

	ctx->kgsldev = &device_3d0.dev;

	/* arm-smmu driver we'll have the right device pointer here. */
	if (of_find_property(node, "iommus", NULL)) {
		ctx->dev = &pdev->dev;
	} else {
		/*
		 * old iommu driver requires that we query the context bank
		 * device rather than getting it from dt.
		 */
		ctx->dev = kgsl_mmu_get_ctx(ctx->name);
		if (IS_ERR_OR_NULL(ctx->dev)) {
			ret = (ctx->dev == NULL) ? -ENODEV : PTR_ERR(ctx->dev);
			KGSL_CORE_ERR("ctx %s: kgsl_mmu_get_ctx err: %d\n",
					ctx->name, ret);
			return ret;
		}
	}

	kgsl_mmu_set_mmutype(KGSL_MMU_TYPE_IOMMU);

	return ret;
}

static struct of_device_id iommu_match_table[] = {
	{ .compatible = "qcom,kgsl-smmu-v1", },
	{ .compatible = "qcom,kgsl-smmu-v2", },
	{ .compatible = "qcom,smmu-kgsl-cb", },
	{}
};

/**
 * adreno_iommu_pdev_probe() - Adreno iommu context bank probe
 * @pdev: Platform device
 *
 * Iommu probe function.
 */
static int adreno_iommu_pdev_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	const char *cname;
	struct property *prop;
	u32 reg_val[2];
	int i = 0;
	struct kgsl_iommu *iommu = &device_3d0_iommu;

	if (of_device_is_compatible(dev->of_node, "qcom,smmu-kgsl-cb"))
		return adreno_iommu_cb_probe(pdev);
	else if (of_device_is_compatible(dev->of_node, "qcom,kgsl-smmu-v1"))
		iommu->version = 1;
	else
		iommu->version = 2;

	if (of_property_read_u32_array(pdev->dev.of_node, "reg", reg_val, 2)) {
		KGSL_CORE_ERR("dt: Unable to read KGSL IOMMU register range\n");
		return -EINVAL;
	}
	iommu->regstart = reg_val[0];
	iommu->regsize = reg_val[1];

	/* Protecting the SMMU registers is mandatory */
	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,protect",
					reg_val, 2)) {
		KGSL_CORE_ERR("dt: no iommu protection range specified\n");
		return -EINVAL;
	}
	iommu->protect.base = reg_val[0] / sizeof(u32);
	iommu->protect.range = ilog2(reg_val[1] / sizeof(u32));

	of_property_for_each_string(dev->of_node, "clock-names", prop, cname) {
		struct clk *c = devm_clk_get(dev, cname);
		if (IS_ERR(c)) {
			KGSL_CORE_ERR("dt: Couldn't get clock: %s\n", cname);
			return -ENODEV;
		}
		if (i >= KGSL_IOMMU_MAX_CLKS) {
			KGSL_CORE_ERR("dt: too many clocks defined.\n");
			return -EINVAL;
		}

		iommu->clks[i] = c;
		++i;
	}

	if (of_property_read_bool(pdev->dev.of_node, "qcom,retention"))
		device_3d0.dev.mmu.features |= KGSL_MMU_RETENTION;

	if (of_property_read_bool(pdev->dev.of_node, "qcom,global_pt"))
		device_3d0.dev.mmu.features |= KGSL_MMU_GLOBAL_PAGETABLE;

	if (of_property_read_bool(pdev->dev.of_node, "qcom,hyp_secure_alloc"))
		device_3d0.dev.mmu.features |= KGSL_MMU_HYP_SECURE_ALLOC;

	if (of_property_read_bool(pdev->dev.of_node, "qcom,force-32bit"))
		device_3d0.dev.mmu.features |= KGSL_MMU_FORCE_32BIT;

	if (of_property_read_u32(pdev->dev.of_node, "qcom,micro-mmu-control",
				&iommu->micro_mmu_ctrl))
		iommu->micro_mmu_ctrl = UINT_MAX;

	if (of_property_read_bool(pdev->dev.of_node, "qcom,coherent-htw"))
		device_3d0.dev.mmu.features |= KGSL_MMU_COHERENT_HTW;

	if (of_property_read_u32(pdev->dev.of_node, "qcom,secure_align_mask",
		&device_3d0.dev.mmu.secure_align_mask))
		device_3d0.dev.mmu.secure_align_mask = 0xfff;

	return of_platform_populate(pdev->dev.of_node, iommu_match_table,
					NULL, &pdev->dev);
}

static struct platform_driver kgsl_iommu_platform_driver = {
	.probe = adreno_iommu_pdev_probe,
	.driver = {
		.owner = THIS_MODULE,
		.name = "kgsl-iommu",
		.of_match_table = iommu_match_table,
	}
};

static int _get_counter(struct adreno_device *adreno_dev,
		int group, int countable, unsigned int *lo,
		unsigned int *hi)
@@ -1038,10 +879,6 @@ static int adreno_probe(struct platform_device *pdev)
	struct adreno_device *adreno_dev;
	int status;

	/* Defer adreno probe if IOMMU is not already probed */
	if (device_3d0_iommu.regstart == 0)
		return -EPROBE_DEFER;

	adreno_dev = adreno_get_dev(pdev);

	if (adreno_dev == NULL) {
@@ -1051,7 +888,6 @@ static int adreno_probe(struct platform_device *pdev)

	device = KGSL_DEVICE(adreno_dev);
	device->pdev = pdev;
	device->mmu.priv = &device_3d0_iommu;

	/* Get the chip ID from the DT and set up target specific parameters */
	adreno_identify_gpu(adreno_dev);
@@ -1830,7 +1666,8 @@ static int adreno_getproperty(struct kgsl_device *device,
			memset(&devinfo, 0, sizeof(devinfo));
			devinfo.device_id = device->id+1;
			devinfo.chip_id = adreno_dev->chipid;
			devinfo.mmu_enabled = kgsl_mmu_enabled();
			devinfo.mmu_enabled =
				MMU_FEATURE(&device->mmu, KGSL_MMU_PAGED);
			devinfo.gmem_gpubaseaddr = adreno_dev->gmem_base;
			devinfo.gmem_sizebytes = adreno_dev->gmem_size;

@@ -1873,9 +1710,11 @@ static int adreno_getproperty(struct kgsl_device *device,
		break;
	case KGSL_PROP_MMU_ENABLE:
		{
			int mmu_prop = kgsl_mmu_enabled();
			/* Report MMU only if we can handle paged memory */
			int mmu_prop = MMU_FEATURE(&device->mmu,
				KGSL_MMU_PAGED);

			if (sizebytes != sizeof(int)) {
			if (sizebytes < sizeof(mmu_prop)) {
				status = -EINVAL;
				break;
			}
@@ -2919,27 +2758,6 @@ static struct platform_driver kgsl_bus_platform_driver = {
	}
};

#if defined(CONFIG_ARM_SMMU) || defined(CONFIG_MSM_IOMMU)
static int kgsl_iommu_driver_register(void)
{
	return platform_driver_register(&kgsl_iommu_platform_driver);
}

static void kgsl_iommu_driver_unregister(void)
{
	platform_driver_unregister(&kgsl_iommu_platform_driver);
}
#else
static inline int kgsl_iommu_driver_register(void)
{
	return 0;
}

static inline void kgsl_iommu_driver_unregister(void)
{
}
#endif

static int __init kgsl_3d_init(void)
{
	int ret;
@@ -2948,17 +2766,9 @@ static int __init kgsl_3d_init(void)
	if (ret)
		return ret;

	ret = kgsl_iommu_driver_register();
	if (ret) {
		platform_driver_unregister(&kgsl_bus_platform_driver);
		return ret;
	}

	ret = platform_driver_register(&adreno_platform_driver);
	if (ret) {
		kgsl_iommu_driver_unregister();
	if (ret)
		platform_driver_unregister(&kgsl_bus_platform_driver);
	}

	return ret;
}
@@ -2966,9 +2776,7 @@ static int __init kgsl_3d_init(void)
static void __exit kgsl_3d_exit(void)
{
	platform_driver_unregister(&adreno_platform_driver);
	kgsl_iommu_driver_unregister();
	platform_driver_unregister(&kgsl_bus_platform_driver);

}

module_init(kgsl_3d_init);
+0 −21
Original line number Diff line number Diff line
@@ -855,30 +855,12 @@ void adreno_coresight_remove(struct adreno_device *adreno_dev);

bool adreno_hw_isidle(struct adreno_device *adreno_dev);

int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
			struct kgsl_pagetable *new_pt,
			struct adreno_context *drawctxt);

int adreno_iommu_init(struct adreno_device *adreno_dev);

void adreno_iommu_set_pt_generate_rb_cmds(struct adreno_ringbuffer *rb,
					struct kgsl_pagetable *pt);

void adreno_fault_detect_start(struct adreno_device *adreno_dev);
void adreno_fault_detect_stop(struct adreno_device *adreno_dev);

void adreno_hang_int_callback(struct adreno_device *adreno_dev, int bit);
void adreno_cp_callback(struct adreno_device *adreno_dev, int bit);

unsigned int adreno_iommu_set_pt_ib(struct adreno_ringbuffer *rb,
					unsigned int *cmds,
					struct kgsl_pagetable *pt);

unsigned int adreno_iommu_set_pt_generate_cmds(
				struct adreno_ringbuffer *rb,
				unsigned int *cmds,
				struct kgsl_pagetable *pt);

int adreno_sysfs_init(struct adreno_device *adreno_dev);
void adreno_sysfs_close(struct adreno_device *adreno_dev);

@@ -1407,9 +1389,6 @@ void adreno_readreg64(struct adreno_device *adreno_dev,
void adreno_writereg64(struct adreno_device *adreno_dev,
		enum adreno_regs lo, enum adreno_regs hi, uint64_t val);

unsigned int adreno_iommu_set_apriv(struct adreno_device *adreno_dev,
				unsigned int *cmds, int set);

static inline bool adreno_soft_fault_detect(struct adreno_device *adreno_dev)
{
	return adreno_dev->fast_hang_detect &&
+86 −2
Original line number Diff line number Diff line
@@ -1798,6 +1798,90 @@ static struct adreno_snapshot_data a4xx_snapshot_data = {
	.sect_sizes = &a4xx_snap_sizes,
};

#define ADRENO_RB_PREEMPT_TOKEN_DWORDS		125

static int a4xx_submit_preempt_token(struct adreno_ringbuffer *rb,
					struct adreno_ringbuffer *incoming_rb)
{
	struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	unsigned int *ringcmds, *start;
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	int ptname;
	struct kgsl_pagetable *pt;
	int pt_switch_sizedwords = 0, total_sizedwords = 20;
	unsigned link[ADRENO_RB_PREEMPT_TOKEN_DWORDS];
	uint i;

	if (incoming_rb->preempted_midway) {

		kgsl_sharedmem_readl(&incoming_rb->pagetable_desc,
			&ptname, offsetof(
			struct adreno_ringbuffer_pagetable_info,
			current_rb_ptname));
		pt = kgsl_mmu_get_pt_from_ptname(&(device->mmu),
			ptname);
		/*
		 * always expect a valid pt, else pt refcounting is
		 * messed up or current pt tracking has a bug which
		 * could lead to eventual disaster
		 */
		BUG_ON(!pt);
		/* set the ringbuffer for incoming RB */
		pt_switch_sizedwords =
			adreno_iommu_set_pt_generate_cmds(incoming_rb,
							&link[0], pt);
		total_sizedwords += pt_switch_sizedwords;
	}

	/*
	 *  Allocate total_sizedwords space in RB, this is the max space
	 *  required.
	 */
	ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);

	if (IS_ERR(ringcmds))
		return PTR_ERR(ringcmds);

	start = ringcmds;

	*ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
	*ringcmds++ = 0;

	if (incoming_rb->preempted_midway) {
		for (i = 0; i < pt_switch_sizedwords; i++)
			*ringcmds++ = link[i];
	}

	*ringcmds++ = cp_register(adreno_dev, adreno_getreg(adreno_dev,
			ADRENO_REG_CP_PREEMPT_DISABLE), 1);
	*ringcmds++ = 0;

	*ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
	*ringcmds++ = 1;

	ringcmds += gpudev->preemption_token(adreno_dev, rb, ringcmds,
				device->memstore.gpuaddr +
				KGSL_MEMSTORE_RB_OFFSET(rb, preempted));

	if ((uint)(ringcmds - start) > total_sizedwords) {
		KGSL_DRV_ERR(device, "Insufficient rb size allocated\n");
		BUG();
	}

	/*
	 * If we have commands less than the space reserved in RB
	 *  adjust the wptr accordingly
	 */
	rb->wptr = rb->wptr - (total_sizedwords - (uint)(ringcmds - start));

	/* submit just the preempt token */
	mb();
	kgsl_pwrscale_busy(device);
	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr);
	return 0;
}

/**
 * a4xx_preempt_trig_state() - Schedule preemption in TRIGGERRED
 * state
@@ -1886,7 +1970,7 @@ static void a4xx_preempt_trig_state(
	/* Submit preempt token to make preemption happen */
	if (adreno_drawctxt_switch(adreno_dev, adreno_dev->cur_rb, NULL, 0))
		BUG();
	if (adreno_ringbuffer_submit_preempt_token(adreno_dev->cur_rb,
	if (a4xx_submit_preempt_token(adreno_dev->cur_rb,
						adreno_dev->next_rb))
		BUG();
	dispatcher->preempt_token_submit = 1;
@@ -1997,7 +2081,7 @@ static void a4xx_preempt_clear_state(
			adreno_dev->next_rb, adreno_dev->next_rb->timestamp);
	/* submit preempt token packet to ensure preemption */
	if (switch_low_to_high < 0) {
		ret = adreno_ringbuffer_submit_preempt_token(
		ret = a4xx_submit_preempt_token(
			adreno_dev->cur_rb, adreno_dev->next_rb);
		/*
		 * unexpected since we are submitting this when rptr = wptr,
Loading