Commit 48075a66 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux into drm-next



This time we've added support for reporting of GPU load via the common
fdinfo format, as already supported by multiple other drivers. Improved
diagnostic messages for MMU faults. And finally added experimental
support for driving the VeriSilicon NPU cores, which are very close
relatives to the GPU designs, so close in fact that they can run the
same compute instruction set, but with a big NN-fabric/matrix/tensor
execution array glued to the side.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
From: Lucas Stach <l.stach@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/80ceb4eedf7d88e434deeb69607d5ce0a0759581.camel@pengutronix.de
parents 78e98001 4c22c61e
Loading
Loading
Loading
Loading
+53 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "etnaviv_perfmon.h"
#include "common.xml.h"

/*
 * DRM operations:
@@ -56,6 +57,11 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
	if (!ctx)
		return -ENOMEM;

	ret = xa_alloc_cyclic(&priv->active_contexts, &ctx->id, ctx,
			      xa_limit_32b, &priv->next_context_id, GFP_KERNEL);
	if (ret < 0)
		goto out_free;

	ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global,
					      priv->cmdbuf_suballoc);
	if (!ctx->mmu) {
@@ -99,6 +105,8 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)

	etnaviv_iommu_context_put(ctx->mmu);

	xa_erase(&priv->active_contexts, ctx->id);

	kfree(ctx);
}

@@ -468,7 +476,47 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = {
	ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW),
};

DEFINE_DRM_GEM_FOPS(fops);
static void etnaviv_fop_show_fdinfo(struct seq_file *m, struct file *f)
{
	struct drm_file *file = f->private_data;
	struct drm_device *dev = file->minor->dev;
	struct etnaviv_drm_private *priv = dev->dev_private;
	struct etnaviv_file_private *ctx = file->driver_priv;

	/*
	 * For a description of the text output format used here, see
	 * Documentation/gpu/drm-usage-stats.rst.
	 */
	seq_printf(m, "drm-driver:\t%s\n", dev->driver->name);
	seq_printf(m, "drm-client-id:\t%u\n", ctx->id);

	for (int i = 0; i < ETNA_MAX_PIPES; i++) {
		struct etnaviv_gpu *gpu = priv->gpu[i];
		char engine[10] = "UNK";
		int cur = 0;

		if (!gpu)
			continue;

		if (gpu->identity.features & chipFeatures_PIPE_2D)
			cur = snprintf(engine, sizeof(engine), "2D");
		if (gpu->identity.features & chipFeatures_PIPE_3D)
			cur = snprintf(engine + cur, sizeof(engine) - cur,
				       "%s3D", cur ? "/" : "");
		if (gpu->identity.nn_core_count > 0)
			cur = snprintf(engine + cur, sizeof(engine) - cur,
				       "%sNN", cur ? "/" : "");

		seq_printf(m, "drm-engine-%s:\t%llu ns\n", engine,
			   ctx->sched_entity[i].elapsed_ns);
	}
}

static const struct file_operations fops = {
	.owner = THIS_MODULE,
	DRM_GEM_FOPS,
	.show_fdinfo = etnaviv_fop_show_fdinfo,
};

static const struct drm_driver etnaviv_drm_driver = {
	.driver_features    = DRIVER_GEM | DRIVER_RENDER,
@@ -514,6 +562,8 @@ static int etnaviv_bind(struct device *dev)

	dma_set_max_seg_size(dev, SZ_2G);

	xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);

	mutex_init(&priv->gem_lock);
	INIT_LIST_HEAD(&priv->gem_list);
	priv->num_gpus = 0;
@@ -563,6 +613,8 @@ static void etnaviv_unbind(struct device *dev)

	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);

	xa_destroy(&priv->active_contexts);

	drm->dev_private = NULL;
	kfree(priv);

+5 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/sizes.h>
#include <linux/time64.h>
#include <linux/types.h>
#include <linux/xarray.h>

#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
@@ -28,6 +29,7 @@ struct etnaviv_iommu_global;
#define ETNAVIV_SOFTPIN_START_ADDRESS	SZ_4M /* must be >= SUBALLOC_SIZE */

struct etnaviv_file_private {
	int id;
	struct etnaviv_iommu_context	*mmu;
	struct drm_sched_entity		sched_entity[ETNA_MAX_PIPES];
};
@@ -40,6 +42,9 @@ struct etnaviv_drm_private {
	struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc;
	struct etnaviv_iommu_global *mmu_global;

	struct xarray active_contexts;
	u32 next_context_id;

	/* list of GEM objects: */
	struct mutex gem_lock;
	struct list_head gem_list;
+5 −4
Original line number Diff line number Diff line
@@ -393,10 +393,11 @@ static void submit_cleanup(struct kref *kref)
	wake_up_all(&submit->gpu->fence_event);

	if (submit->out_fence) {
		/* first remove from IDR, so fence can not be found anymore */
		mutex_lock(&submit->gpu->fence_lock);
		idr_remove(&submit->gpu->fence_idr, submit->out_fence_id);
		mutex_unlock(&submit->gpu->fence_lock);
		/*
		 * Remove from user fence array before dropping the reference,
		 * so fence can not be found in lookup anymore.
		 */
		xa_erase(&submit->gpu->user_fences, submit->out_fence_id);
		dma_fence_put(submit->out_fence);
	}

+41 −25
Original line number Diff line number Diff line
@@ -773,6 +773,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
		goto fail;
	}

	if (gpu->identity.nn_core_count > 0)
		dev_warn(gpu->dev, "etnaviv has been instantiated on a NPU, "
                                   "for which the UAPI is still experimental\n");

	/* Exclude VG cores with FE2.0 */
	if (gpu->identity.features & chipFeatures_PIPE_VG &&
	    gpu->identity.features & chipFeatures_FE20) {
@@ -957,6 +961,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
			gpu->identity.vertex_cache_size);
	seq_printf(m, "\t shader_core_count: %d\n",
			gpu->identity.shader_core_count);
	seq_printf(m, "\t nn_core_count: %d\n",
			gpu->identity.nn_core_count);
	seq_printf(m, "\t pixel_pipes: %d\n",
			gpu->identity.pixel_pipes);
	seq_printf(m, "\t vertex_output_buffer_size: %d\n",
@@ -1240,7 +1246,7 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
	 * pretends we didn't find a fence in that case.
	 */
	rcu_read_lock();
	fence = idr_find(&gpu->fence_idr, id);
	fence = xa_load(&gpu->user_fences, id);
	if (fence)
		fence = dma_fence_get_rcu(fence);
	rcu_read_unlock();
@@ -1450,6 +1456,15 @@ static void sync_point_worker(struct work_struct *work)

static void dump_mmu_fault(struct etnaviv_gpu *gpu)
{
	static const char *fault_reasons[] = {
		"slave not present",
		"page not present",
		"write violation",
		"out of bounds",
		"read security violation",
		"write security violation",
	};

	u32 status_reg, status;
	int i;

@@ -1462,18 +1477,25 @@ static void dump_mmu_fault(struct etnaviv_gpu *gpu)
	dev_err_ratelimited(gpu->dev, "MMU fault status 0x%08x\n", status);

	for (i = 0; i < 4; i++) {
		const char *reason = "unknown";
		u32 address_reg;
		u32 mmu_status;

		if (!(status & (VIVS_MMUv2_STATUS_EXCEPTION0__MASK << (i * 4))))
		mmu_status = (status >> (i * 4)) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK;
		if (!mmu_status)
			continue;

		if ((mmu_status - 1) < ARRAY_SIZE(fault_reasons))
			reason = fault_reasons[mmu_status - 1];

		if (gpu->sec_mode == ETNA_SEC_NONE)
			address_reg = VIVS_MMUv2_EXCEPTION_ADDR(i);
		else
			address_reg = VIVS_MMUv2_SEC_EXCEPTION_ADDR;

		dev_err_ratelimited(gpu->dev, "MMU %d fault addr 0x%08x\n", i,
				    gpu_read(gpu, address_reg));
		dev_err_ratelimited(gpu->dev,
				    "MMU %d fault (%s) addr 0x%08x\n",
				    i, reason, gpu_read(gpu, address_reg));
	}
}

@@ -1629,7 +1651,6 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
	return etnaviv_gpu_clk_disable(gpu);
}

#ifdef CONFIG_PM
static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
{
	int ret;
@@ -1645,7 +1666,6 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)

	return 0;
}
#endif

static int
etnaviv_gpu_cooling_get_max_state(struct thermal_cooling_device *cdev,
@@ -1713,18 +1733,17 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
	if (ret)
		goto out_workqueue;

#ifdef CONFIG_PM
	if (IS_ENABLED(CONFIG_PM))
		ret = pm_runtime_get_sync(gpu->dev);
#else
	else
		ret = etnaviv_gpu_clk_enable(gpu);
#endif
	if (ret < 0)
		goto out_sched;


	gpu->drm = drm;
	gpu->fence_context = dma_fence_context_alloc(1);
	idr_init(&gpu->fence_idr);
	xa_init_flags(&gpu->user_fences, XA_FLAGS_ALLOC);
	spin_lock_init(&gpu->fence_spinlock);

	INIT_WORK(&gpu->sync_point_work, sync_point_worker);
@@ -1761,12 +1780,12 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,

	etnaviv_sched_fini(gpu);

#ifdef CONFIG_PM
	if (IS_ENABLED(CONFIG_PM)) {
		pm_runtime_get_sync(gpu->dev);
		pm_runtime_put_sync_suspend(gpu->dev);
#else
	} else {
		etnaviv_gpu_hw_suspend(gpu);
#endif
	}

	if (gpu->mmu_context)
		etnaviv_iommu_context_put(gpu->mmu_context);
@@ -1778,7 +1797,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
	}

	gpu->drm = NULL;
	idr_destroy(&gpu->fence_idr);
	xa_destroy(&gpu->user_fences);

	if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
		thermal_cooling_device_unregister(gpu->cooling);
@@ -1810,7 +1829,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)

	gpu->dev = &pdev->dev;
	mutex_init(&gpu->lock);
	mutex_init(&gpu->fence_lock);
	mutex_init(&gpu->sched_lock);

	/* Map registers: */
	gpu->mmio = devm_platform_ioremap_resource(pdev, 0);
@@ -1880,7 +1899,6 @@ static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
	return 0;
}

#ifdef CONFIG_PM
static int etnaviv_gpu_rpm_suspend(struct device *dev)
{
	struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
@@ -1923,18 +1941,16 @@ static int etnaviv_gpu_rpm_resume(struct device *dev)

	return 0;
}
#endif

static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
	SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
			   NULL)
	RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume, NULL)
};

struct platform_driver etnaviv_gpu_driver = {
	.driver = {
		.name = "etnaviv-gpu",
		.owner = THIS_MODULE,
		.pm = &etnaviv_gpu_pm_ops,
		.pm = pm_ptr(&etnaviv_gpu_pm_ops),
		.of_match_table = etnaviv_gpu_match,
	},
	.probe = etnaviv_gpu_platform_probe,
+6 −2
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ struct etnaviv_chip_identity {
	/* Number of shader cores. */
	u32 shader_core_count;

	/* Number of Neural Network cores. */
	u32 nn_core_count;

	/* Size of the vertex cache. */
	u32 vertex_cache_size;

@@ -100,6 +103,7 @@ struct etnaviv_gpu {
	struct etnaviv_chip_identity identity;
	enum etnaviv_sec_mode sec_mode;
	struct workqueue_struct *wq;
	struct mutex sched_lock;
	struct drm_gpu_scheduler sched;
	bool initialized;
	bool fe_running;
@@ -117,8 +121,8 @@ struct etnaviv_gpu {
	u32 idle_mask;

	/* Fencing support */
	struct mutex fence_lock;
	struct idr fence_idr;
	struct xarray user_fences;
	u32 next_user_fence;
	u32 next_fence;
	u32 completed_fence;
	wait_queue_head_t fence_event;
Loading