From 939fcf7b8691b9e9ac80e92eedeb14476069021b Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Sep 2023 13:34:08 +0000 Subject: [PATCH 0001/1420] drm/etnaviv: Replace strncpy with strscpy_pad `strncpy` is deprecated for use on NUL-terminated destination strings [1]. We should prefer more robust and less ambiguous string interfaces. A suitable replacement is `strscpy_pad` due to the fact that it guarantees NUL-termination on the destination buffer whilst maintaining the NUL-padding behavior that strncpy provides. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Cc: Bo YU Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Reviewed-by: Christian Gmeiner [lst: changed subject according to suggestion from Kees] Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_perfmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c index bafdfe49c1d8e..dc9dea664a28d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c @@ -511,7 +511,7 @@ int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu, domain->id = domain->iter; domain->nr_signals = dom->nr_signals; - strncpy(domain->name, dom->name, sizeof(domain->name)); + strscpy_pad(domain->name, dom->name, sizeof(domain->name)); domain->iter++; if (domain->iter == nr_domains) @@ -540,7 +540,7 @@ int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu, sig = &dom->signal[signal->iter]; signal->id = signal->iter; - strncpy(signal->name, sig->name, sizeof(signal->name)); + strscpy_pad(signal->name, sig->name, sizeof(signal->name)); signal->iter++; if (signal->iter == dom->nr_signals) -- GitLab From 4c6e6c01d82fc0edd8b47cb1ffbd05289029b005 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:03 +0800 Subject: [PATCH 0002/1420] drm/etnaviv: Drop the second argument of the etnaviv_gem_new_impl() The mentioned second parameter is the 'u32 size', but it is not get used by the etnaviv_gem_new_impl() function, so drop it. No functional change. Signed-off-by: Sui Jingfeng Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index b5f73502e3dd4..be2f459c66b5d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -542,7 +542,7 @@ static const struct drm_gem_object_funcs etnaviv_gem_object_funcs = { .vm_ops = &vm_ops, }; -static int etnaviv_gem_new_impl(struct drm_device *dev, u32 size, u32 flags, +static int etnaviv_gem_new_impl(struct drm_device *dev, u32 flags, const struct etnaviv_gem_ops *ops, struct drm_gem_object **obj) { struct etnaviv_gem_object *etnaviv_obj; @@ -591,8 +591,7 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file, size = PAGE_ALIGN(size); - ret = etnaviv_gem_new_impl(dev, size, flags, - &etnaviv_gem_shmem_ops, &obj); + ret = etnaviv_gem_new_impl(dev, flags, &etnaviv_gem_shmem_ops, &obj); if (ret) goto fail; @@ -627,7 +626,7 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags, struct drm_gem_object *obj; int ret; - ret = etnaviv_gem_new_impl(dev, size, flags, ops, &obj); + ret = etnaviv_gem_new_impl(dev, flags, ops, &obj); if (ret) return ret; -- GitLab From 4cb91cc2cd0d31ffc690b23c88901f4f315b9d78 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:04 +0800 Subject: [PATCH 0003/1420] drm/etnaviv: Fix coding style 1) Keep the curly brace aligned. 2) No indentation by double tabs where single tab indentation is enough. Signed-off-by: Sui Jingfeng Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a8d3fa81e4ec5..a3a17316a3289 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -79,7 +79,7 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file) drm_sched_entity_init(&ctx->sched_entity[i], DRM_SCHED_PRIORITY_NORMAL, &sched, 1, NULL); - } + } } file->driver_priv = ctx; @@ -233,11 +233,11 @@ static int show_each_gpu(struct seq_file *m, void *arg) } static struct drm_info_list etnaviv_debugfs_list[] = { - {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, - {"gem", show_unlocked, 0, etnaviv_gem_show}, - { "mm", show_unlocked, 0, etnaviv_mm_show }, - {"mmu", show_each_gpu, 0, etnaviv_mmu_show}, - {"ring", show_each_gpu, 0, etnaviv_ring_show}, + {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, + {"gem", show_unlocked, 0, etnaviv_gem_show}, + { "mm", show_unlocked, 0, etnaviv_mm_show }, + {"mmu", show_each_gpu, 0, etnaviv_mmu_show}, + {"ring", show_each_gpu, 0, etnaviv_ring_show}, }; static void etnaviv_debugfs_init(struct drm_minor *minor) -- GitLab From a10a43eee8589221d79b9050556aed2c5842d8b8 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:05 +0800 Subject: [PATCH 0004/1420] drm/etnaviv: Add helper functions to create and destroy platform device The newly introduced functions are etnaviv_create_platform_device() and etnaviv_destroy_platform_device(). Those two function are pure function and can be shared for other use case. Currently, the benefit is that we no longer need to call of_node_put() for three different cases, we only need to call it once in the etnaviv_init() function. Signed-off-by: Sui Jingfeng Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 53 +++++++++++++++++++-------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a3a17316a3289..8fe39e31d22d9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -655,11 +655,43 @@ static struct platform_driver etnaviv_platform_driver = { }, }; +static int etnaviv_create_platform_device(const char *name, + struct platform_device **ppdev) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); + if (!pdev) + return -ENOMEM; + + ret = platform_device_add(pdev); + if (ret) { + platform_device_put(pdev); + return ret; + } + + *ppdev = pdev; + + return 0; +} + +static void etnaviv_destroy_platform_device(struct platform_device **ppdev) +{ + struct platform_device *pdev = *ppdev; + + if (!pdev) + return; + + platform_device_unregister(pdev); + + *ppdev = NULL; +} + static struct platform_device *etnaviv_drm; static int __init etnaviv_init(void) { - struct platform_device *pdev; int ret; struct device_node *np; @@ -680,23 +712,12 @@ static int __init etnaviv_init(void) for_each_compatible_node(np, NULL, "vivante,gc") { if (!of_device_is_available(np)) continue; + of_node_put(np); - pdev = platform_device_alloc("etnaviv", PLATFORM_DEVID_NONE); - if (!pdev) { - ret = -ENOMEM; - of_node_put(np); - goto unregister_platform_driver; - } - - ret = platform_device_add(pdev); - if (ret) { - platform_device_put(pdev); - of_node_put(np); + ret = etnaviv_create_platform_device("etnaviv", &etnaviv_drm); + if (ret) goto unregister_platform_driver; - } - etnaviv_drm = pdev; - of_node_put(np); break; } @@ -712,7 +733,7 @@ module_init(etnaviv_init); static void __exit etnaviv_exit(void) { - platform_device_unregister(etnaviv_drm); + etnaviv_destroy_platform_device(&etnaviv_drm); platform_driver_unregister(&etnaviv_platform_driver); platform_driver_unregister(&etnaviv_gpu_driver); } -- GitLab From 4350aa21cca48a5d951ba108290bad703fbc0630 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Tue, 12 Dec 2023 14:57:54 -0500 Subject: [PATCH 0005/1420] fbdev/simplefb: change loglevel when the power domains cannot be parsed When the power domains cannot be parsed, the message is incorrectly logged as an info message. Let's change this to an error since an error is returned. Fixes: 92a511a568e4 ("fbdev/simplefb: Add support for generic power-domains") Signed-off-by: Brian Masney Acked-by: Andrew Halaney Acked-by: Javier Martinez Canillas Acked-by: Thierry Reding Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231212195754.232303-1-bmasney@redhat.com --- drivers/video/fbdev/simplefb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 6f58ee276ad1b..028a565250476 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -470,7 +470,7 @@ static int simplefb_attach_genpds(struct simplefb_par *par, if (err == -ENOENT) return 0; - dev_info(dev, "failed to parse power-domains: %d\n", err); + dev_err(dev, "failed to parse power-domains: %d\n", err); return err; } -- GitLab From 9afc1e0aa4851ef48482b03f6304047cf9b550ca Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:27 +0100 Subject: [PATCH 0006/1420] drm/ttm/tests: Add tests for ttm_resource and ttm_sys_man MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test initialization of ttm_resource using different memory domains. Add tests for a system memory manager and functions that can be tested without a fully-featured resource manager. Update ttm_bo_kunit_init() to initialize BO's kref and a genuine GEM drm object. Export ttm_resource_alloc for test purposes only. Signed-off-by: Karolina Stolarek Tested-by: Amaranath Somalapuram Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/68b8b293b6bf5f1170d49a1a089ccce9172e2855.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 22 +- drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h | 3 + drivers/gpu/drm/ttm/tests/ttm_resource_test.c | 335 ++++++++++++++++++ drivers/gpu/drm/ttm/ttm_resource.c | 3 + 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_resource_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index ec87c4fc1ad55..c92fe2052ef6e 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_device_test.o \ ttm_pool_test.o \ + ttm_resource_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index 81661d8827aa2..779fbc038f17d 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -29,19 +29,39 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, struct ttm_test_devices *devs, size_t size) { - struct drm_gem_object gem_obj = { .size = size }; + struct drm_gem_object gem_obj = { }; struct ttm_buffer_object *bo; + int err; bo = kunit_kzalloc(test, sizeof(*bo), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, bo); bo->base = gem_obj; + err = drm_gem_object_init(devs->drm, &bo->base, size); + KUNIT_ASSERT_EQ(test, err, 0); + bo->bdev = devs->ttm_dev; + kref_init(&bo->kref); return bo; } EXPORT_SYMBOL_GPL(ttm_bo_kunit_init); +struct ttm_place *ttm_place_kunit_init(struct kunit *test, + uint32_t mem_type, uint32_t flags) +{ + struct ttm_place *place; + + place = kunit_kzalloc(test, sizeof(*place), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, place); + + place->mem_type = mem_type; + place->flags = flags; + + return place; +} +EXPORT_SYMBOL_GPL(ttm_place_kunit_init); + struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test) { struct ttm_test_devices *devs; diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h index e261e3660d0b3..2f51c833a5367 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,8 @@ int ttm_device_kunit_init(struct ttm_test_devices *priv, struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, struct ttm_test_devices *devs, size_t size); +struct ttm_place *ttm_place_kunit_init(struct kunit *test, + uint32_t mem_type, uint32_t flags); struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test); struct ttm_test_devices *ttm_test_devices_all(struct kunit *test); diff --git a/drivers/gpu/drm/ttm/tests/ttm_resource_test.c b/drivers/gpu/drm/ttm/tests/ttm_resource_test.c new file mode 100644 index 0000000000000..029e1f094bb08 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_resource_test.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include + +#include "ttm_kunit_helpers.h" + +#define RES_SIZE SZ_4K +#define TTM_PRIV_DUMMY_REG (TTM_NUM_MEM_TYPES - 1) + +struct ttm_resource_test_case { + const char *description; + uint32_t mem_type; + uint32_t flags; +}; + +struct ttm_resource_test_priv { + struct ttm_test_devices *devs; + struct ttm_buffer_object *bo; + struct ttm_place *place; +}; + +static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { }; + +static int ttm_resource_test_init(struct kunit *test) +{ + struct ttm_resource_test_priv *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + + priv->devs = ttm_test_devices_all(test); + KUNIT_ASSERT_NOT_NULL(test, priv->devs); + + test->priv = priv; + + return 0; +} + +static void ttm_resource_test_fini(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + + ttm_test_devices_put(test, priv->devs); +} + +static void ttm_init_test_mocks(struct kunit *test, + struct ttm_resource_test_priv *priv, + uint32_t mem_type, uint32_t flags) +{ + size_t size = RES_SIZE; + + /* Make sure we have what we need for a good BO mock */ + KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev); + + priv->bo = ttm_bo_kunit_init(test, priv->devs, size); + priv->place = ttm_place_kunit_init(test, mem_type, flags); +} + +static void ttm_init_test_manager(struct kunit *test, + struct ttm_resource_test_priv *priv, + uint32_t mem_type) +{ + struct ttm_device *ttm_dev = priv->devs->ttm_dev; + struct ttm_resource_manager *man; + size_t size = SZ_16K; + + man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, man); + + man->use_tt = false; + man->func = &ttm_resource_manager_mock_funcs; + + ttm_resource_manager_init(man, ttm_dev, size); + ttm_set_driver_manager(ttm_dev, mem_type, man); + ttm_resource_manager_set_used(man, true); +} + +static const struct ttm_resource_test_case ttm_resource_cases[] = { + { + .description = "Init resource in TTM_PL_SYSTEM", + .mem_type = TTM_PL_SYSTEM, + }, + { + .description = "Init resource in TTM_PL_VRAM", + .mem_type = TTM_PL_VRAM, + }, + { + .description = "Init resource in a private placement", + .mem_type = TTM_PRIV_DUMMY_REG, + }, + { + .description = "Init resource in TTM_PL_SYSTEM, set placement flags", + .mem_type = TTM_PL_SYSTEM, + .flags = TTM_PL_FLAG_TOPDOWN, + }, +}; + +static void ttm_resource_case_desc(const struct ttm_resource_test_case *t, char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc); + +static void ttm_resource_init_basic(struct kunit *test) +{ + const struct ttm_resource_test_case *params = test->param_value; + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + uint64_t expected_usage; + + ttm_init_test_mocks(test, priv, params->mem_type, params->flags); + bo = priv->bo; + place = priv->place; + + if (params->mem_type > TTM_PL_SYSTEM) + ttm_init_test_manager(test, priv, params->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + expected_usage = man->usage + RES_SIZE; + + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); + + ttm_resource_init(bo, place, res); + + KUNIT_ASSERT_EQ(test, res->start, 0); + KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); + KUNIT_ASSERT_EQ(test, res->mem_type, place->mem_type); + KUNIT_ASSERT_EQ(test, res->placement, place->flags); + KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); + + KUNIT_ASSERT_NULL(test, res->bus.addr); + KUNIT_ASSERT_EQ(test, res->bus.offset, 0); + KUNIT_ASSERT_FALSE(test, res->bus.is_iomem); + KUNIT_ASSERT_EQ(test, res->bus.caching, ttm_cached); + KUNIT_ASSERT_EQ(test, man->usage, expected_usage); + + KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority])); + + ttm_resource_fini(man, res); +} + +static void ttm_resource_init_pinned(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + ttm_resource_init(bo, place, res); + KUNIT_ASSERT_TRUE(test, list_is_singular(&bo->bdev->pinned)); + + ttm_bo_unpin(bo); + ttm_resource_fini(man, res); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); +} + +static void ttm_resource_fini_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + ttm_resource_init(bo, place, res); + ttm_resource_fini(man, res); + + KUNIT_ASSERT_TRUE(test, list_empty(&res->lru)); + KUNIT_ASSERT_EQ(test, man->usage, 0); +} + +static void ttm_resource_manager_init_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + size_t size = SZ_16K; + + man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, man); + + ttm_resource_manager_init(man, priv->devs->ttm_dev, size); + + KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev); + KUNIT_ASSERT_EQ(test, man->size, size); + KUNIT_ASSERT_EQ(test, man->usage, 0); + KUNIT_ASSERT_NULL(test, man->move); + KUNIT_ASSERT_NOT_NULL(test, &man->move_lock); + + for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i) + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i])); +} + +static void ttm_resource_manager_usage_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + uint64_t actual_usage; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN); + bo = priv->bo; + place = priv->place; + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + ttm_resource_init(bo, place, res); + actual_usage = ttm_resource_manager_usage(man); + + KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE); + + ttm_resource_fini(man, res); +} + +static void ttm_resource_manager_set_used_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + + man = ttm_manager_type(priv->devs->ttm_dev, TTM_PL_SYSTEM); + KUNIT_ASSERT_TRUE(test, man->use_type); + + ttm_resource_manager_set_used(man, false); + KUNIT_ASSERT_FALSE(test, man->use_type); +} + +static void ttm_sys_man_alloc_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource *res; + uint32_t mem_type = TTM_PL_SYSTEM; + int ret; + + ttm_init_test_mocks(test, priv, mem_type, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, mem_type); + ret = man->func->alloc(man, bo, place, &res); + + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); + KUNIT_ASSERT_EQ(test, res->mem_type, mem_type); + KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); + + ttm_resource_fini(man, res); +} + +static void ttm_sys_man_free_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource *res; + uint32_t mem_type = TTM_PL_SYSTEM; + + ttm_init_test_mocks(test, priv, mem_type, 0); + bo = priv->bo; + place = priv->place; + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + ttm_resource_alloc(bo, place, &res); + + man = ttm_manager_type(priv->devs->ttm_dev, mem_type); + man->func->free(man, res); + + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); + KUNIT_ASSERT_EQ(test, man->usage, 0); +} + +static struct kunit_case ttm_resource_test_cases[] = { + KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params), + KUNIT_CASE(ttm_resource_init_pinned), + KUNIT_CASE(ttm_resource_fini_basic), + KUNIT_CASE(ttm_resource_manager_init_basic), + KUNIT_CASE(ttm_resource_manager_usage_basic), + KUNIT_CASE(ttm_resource_manager_set_used_basic), + KUNIT_CASE(ttm_sys_man_alloc_basic), + KUNIT_CASE(ttm_sys_man_free_basic), + {} +}; + +static struct kunit_suite ttm_resource_test_suite = { + .name = "ttm_resource", + .init = ttm_resource_test_init, + .exit = ttm_resource_test_fini, + .test_cases = ttm_resource_test_cases, +}; + +kunit_test_suites(&ttm_resource_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 46ff9c75bb124..02b96d23fdb9d 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -30,6 +30,8 @@ #include #include +#include + /** * ttm_lru_bulk_move_init - initialize a bulk move structure * @bulk: the structure to init @@ -240,6 +242,7 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo, spin_unlock(&bo->bdev->lru_lock); return 0; } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_resource_alloc); void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res) { -- GitLab From e6f7c641fae339cd5df28186677de1741e0c40c7 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:28 +0100 Subject: [PATCH 0007/1420] drm/ttm/tests: Add tests for ttm_tt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test initialization, creation and destruction of ttm_tt instances. Export ttm_tt_destroy and ttm_tt_create symbols for testing purposes. Signed-off-by: Karolina Stolarek Reviewed-by: Christian König Tested-by: Amaranath Somalapuram Link: https://patchwork.freedesktop.org/patch/msgid/4459cb89c666bfa377753ae18d0c8917131638e8.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 20 ++ drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 295 ++++++++++++++++++ drivers/gpu/drm/ttm/ttm_tt.c | 3 + 4 files changed, 319 insertions(+) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_tt_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index c92fe2052ef6e..f570530bbb606 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_device_test.o \ ttm_pool_test.o \ ttm_resource_test.o \ + ttm_tt_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index 779fbc038f17d..ba4e5c6891649 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -2,9 +2,29 @@ /* * Copyright © 2023 Intel Corporation */ +#include + #include "ttm_kunit_helpers.h" +static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + struct ttm_tt *tt; + + tt = kzalloc(sizeof(*tt), GFP_KERNEL); + ttm_tt_init(tt, bo, page_flags, ttm_cached, 0); + + return tt; +} + +static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) +{ + kfree(ttm); +} + struct ttm_device_funcs ttm_dev_funcs = { + .ttm_tt_create = ttm_tt_simple_create, + .ttm_tt_destroy = ttm_tt_simple_destroy, }; EXPORT_SYMBOL_GPL(ttm_dev_funcs); diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c new file mode 100644 index 0000000000000..fd4502c18de67 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include +#include + +#include "ttm_kunit_helpers.h" + +#define BO_SIZE SZ_4K + +struct ttm_tt_test_case { + const char *description; + uint32_t size; + uint32_t extra_pages_num; +}; + +static int ttm_tt_test_init(struct kunit *test) +{ + struct ttm_test_devices *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + + priv = ttm_test_devices_all(test); + test->priv = priv; + + return 0; +} + +static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = { + { + .description = "Page-aligned size", + .size = SZ_4K, + }, + { + .description = "Extra pages requested", + .size = SZ_4K, + .extra_pages_num = 1, + }, +}; + +static void ttm_tt_init_case_desc(const struct ttm_tt_test_case *t, + char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases, + ttm_tt_init_case_desc); + +static void ttm_tt_init_basic(struct kunit *test) +{ + const struct ttm_tt_test_case *params = test->param_value; + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + uint32_t page_flags = TTM_TT_FLAG_ZERO_ALLOC; + enum ttm_caching caching = ttm_cached; + uint32_t extra_pages = params->extra_pages_num; + int num_pages = params->size >> PAGE_SHIFT; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, params->size); + + err = ttm_tt_init(tt, bo, page_flags, caching, extra_pages); + KUNIT_ASSERT_EQ(test, err, 0); + + KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages + extra_pages); + + KUNIT_ASSERT_EQ(test, tt->page_flags, page_flags); + KUNIT_ASSERT_EQ(test, tt->caching, caching); + + KUNIT_ASSERT_NULL(test, tt->dma_address); + KUNIT_ASSERT_NULL(test, tt->swap_storage); +} + +static void ttm_tt_init_misaligned(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + uint32_t size = SZ_8K; + int num_pages = (size + SZ_4K) >> PAGE_SHIFT; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, size); + + /* Make the object size misaligned */ + bo->base.size += 1; + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + + KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages); +} + +static void ttm_tt_fini_basic(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, tt->pages); + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->pages); +} + +static void ttm_tt_fini_sg(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_sg_tt_init(tt, bo, 0, caching); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, tt->dma_address); + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->dma_address); +} + +static void ttm_tt_fini_shmem(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + struct file *shmem; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + + shmem = shmem_file_setup("ttm swap", BO_SIZE, 0); + tt->swap_storage = shmem; + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->swap_storage); +} + +static void ttm_tt_create_basic(struct kunit *test) +{ + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_EXPECT_EQ(test, err, 0); + KUNIT_EXPECT_NOT_NULL(test, bo->ttm); + + /* Free manually, as it was allocated outside of KUnit */ + kfree(bo->ttm); +} + +static void ttm_tt_create_invalid_bo_type(struct kunit *test) +{ + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_sg + 1; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_EXPECT_EQ(test, err, -EINVAL); + KUNIT_EXPECT_NULL(test, bo->ttm); +} + +static void ttm_tt_create_ttm_exists(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + bo->ttm = tt; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + /* Expect to keep the previous TTM */ + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_PTR_EQ(test, tt, bo->ttm); +} + +static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + return NULL; +} + +static struct ttm_device_funcs ttm_dev_empty_funcs = { + .ttm_tt_create = ttm_tt_null_create, +}; + +static void ttm_tt_create_failed(struct kunit *test) +{ + const struct ttm_test_devices *devs = test->priv; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + /* Update ttm_device_funcs so we don't alloc ttm_tt */ + devs->ttm_dev->funcs = &ttm_dev_empty_funcs; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, -ENOMEM); +} + +static void ttm_tt_destroy_basic(struct kunit *test) +{ + const struct ttm_test_devices *devs = test->priv; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, bo->ttm); + + ttm_tt_destroy(devs->ttm_dev, bo->ttm); +} + +static struct kunit_case ttm_tt_test_cases[] = { + KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params), + KUNIT_CASE(ttm_tt_init_misaligned), + KUNIT_CASE(ttm_tt_fini_basic), + KUNIT_CASE(ttm_tt_fini_sg), + KUNIT_CASE(ttm_tt_fini_shmem), + KUNIT_CASE(ttm_tt_create_basic), + KUNIT_CASE(ttm_tt_create_invalid_bo_type), + KUNIT_CASE(ttm_tt_create_ttm_exists), + KUNIT_CASE(ttm_tt_create_failed), + KUNIT_CASE(ttm_tt_destroy_basic), + {} +}; + +static struct kunit_suite ttm_tt_test_suite = { + .name = "ttm_tt", + .init = ttm_tt_test_init, + .exit = ttm_test_devices_fini, + .test_cases = ttm_tt_test_cases, +}; + +kunit_test_suites(&ttm_tt_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index e0a77671edd6c..d978dc539a9b9 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) return 0; } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_create); /* * Allocates storage for pointers to the pages that back the ttm. @@ -129,6 +131,7 @@ void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) { bdev->funcs->ttm_tt_destroy(bdev, ttm); } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_destroy); static void ttm_tt_init_fields(struct ttm_tt *ttm, struct ttm_buffer_object *bo, -- GitLab From 995279d280d1ef5cc349b6eafee4dccd720c99bf Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:29 +0100 Subject: [PATCH 0008/1420] drm/ttm/tests: Add tests for ttm_bo functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test reservation and release of TTM buffer objects. Add tests to check pin and unpin operations. Signed-off-by: Karolina Stolarek Tested-by: Amaranath Somalapuram Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/fcd53970f55ae4be8c738e03f9fcf45366d20b47.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_bo_test.c | 622 ++++++++++++++++++ drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 6 + 3 files changed, 629 insertions(+) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_bo_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index f570530bbb606..468535f7eed28 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_pool_test.o \ ttm_resource_test.o \ ttm_tt_test.o \ + ttm_bo_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c new file mode 100644 index 0000000000000..1f8a4f8adc929 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ttm_kunit_helpers.h" + +#define BO_SIZE SZ_8K + +struct ttm_bo_test_case { + const char *description; + bool interruptible; + bool no_wait; +}; + +static const struct ttm_bo_test_case ttm_bo_reserved_cases[] = { + { + .description = "Cannot be interrupted and sleeps", + .interruptible = false, + .no_wait = false, + }, + { + .description = "Cannot be interrupted, locks straight away", + .interruptible = false, + .no_wait = true, + }, + { + .description = "Can be interrupted, sleeps", + .interruptible = true, + .no_wait = false, + }, +}; + +static void ttm_bo_init_case_desc(const struct ttm_bo_test_case *t, + char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_bo_reserve, ttm_bo_reserved_cases, ttm_bo_init_case_desc); + +static void ttm_bo_reserve_optimistic_no_ticket(struct kunit *test) +{ + const struct ttm_bo_test_case *params = test->param_value; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, params->interruptible, params->no_wait, NULL); + KUNIT_ASSERT_EQ(test, err, 0); + + dma_resv_unlock(bo->base.resv); +} + +static void ttm_bo_reserve_locked_no_sleep(struct kunit *test) +{ + struct ttm_buffer_object *bo; + bool interruptible = false; + bool no_wait = true; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + /* Let's lock it beforehand */ + dma_resv_lock(bo->base.resv, NULL); + + err = ttm_bo_reserve(bo, interruptible, no_wait, NULL); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, -EBUSY); +} + +static void ttm_bo_reserve_no_wait_ticket(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ww_acquire_ctx ctx; + bool interruptible = false; + bool no_wait = true; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + KUNIT_ASSERT_EQ(test, err, -EBUSY); + + ww_acquire_fini(&ctx); +} + +static void ttm_bo_reserve_double_resv(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ww_acquire_ctx ctx; + bool interruptible = false; + bool no_wait = false; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + KUNIT_ASSERT_EQ(test, err, 0); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + + dma_resv_unlock(bo->base.resv); + ww_acquire_fini(&ctx); + + KUNIT_ASSERT_EQ(test, err, -EALREADY); +} + +/* + * A test case heavily inspired by ww_test_edeadlk_normal(). It injects + * a deadlock by manipulating the sequence number of the context that holds + * dma_resv lock of bo2 so the other context is "wounded" and has to back off + * (indicated by -EDEADLK). The subtest checks if ttm_bo_reserve() properly + * propagates that error. + */ +static void ttm_bo_reserve_deadlock(struct kunit *test) +{ + struct ttm_buffer_object *bo1, *bo2; + struct ww_acquire_ctx ctx1, ctx2; + bool interruptible = false; + bool no_wait = false; + int err; + + bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + ww_acquire_init(&ctx1, &reservation_ww_class); + mutex_lock(&bo2->base.resv->lock.base); + + /* The deadlock will be caught by WW mutex, don't warn about it */ + lock_release(&bo2->base.resv->lock.base.dep_map, 1); + + bo2->base.resv->lock.ctx = &ctx2; + ctx2 = ctx1; + ctx2.stamp--; /* Make the context holding the lock younger */ + + err = ttm_bo_reserve(bo1, interruptible, no_wait, &ctx1); + KUNIT_ASSERT_EQ(test, err, 0); + + err = ttm_bo_reserve(bo2, interruptible, no_wait, &ctx1); + KUNIT_ASSERT_EQ(test, err, -EDEADLK); + + dma_resv_unlock(bo1->base.resv); + ww_acquire_fini(&ctx1); +} + +#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) +struct signal_timer { + struct timer_list timer; + struct ww_acquire_ctx *ctx; +}; + +static void signal_for_ttm_bo_reserve(struct timer_list *t) +{ + struct signal_timer *s_timer = from_timer(s_timer, t, timer); + struct task_struct *task = s_timer->ctx->task; + + do_send_sig_info(SIGTERM, SEND_SIG_PRIV, task, PIDTYPE_PID); +} + +static int threaded_ttm_bo_reserve(void *arg) +{ + struct ttm_buffer_object *bo = arg; + struct signal_timer s_timer; + struct ww_acquire_ctx ctx; + bool interruptible = true; + bool no_wait = false; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + /* Prepare a signal that will interrupt the reservation attempt */ + timer_setup_on_stack(&s_timer.timer, &signal_for_ttm_bo_reserve, 0); + s_timer.ctx = &ctx; + + mod_timer(&s_timer.timer, msecs_to_jiffies(100)); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + + timer_delete_sync(&s_timer.timer); + destroy_timer_on_stack(&s_timer.timer); + + ww_acquire_fini(&ctx); + + return err; +} + +static void ttm_bo_reserve_interrupted(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct task_struct *task; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + task = kthread_create(threaded_ttm_bo_reserve, bo, "ttm-bo-reserve"); + + if (IS_ERR(task)) + KUNIT_FAIL(test, "Couldn't create ttm bo reserve task\n"); + + /* Take a lock so the threaded reserve has to wait */ + mutex_lock(&bo->base.resv->lock.base); + + wake_up_process(task); + msleep(20); + err = kthread_stop(task); + + mutex_unlock(&bo->base.resv->lock.base); + + KUNIT_ASSERT_EQ(test, err, -ERESTARTSYS); +} +#endif /* IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) */ + +static void ttm_bo_unreserve_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + struct ttm_resource *res1, *res2; + struct ttm_place *place; + struct ttm_resource_manager *man; + unsigned int bo_prio = TTM_MAX_BO_PRIORITY - 1; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->priority = bo_prio; + + err = ttm_resource_alloc(bo, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + + bo->resource = res1; + + /* Add a dummy resource to populate LRU */ + ttm_resource_alloc(bo, place, &res2); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unreserve(bo); + + man = ttm_manager_type(priv->ttm_dev, mem_type); + KUNIT_ASSERT_EQ(test, + list_is_last(&res1->lru, &man->lru[bo->priority]), 1); + + ttm_resource_free(bo, &res2); + ttm_resource_free(bo, &res1); +} + +static void ttm_bo_unreserve_pinned(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + struct ttm_resource *res1, *res2; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + place = ttm_place_kunit_init(test, mem_type, 0); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + + err = ttm_resource_alloc(bo, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res1; + + /* Add a dummy resource to the pinned list */ + err = ttm_resource_alloc(bo, place, &res2); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_EQ(test, + list_is_last(&res2->lru, &priv->ttm_dev->pinned), 1); + + ttm_bo_unreserve(bo); + KUNIT_ASSERT_EQ(test, + list_is_last(&res1->lru, &priv->ttm_dev->pinned), 1); + + ttm_resource_free(bo, &res1); + ttm_resource_free(bo, &res2); +} + +static void ttm_bo_unreserve_bulk(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo1, *bo2; + struct ttm_resource *res1, *res2; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + dma_resv_lock(bo1->base.resv, NULL); + ttm_bo_set_bulk_move(bo1, &lru_bulk_move); + dma_resv_unlock(bo1->base.resv); + + err = ttm_resource_alloc(bo1, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + bo1->resource = res1; + + dma_resv_lock(bo2->base.resv, NULL); + ttm_bo_set_bulk_move(bo2, &lru_bulk_move); + dma_resv_unlock(bo2->base.resv); + + err = ttm_resource_alloc(bo2, place, &res2); + KUNIT_ASSERT_EQ(test, err, 0); + bo2->resource = res2; + + ttm_bo_reserve(bo1, false, false, NULL); + ttm_bo_unreserve(bo1); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + KUNIT_ASSERT_PTR_EQ(test, res1, pos->last); + + ttm_resource_free(bo1, &res1); + ttm_resource_free(bo2, &res2); +} + +static void ttm_bo_put_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + KUNIT_EXPECT_EQ(test, err, 0); + + ttm_bo_put(bo); +} + +static const char *mock_name(struct dma_fence *f) +{ + return "kunit-ttm-bo-put"; +} + +static const struct dma_fence_ops mock_fence_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, +}; + +static void ttm_bo_put_shared_resv(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct dma_resv *external_resv; + struct dma_fence *fence; + /* A dummy DMA fence lock */ + spinlock_t fence_lock; + struct ttm_device *ttm_dev; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + external_resv = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, external_resv); + + dma_resv_init(external_resv); + + fence = kunit_kzalloc(test, sizeof(*fence), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fence); + + spin_lock_init(&fence_lock); + dma_fence_init(fence, &mock_fence_ops, &fence_lock, 0, 0); + + dma_resv_lock(external_resv, NULL); + dma_resv_reserve_fences(external_resv, 1); + dma_resv_add_fence(external_resv, fence, DMA_RESV_USAGE_BOOKKEEP); + dma_resv_unlock(external_resv); + + dma_fence_signal(fence); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + bo->base.resv = external_resv; + + ttm_bo_put(bo); +} + +static void ttm_bo_pin_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + unsigned int no_pins = 3; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + for (int i = 0; i < no_pins; i++) { + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + dma_resv_unlock(bo->base.resv); + } + + KUNIT_ASSERT_EQ(test, bo->pin_count, no_pins); +} + +static void ttm_bo_pin_unpin_resource(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_set_bulk_move(bo, &lru_bulk_move); + ttm_bo_pin(bo); + dma_resv_unlock(bo->base.resv); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + + KUNIT_ASSERT_EQ(test, bo->pin_count, 1); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_PTR_EQ(test, res, pos->last); + KUNIT_ASSERT_EQ(test, bo->pin_count, 0); + + ttm_resource_free(bo, &res); +} + +static void ttm_bo_multiple_pin_one_unpin(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_set_bulk_move(bo, &lru_bulk_move); + + /* Multiple pins */ + ttm_bo_pin(bo); + ttm_bo_pin(bo); + + dma_resv_unlock(bo->base.resv); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + + KUNIT_ASSERT_EQ(test, bo->pin_count, 2); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, bo->pin_count, 1); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + ttm_resource_free(bo, &res); +} + +static struct kunit_case ttm_bo_test_cases[] = { + KUNIT_CASE_PARAM(ttm_bo_reserve_optimistic_no_ticket, + ttm_bo_reserve_gen_params), + KUNIT_CASE(ttm_bo_reserve_locked_no_sleep), + KUNIT_CASE(ttm_bo_reserve_no_wait_ticket), + KUNIT_CASE(ttm_bo_reserve_double_resv), +#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) + KUNIT_CASE(ttm_bo_reserve_interrupted), +#endif + KUNIT_CASE(ttm_bo_reserve_deadlock), + KUNIT_CASE(ttm_bo_unreserve_basic), + KUNIT_CASE(ttm_bo_unreserve_pinned), + KUNIT_CASE(ttm_bo_unreserve_bulk), + KUNIT_CASE(ttm_bo_put_basic), + KUNIT_CASE(ttm_bo_put_shared_resv), + KUNIT_CASE(ttm_bo_pin_basic), + KUNIT_CASE(ttm_bo_pin_unpin_resource), + KUNIT_CASE(ttm_bo_multiple_pin_one_unpin), + {} +}; + +static struct kunit_suite ttm_bo_test_suite = { + .name = "ttm_bo", + .init = ttm_test_devices_init, + .exit = ttm_test_devices_fini, + .test_cases = ttm_bo_test_cases, +}; + +kunit_test_suites(&ttm_bo_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index ba4e5c6891649..7b7c1fa805fcb 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -22,6 +22,10 @@ static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) kfree(ttm); } +static void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo) +{ +} + struct ttm_device_funcs ttm_dev_funcs = { .ttm_tt_create = ttm_tt_simple_create, .ttm_tt_destroy = ttm_tt_simple_destroy, @@ -61,6 +65,8 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, KUNIT_ASSERT_EQ(test, err, 0); bo->bdev = devs->ttm_dev; + bo->destroy = dummy_ttm_bo_destroy; + kref_init(&bo->kref); return bo; -- GitLab From dd20946516b6dc567c733cc3e4538eb9223596cf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Dec 2023 15:25:56 +0200 Subject: [PATCH 0009/1420] drm/edid: replace __attribute__((packed)) with __packed __packed is preferred over __attribute__((packed)). Signed-off-by: Jani Nikula Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231212132557.3777281-1-jani.nikula@intel.com --- include/drm/drm_edid.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 518d1b8106c76..54cc6f04a7086 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -46,7 +46,7 @@ struct est_timings { u8 t1; u8 t2; u8 mfg_rsvd; -} __attribute__((packed)); +} __packed; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ #define EDID_TIMING_ASPECT_SHIFT 6 @@ -59,7 +59,7 @@ struct est_timings { struct std_timing { u8 hsize; /* need to multiply by 8 then add 248 */ u8 vfreq_aspect; -} __attribute__((packed)); +} __packed; #define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1) #define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2) @@ -85,12 +85,12 @@ struct detailed_pixel_timing { u8 hborder; u8 vborder; u8 misc; -} __attribute__((packed)); +} __packed; /* If it's not pixel timing, it'll be one of the below */ struct detailed_data_string { u8 str[13]; -} __attribute__((packed)); +} __packed; #define DRM_EDID_RANGE_OFFSET_MIN_VFREQ (1 << 0) /* 1.4 */ #define DRM_EDID_RANGE_OFFSET_MAX_VFREQ (1 << 1) /* 1.4 */ @@ -120,7 +120,7 @@ struct detailed_data_monitor_range { __le16 m; u8 k; u8 j; /* need to divide by 2 */ - } __attribute__((packed)) gtf2; + } __packed gtf2; struct { u8 version; u8 data1; /* high 6 bits: extra clock resolution */ @@ -129,27 +129,27 @@ struct detailed_data_monitor_range { u8 flags; /* preferred aspect and blanking support */ u8 supported_scalings; u8 preferred_refresh; - } __attribute__((packed)) cvt; - } __attribute__((packed)) formula; -} __attribute__((packed)); + } __packed cvt; + } __packed formula; +} __packed; struct detailed_data_wpindex { u8 white_yx_lo; /* Lower 2 bits each */ u8 white_x_hi; u8 white_y_hi; u8 gamma; /* need to divide by 100 then add 1 */ -} __attribute__((packed)); +} __packed; struct detailed_data_color_point { u8 windex1; u8 wpindex1[3]; u8 windex2; u8 wpindex2[3]; -} __attribute__((packed)); +} __packed; struct cvt_timing { u8 code[3]; -} __attribute__((packed)); +} __packed; struct detailed_non_pixel { u8 pad1; @@ -163,8 +163,8 @@ struct detailed_non_pixel { struct detailed_data_wpindex color; struct std_timing timings[6]; struct cvt_timing cvt[4]; - } __attribute__((packed)) data; -} __attribute__((packed)); + } __packed data; +} __packed; #define EDID_DETAIL_EST_TIMINGS 0xf7 #define EDID_DETAIL_CVT_3BYTE 0xf8 @@ -181,8 +181,8 @@ struct detailed_timing { union { struct detailed_pixel_timing pixel_data; struct detailed_non_pixel other_data; - } __attribute__((packed)) data; -} __attribute__((packed)); + } __packed data; +} __packed; #define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0) #define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 1) @@ -307,7 +307,7 @@ struct edid { u8 extensions; /* Checksum */ u8 checksum; -} __attribute__((packed)); +} __packed; #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) -- GitLab From 8acf543cc68cefb0b41011fd66d5e11fd8fcee56 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Dec 2023 15:25:57 +0200 Subject: [PATCH 0010/1420] drm/ioc32: replace __attribute__((packed)) with __packed __packed is preferred over __attribute__((packed)). Signed-off-by: Jani Nikula Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231212132557.3777281-2-jani.nikula@intel.com --- drivers/gpu/drm/drm_ioc32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 129e2b91dbfe7..e6b5b06de1487 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -229,7 +229,7 @@ typedef struct drm_update_draw32 { unsigned int num; /* 64-bit version has a 32-bit pad here */ u64 data; /**< Pointer */ -} __attribute__((packed)) drm_update_draw32_t; +} __packed drm_update_draw32_t; static int compat_drm_update_draw(struct file *file, unsigned int cmd, unsigned long arg) @@ -296,7 +296,7 @@ typedef struct drm_mode_fb_cmd232 { u32 pitches[4]; u32 offsets[4]; u64 modifier[4]; -} __attribute__((packed)) drm_mode_fb_cmd232_t; +} __packed drm_mode_fb_cmd232_t; static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd, unsigned long arg) -- GitLab From 100035bf8677a57371cb9850fad6faf16a2c0c47 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 14 Dec 2023 10:33:53 +0000 Subject: [PATCH 0011/1420] MAINTAINERS: Remove Donald Robson from powervr driver maintainers I will be leaving Imagination Technologies on 2023-12-15 and will no longer be working on this driver. Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231214103353.122257-1-donald.robson@imgtec.com --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index f2cee321099fb..9d959a6881f70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10407,7 +10407,6 @@ F: drivers/media/rc/img-ir/ IMGTEC POWERVR DRM DRIVER M: Frank Binns -M: Donald Robson M: Matt Coster S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc -- GitLab From afe6fcb9775882230cd29b529203eabd5d2a638d Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 24 Oct 2023 08:07:38 +0000 Subject: [PATCH 0012/1420] drm/tegra: dsi: Add missing check for of_find_device_by_node Add check for the return value of of_find_device_by_node() and return the error if it fails in order to avoid NULL pointer dereference. Fixes: e94236cde4d5 ("drm/tegra: dsi: Add ganged mode support") Signed-off-by: Chen Ni Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20231024080738.825553-1-nichen@iscas.ac.cn --- drivers/gpu/drm/tegra/dsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index fbfe92a816d4b..e419b76e57d3e 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1544,9 +1544,11 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); if (np) { struct platform_device *gangster = of_find_device_by_node(np); + of_node_put(np); + if (!gangster) + return -EPROBE_DEFER; dsi->slave = platform_get_drvdata(gangster); - of_node_put(np); if (!dsi->slave) { put_device(&gangster->dev); -- GitLab From 11aa6d78ab8b135bdeba0bdaa10e63527c837b89 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 13 Dec 2023 12:19:51 +0200 Subject: [PATCH 0013/1420] drm/tegra: include drm/drm_edid.h only where needed Reduce the need for rebuilds when drm_edid.h is modified by including it only where needed. v2: Fix build (kernel test robot ) Signed-off-by: Jani Nikula Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20231213101951.3932273-1-jani.nikula@intel.com --- drivers/gpu/drm/tegra/drm.h | 2 +- drivers/gpu/drm/tegra/output.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index ccb5d74fa2270..682011166a8f6 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -26,6 +25,7 @@ /* XXX move to include/uapi/drm/drm_fourcc.h? */ #define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT_ULL(22) +struct edid; struct reset_control; struct tegra_drm { diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index dc2dcb5ca1c89..88af956ad0e77 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 83341576630d8..bad3b8fcc7269 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include -- GitLab From 0800880f4eb789b7d299db40f2e86e056bd33a4e Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Wed, 4 Oct 2023 22:10:55 +0800 Subject: [PATCH 0014/1420] drm/tegra: dpaux: Fix PM disable depth imbalance in tegra_dpaux_probe The pm_runtime_enable function increases the power disable depth, which means that we must perform a matching decrement on the error handling path to maintain balance within the given context. Additionally, we need to address the same issue for pm_runtime_get_sync. We fix this by invoking pm_runtime_disable and pm_runtime_put_sync when error returns. Fixes: 82b81b3ec1a7 ("drm/tegra: dpaux: Implement runtime PM") Signed-off-by: Zhang Shurong Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/tencent_B13DB7F6C0023C46157250A524966F326A09@qq.com --- drivers/gpu/drm/tegra/dpaux.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index ef02d530f78d7..ae12d001a04bf 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -522,7 +522,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (err < 0) { dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", dpaux->irq, err); - return err; + goto err_pm_disable; } disable_irq(dpaux->irq); @@ -542,7 +542,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) */ err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C); if (err < 0) - return err; + goto err_pm_disable; #ifdef CONFIG_GENERIC_PINCONF dpaux->desc.name = dev_name(&pdev->dev); @@ -555,7 +555,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); if (IS_ERR(dpaux->pinctrl)) { dev_err(&pdev->dev, "failed to register pincontrol\n"); - return PTR_ERR(dpaux->pinctrl); + err = PTR_ERR(dpaux->pinctrl); + goto err_pm_disable; } #endif /* enable and clear all interrupts */ @@ -571,10 +572,15 @@ static int tegra_dpaux_probe(struct platform_device *pdev) err = devm_of_dp_aux_populate_ep_devices(&dpaux->aux); if (err < 0) { dev_err(dpaux->dev, "failed to populate AUX bus: %d\n", err); - return err; + goto err_pm_disable; } return 0; + +err_pm_disable: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return err; } static void tegra_dpaux_remove(struct platform_device *pdev) -- GitLab From 830c1ded356369cd1303e8bb87ce3fea6e744de8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:08 +0200 Subject: [PATCH 0015/1420] drm/tegra: dsi: Fix some error handling paths in tegra_dsi_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: dec727399a4b ("drm/tegra: Add DSI support") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/16820073278d031f6c474a08d5f22a255158585e.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/dsi.c | 54 ++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index e419b76e57d3e..0c8ad8ee5009a 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1596,44 +1596,58 @@ static int tegra_dsi_probe(struct platform_device *pdev) if (!pdev->dev.pm_domain) { dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); - if (IS_ERR(dsi->rst)) - return PTR_ERR(dsi->rst); + if (IS_ERR(dsi->rst)) { + err = PTR_ERR(dsi->rst); + goto remove; + } } dsi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dsi->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), - "cannot get DSI clock\n"); + if (IS_ERR(dsi->clk)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), + "cannot get DSI clock\n"); + goto remove; + } dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); - if (IS_ERR(dsi->clk_lp)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), - "cannot get low-power clock\n"); + if (IS_ERR(dsi->clk_lp)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), + "cannot get low-power clock\n"); + goto remove; + } dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); - if (IS_ERR(dsi->clk_parent)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), - "cannot get parent clock\n"); + if (IS_ERR(dsi->clk_parent)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), + "cannot get parent clock\n"); + goto remove; + } dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); - if (IS_ERR(dsi->vdd)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), - "cannot get VDD supply\n"); + if (IS_ERR(dsi->vdd)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), + "cannot get VDD supply\n"); + goto remove; + } err = tegra_dsi_setup_clocks(dsi); if (err < 0) { dev_err(&pdev->dev, "cannot setup clocks\n"); - return err; + goto remove; } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); dsi->regs = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(dsi->regs)) - return PTR_ERR(dsi->regs); + if (IS_ERR(dsi->regs)) { + err = PTR_ERR(dsi->regs); + goto remove; + } dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node); - if (IS_ERR(dsi->mipi)) - return PTR_ERR(dsi->mipi); + if (IS_ERR(dsi->mipi)) { + err = PTR_ERR(dsi->mipi); + goto remove; + } dsi->host.ops = &tegra_dsi_host_ops; dsi->host.dev = &pdev->dev; @@ -1664,6 +1678,8 @@ static int tegra_dsi_probe(struct platform_device *pdev) mipi_dsi_host_unregister(&dsi->host); mipi_free: tegra_mipi_free(dsi->mipi); +remove: + tegra_output_remove(&dsi->output); return err; } -- GitLab From 5286a9fc280c45b6b307ee1b07f7a997e042252c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:09 +0200 Subject: [PATCH 0016/1420] drm/tegra: dsi: Fix missing pm_runtime_disable() in the error handling path of tegra_dsi_probe() If an error occurs after calling pm_runtime_enable(), pm_runtime_disable() should be called as already done in the remove function. Fixes: ef8187d75265 ("drm/tegra: dsi: Implement runtime PM") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/ee4a15c9cd4b574a55cd67c30d2411239ba2cee9.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/dsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 0c8ad8ee5009a..db606e151afc8 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1675,6 +1675,7 @@ static int tegra_dsi_probe(struct platform_device *pdev) return 0; unregister: + pm_runtime_disable(&pdev->dev); mipi_dsi_host_unregister(&dsi->host); mipi_free: tegra_mipi_free(dsi->mipi); -- GitLab From 643ae131b8598fb2940c92c7d23fe62823a119c8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:10 +0200 Subject: [PATCH 0017/1420] drm/tegra: hdmi: Fix some error handling paths in tegra_hdmi_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: 59d29c0ec93f ("drm/tegra: Allocate resources at probe time") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/9b7c564eb71977678b20abd73ee52001a51cf327.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/hdmi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index a1fcee665023b..417fb884240a6 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1856,12 +1856,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return err; hdmi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hdmi->regs)) - return PTR_ERR(hdmi->regs); + if (IS_ERR(hdmi->regs)) { + err = PTR_ERR(hdmi->regs); + goto remove; + } err = platform_get_irq(pdev, 0); if (err < 0) - return err; + goto remove; hdmi->irq = err; @@ -1870,18 +1872,18 @@ static int tegra_hdmi_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", hdmi->irq, err); - return err; + goto remove; } platform_set_drvdata(pdev, hdmi); err = devm_pm_runtime_enable(&pdev->dev); if (err) - return err; + goto remove; err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (err) - return err; + goto remove; INIT_LIST_HEAD(&hdmi->client.list); hdmi->client.ops = &hdmi_client_ops; @@ -1891,10 +1893,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to register host1x client: %d\n", err); - return err; + goto remove; } return 0; + +remove: + tegra_output_remove(&hdmi->output); + return err; } static void tegra_hdmi_remove(struct platform_device *pdev) -- GitLab From bc456b5d93dbfdbd89f2a036f4f3d8026595f9e4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:11 +0200 Subject: [PATCH 0018/1420] drm/tegra: rgb: Fix some error handling paths in tegra_dc_rgb_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: 59d29c0ec93f ("drm/tegra: Allocate resources at probe time") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/0001f61eb89048bc36241629b564195689cf54b6.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/rgb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index fc66bbd913b24..53c492b13d129 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -225,26 +225,28 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) rgb->clk = devm_clk_get(dc->dev, NULL); if (IS_ERR(rgb->clk)) { dev_err(dc->dev, "failed to get clock\n"); - return PTR_ERR(rgb->clk); + err = PTR_ERR(rgb->clk); + goto remove; } rgb->clk_parent = devm_clk_get(dc->dev, "parent"); if (IS_ERR(rgb->clk_parent)) { dev_err(dc->dev, "failed to get parent clock\n"); - return PTR_ERR(rgb->clk_parent); + err = PTR_ERR(rgb->clk_parent); + goto remove; } err = clk_set_parent(rgb->clk, rgb->clk_parent); if (err < 0) { dev_err(dc->dev, "failed to set parent clock: %d\n", err); - return err; + goto remove; } rgb->pll_d_out0 = clk_get_sys(NULL, "pll_d_out0"); if (IS_ERR(rgb->pll_d_out0)) { err = PTR_ERR(rgb->pll_d_out0); dev_err(dc->dev, "failed to get pll_d_out0: %d\n", err); - return err; + goto remove; } if (dc->soc->has_pll_d2_out0) { @@ -252,13 +254,17 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) if (IS_ERR(rgb->pll_d2_out0)) { err = PTR_ERR(rgb->pll_d2_out0); dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err); - return err; + goto remove; } } dc->rgb = &rgb->output; return 0; + +remove: + tegra_output_remove(&rgb->output); + return err; } void tegra_dc_rgb_remove(struct tegra_dc *dc) -- GitLab From 45c8034db47842b25a3ab6139d71e13b4e67b9b3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:12 +0200 Subject: [PATCH 0019/1420] drm/tegra: rgb: Fix missing clk_put() in the error handling paths of tegra_dc_rgb_probe() If clk_get_sys(..., "pll_d2_out0") fails, the clk_get_sys() call must be undone. Add the missing clk_put and a new 'put_pll_d_out0' label in the error handling path, and use it. Fixes: 0c921b6d4ba0 ("drm/tegra: dc: rgb: Allow changing PLLD rate on Tegra30+") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/0182895ead4e4730426616b0d9995954c960b634.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/rgb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 53c492b13d129..1e8ec50b759e4 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -254,7 +254,7 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) if (IS_ERR(rgb->pll_d2_out0)) { err = PTR_ERR(rgb->pll_d2_out0); dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err); - goto remove; + goto put_pll; } } @@ -262,6 +262,8 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) return 0; +put_pll: + clk_put(rgb->pll_d_out0); remove: tegra_output_remove(&rgb->output); return err; -- GitLab From 2db4578ef6ffb2b52115ca0ebf897b60ec559556 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:13 +0200 Subject: [PATCH 0020/1420] drm/tegra: output: Fix missing i2c_put_adapter() in the error handling paths of tegra_output_probe() If an error occurs after a successful of_get_i2c_adapter_by_node() call, it should be undone by a corresponding i2c_put_adapter(). Add the missing i2c_put_adapter() call. Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/b38604178991e1f08b2cda219103be266be2d680.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/output.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 88af956ad0e77..4da3c3d1abbc7 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -143,8 +143,10 @@ int tegra_output_probe(struct tegra_output *output) GPIOD_IN, "HDMI hotplug detect"); if (IS_ERR(output->hpd_gpio)) { - if (PTR_ERR(output->hpd_gpio) != -ENOENT) - return PTR_ERR(output->hpd_gpio); + if (PTR_ERR(output->hpd_gpio) != -ENOENT) { + err = PTR_ERR(output->hpd_gpio); + goto put_i2c; + } output->hpd_gpio = NULL; } @@ -153,7 +155,7 @@ int tegra_output_probe(struct tegra_output *output) err = gpiod_to_irq(output->hpd_gpio); if (err < 0) { dev_err(output->dev, "gpiod_to_irq(): %d\n", err); - return err; + goto put_i2c; } output->hpd_irq = err; @@ -166,7 +168,7 @@ int tegra_output_probe(struct tegra_output *output) if (err < 0) { dev_err(output->dev, "failed to request IRQ#%u: %d\n", output->hpd_irq, err); - return err; + goto put_i2c; } output->connector.polled = DRM_CONNECTOR_POLL_HPD; @@ -180,6 +182,12 @@ int tegra_output_probe(struct tegra_output *output) } return 0; + +put_i2c: + if (output->ddc) + i2c_put_adapter(output->ddc); + + return err; } void tegra_output_remove(struct tegra_output *output) -- GitLab From c3b78577462782e20c18cd30f8fe9b735746467b Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:51 +0100 Subject: [PATCH 0021/1420] drm/bridge: tc358767: Use regmap_access_table for writeable registers Using ranges it is easier to add more register where writing is not allowed, especially for sequences of registers. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-2-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 615cc8f950d7b..b8b29b291b72f 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1992,12 +1992,15 @@ static const struct regmap_access_table tc_volatile_table = { .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), }; -static bool tc_writeable_reg(struct device *dev, unsigned int reg) -{ - return (reg != TC_IDREG) && - (reg != DP0_LTSTAT) && - (reg != DP0_SNKLTCHGREQ); -} +static const struct regmap_range tc_non_writeable_ranges[] = { + regmap_reg_range(TC_IDREG, TC_IDREG), + regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), +}; + +static const struct regmap_access_table tc_writeable_table = { + .no_ranges = tc_non_writeable_ranges, + .n_no_ranges = ARRAY_SIZE(tc_non_writeable_ranges), +}; static const struct regmap_config tc_regmap_config = { .name = "tc358767", @@ -2008,7 +2011,7 @@ static const struct regmap_config tc_regmap_config = { .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, - .writeable_reg = tc_writeable_reg, + .wr_table = &tc_writeable_table, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; -- GitLab From 31094d3d2a5c67a9d47ea64eea38ba27335ff67f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:52 +0100 Subject: [PATCH 0022/1420] drm/bridge: tc358767: Fix order of register defines 0x0510 is bigger than 0x50c, order them accordingly. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-3-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index b8b29b291b72f..637d38ec7628c 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -116,13 +116,6 @@ /* System */ #define TC_IDREG 0x0500 #define SYSSTAT 0x0508 -#define SYSCTRL 0x0510 -#define DP0_AUDSRC_NO_INPUT (0 << 3) -#define DP0_AUDSRC_I2S_RX (1 << 3) -#define DP0_VIDSRC_NO_INPUT (0 << 0) -#define DP0_VIDSRC_DSI_RX (1 << 0) -#define DP0_VIDSRC_DPI_RX (2 << 0) -#define DP0_VIDSRC_COLOR_BAR (3 << 0) #define SYSRSTENB 0x050c #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) @@ -130,6 +123,13 @@ #define ENBDSIRX (1 << 4) #define ENBREG (1 << 5) #define ENBHDCP (1 << 8) +#define SYSCTRL 0x0510 /* System Control Register */ +#define DP0_AUDSRC_NO_INPUT (0 << 3) +#define DP0_AUDSRC_I2S_RX (1 << 3) +#define DP0_VIDSRC_NO_INPUT (0 << 0) +#define DP0_VIDSRC_DSI_RX (1 << 0) +#define DP0_VIDSRC_DPI_RX (2 << 0) +#define DP0_VIDSRC_COLOR_BAR (3 << 0) #define GPIOM 0x0540 #define GPIOC 0x0544 #define GPIOO 0x0548 -- GitLab From f8a4ac9e9e3c56047c3f92748c30fb90476015e4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:53 +0100 Subject: [PATCH 0023/1420] drm/bridge: tc358767: Add more registers to non-writeable range While at it, also add missing register definitions. HDCP registers are skipped as they are not named, range 0x0980 - 0x09ac. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-4-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 87 ++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 637d38ec7628c..e07b71d1ea8ef 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -41,8 +41,24 @@ /* Registers */ +/* DSI D-PHY Layer registers */ +#define D0W_DPHYCONTTX 0x0004 +#define CLW_DPHYCONTTX 0x0020 +#define D0W_DPHYCONTRX 0x0024 +#define D1W_DPHYCONTRX 0x0028 +#define D2W_DPHYCONTRX 0x002c +#define D3W_DPHYCONTRX 0x0030 +#define COM_DPHYCONTRX 0x0038 +#define CLW_CNTRL 0x0040 +#define D0W_CNTRL 0x0044 +#define D1W_CNTRL 0x0048 +#define D2W_CNTRL 0x004c +#define D3W_CNTRL 0x0050 +#define TESTMODE_CNTRL 0x0054 + /* PPI layer registers */ #define PPI_STARTPPI 0x0104 /* START control bit */ +#define PPI_BUSYPPI 0x0108 /* PPI busy status */ #define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ #define LPX_PERIOD 3 #define PPI_LANEENABLE 0x0134 @@ -59,6 +75,7 @@ /* DSI layer registers */ #define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ +#define DSI_BUSYDSI 0x0208 /* DSI busy status */ #define DSI_LANEENABLE 0x0210 /* Enables each lane */ #define DSI_RX_START BIT(0) @@ -69,6 +86,20 @@ #define LANEENABLE_L2EN BIT(1) #define LANEENABLE_L3EN BIT(2) +#define DSI_LANESTATUS0 0x0214 /* DSI lane status 0 */ +#define DSI_LANESTATUS1 0x0218 /* DSI lane status 1 */ +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ +#define DSI_LPTXTO 0x0230 /* LPTX Time Out Counter */ + +/* DSI General Registers */ +#define DSIERRCNT 0x0300 /* DSI Error Count Register */ + +/* DSI Application Layer Registers */ +#define APLCTRL 0x0400 /* Application layer Control Register */ +#define RDPKTLN 0x0404 /* DSI Read packet Length Register */ + /* Display Parallel Input Interface */ #define DPIPXLFMT 0x0440 #define VS_POL_ACTIVE_LOW (1 << 10) @@ -117,6 +148,7 @@ #define TC_IDREG 0x0500 #define SYSSTAT 0x0508 #define SYSRSTENB 0x050c +#define SYSBOOT 0x0504 /* System BootStrap Status Register */ #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) #define ENBBM (1 << 3) @@ -141,6 +173,9 @@ #define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10)) #define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11)) +#define TEST_INT_C 0x0570 /* Test Interrupts Control Register */ +#define TEST_INT_S 0x0574 /* Test Interrupts Status Register */ + #define INT_GP0_LCNT 0x0584 #define INT_GP1_LCNT 0x0588 @@ -155,6 +190,9 @@ #define DP0_VIDMNGEN0 0x0610 #define DP0_VIDMNGEN1 0x0614 #define DP0_VMNGENSTATUS 0x0618 +#define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */ +#define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */ +#define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */ /* Main Channel */ #define DP0_SECSAMPLE 0x0640 @@ -224,6 +262,20 @@ #define DP0_SNKLTCHGREQ 0x06d4 #define DP0_LTLOOPCTRL 0x06d8 #define DP0_SNKLTCTRL 0x06e4 +#define DP0_TPATDAT0 0x06e8 /* DP0 Test Pattern bits 29 to 0 */ +#define DP0_TPATDAT1 0x06ec /* DP0 Test Pattern bits 59 to 30 */ +#define DP0_TPATDAT2 0x06f0 /* DP0 Test Pattern bits 89 to 60 */ +#define DP0_TPATDAT3 0x06f4 /* DP0 Test Pattern bits 119 to 90 */ + +#define AUDCFG0 0x0700 /* DP0 Audio Config0 Register */ +#define AUDCFG1 0x0704 /* DP0 Audio Config1 Register */ +#define AUDIFDATA0 0x0708 /* DP0 Audio Info Frame Bytes 3 to 0 */ +#define AUDIFDATA1 0x070c /* DP0 Audio Info Frame Bytes 7 to 4 */ +#define AUDIFDATA2 0x0710 /* DP0 Audio Info Frame Bytes 11 to 8 */ +#define AUDIFDATA3 0x0714 /* DP0 Audio Info Frame Bytes 15 to 12 */ +#define AUDIFDATA4 0x0718 /* DP0 Audio Info Frame Bytes 19 to 16 */ +#define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */ +#define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */ #define DP1_SRCCTRL 0x07a0 @@ -238,6 +290,25 @@ #define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */ #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ +#define DP_PHY_CFG_WR 0x0810 /* DP PHY Configuration Test Write Register */ +#define DP_PHY_CFG_RD 0x0814 /* DP PHY Configuration Test Read Register */ +#define DP0_AUX_PHY_CTRL 0x0820 /* DP0 AUX PHY Control Register */ +#define DP0_MAIN_PHY_DBG 0x0840 /* DP0 Main PHY Test Debug Register */ + +/* I2S */ +#define I2SCFG 0x0880 /* I2S Audio Config 0 Register */ +#define I2SCH0STAT0 0x0888 /* I2S Audio Channel 0 Status Bytes 3 to 0 */ +#define I2SCH0STAT1 0x088c /* I2S Audio Channel 0 Status Bytes 7 to 4 */ +#define I2SCH0STAT2 0x0890 /* I2S Audio Channel 0 Status Bytes 11 to 8 */ +#define I2SCH0STAT3 0x0894 /* I2S Audio Channel 0 Status Bytes 15 to 12 */ +#define I2SCH0STAT4 0x0898 /* I2S Audio Channel 0 Status Bytes 19 to 16 */ +#define I2SCH0STAT5 0x089c /* I2S Audio Channel 0 Status Bytes 23 to 20 */ +#define I2SCH1STAT0 0x08a0 /* I2S Audio Channel 1 Status Bytes 3 to 0 */ +#define I2SCH1STAT1 0x08a4 /* I2S Audio Channel 1 Status Bytes 7 to 4 */ +#define I2SCH1STAT2 0x08a8 /* I2S Audio Channel 1 Status Bytes 11 to 8 */ +#define I2SCH1STAT3 0x08ac /* I2S Audio Channel 1 Status Bytes 15 to 12 */ +#define I2SCH1STAT4 0x08b0 /* I2S Audio Channel 1 Status Bytes 19 to 16 */ +#define I2SCH1STAT5 0x08b4 /* I2S Audio Channel 1 Status Bytes 23 to 20 */ /* PLL */ #define DP0_PLLCTRL 0x0900 @@ -1833,16 +1904,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) case 0x1f4: /* DSI Protocol Layer */ case DSI_STARTDSI: - case 0x208: + case DSI_BUSYDSI: case DSI_LANEENABLE: - case 0x214: - case 0x218: - case 0x220: + case DSI_LANESTATUS0: + case DSI_LANESTATUS1: + case DSI_INTSTATUS: case 0x224: case 0x228: case 0x230: /* DSI General */ - case 0x300: + case DSIERRCNT: /* DSI Application Layer */ case 0x400: case 0x404: @@ -1993,7 +2064,11 @@ static const struct regmap_access_table tc_volatile_table = { }; static const struct regmap_range tc_non_writeable_ranges[] = { - regmap_reg_range(TC_IDREG, TC_IDREG), + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(TC_IDREG, SYSSTAT), + regmap_reg_range(GPIOI, GPIOI), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), }; -- GitLab From b36bc498d1837398e5b355c019dc400201040811 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:54 +0100 Subject: [PATCH 0024/1420] drm/bridge: tc358767: Sort volatile registers according to address Sort the list by the starting address to ease adding new entries. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-5-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index e07b71d1ea8ef..45f8876210fea 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2049,13 +2049,13 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) } static const struct regmap_range tc_volatile_ranges[] = { + regmap_reg_range(VFUEN0, VFUEN0), + regmap_reg_range(GPIOI, GPIOI), + regmap_reg_range(INTSTS_G, INTSTS_G), regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL), - regmap_reg_range(VFUEN0, VFUEN0), - regmap_reg_range(INTSTS_G, INTSTS_G), - regmap_reg_range(GPIOI, GPIOI), }; static const struct regmap_access_table tc_volatile_table = { -- GitLab From ef34c0eb0b58dfdd846093b1a26e63a08acaaf22 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:55 +0100 Subject: [PATCH 0025/1420] drm/bridge: tc358767: Add more volatile registers These registers might change their value without any host write operation. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-6-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 45f8876210fea..d1cde022cb5e6 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2049,9 +2049,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) } static const struct regmap_range tc_volatile_ranges[] = { + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(DSIERRCNT, DSIERRCNT), regmap_reg_range(VFUEN0, VFUEN0), + regmap_reg_range(SYSSTAT, SYSSTAT), regmap_reg_range(GPIOI, GPIOI), regmap_reg_range(INTSTS_G, INTSTS_G), + regmap_reg_range(DP0_VMNGENSTATUS, DP0_VMNGENSTATUS), + regmap_reg_range(DP0_AMNGENSTATUS, DP0_AMNGENSTATUS), regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), -- GitLab From 230dae78d6d4531cd440daa782533d16ea3cfc33 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:56 +0100 Subject: [PATCH 0026/1420] drm/bridge: tc358767: Add precious register SYSSTAT This is the single register which clears its value upon read operation. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-7-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index d1cde022cb5e6..10465398d4e65 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2070,6 +2070,15 @@ static const struct regmap_access_table tc_volatile_table = { .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), }; +static const struct regmap_range tc_precious_ranges[] = { + regmap_reg_range(SYSSTAT, SYSSTAT), +}; + +static const struct regmap_access_table tc_precious_table = { + .yes_ranges = tc_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(tc_precious_ranges), +}; + static const struct regmap_range tc_non_writeable_ranges[] = { regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), @@ -2093,6 +2102,7 @@ static const struct regmap_config tc_regmap_config = { .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, + .precious_table = &tc_precious_table, .wr_table = &tc_writeable_table, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_LITTLE, -- GitLab From 9203f67272531ee17d58966e51f086e9a5deb840 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:57 +0100 Subject: [PATCH 0027/1420] drm/bridge: tc358767: Add descriptions to register definitions Use the register names from the datasheet. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-8-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 10465398d4e65..eb0d82a91cb95 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -145,10 +145,10 @@ #define VFUEN BIT(0) /* Video Frame Timing Upload */ /* System */ -#define TC_IDREG 0x0500 -#define SYSSTAT 0x0508 -#define SYSRSTENB 0x050c +#define TC_IDREG 0x0500 /* Chip ID and Revision ID */ #define SYSBOOT 0x0504 /* System BootStrap Status Register */ +#define SYSSTAT 0x0508 /* System Status Register */ +#define SYSRSTENB 0x050c /* System Reset/Enable Register */ #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) #define ENBBM (1 << 3) @@ -162,12 +162,12 @@ #define DP0_VIDSRC_DSI_RX (1 << 0) #define DP0_VIDSRC_DPI_RX (2 << 0) #define DP0_VIDSRC_COLOR_BAR (3 << 0) -#define GPIOM 0x0540 -#define GPIOC 0x0544 -#define GPIOO 0x0548 -#define GPIOI 0x054c -#define INTCTL_G 0x0560 -#define INTSTS_G 0x0564 +#define GPIOM 0x0540 /* GPIO Mode Control Register */ +#define GPIOC 0x0544 /* GPIO Direction Control Register */ +#define GPIOO 0x0548 /* GPIO Output Register */ +#define GPIOI 0x054c /* GPIO Input Register */ +#define INTCTL_G 0x0560 /* General Interrupts Control Register */ +#define INTSTS_G 0x0564 /* General Interrupts Status Register */ #define INT_SYSERR BIT(16) #define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10)) @@ -176,8 +176,8 @@ #define TEST_INT_C 0x0570 /* Test Interrupts Control Register */ #define TEST_INT_S 0x0574 /* Test Interrupts Status Register */ -#define INT_GP0_LCNT 0x0584 -#define INT_GP1_LCNT 0x0588 +#define INT_GP0_LCNT 0x0584 /* Interrupt GPIO0 Low Count Value Register */ +#define INT_GP1_LCNT 0x0588 /* Interrupt GPIO1 Low Count Value Register */ /* Control */ #define DP0CTL 0x0600 @@ -187,9 +187,9 @@ #define DP_EN BIT(0) /* Enable DPTX function */ /* Clocks */ -#define DP0_VIDMNGEN0 0x0610 -#define DP0_VIDMNGEN1 0x0614 -#define DP0_VMNGENSTATUS 0x0618 +#define DP0_VIDMNGEN0 0x0610 /* DP0 Video Force M Value Register */ +#define DP0_VIDMNGEN1 0x0614 /* DP0 Video Force N Value Register */ +#define DP0_VMNGENSTATUS 0x0618 /* DP0 Video Current M Value Register */ #define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */ #define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */ #define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */ @@ -277,7 +277,7 @@ #define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */ #define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */ -#define DP1_SRCCTRL 0x07a0 +#define DP1_SRCCTRL 0x07a0 /* DP1 Control Register */ /* PHY */ #define DP_PHY_CTRL 0x0800 -- GitLab From 045159f5018eee5fd2b502dbbfdc31985ac8f516 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 7 Dec 2023 17:10:43 +0100 Subject: [PATCH 0028/1420] drm/bridge: samsung-dsim: check the return value only if necessary It was useless to check again the "ret" variable if the function register_host() was not called. Signed-off-by: Dario Binacchi Reviewed-by: Frieder Schrempf Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231207161056.183442-1-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/bridge/samsung-dsim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index be5914caa17d5..98cd589e4427e 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -2020,11 +2020,11 @@ int samsung_dsim_probe(struct platform_device *pdev) else dsi->bridge.timings = &samsung_dsim_bridge_timings_de_high; - if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) + if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) { ret = dsi->plat_data->host_ops->register_host(dsi); - - if (ret) - goto err_disable_runtime; + if (ret) + goto err_disable_runtime; + } return 0; -- GitLab From 216d86b9a430f3280e5b631c51e6fd1a7774cfa0 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 15 Sep 2023 18:59:18 +0800 Subject: [PATCH 0029/1420] drm/virtio: add definition for venus capset This Venus capset definition is used by Qemu, and Qemu imports the kernel protocol header file. Add Venus capset to the VirtIO-GPU protocol. Signed-off-by: Huang Rui [dmitry.osipenko@collabora.com: edit commit message] Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20230915105918.3763061-1-ray.huang@amd.com --- include/uapi/linux/virtio_gpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index f556fde07b76b..0e21f39981086 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -309,6 +309,8 @@ struct virtio_gpu_cmd_submit { #define VIRTIO_GPU_CAPSET_VIRGL 1 #define VIRTIO_GPU_CAPSET_VIRGL2 2 +/* 3 is reserved for gfxstream */ +#define VIRTIO_GPU_CAPSET_VENUS 4 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ struct virtio_gpu_get_capset_info { -- GitLab From 0808aef86dc2776f75c7961015ee0280b78d868d Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:51 -0700 Subject: [PATCH 0030/1420] accel/qaic: Deprecate ->size field from attach slice IOCTL structure ->size in struct qaic_attach_slice_hdr is redundant since we have BO handle and its size can be retrieved from base BO structure. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-2-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 17 ++++------------- include/uapi/drm/qaic_accel.h | 13 +------------ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index cf2898eda7ae3..0c6f1328df68e 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -830,9 +830,6 @@ static int qaic_prepare_import_bo(struct qaic_bo *bo, struct qaic_attach_slice_h struct sg_table *sgt; int ret; - if (obj->import_attach->dmabuf->size < hdr->size) - return -EINVAL; - sgt = dma_buf_map_attachment(obj->import_attach, hdr->dir); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); @@ -849,9 +846,6 @@ static int qaic_prepare_export_bo(struct qaic_device *qdev, struct qaic_bo *bo, { int ret; - if (bo->base.size < hdr->size) - return -EINVAL; - ret = dma_map_sgtable(&qdev->pdev->dev, bo->sgt, hdr->dir, 0); if (ret) return -EFAULT; @@ -952,9 +946,6 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi if (arg_size / args->hdr.count != sizeof(*slice_ent)) return -EINVAL; - if (args->hdr.size == 0) - return -EINVAL; - if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE)) return -EINVAL; @@ -994,16 +985,16 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi goto free_slice_ent; } - ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, args->hdr.size); - if (ret) - goto free_slice_ent; - obj = drm_gem_object_lookup(file_priv, args->hdr.handle); if (!obj) { ret = -ENOENT; goto free_slice_ent; } + ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, obj->size); + if (ret) + goto put_bo; + bo = to_qaic_bo(obj); ret = mutex_lock_interruptible(&bo->lock); if (ret) diff --git a/include/uapi/drm/qaic_accel.h b/include/uapi/drm/qaic_accel.h index 9dab32316aee4..d3ca876a08e92 100644 --- a/include/uapi/drm/qaic_accel.h +++ b/include/uapi/drm/qaic_accel.h @@ -242,18 +242,7 @@ struct qaic_attach_slice_entry { * @dbc_id: In. Associate the sliced BO with this DBC. * @handle: In. GEM handle of the BO to slice. * @dir: In. Direction of data flow. 1 = DMA_TO_DEVICE, 2 = DMA_FROM_DEVICE - * @size: In. Total length of BO being used. This should not exceed base - * size of BO (struct drm_gem_object.base) - * For BOs being allocated using DRM_IOCTL_QAIC_CREATE_BO, size of - * BO requested is PAGE_SIZE aligned then allocated hence allocated - * BO size maybe bigger. This size should not exceed the new - * PAGE_SIZE aligned BO size. - * @dev_addr: In. Device address this slice pushes to or pulls from. - * @db_addr: In. Address of the doorbell to ring. - * @db_data: In. Data to write to the doorbell. - * @db_len: In. Size of the doorbell data in bits - 32, 16, or 8. 0 is for - * inactive doorbells. - * @offset: In. Start of this slice as an offset from the start of the BO. + * @size: Deprecated. This value is ignored and size of @handle is used instead. */ struct qaic_attach_slice_hdr { __u32 count; -- GitLab From 401c005c16c954803850e9ee57486c385245bc73 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:52 -0700 Subject: [PATCH 0031/1420] accel/qaic: Remove bo->queued field ->queued field is used to track whether the BO is submitted to hardware for DMA or not. Since same information can be retrieved using ->xfer_list field of same structure remove ->queued as it is redundant. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-3-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 2 -- drivers/accel/qaic/qaic_data.c | 23 +++++++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 582836f9538f9..2b3ef588b717a 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -191,8 +191,6 @@ struct qaic_bo { u32 nr_slice; /* Number of slice that have been transferred by DMA engine */ u32 nr_slice_xfer_done; - /* true = BO is queued for execution, true = BO is not queued */ - bool queued; /* * If true then user has attached slicing information to this BO by * calling DRM_IOCTL_QAIC_ATTACH_SLICE_BO ioctl. diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 0c6f1328df68e..89ab8fa193151 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -141,6 +141,11 @@ struct dbc_rsp { __le16 status; } __packed; +static inline bool bo_queued(struct qaic_bo *bo) +{ + return !list_empty(&bo->xfer_list); +} + inline int get_dbc_req_elem_size(void) { return sizeof(struct dbc_req); @@ -648,6 +653,7 @@ static void qaic_init_bo(struct qaic_bo *bo, bool reinit) } complete_all(&bo->xfer_done); INIT_LIST_HEAD(&bo->slices); + INIT_LIST_HEAD(&bo->xfer_list); } static struct qaic_bo *qaic_alloc_init_bo(void) @@ -1166,7 +1172,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil struct bo_slice *slice; unsigned long flags; struct qaic_bo *bo; - bool queued; int i, j; int ret; @@ -1198,9 +1203,7 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil } spin_lock_irqsave(&dbc->xfer_lock, flags); - queued = bo->queued; - bo->queued = true; - if (queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EINVAL; goto unlock_bo; @@ -1223,7 +1226,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil else ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail); if (ret) { - bo->queued = false; spin_unlock_irqrestore(&dbc->xfer_lock, flags); goto unlock_bo; } @@ -1246,8 +1248,7 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil spin_lock_irqsave(&dbc->xfer_lock, flags); bo = list_last_entry(&dbc->xfer_list, struct qaic_bo, xfer_list); obj = &bo->base; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); drm_gem_object_put(obj); @@ -1608,8 +1609,7 @@ irqreturn_t dbc_irq_threaded_fn(int irq, void *data) */ dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); bo->nr_slice_xfer_done = 0; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); bo->perf_stats.req_processed_ts = ktime_get_ns(); complete_all(&bo->xfer_done); drm_gem_object_put(&bo->base); @@ -1868,7 +1868,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi /* Check if BO is committed to H/W for DMA */ spin_lock_irqsave(&dbc->xfer_lock, flags); - if (bo->queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EBUSY; goto unlock_ch_srcu; @@ -1898,8 +1898,7 @@ static void empty_xfer_list(struct qaic_device *qdev, struct dma_bridge_chan *db spin_lock_irqsave(&dbc->xfer_lock, flags); while (!list_empty(&dbc->xfer_list)) { bo = list_first_entry(&dbc->xfer_list, typeof(*bo), xfer_list); - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); bo->nr_slice_xfer_done = 0; bo->req_id = 0; -- GitLab From fbd60a67f4975d6bad25d9d504055fae8c1c27b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 8 Dec 2023 09:34:53 -0700 Subject: [PATCH 0032/1420] accel/qaic: Fix MHI channel struct field order The timesync channels have their struct fields out of order with the rest of the channels. Fix them so there is a consistent style in the file. Signed-off-by: Jeffrey Hugo Reviewed-by: Carl Vanderlip Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-4-quic_jhugo@quicinc.com --- drivers/accel/qaic/mhi_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 832464f2833ad..364eede0ac022 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -358,8 +358,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 21, .name = "QAIC_TIMESYNC", + .num = 21, .num_elements = 32, .local_elements = 0, .event_ring = 0, @@ -390,8 +390,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 23, .name = "QAIC_TIMESYNC_PERIODIC", + .num = 23, .num_elements = 32, .local_elements = 0, .event_ring = 0, -- GitLab From ce5fed9aa0f6ff951bc1ef02f274875e67f070d2 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:54 -0700 Subject: [PATCH 0033/1420] accel/qaic: Drop the reference to BO in error path of create BO IOCTL Do not free BO explicitly in error path, just drop its reference, cleanup will be taken care by DRM as we have registered for ->free() callback. This patch makes sure that there is only one code path for BO to be freed. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Carl Vanderlip Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-5-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 89ab8fa193151..7faa00705c1d5 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -574,6 +574,9 @@ static void qaic_free_sgt(struct sg_table *sgt) { struct scatterlist *sg; + if (!sgt) + return; + for (sg = sgt->sgl; sg; sg = sg_next(sg)) if (sg_page(sg)) __free_pages(sg_page(sg), get_order(sg->length)); @@ -717,7 +720,7 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi ret = drm_gem_handle_create(file_priv, obj, &args->handle); if (ret) - goto free_sgt; + goto free_bo; bo->handle = args->handle; drm_gem_object_put(obj); @@ -726,10 +729,8 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi return 0; -free_sgt: - qaic_free_sgt(bo->sgt); free_bo: - kfree(bo); + drm_gem_object_put(obj); unlock_dev_srcu: srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); unlock_usr_srcu: -- GitLab From 2f4494b34fe3f6fd810e3690a3cf66b551cef3da Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:55 -0700 Subject: [PATCH 0034/1420] accel/qaic: Call drm_gem_create_mmap_offset() once for each BO Every time QAIC_MMAP_BO ioctl is called for a BO, drm_gem_create_mmap_offset() is called. Calling drm_gem_create_mmap_offset() more then once for a BO seems redundant. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-6-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 7faa00705c1d5..f88d925c8001c 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -718,6 +718,10 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (ret) goto free_bo; + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto free_bo; + ret = drm_gem_handle_create(file_priv, obj, &args->handle); if (ret) goto free_bo; @@ -745,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file struct drm_gem_object *obj; struct qaic_device *qdev; struct qaic_user *usr; - int ret; + int ret = 0; usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); @@ -767,9 +771,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file goto unlock_dev_srcu; } - ret = drm_gem_create_mmap_offset(obj); - if (ret == 0) - args->offset = drm_vma_node_offset_addr(&obj->vma_node); + args->offset = drm_vma_node_offset_addr(&obj->vma_node); drm_gem_object_put(obj); -- GitLab From 8505e70821ade706f98f7114a2cbcd51326f7b82 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:26 +0100 Subject: [PATCH 0035/1420] fbdev/efifb: Replace references to global screen_info by local pointer Get the global screen_info's address once and access the data via this pointer. Limits the use of global state. v3: * use const screen_info in several places (Sui) * fix build for deferred takeover (kernel test robot) Signed-off-by: Thomas Zimmermann Tested-by: Sui Jingfeng Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-2-tzimmermann@suse.de --- drivers/video/fbdev/efifb.c | 124 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index f9b4ddd592ce4..6b3b5cca1d41d 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -108,7 +108,7 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, */ #if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ defined CONFIG_ACPI_BGRT -static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) +static void efifb_copy_bmp(u8 *src, u32 *dst, int width, const struct screen_info *si) { u8 r, g, b; @@ -130,7 +130,7 @@ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) * resolution still fits, it will be displayed very close to the right edge of * the display looking quite bad. This function checks for this. */ -static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width) { /* * All x86 firmwares horizontally center the image (the yoffset @@ -141,16 +141,15 @@ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) return bgrt_tab.image_offset_x == expected_xoffset; } #else -static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width) { return true; } #endif -static void efifb_show_boot_graphics(struct fb_info *info) +static void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si) { u32 bmp_width, bmp_height, bmp_pitch, dst_x, y, src_y; - struct screen_info *si = &screen_info; struct bmp_file_header *file_header; struct bmp_dib_header *dib_header; void *bgrt_image = NULL; @@ -247,7 +246,8 @@ static void efifb_show_boot_graphics(struct fb_info *info) pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n"); } #else -static inline void efifb_show_boot_graphics(struct fb_info *info) {} +static inline void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si) +{ } #endif /* @@ -282,7 +282,7 @@ static const struct fb_ops efifb_ops = { .fb_setcolreg = efifb_setcolreg, }; -static int efifb_setup(char *options) +static int efifb_setup(struct screen_info *si, char *options) { char *this_opt; @@ -290,16 +290,16 @@ static int efifb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; - efifb_setup_from_dmi(&screen_info, this_opt); + efifb_setup_from_dmi(si, this_opt); if (!strncmp(this_opt, "base:", 5)) - screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); + si->lfb_base = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "stride:", 7)) - screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; + si->lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; else if (!strncmp(this_opt, "height:", 7)) - screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0); + si->lfb_height = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "width:", 6)) - screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); + si->lfb_width = simple_strtoul(this_opt+6, NULL, 0); else if (!strcmp(this_opt, "nowc")) mem_flags &= ~EFI_MEMORY_WC; else if (!strcmp(this_opt, "nobgrt")) @@ -310,15 +310,15 @@ static int efifb_setup(char *options) return 0; } -static inline bool fb_base_is_valid(void) +static inline bool fb_base_is_valid(struct screen_info *si) { - if (screen_info.lfb_base) + if (si->lfb_base) return true; - if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)) + if (!(si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)) return false; - if (screen_info.ext_lfb_base) + if (si->ext_lfb_base) return true; return false; @@ -329,7 +329,10 @@ static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return sprintf(buf, fmt "\n", (screen_info.lfb_##name)); \ + struct screen_info *si = dev_get_platdata(dev); \ + if (!si) \ + return -ENODEV; \ + return sprintf(buf, fmt "\n", (si->lfb_##name)); \ } \ static DEVICE_ATTR_RO(name) @@ -356,6 +359,7 @@ static u64 bar_offset; static int efifb_probe(struct platform_device *dev) { + struct screen_info *si = &screen_info; struct fb_info *info; struct efifb_par *par; int err, orientation; @@ -365,48 +369,48 @@ static int efifb_probe(struct platform_device *dev) char *option = NULL; efi_memory_desc_t md; - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) + if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; if (fb_get_options("efifb", &option)) return -ENODEV; - efifb_setup(option); + efifb_setup(si, option); /* We don't get linelength from UGA Draw Protocol, only from * EFI Graphics Protocol. So if it's not in DMI, and it's not * passed in from the user, we really can't use the framebuffer. */ - if (!screen_info.lfb_linelength) + if (!si->lfb_linelength) return -ENODEV; - if (!screen_info.lfb_depth) - screen_info.lfb_depth = 32; - if (!screen_info.pages) - screen_info.pages = 1; - if (!fb_base_is_valid()) { + if (!si->lfb_depth) + si->lfb_depth = 32; + if (!si->pages) + si->pages = 1; + if (!fb_base_is_valid(si)) { printk(KERN_DEBUG "efifb: invalid framebuffer address\n"); return -ENODEV; } printk(KERN_INFO "efifb: probing for efifb\n"); /* just assume they're all unset if any are */ - if (!screen_info.blue_size) { - screen_info.blue_size = 8; - screen_info.blue_pos = 0; - screen_info.green_size = 8; - screen_info.green_pos = 8; - screen_info.red_size = 8; - screen_info.red_pos = 16; - screen_info.rsvd_size = 8; - screen_info.rsvd_pos = 24; + if (!si->blue_size) { + si->blue_size = 8; + si->blue_pos = 0; + si->green_size = 8; + si->green_pos = 8; + si->red_size = 8; + si->red_pos = 16; + si->rsvd_size = 8; + si->rsvd_pos = 24; } - efifb_fix.smem_start = screen_info.lfb_base; + efifb_fix.smem_start = si->lfb_base; - if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) { + if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) { u64 ext_lfb_base; - ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32; + ext_lfb_base = (u64)(unsigned long)si->ext_lfb_base << 32; efifb_fix.smem_start |= ext_lfb_base; } @@ -417,10 +421,10 @@ static int efifb_probe(struct platform_device *dev) efifb_fix.smem_start = bar_resource->start + bar_offset; } - efifb_defined.bits_per_pixel = screen_info.lfb_depth; - efifb_defined.xres = screen_info.lfb_width; - efifb_defined.yres = screen_info.lfb_height; - efifb_fix.line_length = screen_info.lfb_linelength; + efifb_defined.bits_per_pixel = si->lfb_depth; + efifb_defined.xres = si->lfb_width; + efifb_defined.yres = si->lfb_height; + efifb_fix.line_length = si->lfb_linelength; /* size_vmode -- that is the amount of memory needed for the * used video mode, i.e. the minimum amount of @@ -430,7 +434,7 @@ static int efifb_probe(struct platform_device *dev) /* size_total -- all video memory we have. Used for * entries, ressource allocation and bounds * checking. */ - size_total = screen_info.lfb_size; + size_total = si->lfb_size; if (size_total < size_vmode) size_total = size_vmode; @@ -505,14 +509,14 @@ static int efifb_probe(struct platform_device *dev) goto err_release_fb; } - efifb_show_boot_graphics(info); + efifb_show_boot_graphics(info, si); pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", efifb_fix.smem_start, size_remap/1024, size_total/1024); pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", efifb_defined.xres, efifb_defined.yres, efifb_defined.bits_per_pixel, efifb_fix.line_length, - screen_info.pages); + si->pages); efifb_defined.xres_virtual = efifb_defined.xres; efifb_defined.yres_virtual = efifb_fix.smem_len / @@ -526,26 +530,26 @@ static int efifb_probe(struct platform_device *dev) efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8; efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8; - efifb_defined.red.offset = screen_info.red_pos; - efifb_defined.red.length = screen_info.red_size; - efifb_defined.green.offset = screen_info.green_pos; - efifb_defined.green.length = screen_info.green_size; - efifb_defined.blue.offset = screen_info.blue_pos; - efifb_defined.blue.length = screen_info.blue_size; - efifb_defined.transp.offset = screen_info.rsvd_pos; - efifb_defined.transp.length = screen_info.rsvd_size; + efifb_defined.red.offset = si->red_pos; + efifb_defined.red.length = si->red_size; + efifb_defined.green.offset = si->green_pos; + efifb_defined.green.length = si->green_size; + efifb_defined.blue.offset = si->blue_pos; + efifb_defined.blue.length = si->blue_size; + efifb_defined.transp.offset = si->rsvd_pos; + efifb_defined.transp.length = si->rsvd_size; pr_info("efifb: %s: " "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", "Truecolor", - screen_info.rsvd_size, - screen_info.red_size, - screen_info.green_size, - screen_info.blue_size, - screen_info.rsvd_pos, - screen_info.red_pos, - screen_info.green_pos, - screen_info.blue_pos); + si->rsvd_size, + si->red_size, + si->green_size, + si->blue_size, + si->rsvd_pos, + si->red_pos, + si->green_pos, + si->blue_pos); efifb_fix.ypanstep = 0; efifb_fix.ywrapstep = 0; -- GitLab From b9cfd1d271ab51d677cd16b02b74267b5bac6508 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:27 +0100 Subject: [PATCH 0036/1420] fbdev/efifb: Use screen_info pointer from device Use the screen_info instance from the device instead of dereferencing the global screen_info state. Decouples the driver from per-architecture code. Duplicated the screen_info data, so that efifb can modify it at will. v2: * comment on devm_kmemdup() usage (Javier) Signed-off-by: Thomas Zimmermann Tested-by: Sui Jingfeng Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-3-tzimmermann@suse.de --- drivers/video/fbdev/efifb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 6b3b5cca1d41d..10fc14ad5d127 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -359,7 +359,7 @@ static u64 bar_offset; static int efifb_probe(struct platform_device *dev) { - struct screen_info *si = &screen_info; + struct screen_info *si; struct fb_info *info; struct efifb_par *par; int err, orientation; @@ -369,6 +369,18 @@ static int efifb_probe(struct platform_device *dev) char *option = NULL; efi_memory_desc_t md; + /* + * If we fail probing the device, the kernel might try a different + * driver. We get a copy of the attached screen_info, so that we can + * modify its values without affecting later drivers. + */ + si = dev_get_platdata(&dev->dev); + if (!si) + return -ENODEV; + si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL); + if (!si) + return -ENOMEM; + if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; -- GitLab From 3218286bbb78cac3dde713514529e0480d678173 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:28 +0100 Subject: [PATCH 0037/1420] fbdev/vesafb: Replace references to global screen_info by local pointer Get the global screen_info's address once and access the data via this pointer. Limits the use of global state. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-4-tzimmermann@suse.de --- drivers/video/fbdev/vesafb.c | 66 +++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c index c0edceea0a793..ea89accbec385 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -243,6 +243,7 @@ static int vesafb_setup(char *options) static int vesafb_probe(struct platform_device *dev) { + struct screen_info *si = &screen_info; struct fb_info *info; struct vesafb_par *par; int i, err; @@ -255,17 +256,17 @@ static int vesafb_probe(struct platform_device *dev) fb_get_options("vesafb", &option); vesafb_setup(option); - if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) + if (si->orig_video_isVGA != VIDEO_TYPE_VLFB) return -ENODEV; - vga_compat = (screen_info.capabilities & 2) ? 0 : 1; - vesafb_fix.smem_start = screen_info.lfb_base; - vesafb_defined.bits_per_pixel = screen_info.lfb_depth; + vga_compat = (si->capabilities & 2) ? 0 : 1; + vesafb_fix.smem_start = si->lfb_base; + vesafb_defined.bits_per_pixel = si->lfb_depth; if (15 == vesafb_defined.bits_per_pixel) vesafb_defined.bits_per_pixel = 16; - vesafb_defined.xres = screen_info.lfb_width; - vesafb_defined.yres = screen_info.lfb_height; - vesafb_fix.line_length = screen_info.lfb_linelength; + vesafb_defined.xres = si->lfb_width; + vesafb_defined.yres = si->lfb_height; + vesafb_fix.line_length = si->lfb_linelength; vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; @@ -277,7 +278,7 @@ static int vesafb_probe(struct platform_device *dev) /* size_total -- all video memory we have. Used for mtrr * entries, resource allocation and bounds * checking. */ - size_total = screen_info.lfb_size * 65536; + size_total = si->lfb_size * 65536; if (vram_total) size_total = vram_total * 1024 * 1024; if (size_total < size_vmode) @@ -297,7 +298,7 @@ static int vesafb_probe(struct platform_device *dev) vesafb_fix.smem_len = size_remap; #ifndef __i386__ - screen_info.vesapm_seg = 0; + si->vesapm_seg = 0; #endif if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { @@ -317,23 +318,26 @@ static int vesafb_probe(struct platform_device *dev) par = info->par; info->pseudo_palette = par->pseudo_palette; - par->base = screen_info.lfb_base; + par->base = si->lfb_base; par->size = size_total; printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", - vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, + vesafb_fix.line_length, si->pages); - if (screen_info.vesapm_seg) { + if (si->vesapm_seg) { printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", - screen_info.vesapm_seg,screen_info.vesapm_off); + si->vesapm_seg, si->vesapm_off); } - if (screen_info.vesapm_seg < 0xc000) + if (si->vesapm_seg < 0xc000) ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ if (ypan || pmi_setpal) { + unsigned long pmi_phys; unsigned short *pmi_base; - pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_phys = ((unsigned long)si->vesapm_seg << 4) + si->vesapm_off; + pmi_base = (unsigned short *)phys_to_virt(pmi_phys); pmi_start = (void*)((char*)pmi_base + pmi_base[1]); pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); @@ -377,14 +381,14 @@ static int vesafb_probe(struct platform_device *dev) vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8; vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8; - vesafb_defined.red.offset = screen_info.red_pos; - vesafb_defined.red.length = screen_info.red_size; - vesafb_defined.green.offset = screen_info.green_pos; - vesafb_defined.green.length = screen_info.green_size; - vesafb_defined.blue.offset = screen_info.blue_pos; - vesafb_defined.blue.length = screen_info.blue_size; - vesafb_defined.transp.offset = screen_info.rsvd_pos; - vesafb_defined.transp.length = screen_info.rsvd_size; + vesafb_defined.red.offset = si->red_pos; + vesafb_defined.red.length = si->red_size; + vesafb_defined.green.offset = si->green_pos; + vesafb_defined.green.length = si->green_size; + vesafb_defined.blue.offset = si->blue_pos; + vesafb_defined.blue.length = si->blue_size; + vesafb_defined.transp.offset = si->rsvd_pos; + vesafb_defined.transp.length = si->rsvd_size; if (vesafb_defined.bits_per_pixel <= 8) { depth = vesafb_defined.green.length; @@ -399,14 +403,14 @@ static int vesafb_probe(struct platform_device *dev) (vesafb_defined.bits_per_pixel > 8) ? "Truecolor" : (vga_compat || pmi_setpal) ? "Pseudocolor" : "Static Pseudocolor", - screen_info.rsvd_size, - screen_info.red_size, - screen_info.green_size, - screen_info.blue_size, - screen_info.rsvd_pos, - screen_info.red_pos, - screen_info.green_pos, - screen_info.blue_pos); + si->rsvd_size, + si->red_size, + si->green_size, + si->blue_size, + si->rsvd_pos, + si->red_pos, + si->green_pos, + si->blue_pos); vesafb_fix.ypanstep = ypan ? 1 : 0; vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; -- GitLab From 0f7c246235a0639d90b5380277a43c853ba73681 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:29 +0100 Subject: [PATCH 0038/1420] fbdev/vesafb: Use screen_info pointer from device Use the screen_info instance from the device instead of dereferencing the global screen_info state. Decouples the driver from per-architecture code. Duplicated the screen_info data, so that vesafb can modify it at will. v2: * comment on devm_kmemdup() usage (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-5-tzimmermann@suse.de --- drivers/video/fbdev/vesafb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c index ea89accbec385..8ab64ae4cad3e 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -243,7 +243,7 @@ static int vesafb_setup(char *options) static int vesafb_probe(struct platform_device *dev) { - struct screen_info *si = &screen_info; + struct screen_info *si; struct fb_info *info; struct vesafb_par *par; int i, err; @@ -252,6 +252,18 @@ static int vesafb_probe(struct platform_device *dev) unsigned int size_total; char *option = NULL; + /* + * If we fail probing the device, the kernel might try a different + * driver. We get a copy of the attached screen_info, so that we can + * modify its values without affecting later drivers. + */ + si = dev_get_platdata(&dev->dev); + if (!si) + return -ENODEV; + si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL); + if (!si) + return -ENOMEM; + /* ignore error return of fb_get_options */ fb_get_options("vesafb", &option); vesafb_setup(option); -- GitLab From 1c20d8b8e171b92194a4f9b45821c821606b8936 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:12 +0100 Subject: [PATCH 0039/1420] drm/atomic: Move the drm_atomic_state field doc inline Some fields of drm_atomic_state have been documented in-line, but some were documented in the main kerneldoc block before the structure. Since the former is the preferred option in DRM, let's move all the fields to an inline documentation. Acked-by: Sui Jingfeng Link: https://lore.kernel.org/r/20231214100917.277842-1-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 50 ++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index cf8e1220a4ac4..2a08030fcd757 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -347,24 +347,22 @@ struct __drm_private_objs_state { /** * struct drm_atomic_state - the global state object for atomic updates - * @ref: count of all references to this state (will not be freed until zero) - * @dev: parent DRM device - * @async_update: hint for asynchronous plane update - * @planes: pointer to array of structures with per-plane data - * @crtcs: pointer to array of CRTC pointers - * @num_connector: size of the @connectors and @connector_states arrays - * @connectors: pointer to array of structures with per-connector data - * @num_private_objs: size of the @private_objs array - * @private_objs: pointer to array of private object pointers - * @acquire_ctx: acquire context for this atomic modeset state update * * States are added to an atomic update by calling drm_atomic_get_crtc_state(), * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for * private state structures, drm_atomic_get_private_obj_state(). */ struct drm_atomic_state { + /** + * @ref: + * + * Count of all references to this update (will not be freed until zero). + */ struct kref ref; + /** + * @dev: Parent DRM Device. + */ struct drm_device *dev; /** @@ -388,7 +386,12 @@ struct drm_atomic_state { * flag are not allowed. */ bool legacy_cursor_update : 1; + + /** + * @async_update: hint for asynchronous plane update + */ bool async_update : 1; + /** * @duplicated: * @@ -398,13 +401,40 @@ struct drm_atomic_state { * states. */ bool duplicated : 1; + + /** + * @planes: pointer to array of structures with per-plane data + */ struct __drm_planes_state *planes; + + /** + * @crtcs: pointer to array of CRTC pointers + */ struct __drm_crtcs_state *crtcs; + + /** + * @num_connector: size of the @connectors and @connector_states arrays + */ int num_connector; + + /** + * @connectors: pointer to array of structures with per-connector data + */ struct __drm_connnectors_state *connectors; + + /** + * @num_private_objs: size of the @private_objs array + */ int num_private_objs; + + /** + * @private_objs: pointer to array of private object pointers + */ struct __drm_private_objs_state *private_objs; + /** + * @acquire_ctx: acquire context for this atomic modeset state update + */ struct drm_modeset_acquire_ctx *acquire_ctx; /** -- GitLab From 786f6c2fa4ae3913f0fdcd371e871bd97aff8481 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:13 +0100 Subject: [PATCH 0040/1420] drm/atomic: Remove inexistent reference Commit 63e83c1dba54 ("drm: Consolidate connector arrays in drm_atomic_state") removed the connector_states field but didn't remove its mention in the num_connectors documentation. Acked-by: Sui Jingfeng Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-2-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 2a08030fcd757..13cecdc1257da 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -413,7 +413,7 @@ struct drm_atomic_state { struct __drm_crtcs_state *crtcs; /** - * @num_connector: size of the @connectors and @connector_states arrays + * @num_connector: size of the @connectors array */ int num_connector; -- GitLab From 17beda5e951aac35fee26703719c252bb216b56b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:14 +0100 Subject: [PATCH 0041/1420] drm/atomic: Rework the object doc a bit Commits 63e83c1dba54 ("drm: Consolidate connector arrays in drm_atomic_state"), b8b5342b699b ("drm: Consolidate plane arrays in drm_atomic_state") and 5d943aa6c0d4 ("drm: Consolidate crtc arrays in drm_atomic_state") moved the object pointer and their state pointer to an intermediate structure storing both. The CRTC commit didn't update the doc of the crtcs field to reflect that, and the doc for the planes and connectors fields mention that they are pointers to an array of structures with per-$OBJECT data. The private_objs field was added later on by commit b430c27a7de3 ("drm: Add driver-private objects to atomic state") reusing the same sentence than the crtcs field, probably due to copy and paste. While these fields are indeed pointers to an array, each item of that array contain a pointer to the object structure affected by the update, and its old and new state. There's no per-object data there, and there's more than just a pointer to the objects. Let's rephrase those fields a bit to better match the current situation. Acked-by: Sui Jingfeng Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-3-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 13cecdc1257da..914574b58ae7c 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -403,12 +403,18 @@ struct drm_atomic_state { bool duplicated : 1; /** - * @planes: pointer to array of structures with per-plane data + * @planes: + * + * Pointer to array of @drm_plane and @drm_plane_state part of this + * update. */ struct __drm_planes_state *planes; /** - * @crtcs: pointer to array of CRTC pointers + * @crtcs: + * + * Pointer to array of @drm_crtc and @drm_crtc_state part of this + * update. */ struct __drm_crtcs_state *crtcs; @@ -418,7 +424,10 @@ struct drm_atomic_state { int num_connector; /** - * @connectors: pointer to array of structures with per-connector data + * @connectors: + * + * Pointer to array of @drm_connector and @drm_connector_state part of + * this update. */ struct __drm_connnectors_state *connectors; @@ -428,7 +437,10 @@ struct drm_atomic_state { int num_private_objs; /** - * @private_objs: pointer to array of private object pointers + * @private_objs: + * + * Pointer to array of @drm_private_obj and @drm_private_obj_state part + * of this update. */ struct __drm_private_objs_state *private_objs; -- GitLab From ab9fabeae4e71095d29216ff14f8a56e4fdda895 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:15 +0100 Subject: [PATCH 0042/1420] drm/atomic: Make the drm_atomic_state documentation less ambiguous The current documentation of drm_atomic_state says that it's the "global state object". This is confusing since, while it does contain all the objects affected by an update and their respective states, if an object isn't affected by this update it won't be part of it. Thus, it's not truly a "global state", unlike object state structures that do contain the entire state of a given object. Reviewed-by: Hamza Mahfooz Acked-by: Pekka Paalanen Link: https://lore.kernel.org/r/20231214100917.277842-4-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 914574b58ae7c..4d7f4c5f20018 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -346,7 +346,13 @@ struct __drm_private_objs_state { }; /** - * struct drm_atomic_state - the global state object for atomic updates + * struct drm_atomic_state - Atomic commit structure + * + * This structure is the kernel counterpart of @drm_mode_atomic and represents + * an atomic commit that transitions from an old to a new display state. It + * contains all the objects affected by the atomic commit and both the new + * state structures and pointers to the old state structures for + * these. * * States are added to an atomic update by calling drm_atomic_get_crtc_state(), * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for -- GitLab From d0ac5722dae5f4302bb4ef6df10d0afa718df80b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:16 +0100 Subject: [PATCH 0043/1420] drm/todo: Add entry to rename drm_atomic_state The name of the structure drm_atomic_state is confusing. Let's add an entry to our todo list to rename it. Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-5-mripard@kernel.org Signed-off-by: Maxime Ripard --- Documentation/gpu/todo.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 41a264bf84ce0..fb9ad120b1414 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -120,6 +120,29 @@ Contact: Daniel Vetter, respective driver maintainers Level: Advanced +Rename drm_atomic_state +----------------------- + +The KMS framework uses two slightly different definitions for the ``state`` +concept. For a given object (plane, CRTC, encoder, etc., so +``drm_$OBJECT_state``), the state is the entire state of that object. However, +at the device level, ``drm_atomic_state`` refers to a state update for a +limited number of objects. + +The state isn't the entire device state, but only the full state of some +objects in that device. This is confusing to newcomers, and +``drm_atomic_state`` should be renamed to something clearer like +``drm_atomic_commit``. + +In addition to renaming the structure itself, it would also imply renaming some +related functions (``drm_atomic_state_alloc``, ``drm_atomic_state_get``, +``drm_atomic_state_put``, ``drm_atomic_state_init``, +``__drm_atomic_state_free``, etc.). + +Contact: Maxime Ripard + +Level: Advanced + Fallout from atomic KMS ----------------------- -- GitLab From 3a63826c720675f35144a444b9a8e506493f5166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 15 Dec 2023 13:11:29 +0200 Subject: [PATCH 0044/1420] drm/mm: Allow CONFIG_DRM_MM_DEBUG with DRM=m MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original rationale for commit cd456f8d06d2 ("drm: Restrict stackdepot usage to builtin drm.ko") was that depot_save_stack() (which is what we used back then) wasn't exported. stack_depot_save() (which is what we use now) is exported however, so relax the dependency allow CONFIG_DRM_MM_DEBUG with DRM=m. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231215111129.9559-1-ville.syrjala@linux.intel.com Acked-by: Javier Martinez Canillas --- drivers/gpu/drm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 31cfe2c2a2afa..4b8b8f8a0e72b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -42,7 +42,7 @@ config DRM_MIPI_DSI config DRM_DEBUG_MM bool "Insert extra checks and debug info into the DRM range managers" default n - depends on DRM=y + depends on DRM depends on STACKTRACE_SUPPORT select STACKDEPOT help -- GitLab From 4464af92f276537716db87aa21828190b5e12463 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:50 +0800 Subject: [PATCH 0045/1420] drm/panel-edp: Add powered_on_to_enable delay Add the support of powered_on_to_enable delay as the minimum time that needs to have passed between the panel powered on and enable may begin. This delay is seen in BOE panels as the minimum delay of T3+T4+T5+T6+T8 in the eDP timing diagrams. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-2-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index a0b6f69b916f9..44acf9cacaf70 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -70,6 +70,21 @@ struct panel_delay { */ unsigned int hpd_absent; + /** + * @powered_on_to_enable: Time between panel powered on and enable. + * + * The minimum time, in milliseconds, that needs to have passed + * between when panel powered on and enable may begin. + * + * This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the + * power supply enabled until we can turn the backlight on and see + * valid data. + * + * This doesn't normally need to be set if timings are already met by + * prepare_to_enable or enable. + */ + unsigned int powered_on_to_enable; + /** * @prepare_to_enable: Time between prepare and enable. * @@ -216,6 +231,7 @@ struct panel_edp { bool prepared; ktime_t prepared_time; + ktime_t powered_on_time; ktime_t unprepared_time; const struct panel_desc *desc; @@ -455,6 +471,8 @@ static int panel_edp_prepare_once(struct panel_edp *p) gpiod_set_value_cansleep(p->enable_gpio, 1); + p->powered_on_time = ktime_get_boottime(); + delay = p->desc->delay.hpd_reliable; if (p->no_hpd) delay = max(delay, p->desc->delay.hpd_absent); @@ -579,6 +597,8 @@ static int panel_edp_enable(struct drm_panel *panel) panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable); + panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable); + p->enabled = true; return 0; -- GitLab From f4ccd9fea227070497df29d68dcbcb55bdb3a9e3 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:51 +0800 Subject: [PATCH 0046/1420] drm/edp-panel: Add panels delay entries Add panels used by Mediatek MT8173 Chromebooks. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-3-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 44acf9cacaf70..b059f5895d3a1 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1857,6 +1857,13 @@ static const struct panel_delay delay_200_500_p2e80 = { .prepare_to_enable = 80, }; +static const struct panel_delay delay_200_500_e50_p2e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .prepare_to_enable = 80, +}; + static const struct panel_delay delay_200_500_p2e100 = { .hpd_absent = 200, .unprepare = 500, @@ -1894,6 +1901,13 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 200, +}; + static const struct panel_delay delay_200_500_e200_d10 = { .hpd_absent = 200, .unprepare = 500, @@ -1907,6 +1921,13 @@ static const struct panel_delay delay_200_150_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e50_po2e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .powered_on_to_enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1932,6 +1953,7 @@ static const struct panel_delay delay_200_150_e200 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), @@ -1948,23 +1970,31 @@ static const struct edp_panel_entry edp_panels[] = { &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x096e, &delay_200_500_e50_po2e200, "NV116WHM-T07 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0993, &delay_200_500_e80, "NV116WHM-T14 V8.0"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), @@ -1973,6 +2003,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), @@ -1985,6 +2016,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), @@ -2000,10 +2032,17 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, &delay_200_500_e50, "KD116N9-30NH-F3"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), -- GitLab From 7c8690d8fc80e6149d9a8c85d22ba03f4d8dcc69 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:52 +0800 Subject: [PATCH 0047/1420] drm/panel-edp: Add some panels with conservative timings These panels are used by Mediatek MT8173 Chromebooks, and they used to work with the downstream v4.19 kernel without any specified delay. Back in the v4.19 kernel, they used the "little white lie" approach, which is making the devicetree claim a specific panel's compatible string for many different panels. That was a common solution before the generic edp-panel driver. After we uprevved the device to a newer kernel and used the edp-panel driver, we saw multiple devices reporting warnings of using an unknown panel and falling back to the conservative timings, which means that they turn on/off much more slowly than they should. We tried to fill in the timings for those panels, but we failed to find all the data sheets for them. Therefore, instead of having them use the default conservative timings, update them with less-conservative timings from other panels of the same vendor. The panels should still work under those timings, and we can save some delays and suppress the warnings. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-4-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index b059f5895d3a1..e23737284f319 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1955,6 +1955,7 @@ static const struct panel_delay delay_200_500_e50_po2e200 = { static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), @@ -1965,6 +1966,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", &auo_b116xa3_mode), @@ -1974,18 +1976,34 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f8, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0813, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0843, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), @@ -1997,6 +2015,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), @@ -2007,11 +2026,14 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1141, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x114a, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), @@ -2023,6 +2045,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), @@ -2031,6 +2055,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), @@ -2039,9 +2064,15 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0000, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x048d, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0537, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), -- GitLab From 0547692ac14650d0574e065094891bed31e37007 Mon Sep 17 00:00:00 2001 From: Xuxin Xiong Date: Mon, 18 Dec 2023 17:59:33 +0800 Subject: [PATCH 0048/1420] drm/panel-edp: Add several generic edp panels Add support for the following 3 panels: 1. BOE NV116WHM-N49 V8.0 2. BOE NV122WUM-N41 3. CSO MNC207QS1-1 Signed-off-by: Xuxin Xiong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231218095933.2487360-1-xuxinxiong@huaqin.corp-partner.google.com --- drivers/gpu/drm/panel/panel-edp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index e23737284f319..cd05c76868e3c 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -2016,8 +2016,10 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), @@ -2045,6 +2047,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50, "MNC207QS1-1"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), -- GitLab From 4773293bc564b967e8f863e05dbcc729a58b0409 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 19 Dec 2023 12:47:45 +0200 Subject: [PATCH 0049/1420] drm/i915/hdcp: unify connector logging format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's customary to debug log connectors using [CONNECTOR:%d:%s] format. Make the HDCP code follow suit. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231219104746.1065431-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdcp.c | 68 +++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 39b3f7c0c77c9..f9010094ff296 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -853,8 +853,8 @@ static int intel_hdcp_auth(struct intel_connector *connector) if (shim->stream_encryption) { ret = shim->stream_encryption(connector, true); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 1.4 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encrypted\n", @@ -878,14 +878,14 @@ static int _intel_hdcp_disable(struct intel_connector *connector) u32 repeater_ctl; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being disabled...\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being disabled...\n", + connector->base.base.id, connector->base.name); if (hdcp->shim->stream_encryption) { ret = hdcp->shim->stream_encryption(connector, false); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 1.4 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n", @@ -929,8 +929,8 @@ static int intel_hdcp1_enable(struct intel_connector *connector) struct intel_hdcp *hdcp = &connector->hdcp; int i, ret, tries = 3; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being enabled...\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being enabled...\n", + connector->base.base.id, connector->base.name); if (!hdcp_key_loadable(i915)) { drm_err(&i915->drm, "HDCP key Load is not possible\n"); @@ -1027,8 +1027,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector) if (drm_WARN_ON(&i915->drm, !intel_hdcp_in_use(i915, cpu_transcoder, port))) { drm_err(&i915->drm, - "%s:%d HDCP link stopped encryption,%x\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] HDCP link stopped encryption,%x\n", + connector->base.base.id, connector->base.name, intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port))); ret = -ENXIO; intel_hdcp_update_value(connector, @@ -1046,8 +1046,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector) } drm_dbg_kms(&i915->drm, - "[%s:%d] HDCP link failed, retrying authentication\n", - connector->base.name, connector->base.base.id); + "[CONNECTOR:%d:%s] HDCP link failed, retrying authentication\n", + connector->base.base.id, connector->base.name); ret = _intel_hdcp_disable(connector); if (ret) { @@ -1731,8 +1731,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector) if (!(intel_de_read(i915, HDCP2_STATUS(i915, cpu_transcoder, port)) & LINK_ENCRYPTION_STATUS)) { - drm_err(&i915->drm, "[%s:%d] HDCP 2.2 Link is not encrypted\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] HDCP 2.2 Link is not encrypted\n", + connector->base.base.id, connector->base.name); ret = -EPERM; goto link_recover; } @@ -1740,8 +1740,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector) if (hdcp->shim->stream_2_2_encryption) { ret = hdcp->shim->stream_2_2_encryption(connector, true); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 2.2 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 2.2 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encrypted\n", @@ -1925,8 +1925,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector) struct intel_hdcp *hdcp = &connector->hdcp; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being enabled. Type: %d\n", - connector->base.name, connector->base.base.id, + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being enabled. Type: %d\n", + connector->base.base.id, connector->base.name, hdcp->content_type); ret = hdcp2_authenticate_and_encrypt(connector); @@ -1936,8 +1936,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector) return ret; } - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is enabled. Type %d\n", - connector->base.name, connector->base.base.id, + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is enabled. Type %d\n", + connector->base.base.id, connector->base.name, hdcp->content_type); hdcp->hdcp2_encrypted = true; @@ -1953,14 +1953,14 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery struct intel_hdcp *hdcp = &connector->hdcp; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being Disabled\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being Disabled\n", + connector->base.base.id, connector->base.name); if (hdcp->shim->stream_2_2_encryption) { ret = hdcp->shim->stream_2_2_encryption(connector, false); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 2.2 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 2.2 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encryption disabled\n", @@ -2040,20 +2040,20 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) goto out; } drm_dbg_kms(&i915->drm, - "[%s:%d] Repeater topology auth failed.(%d)\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] Repeater topology auth failed.(%d)\n", + connector->base.base.id, connector->base.name, ret); } else { drm_dbg_kms(&i915->drm, - "[%s:%d] HDCP2.2 link failed, retrying auth\n", - connector->base.name, connector->base.base.id); + "[CONNECTOR:%d:%s] HDCP2.2 link failed, retrying auth\n", + connector->base.base.id, connector->base.name); } ret = _intel_hdcp2_disable(connector, true); if (ret) { drm_err(&i915->drm, - "[%s:%d] Failed to disable hdcp2.2 (%d)\n", - connector->base.name, connector->base.base.id, ret); + "[CONNECTOR:%d:%s] Failed to disable hdcp2.2 (%d)\n", + connector->base.base.id, connector->base.name, ret); intel_hdcp_update_value(connector, DRM_MODE_CONTENT_PROTECTION_DESIRED, true); goto out; @@ -2062,8 +2062,8 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) ret = _intel_hdcp2_enable(connector); if (ret) { drm_dbg_kms(&i915->drm, - "[%s:%d] Failed to enable hdcp2.2 (%d)\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] Failed to enable hdcp2.2 (%d)\n", + connector->base.base.id, connector->base.name, ret); intel_hdcp_update_value(connector, DRM_MODE_CONTENT_PROTECTION_DESIRED, @@ -2341,8 +2341,8 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, return -ENOENT; if (!connector->encoder) { - drm_err(&i915->drm, "[%s:%d] encoder is not initialized\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] encoder is not initialized\n", + connector->base.base.id, connector->base.name); return -ENODEV; } -- GitLab From 547a720e8e8f1b2c93f29a5dbe7315e285eb73a6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 19 Dec 2023 12:47:46 +0200 Subject: [PATCH 0050/1420] drm/i915/hdcp: fix intel_hdcp_get_repeater_ctl() error return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_hdcp_get_repeater_ctl() is supposed to return unsigned register contents. Returning negative error values is unexpected, and none of the callers check for that. Sort of fix the error cases by returning 0. I don't think we should hit these cases anyway, and using 0 for the registers is safer than 0xffffffea (-EINVAL). Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231219104746.1065431-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index f9010094ff296..ee29fcb860e46 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -347,7 +347,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915, default: drm_err(&i915->drm, "Unknown transcoder %d\n", cpu_transcoder); - return -EINVAL; + return 0; } } @@ -364,7 +364,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915, return HDCP_DDIE_REP_PRESENT | HDCP_DDIE_SHA1_M0; default: drm_err(&i915->drm, "Unknown port %d\n", port); - return -EINVAL; + return 0; } } -- GitLab From 86ceaaaec59707b06216a15b3852867fa2f1574e Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 28 Nov 2023 08:25:05 -0800 Subject: [PATCH 0051/1420] drm/i915/gem: Atomically invalidate userptr on mmu-notifier Never block for outstanding work on userptr object upon receipt of a mmu-notifier. The reason we originally did so was to immediately unbind the userptr and unpin its pages, but since that has been dropped in commit b4b9731b02c3c ("drm/i915: Simplify userptr locking"), we never return the pages to the system i.e. never drop our page->mapcount and so do not allow the page and CPU PTE to be revoked. Based on this history, we know we are safe to drop the wait entirely. Upon return from mmu-notifier, we will still have the userptr pages pinned preventing the following PTE operation (such as try_to_unmap) adjusting the vm_area_struct, so it is safe to keep the pages around for as long as we still have i/o pending. We do not have any means currently to asynchronously revalidate the userptr pages, that is always prior to next use. Signed-off-by: Chris Wilson Signed-off-by: Jonathan Cavitt Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231128162505.3493942-1-jonathan.cavitt@intel.com --- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 8 ---- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 42 ------------------- drivers/gpu/drm/i915/gem/i915_gem_userptr.h | 14 ------- drivers/gpu/drm/i915/i915_drv.h | 8 ---- drivers/gpu/drm/i915/i915_gem.c | 5 --- 5 files changed, 77 deletions(-) delete mode 100644 drivers/gpu/drm/i915/gem/i915_gem_userptr.h diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 12cb2ef8dbd62..8968a09f3e441 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2159,12 +2159,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) #ifdef CONFIG_MMU_NOTIFIER if (!err && (eb->args->flags & __EXEC_USERPTR_USED)) { - read_lock(&eb->i915->mm.notifier_lock); - - /* - * count is always at least 1, otherwise __EXEC_USERPTR_USED - * could not have been set - */ for (i = 0; i < count; i++) { struct eb_vma *ev = &eb->vma[i]; struct drm_i915_gem_object *obj = ev->vma->obj; @@ -2176,8 +2170,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) if (err) break; } - - read_unlock(&eb->i915->mm.notifier_lock); } #endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 1d3ebdf4069b5..0e21ce9d3e5ac 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -42,7 +42,6 @@ #include "i915_drv.h" #include "i915_gem_ioctls.h" #include "i915_gem_object.h" -#include "i915_gem_userptr.h" #include "i915_scatterlist.h" #ifdef CONFIG_MMU_NOTIFIER @@ -61,36 +60,7 @@ static bool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni, const struct mmu_notifier_range *range, unsigned long cur_seq) { - struct drm_i915_gem_object *obj = container_of(mni, struct drm_i915_gem_object, userptr.notifier); - struct drm_i915_private *i915 = to_i915(obj->base.dev); - long r; - - if (!mmu_notifier_range_blockable(range)) - return false; - - write_lock(&i915->mm.notifier_lock); - mmu_interval_set_seq(mni, cur_seq); - - write_unlock(&i915->mm.notifier_lock); - - /* - * We don't wait when the process is exiting. This is valid - * because the object will be cleaned up anyway. - * - * This is also temporarily required as a hack, because we - * cannot currently force non-consistent batch buffers to preempt - * and reschedule by waiting on it, hanging processes on exit. - */ - if (current->flags & PF_EXITING) - return true; - - /* we will unbind on next submission, still have userptr pins */ - r = dma_resv_wait_timeout(obj->base.resv, DMA_RESV_USAGE_BOOKKEEP, false, - MAX_SCHEDULE_TIMEOUT); - if (r <= 0) - drm_err(&i915->drm, "(%ld) failed to wait for idle\n", r); - return true; } @@ -580,15 +550,3 @@ i915_gem_userptr_ioctl(struct drm_device *dev, #endif } -int i915_gem_init_userptr(struct drm_i915_private *dev_priv) -{ -#ifdef CONFIG_MMU_NOTIFIER - rwlock_init(&dev_priv->mm.notifier_lock); -#endif - - return 0; -} - -void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv) -{ -} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.h b/drivers/gpu/drm/i915/gem/i915_gem_userptr.h deleted file mode 100644 index 8dadb2f8436d4..0000000000000 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2021 Intel Corporation - */ - -#ifndef __I915_GEM_USERPTR_H__ -#define __I915_GEM_USERPTR_H__ - -struct drm_i915_private; - -int i915_gem_init_userptr(struct drm_i915_private *dev_priv); -void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv); - -#endif /* __I915_GEM_USERPTR_H__ */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6a2a78c61f212..a72cecd2dbc74 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -165,14 +165,6 @@ struct i915_gem_mm { struct notifier_block vmap_notifier; struct shrinker shrinker; -#ifdef CONFIG_MMU_NOTIFIER - /** - * notifier_lock for mmu notifiers, memory may not be allocated - * while holding this lock. - */ - rwlock_t notifier_lock; -#endif - /* shrinker accounting, also useful for userland debugging */ u64 shrink_memory; u32 shrink_count; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c166ad5e187a3..02e10451867a5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -48,7 +48,6 @@ #include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_pm.h" #include "gem/i915_gem_region.h" -#include "gem/i915_gem_userptr.h" #include "gt/intel_engine_user.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" @@ -1165,10 +1164,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (intel_vgpu_active(dev_priv) && !intel_vgpu_has_huge_gtt(dev_priv)) RUNTIME_INFO(dev_priv)->page_sizes = I915_GTT_PAGE_SIZE_4K; - ret = i915_gem_init_userptr(dev_priv); - if (ret) - return ret; - for_each_gt(gt, dev_priv, i) { intel_uc_fetch_firmwares(>->uc); intel_wopcm_init(>->wopcm); -- GitLab From 20f5583dd7a5103427147f6ee0b29d49647f3c62 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 6 Dec 2023 22:09:47 +0100 Subject: [PATCH 0052/1420] drm/print: Add drm_dbg_ratelimited Add a function for ratelimitted debug print. Signed-off-by: Nirmoy Das Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Reviewed-by: Matthew Auld Reviewed-by: Andrzej Hajda Reviewed-by: Andi Shyti Reviewed-by: Sam Ravnborg Acked-by: Maxime Ripard Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231206210948.106238-2-andi.shyti@linux.intel.com --- include/drm/drm_print.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index a93a387f8a1a1..ad77ac4b68083 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -602,6 +602,9 @@ void __drm_err(const char *format, ...); drm_dev_printk(drm_ ? drm_->dev : NULL, KERN_DEBUG, fmt, ## __VA_ARGS__); \ }) +#define drm_dbg_ratelimited(drm, fmt, ...) \ + __DRM_DEFINE_DBG_RATELIMITED(DRIVER, drm, fmt, ## __VA_ARGS__) + #define drm_dbg_kms_ratelimited(drm, fmt, ...) \ __DRM_DEFINE_DBG_RATELIMITED(KMS, drm, fmt, ## __VA_ARGS__) -- GitLab From 47cdb66a55f559e89da55a1e305530633e7f6f7c Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 6 Dec 2023 22:09:48 +0100 Subject: [PATCH 0053/1420] drm/i915: Ratelimit debug log in vm_fault_ttm Test like i915_gem_mman_live_selftests/igt_mmap_migrate can cause dmesg spamming. Use ratelimit api to reduce log rate. References: https://gitlab.freedesktop.org/drm/intel/-/issues/7038 Signed-off-by: Nirmoy Das Cc: Matthew Auld Reviewed-by: Matthew Auld Reviewed-by: Andrzej Hajda Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231206210948.106238-3-andi.shyti@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 9227f8146a583..6b69ef0cdbb42 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1101,8 +1101,9 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) } if (err) { - drm_dbg(dev, "Unable to make resource CPU accessible(err = %pe)\n", - ERR_PTR(err)); + drm_dbg_ratelimited(dev, + "Unable to make resource CPU accessible(err = %pe)\n", + ERR_PTR(err)); dma_resv_unlock(bo->base.resv); ret = VM_FAULT_SIGBUS; goto out_rpm; -- GitLab From 8e1cd40ddfbaaac475e521db7b699a906dad895b Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:40 -0800 Subject: [PATCH 0054/1420] drm/i915/dp: Use LINK_QUAL_PATTERN_* Phy test pattern names Starting from DP2.0 specs, DPCD 248h is renamed LINK_QUAL_PATTERN_SELECT and it has the same values of registers DPCD 10Bh-10Eh. Use the PHY pattern names defined for DPCD 10Bh-10Eh in order to add CP2520 Pattern 3 (TPS4) phy pattern support in the next patch of this series and DP2.1 PHY patterns for future series. v2: rebase Cc: Jani Nikula Cc: Imre Deak Cc: Lee Shawn C Signed-off-by: Khaled Almahallawy Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231213211542.3585105-1-khaled.almahallawy@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0b24c0cba94e3..7194d844a2b45 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4683,27 +4683,27 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, u32 pattern_val; switch (data->phy_pattern) { - case DP_PHY_TEST_PATTERN_NONE: + case DP_LINK_QUAL_PATTERN_DISABLE: drm_dbg_kms(&dev_priv->drm, "Disable Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); break; - case DP_PHY_TEST_PATTERN_D10_2: + case DP_LINK_QUAL_PATTERN_D10_2: drm_dbg_kms(&dev_priv->drm, "Set D10.2 Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2); break; - case DP_PHY_TEST_PATTERN_ERROR_COUNT: + case DP_LINK_QUAL_PATTERN_ERROR_RATE: drm_dbg_kms(&dev_priv->drm, "Set Error Count Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_SCRAMBLED_0); break; - case DP_PHY_TEST_PATTERN_PRBS7: + case DP_LINK_QUAL_PATTERN_PRBS7: drm_dbg_kms(&dev_priv->drm, "Set PRBS7 Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7); break; - case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: + case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM: /* * FIXME: Ideally pattern should come from DPCD 0x250. As * current firmware of DPR-100 could not set it, so hardcoding @@ -4721,7 +4721,7 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_CUSTOM80); break; - case DP_PHY_TEST_PATTERN_CP2520: + case DP_LINK_QUAL_PATTERN_CP2520_PAT_1: /* * FIXME: Ideally pattern should come from DPCD 0x24A. As * current firmware of DPR-100 could not set it, so hardcoding -- GitLab From 6c7ffa7a1c92c161d4876e5b267bdac50b8a5435 Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:41 -0800 Subject: [PATCH 0055/1420] drm/i915/dp: Add TPS4 PHY test pattern support Adding support for TPS4 (CP2520 Pattern 3) PHY pattern source tests. v2: rebase v3: - Enable TPS4 only for supported platforms (Jani) - Uppercase in macro names (Jani) - Fix indentation (Jani) - Use drm_warn instead of WARN v4: Disable TPS4 pattern on supported platforms only Bspec: 50482, 50484, 7557 Cc: Jani Nikula Cc: Imre Deak Cc: Lee Shawn C Signed-off-by: Khaled Almahallawy Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231213211542.3585105-2-khaled.almahallawy@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 18 +++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7194d844a2b45..8cbf026a27abf 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4679,6 +4679,7 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, struct drm_dp_phy_test_params *data = &intel_dp->compliance.test_data.phytest; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; enum pipe pipe = crtc->pipe; u32 pattern_val; @@ -4686,6 +4687,10 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, case DP_LINK_QUAL_PATTERN_DISABLE: drm_dbg_kms(&dev_priv->drm, "Disable Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); + if (DISPLAY_VER(dev_priv) >= 10) + intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), + DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK, + DP_TP_CTL_LINK_TRAIN_NORMAL); break; case DP_LINK_QUAL_PATTERN_D10_2: drm_dbg_kms(&dev_priv->drm, "Set D10.2 Phy Test Pattern\n"); @@ -4733,8 +4738,19 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 | pattern_val); break; + case DP_LINK_QUAL_PATTERN_CP2520_PAT_3: + if (DISPLAY_VER(dev_priv) < 10) { + drm_warn(&dev_priv->drm, "Platform does not support TPS4\n"); + break; + } + drm_dbg_kms(&dev_priv->drm, "Set TPS4 compliance Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); + intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), + DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK, + DP_TP_CTL_TRAIN_PAT4_SEL_TP4A | DP_TP_CTL_LINK_TRAIN_PAT4); + break; default: - WARN(1, "Invalid Phy Test Pattern\n"); + drm_warn(&dev_priv->drm, "Invalid Phy Test Pattern\n"); } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 27dc903f0553c..220fcd9f8f1db 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5652,6 +5652,10 @@ enum skl_power_gate { #define DP_TP_CTL_MODE_SST (0 << 27) #define DP_TP_CTL_MODE_MST (1 << 27) #define DP_TP_CTL_FORCE_ACT (1 << 25) +#define DP_TP_CTL_TRAIN_PAT4_SEL_MASK (3 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4A (0 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4B (1 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4C (2 << 19) #define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1 << 18) #define DP_TP_CTL_FDI_AUTOTRAIN (1 << 15) #define DP_TP_CTL_LINK_TRAIN_MASK (7 << 8) -- GitLab From 3ee302ec22d6e1d7d1e6d381b0d507ee80f2135c Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:42 -0800 Subject: [PATCH 0056/1420] drm/i915/dp: Fix passing the correct DPCD_REV for drm_dp_set_phy_test_pattern Using link_status to get DPCD_REV fails when disabling/defaulting phy pattern. Use intel_dp->dpcd to access DPCD_REV correctly. Fixes: 8cdf72711928 ("drm/i915/dp: Program vswing, pre-emphasis, test-pattern") Cc: Jani Nikula Cc: Imre Deak Cc: Lee Shawn C Signed-off-by: Khaled Almahallawy Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231213211542.3585105-3-khaled.almahallawy@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8cbf026a27abf..dcfcc626d503f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4780,7 +4780,7 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp, intel_dp->train_set, crtc_state->lane_count); drm_dp_set_phy_test_pattern(&intel_dp->aux, data, - link_status[DP_DPCD_REV]); + intel_dp->dpcd[DP_DPCD_REV]); } static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp) -- GitLab From 89d6708d947ac76cd5444ca93dd5cedf084212f9 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 24 Nov 2023 17:55:23 -0300 Subject: [PATCH 0057/1420] drm/i915/cdclk: Remove divider field from tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cdclk tables were introduced with commit 736da8112fee ("drm/i915: Use literal representation of cdclk tables"). It has been almost 4 years and the divider field was not really used yet. Let's remove it. Cc: Matt Roper Cc: Ville Syrjälä Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231124205522.57696-2-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 269 ++++++++++----------- 1 file changed, 134 insertions(+), 135 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c985ebb6831a3..0da9bcce25b17 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1227,183 +1227,182 @@ struct intel_cdclk_vals { u32 cdclk; u16 refclk; u16 waveform; - u8 divider; /* CD2X divider * 2 */ u8 ratio; }; static const struct intel_cdclk_vals bxt_cdclk_table[] = { - { .refclk = 19200, .cdclk = 144000, .divider = 8, .ratio = 60 }, - { .refclk = 19200, .cdclk = 288000, .divider = 4, .ratio = 60 }, - { .refclk = 19200, .cdclk = 384000, .divider = 3, .ratio = 60 }, - { .refclk = 19200, .cdclk = 576000, .divider = 2, .ratio = 60 }, - { .refclk = 19200, .cdclk = 624000, .divider = 2, .ratio = 65 }, + { .refclk = 19200, .cdclk = 144000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 288000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 384000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 576000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 624000, .ratio = 65 }, {} }; static const struct intel_cdclk_vals glk_cdclk_table[] = { - { .refclk = 19200, .cdclk = 79200, .divider = 8, .ratio = 33 }, - { .refclk = 19200, .cdclk = 158400, .divider = 4, .ratio = 33 }, - { .refclk = 19200, .cdclk = 316800, .divider = 2, .ratio = 33 }, + { .refclk = 19200, .cdclk = 79200, .ratio = 33 }, + { .refclk = 19200, .cdclk = 158400, .ratio = 33 }, + { .refclk = 19200, .cdclk = 316800, .ratio = 33 }, {} }; static const struct intel_cdclk_vals icl_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 2, .ratio = 18 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 326400, .divider = 4, .ratio = 68 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 180000, .divider = 2, .ratio = 15 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 324000, .divider = 4, .ratio = 54 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 9 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 326400, .divider = 4, .ratio = 34 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 18 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 326400, .ratio = 68 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 180000, .ratio = 15 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 324000, .ratio = 54 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 172800, .ratio = 9 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 326400, .ratio = 34 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals rkl_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 4, .ratio = 36 }, - { .refclk = 19200, .cdclk = 192000, .divider = 4, .ratio = 40 }, - { .refclk = 19200, .cdclk = 307200, .divider = 4, .ratio = 64 }, - { .refclk = 19200, .cdclk = 326400, .divider = 8, .ratio = 136 }, - { .refclk = 19200, .cdclk = 556800, .divider = 4, .ratio = 116 }, - { .refclk = 19200, .cdclk = 652800, .divider = 4, .ratio = 136 }, - - { .refclk = 24000, .cdclk = 180000, .divider = 4, .ratio = 30 }, - { .refclk = 24000, .cdclk = 192000, .divider = 4, .ratio = 32 }, - { .refclk = 24000, .cdclk = 312000, .divider = 4, .ratio = 52 }, - { .refclk = 24000, .cdclk = 324000, .divider = 8, .ratio = 108 }, - { .refclk = 24000, .cdclk = 552000, .divider = 4, .ratio = 92 }, - { .refclk = 24000, .cdclk = 648000, .divider = 4, .ratio = 108 }, - - { .refclk = 38400, .cdclk = 172800, .divider = 4, .ratio = 18 }, - { .refclk = 38400, .cdclk = 192000, .divider = 4, .ratio = 20 }, - { .refclk = 38400, .cdclk = 307200, .divider = 4, .ratio = 32 }, - { .refclk = 38400, .cdclk = 326400, .divider = 8, .ratio = 68 }, - { .refclk = 38400, .cdclk = 556800, .divider = 4, .ratio = 58 }, - { .refclk = 38400, .cdclk = 652800, .divider = 4, .ratio = 68 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 36 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 40 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 64 }, + { .refclk = 19200, .cdclk = 326400, .ratio = 136 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 116 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 136 }, + + { .refclk = 24000, .cdclk = 180000, .ratio = 30 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 32 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 52 }, + { .refclk = 24000, .cdclk = 324000, .ratio = 108 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 92 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 108 }, + + { .refclk = 38400, .cdclk = 172800, .ratio = 18 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 20 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 32 }, + { .refclk = 38400, .cdclk = 326400, .ratio = 68 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 58 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 68 }, {} }; static const struct intel_cdclk_vals adlp_a_step_cdclk_table[] = { - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24400, .cdclk = 648000, .ratio = 54 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals adlp_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 27 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 176000, .ratio = 22 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 179200, .ratio = 14 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals rplu_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 480000, .divider = 2, .ratio = 50 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 480000, .divider = 2, .ratio = 40 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 27 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 480000, .ratio = 50 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 176000, .ratio = 22 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 480000, .ratio = 40 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 179200, .ratio = 14 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals dg2_cdclk_table[] = { - { .refclk = 38400, .cdclk = 163200, .divider = 2, .ratio = 34, .waveform = 0x8888 }, - { .refclk = 38400, .cdclk = 204000, .divider = 2, .ratio = 34, .waveform = 0x9248 }, - { .refclk = 38400, .cdclk = 244800, .divider = 2, .ratio = 34, .waveform = 0xa4a4 }, - { .refclk = 38400, .cdclk = 285600, .divider = 2, .ratio = 34, .waveform = 0xa54a }, - { .refclk = 38400, .cdclk = 326400, .divider = 2, .ratio = 34, .waveform = 0xaaaa }, - { .refclk = 38400, .cdclk = 367200, .divider = 2, .ratio = 34, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 408000, .divider = 2, .ratio = 34, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 448800, .divider = 2, .ratio = 34, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 489600, .divider = 2, .ratio = 34, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 530400, .divider = 2, .ratio = 34, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 163200, .ratio = 34, .waveform = 0x8888 }, + { .refclk = 38400, .cdclk = 204000, .ratio = 34, .waveform = 0x9248 }, + { .refclk = 38400, .cdclk = 244800, .ratio = 34, .waveform = 0xa4a4 }, + { .refclk = 38400, .cdclk = 285600, .ratio = 34, .waveform = 0xa54a }, + { .refclk = 38400, .cdclk = 326400, .ratio = 34, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 367200, .ratio = 34, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 408000, .ratio = 34, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 448800, .ratio = 34, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 489600, .ratio = 34, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 530400, .ratio = 34, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, {} }; static const struct intel_cdclk_vals mtl_cdclk_table[] = { - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0x0000 }, {} }; static const struct intel_cdclk_vals lnl_cdclk_table[] = { - { .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa }, - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 153600, .ratio = 16, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 211200, .ratio = 16, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 230400, .ratio = 16, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 249600, .ratio = 16, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 268800, .ratio = 16, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 288000, .ratio = 16, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 330000, .ratio = 25, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 360000, .ratio = 25, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 390000, .ratio = 25, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 420000, .ratio = 25, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 450000, .ratio = 25, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 487200, .ratio = 29, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 522000, .ratio = 29, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, {} }; -- GitLab From 22ec9a3b73ddf5debf186a8041ad6c00a7b82b9c Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:56 -0700 Subject: [PATCH 0058/1420] accel/qaic: Leverage DRM managed APIs to release resources Offload the balancing of init and destroy calls to DRM managed APIs. mutex destroy for ->cntl_mutex is not called during device release and destroy workqueue is not called in error path of create_qdev(). So, use DRM managed APIs to manage the release of resources and avoid such problems. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-7-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 1 + drivers/accel/qaic/qaic_drv.c | 138 ++++++++++++++++++++++------------ 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 2b3ef588b717a..9256653b30362 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -30,6 +30,7 @@ #define to_qaic_drm_device(dev) container_of(dev, struct qaic_drm_device, drm) #define to_drm(qddev) (&(qddev)->drm) #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ +#define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev) enum __packed dev_states { /* Device is offline or will be very soon */ diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 2a313eb69b121..10a43d02844fd 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -44,6 +44,53 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); static bool link_up; static DEFINE_IDA(qaic_usrs); +static void qaicm_wq_release(struct drm_device *dev, void *res) +{ + struct workqueue_struct *wq = res; + + destroy_workqueue(wq); +} + +static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt) +{ + struct workqueue_struct *wq; + int ret; + + wq = alloc_workqueue(fmt, WQ_UNBOUND, 0); + if (!wq) + return ERR_PTR(-ENOMEM); + ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq); + if (ret) + return ERR_PTR(ret); + + return wq; +} + +static void qaicm_srcu_release(struct drm_device *dev, void *res) +{ + struct srcu_struct *lock = res; + + cleanup_srcu_struct(lock); +} + +static int qaicm_srcu_init(struct drm_device *dev, struct srcu_struct *lock) +{ + int ret; + + ret = init_srcu_struct(lock); + if (ret) + return ret; + + return drmm_add_action_or_reset(dev, qaicm_srcu_release, lock); +} + +static void qaicm_pci_release(struct drm_device *dev, void *res) +{ + struct qaic_device *qdev = to_qaic_device(dev); + + pci_set_drvdata(qdev->pdev, NULL); +} + static void free_usr(struct kref *kref) { struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count); @@ -299,74 +346,73 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) release_dbc(qdev, i); } -static void cleanup_qdev(struct qaic_device *qdev) -{ - int i; - - for (i = 0; i < qdev->num_dbc; ++i) - cleanup_srcu_struct(&qdev->dbc[i].ch_lock); - cleanup_srcu_struct(&qdev->dev_lock); - pci_set_drvdata(qdev->pdev, NULL); - destroy_workqueue(qdev->cntl_wq); - destroy_workqueue(qdev->qts_wq); -} - static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct qaic_drm_device *qddev; struct qaic_device *qdev; - int i; + struct drm_device *drm; + int i, ret; - qdev = devm_kzalloc(&pdev->dev, sizeof(*qdev), GFP_KERNEL); + qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL); if (!qdev) return NULL; qdev->dev_state = QAIC_OFFLINE; if (id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; - qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); + qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); if (!qdev->dbc) return NULL; } - qdev->cntl_wq = alloc_workqueue("qaic_cntl", WQ_UNBOUND, 0); - if (!qdev->cntl_wq) + qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); + if (IS_ERR(qddev)) + return NULL; + + drm = to_drm(qddev); + pci_set_drvdata(pdev, qdev); + + ret = drmm_mutex_init(drm, &qddev->users_mutex); + if (ret) + return NULL; + ret = drmm_add_action_or_reset(drm, qaicm_pci_release, NULL); + if (ret) + return NULL; + ret = drmm_mutex_init(drm, &qdev->cntl_mutex); + if (ret) return NULL; - qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0); - if (!qdev->qts_wq) { - destroy_workqueue(qdev->cntl_wq); + qdev->cntl_wq = qaicm_wq_init(drm, "qaic_cntl"); + if (IS_ERR(qdev->cntl_wq)) + return NULL; + qdev->qts_wq = qaicm_wq_init(drm, "qaic_ts"); + if (IS_ERR(qdev->qts_wq)) return NULL; - } - pci_set_drvdata(pdev, qdev); + ret = qaicm_srcu_init(drm, &qdev->dev_lock); + if (ret) + return NULL; + + qdev->qddev = qddev; qdev->pdev = pdev; + qddev->qdev = qdev; - mutex_init(&qdev->cntl_mutex); INIT_LIST_HEAD(&qdev->cntl_xfer_list); - init_srcu_struct(&qdev->dev_lock); + INIT_LIST_HEAD(&qddev->users); for (i = 0; i < qdev->num_dbc; ++i) { spin_lock_init(&qdev->dbc[i].xfer_lock); qdev->dbc[i].qdev = qdev; qdev->dbc[i].id = i; INIT_LIST_HEAD(&qdev->dbc[i].xfer_list); - init_srcu_struct(&qdev->dbc[i].ch_lock); + ret = qaicm_srcu_init(drm, &qdev->dbc[i].ch_lock); + if (ret) + return NULL; init_waitqueue_head(&qdev->dbc[i].dbc_release); INIT_LIST_HEAD(&qdev->dbc[i].bo_lists); } - qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); - if (IS_ERR(qddev)) { - cleanup_qdev(qdev); - return NULL; - } - - drmm_mutex_init(to_drm(qddev), &qddev->users_mutex); - INIT_LIST_HEAD(&qddev->users); - qddev->qdev = qdev; - qdev->qddev = qddev; - return qdev; } @@ -472,35 +518,28 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = init_pci(qdev, pdev); if (ret) - goto cleanup_qdev; + return ret; for (i = 0; i < qdev->num_dbc; ++i) qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i); mhi_irq = init_msi(qdev, pdev); - if (mhi_irq < 0) { - ret = mhi_irq; - goto cleanup_qdev; - } + if (mhi_irq < 0) + return mhi_irq; ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); if (ret) - goto cleanup_qdev; + return ret; qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); - goto cleanup_drm_dev; + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); + return ret; } return 0; - -cleanup_drm_dev: - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); -cleanup_qdev: - cleanup_qdev(qdev); - return ret; } static void qaic_pci_remove(struct pci_dev *pdev) @@ -513,7 +552,6 @@ static void qaic_pci_remove(struct pci_dev *pdev) qaic_dev_reset_clean_local_state(qdev); qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); - cleanup_qdev(qdev); } static void qaic_pci_shutdown(struct pci_dev *pdev) -- GitLab From 5202c721da4c96c137041b41c3d7caa57a329137 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 8 Dec 2023 09:34:57 -0700 Subject: [PATCH 0059/1420] accel/qaic: Order pci_remove() operations in reverse of probe() In probe() we create the drm_device, and then register the MHI controller. In remove(), we should unregister the controller first, then remove the drm_device. Update the remove() operations to match. Signed-off-by: Jeffrey Hugo Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Carl Vanderlip Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-8-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 10a43d02844fd..d1a632dbaec6e 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -550,8 +550,8 @@ static void qaic_pci_remove(struct pci_dev *pdev) return; qaic_dev_reset_clean_local_state(qdev); - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); } static void qaic_pci_shutdown(struct pci_dev *pdev) -- GitLab From 20277d8c1ff57b575dc2c1a1b2898cf211c51800 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 15 Dec 2023 15:02:03 -0800 Subject: [PATCH 0060/1420] drm/xe: Fix UBSAN splat in add_preempt_fences() add_preempt_fences() calls dma_resv_reserve_fences() with num_fences == 0 resulting in the below UBSAN splat. Short circuit add_preempt_fences() if num_fences == 0. [ 58.652241] ================================================================================ [ 58.660736] UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13 [ 58.667281] shift exponent 64 is too large for 64-bit type 'long unsigned int' [ 58.674539] CPU: 2 PID: 1170 Comm: xe_gpgpu_fill Not tainted 6.6.0-rc3-guc+ #630 [ 58.674545] Hardware name: Intel Corporation Tiger Lake Client Platform/TigerLake U DDR4 SODIMM RVP, BIOS TGLSFWI1.R00.3243.A01.2006102133 06/10/2020 [ 58.674547] Call Trace: [ 58.674548] [ 58.674550] dump_stack_lvl+0x92/0xb0 [ 58.674555] __ubsan_handle_shift_out_of_bounds+0x15a/0x300 [ 58.674559] ? rcu_is_watching+0x12/0x60 [ 58.674564] ? software_resume+0x141/0x210 [ 58.674575] ? new_vma+0x44b/0x600 [xe] [ 58.674606] dma_resv_reserve_fences.cold+0x40/0x66 [ 58.674612] new_vma+0x4b3/0x600 [xe] [ 58.674638] xe_vm_bind_ioctl+0xffd/0x1e00 [xe] [ 58.674663] ? __pfx_xe_vm_bind_ioctl+0x10/0x10 [xe] [ 58.674680] drm_ioctl_kernel+0xc1/0x170 [ 58.674686] ? __pfx_xe_vm_bind_ioctl+0x10/0x10 [xe] [ 58.674703] drm_ioctl+0x247/0x4c0 [ 58.674709] ? find_held_lock+0x2b/0x80 [ 58.674716] __x64_sys_ioctl+0x8c/0xb0 [ 58.674720] do_syscall_64+0x3c/0x90 [ 58.674723] entry_SYSCALL_64_after_hwframe+0x6e/0xd8 [ 58.674727] RIP: 0033:0x7fce4bd1aaff [ 58.674730] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00 [ 58.674731] RSP: 002b:00007ffc57434050 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 58.674734] RAX: ffffffffffffffda RBX: 00007ffc574340e0 RCX: 00007fce4bd1aaff [ 58.674736] RDX: 00007ffc574340e0 RSI: 0000000040886445 RDI: 0000000000000003 [ 58.674737] RBP: 0000000040886445 R08: 0000000000000002 R09: 00007ffc574341b0 [ 58.674739] R10: 000055de43eb3780 R11: 0000000000000246 R12: 00007ffc574340e0 [ 58.674740] R13: 0000000000000003 R14: 00007ffc574341b0 R15: 0000000000000001 [ 58.674747] [ 58.674748] ================================================================================ Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: Lucas De Marchi Signed-off-by: Matthew Brost Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231215230203.719244-1-matthew.brost@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 322c1ecceccac..1ca917b8315c2 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -279,6 +279,9 @@ static int add_preempt_fences(struct xe_vm *vm, struct xe_bo *bo) struct xe_exec_queue *q; int err; + if (!vm->preempt.num_exec_queues) + return 0; + err = xe_bo_lock(bo, true); if (err) return err; -- GitLab From 717cf0a78340f5bf0e47ed5000e6b8685890d9d7 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Mon, 18 Dec 2023 08:33:01 -0800 Subject: [PATCH 0061/1420] drm/xe: Fix warning on impossible condition Having a different value for op is not possible: this is already kept out of user-visible warning by the check in xe_wait_user_fence_ioctl() if op > MAX_OP. The warning is useful as if this switch() is not update when a new op is added, it should be triggered. Fix warning as reported by 0-DAY CI Kernel: drivers/gpu/drm/xe/xe_wait_user_fence.c:46:2: warning: variable 'passed' is used uninitialized whenever switch default is taken [-Wsometimes-uninitialized] Closes: https://lore.kernel.org/oe-kbuild-all/202312170357.KPSinwPs-lkp@intel.com/ Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Reviewed-by: Rodrigo Vivi Link: https://lore.kernel.org/r/20231218163301.3453285-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_wait_user_fence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c index b0a7896f7fcb6..a75eeba7bfe58 100644 --- a/drivers/gpu/drm/xe/xe_wait_user_fence.c +++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c @@ -46,6 +46,7 @@ static int do_compare(u64 addr, u64 value, u64 mask, u16 op) break; default: XE_WARN_ON("Not possible"); + return -EINVAL; } return passed ? 0 : 1; -- GitLab From 4e124151fcfc3b13786b81627b5d4f0373d3c8f1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 15 Dec 2023 13:45:31 -0800 Subject: [PATCH 0062/1420] drm/xe/dg2: Drop pre-production workarounds Pre-production hardware is anything before C0 (for DG2-G10), before B1 (for DG2-G11), or before A1 (for DG2-G12). Workarounds specific to such hardware was already removed from i915 in commit eaeb4b361452 ("drm/i915/dg2: Drop pre-production GT workarounds") and there's even less value keeping these around in the Xe driver. v2: - Drop Wa_14011441408 from xe_mocs.c. (Gustavo) - Drop Wa_14010648519, Wa_14010198302, and Wa_1608949956 which were mis-implemented; they were only supposed to apply to early steppings of DG2-G10, but were being applied unconditionally on all DG2. (Gustavo) - Drop reference to Wa_16011620976; the implementation stays because it still matches Wa_22015475538. (Gustavo) Cc: Gustavo Sousa Reviewed-by: Gustavo Sousa Link: https://lore.kernel.org/r/20231215214531.2576215-2-matthew.d.roper@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_guc.c | 8 +- drivers/gpu/drm/xe/xe_mocs.c | 23 +--- drivers/gpu/drm/xe/xe_wa.c | 174 +---------------------------- drivers/gpu/drm/xe/xe_wa_oob.rules | 7 +- 4 files changed, 5 insertions(+), 207 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 482cb0df9f15b..76b31d542e1ae 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -133,13 +133,10 @@ static u32 guc_ctl_wa_flags(struct xe_guc *guc) if (XE_WA(gt, 22012773006)) flags |= GUC_WA_POLLCS; - if (XE_WA(gt, 16011759253)) - flags |= GUC_WA_GAM_CREDITS; - if (XE_WA(gt, 14014475959)) flags |= GUC_WA_HOLD_CCS_SWITCHOUT; - if (XE_WA(gt, 22011391025) || XE_WA(gt, 14012197797)) + if (XE_WA(gt, 22011391025)) flags |= GUC_WA_DUAL_QUEUE; /* @@ -150,9 +147,6 @@ static u32 guc_ctl_wa_flags(struct xe_guc *guc) if (GRAPHICS_VERx100(xe) < 1270) flags |= GUC_WA_PRE_PARSER; - if (XE_WA(gt, 16011777198)) - flags |= GUC_WA_RCS_RESET_BEFORE_RC6; - if (XE_WA(gt, 22012727170) || XE_WA(gt, 22012727685)) flags |= GUC_WA_CONTEXT_ISOLATION; diff --git a/drivers/gpu/drm/xe/xe_mocs.c b/drivers/gpu/drm/xe/xe_mocs.c index ef79552e4f2fe..d205d684d8090 100644 --- a/drivers/gpu/drm/xe/xe_mocs.c +++ b/drivers/gpu/drm/xe/xe_mocs.c @@ -290,18 +290,6 @@ static const struct xe_mocs_entry dg2_mocs_desc[] = { MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), }; -static const struct xe_mocs_entry dg2_mocs_desc_g10_ax[] = { - /* Wa_14011441408: Set Go to Memory for MOCS#0 */ - MOCS_ENTRY(0, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), - /* UC - Coherent; GO:Memory */ - MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), - /* UC - Non-Coherent; GO:Memory */ - MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)), - - /* WB - LC */ - MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), -}; - static const struct xe_mocs_entry pvc_mocs_desc[] = { /* Error */ MOCS_ENTRY(0, 0, L3_3_WB), @@ -409,15 +397,8 @@ static unsigned int get_mocs_settings(struct xe_device *xe, info->unused_entries_index = 1; break; case XE_DG2: - if (xe->info.subplatform == XE_SUBPLATFORM_DG2_G10 && - xe->info.step.graphics >= STEP_A0 && - xe->info.step.graphics <= STEP_B0) { - info->size = ARRAY_SIZE(dg2_mocs_desc_g10_ax); - info->table = dg2_mocs_desc_g10_ax; - } else { - info->size = ARRAY_SIZE(dg2_mocs_desc); - info->table = dg2_mocs_desc; - } + info->size = ARRAY_SIZE(dg2_mocs_desc); + info->table = dg2_mocs_desc; info->uc_index = 1; info->n_entries = XELP_NUM_MOCS_ENTRIES; info->unused_entries_index = 3; diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 5f61dd87c5868..7d6b86d602c8a 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -125,13 +125,6 @@ static const struct xe_rtp_entry_sr gt_was[] = { /* DG2 */ - { XE_RTP_NAME("16010515920"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), - GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(VIDEO_DECODE)), - XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F18(0), ALNUNIT_CLKGATE_DIS)), - XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), - }, { XE_RTP_NAME("22010523718"), XE_RTP_RULES(SUBPLATFORM(DG2, G10)), XE_RTP_ACTIONS(SET(UNSLICE_UNIT_LEVEL_CLKGATE, CG3DDISCFEG_CLKGATE_DIS)) @@ -140,61 +133,6 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_RULES(SUBPLATFORM(DG2, G10)), XE_RTP_ACTIONS(SET(SUBSLICE_UNIT_LEVEL_CLKGATE, DSS_ROUTER_CLKGATE_DIS)) }, - { XE_RTP_NAME("14012362059"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB)) - }, - { XE_RTP_NAME("14012362059"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB)) - }, - { XE_RTP_NAME("14010948348"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(UNSLCGCTL9430, MSQDUNIT_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14011037102"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(UNSLCGCTL9444, LTCDD_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14011371254"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14011431319"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(UNSLCGCTL9440, - GAMTLBOACS_CLKGATE_DIS | - GAMTLBVDBOX7_CLKGATE_DIS | GAMTLBVDBOX6_CLKGATE_DIS | - GAMTLBVDBOX5_CLKGATE_DIS | GAMTLBVDBOX4_CLKGATE_DIS | - GAMTLBVDBOX3_CLKGATE_DIS | GAMTLBVDBOX2_CLKGATE_DIS | - GAMTLBVDBOX1_CLKGATE_DIS | GAMTLBVDBOX0_CLKGATE_DIS | - GAMTLBKCR_CLKGATE_DIS | GAMTLBGUC_CLKGATE_DIS | - GAMTLBBLT_CLKGATE_DIS), - SET(UNSLCGCTL9444, - GAMTLBGFXA0_CLKGATE_DIS | GAMTLBGFXA1_CLKGATE_DIS | - GAMTLBCOMPA0_CLKGATE_DIS | GAMTLBCOMPA1_CLKGATE_DIS | - GAMTLBCOMPB0_CLKGATE_DIS | GAMTLBCOMPB1_CLKGATE_DIS | - GAMTLBCOMPC0_CLKGATE_DIS | GAMTLBCOMPC1_CLKGATE_DIS | - GAMTLBCOMPD0_CLKGATE_DIS | GAMTLBCOMPD1_CLKGATE_DIS | - GAMTLBMERT_CLKGATE_DIS | - GAMTLBVEBOX3_CLKGATE_DIS | GAMTLBVEBOX2_CLKGATE_DIS | - GAMTLBVEBOX1_CLKGATE_DIS | GAMTLBVEBOX0_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14010569222"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(UNSLICE_UNIT_LEVEL_CLKGATE, GAMEDIA_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14011028019"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(SSMCGCTL9530, RTFUNIT_CLKGATE_DIS)) - }, - { XE_RTP_NAME("14010680813"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_GAMSTLB_CTRL, - CONTROL_BLOCK_CLKGATE_DIS | - EGRESS_BLOCK_CLKGATE_DIS | - TAG_BLOCK_CLKGATE_DIS)) - }, { XE_RTP_NAME("14014830051"), XE_RTP_RULES(PLATFORM(DG2)), XE_RTP_ACTIONS(CLR(SARB_CHICKEN1, COMP_CKN_IN)) @@ -212,10 +150,6 @@ static const struct xe_rtp_entry_sr gt_was[] = { INVALIDATION_BROADCAST_MODE_DIS | GLOBAL_INVALIDATION_MODE)) }, - { XE_RTP_NAME("14010648519"), - XE_RTP_RULES(PLATFORM(DG2)), - XE_RTP_ACTIONS(SET(XEHP_L3NODEARBCFG, XEHP_LNESPARE)) - }, /* PVC */ @@ -376,13 +310,6 @@ static const struct xe_rtp_entry_sr engine_was[] = { XE_RTP_ACTIONS(SET(VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE)) }, - { XE_RTP_NAME("22012826095, 22013059131"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(B0, C0), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(FIELD_SET(LSC_CHICKEN_BIT_0_UDW, - MAXREQS_PER_BANK, - REG_FIELD_PREP(MAXREQS_PER_BANK, 2))) - }, { XE_RTP_NAME("22012826095, 22013059131"), XE_RTP_RULES(SUBPLATFORM(DG2, G11), FUNC(xe_rtp_match_first_render_or_compute)), @@ -390,28 +317,11 @@ static const struct xe_rtp_entry_sr engine_was[] = { MAXREQS_PER_BANK, REG_FIELD_PREP(MAXREQS_PER_BANK, 2))) }, - { XE_RTP_NAME("22013059131"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(B0, C0), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0, FORCE_1_SUB_MESSAGE_PER_FRAGMENT)) - }, { XE_RTP_NAME("22013059131"), XE_RTP_RULES(SUBPLATFORM(DG2, G11), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0, FORCE_1_SUB_MESSAGE_PER_FRAGMENT)) }, - { XE_RTP_NAME("14010918519"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, - FORCE_SLM_FENCE_SCOPE_TO_TILE | - FORCE_UGM_FENCE_SCOPE_TO_TILE, - /* - * Ignore read back as it always returns 0 in these - * steps - */ - .read_mask = 0)) - }, { XE_RTP_NAME("14015227452"), XE_RTP_RULES(PLATFORM(DG2), FUNC(xe_rtp_match_first_render_or_compute)), @@ -428,21 +338,11 @@ static const struct xe_rtp_entry_sr engine_was[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3)) }, - { XE_RTP_NAME("16011620976, 22015475538"), + { XE_RTP_NAME("22015475538"), XE_RTP_RULES(PLATFORM(DG2), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8)) }, - { XE_RTP_NAME("22012654132"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, C0), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(SET(CACHE_MODE_SS, ENABLE_PREFETCH_INTO_IC, - /* - * Register can't be read back for verification on - * DG2 due to Wa_14012342262 - */ - .read_mask = 0)) - }, { XE_RTP_NAME("22012654132"), XE_RTP_RULES(SUBPLATFORM(DG2, G11), FUNC(xe_rtp_match_first_render_or_compute)), @@ -461,68 +361,11 @@ static const struct xe_rtp_entry_sr engine_was[] = { XE_RTP_RULES(PLATFORM(DG2), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(ROW_CHICKEN2, DISABLE_READ_SUPPRESSION)) }, - { XE_RTP_NAME("14013392000"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(ROW_CHICKEN2, ENABLE_LARGE_GRF_MODE)) - }, - { XE_RTP_NAME("14012419201"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(ROW_CHICKEN4, - DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX)) - }, - { XE_RTP_NAME("14012419201"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(ROW_CHICKEN4, - DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX)) - }, - { XE_RTP_NAME("1308578152"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(B0, C0), - ENGINE_CLASS(RENDER), - FUNC(xe_rtp_match_first_gslice_fused_off)), - XE_RTP_ACTIONS(CLR(CS_DEBUG_MODE1(RENDER_RING_BASE), - REPLAY_MODE_GRANULARITY)) - }, { XE_RTP_NAME("22010960976, 14013347512"), XE_RTP_RULES(PLATFORM(DG2), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(CLR(XEHP_HDC_CHICKEN0, LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK)) }, - { XE_RTP_NAME("1608949956, 14010198302"), - XE_RTP_RULES(PLATFORM(DG2), ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(ROW_CHICKEN, - MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE)) - }, - { XE_RTP_NAME("22010430635"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(ROW_CHICKEN4, - DISABLE_GRF_CLEAR)) - }, - { XE_RTP_NAME("14013202645"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(B0, C0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(RT_CTRL, DIS_NULL_QUERY)) - }, - { XE_RTP_NAME("14013202645"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(RT_CTRL, DIS_NULL_QUERY)) - }, - { XE_RTP_NAME("22012532006"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, C0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, - DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA)) - }, - { XE_RTP_NAME("22012532006"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0), - ENGINE_CLASS(RENDER)), - XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, - DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA)) - }, { XE_RTP_NAME("14015150844"), XE_RTP_RULES(PLATFORM(DG2), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(XEHP_HDC_CHICKEN0, DIS_ATOMIC_CHAINING_TYPED_WRITES, @@ -652,21 +495,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { /* DG2 */ - { XE_RTP_NAME("16011186671"), - XE_RTP_RULES(SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(CLR(VFLSKPD, DIS_MULT_MISS_RD_SQUASH), - SET(VFLSKPD, DIS_OVER_FETCH_CACHE)) - }, - { XE_RTP_NAME("14010469329"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN3, - XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE)) - }, - { XE_RTP_NAME("14010698770, 22010613112, 22010465075"), - XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)), - XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN3, - DISABLE_CPS_AWARE_COLOR_PIPE)) - }, { XE_RTP_NAME("16013271637"), XE_RTP_RULES(PLATFORM(DG2)), XE_RTP_ACTIONS(SET(XEHP_SLICE_COMMON_ECO_CHICKEN1, diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index 727bdc4292124..e73b84e01ea1b 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -1,13 +1,8 @@ 22012773006 GRAPHICS_VERSION_RANGE(1200, 1250) -16011759253 SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0) 14014475959 GRAPHICS_VERSION_RANGE(1270, 1271), GRAPHICS_STEP(A0, B0) PLATFORM(DG2) 22011391025 PLATFORM(DG2) -14012197797 PLATFORM(DG2), GRAPHICS_STEP(A0, B0) -16011777198 SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, C0) - SUBPLATFORM(DG2, G11), GRAPHICS_STEP(A0, B0) -22012727170 SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, C0) - SUBPLATFORM(DG2, G11) +22012727170 SUBPLATFORM(DG2, G11) 22012727685 SUBPLATFORM(DG2, G11) 16015675438 PLATFORM(PVC) SUBPLATFORM(DG2, G10) -- GitLab From 6901f732691f12154f35ee405c25b00ef51266ab Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:35 +0100 Subject: [PATCH 0063/1420] drm/xe: Add command MI_LOAD_REGISTER_MEM We will need this shortly during context state preparation. Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-2-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/instructions/xe_mi_commands.h | 3 +++ drivers/gpu/drm/xe/xe_lrc.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/xe/instructions/xe_mi_commands.h b/drivers/gpu/drm/xe/instructions/xe_mi_commands.h index 1cfa96167fde3..c74ceb550dce7 100644 --- a/drivers/gpu/drm/xe/instructions/xe_mi_commands.h +++ b/drivers/gpu/drm/xe/instructions/xe_mi_commands.h @@ -56,6 +56,9 @@ #define MI_FLUSH_IMM_QW REG_FIELD_PREP(MI_FLUSH_DW_LEN_DW, 5 - 2) #define MI_FLUSH_DW_USE_GTT REG_BIT(2) +#define MI_LOAD_REGISTER_MEM (__MI_INSTR(0x29) | XE_INSTR_NUM_DW(4)) +#define MI_LRM_USE_GGTT REG_BIT(22) + #define MI_BATCH_BUFFER_START __MI_INSTR(0x31) #endif diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index b7fa3831b6845..44586e612eaf5 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -964,6 +964,20 @@ static int dump_mi_command(struct drm_printer *p, drm_printf(p, " - %#6x = %#010x\n", dw[i], dw[i + 1]); return numdw; + case MI_LOAD_REGISTER_MEM & MI_OPCODE: + drm_printf(p, "[%#010x] MI_LOAD_REGISTER_MEM: %s%s\n", + inst_header, + dw[0] & MI_LRI_LRM_CS_MMIO ? "CS_MMIO " : "", + dw[0] & MI_LRM_USE_GGTT ? "USE_GGTT " : ""); + if (numdw == 4) + drm_printf(p, " - %#6x = %#010llx\n", + dw[1], ((u64)(dw[3]) << 32 | (u64)(dw[2]))); + else + drm_printf(p, " - %*ph (%s)\n", + (int)sizeof(u32) * (numdw - 1), dw + 1, + numdw < 4 ? "truncated" : "malformed"); + return numdw; + case MI_FORCE_WAKEUP: drm_printf(p, "[%#010x] MI_FORCE_WAKEUP\n", inst_header); return numdw; -- GitLab From 54020e2b406d8d4be6d79409957f2130e93b4fa3 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:36 +0100 Subject: [PATCH 0064/1420] drm/xe: Define registers used by memory based irq processing The RING_INT_SRC_RPT_PTR register points to a cacheline in memory to which an engine must report as source of interrupt prior to generating an interrupt to the host. The RING_INT_STATUS_RPT_PTR register points to the first cacheline of the Interrupt Status Report (ISR) page (4KB) in graphics memory to which all engines report their interrupt status. The RING_IMR register has the interrupt enables and interrupt masks for an engine. We will refer to these registers shortly. Bspec: 45963, 45964, 45965 Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-3-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/regs/xe_engine_regs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h index 5592774fc6903..bd9c956f48a7c 100644 --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h @@ -75,7 +75,9 @@ #define FF_THREAD_MODE(base) XE_REG((base) + 0xa0) #define FF_TESSELATION_DOP_GATE_DISABLE BIT(19) +#define RING_INT_SRC_RPT_PTR(base) XE_REG((base) + 0xa4) #define RING_IMR(base) XE_REG((base) + 0xa8) +#define RING_INT_STATUS_RPT_PTR(base) XE_REG((base) + 0xac) #define RING_EIR(base) XE_REG((base) + 0xb0) #define RING_EMR(base) XE_REG((base) + 0xb4) -- GitLab From e3408839dd27b2645636f91c85a7fd847e36cb91 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:37 +0100 Subject: [PATCH 0065/1420] drm/xe: Update LRC context layout definitions The new memory based interrupt processing uses additional entries in the context. Add required definitions. Bspec: 45585, 60184 Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-4-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/regs/xe_lrc_layout.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h index 4be81abc86ad9..1825d8f79db64 100644 --- a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h +++ b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h @@ -14,4 +14,13 @@ #define CTX_PDP0_UDW (0x30 + 1) #define CTX_PDP0_LDW (0x32 + 1) +#define CTX_LRM_INT_MASK_ENABLE 0x50 +#define CTX_INT_MASK_ENABLE_REG (CTX_LRM_INT_MASK_ENABLE + 1) +#define CTX_INT_MASK_ENABLE_PTR (CTX_LRM_INT_MASK_ENABLE + 2) +#define CTX_LRI_INT_REPORT_PTR 0x55 +#define CTX_INT_STATUS_REPORT_REG (CTX_LRI_INT_REPORT_PTR + 1) +#define CTX_INT_STATUS_REPORT_PTR (CTX_LRI_INT_REPORT_PTR + 2) +#define CTX_INT_SRC_REPORT_REG (CTX_LRI_INT_REPORT_PTR + 3) +#define CTX_INT_SRC_REPORT_PTR (CTX_LRI_INT_REPORT_PTR + 4) + #endif -- GitLab From 7158a688935ca90c5036e67b2b95c3119b3a0ac7 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:38 +0100 Subject: [PATCH 0066/1420] drm/xe: Update definition of GT_INTR_DW Add bits definitions that we will be using in upcoming patch. Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-5-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 1dd361046b5dc..6aaaf1f63c728 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -430,6 +430,15 @@ #define VOLTAGE_MASK REG_GENMASK(10, 0) #define GT_INTR_DW(x) XE_REG(0x190018 + ((x) * 4)) +#define INTR_GSC REG_BIT(31) +#define INTR_GUC REG_BIT(25) +#define INTR_MGUC REG_BIT(24) +#define INTR_BCS8 REG_BIT(23) +#define INTR_BCS(x) REG_BIT(15 - (x)) +#define INTR_CCS(x) REG_BIT(4 + (x)) +#define INTR_RCS0 REG_BIT(0) +#define INTR_VECS(x) REG_BIT(31 - (x)) +#define INTR_VCS(x) REG_BIT(x) #define RENDER_COPY_INTR_ENABLE XE_REG(0x190030) #define VCS_VECS_INTR_ENABLE XE_REG(0x190034) -- GitLab From 35c933f68048da55ca043b1a2f1fef386e133a9d Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:39 +0100 Subject: [PATCH 0067/1420] drm/xe: Define IRQ offsets used by HW engines When interrupts are delivered using memory based mechanism, engines will write status to the report page at the offset (in bytes) that corresponds to their interrupt bit from the GT_INTR_DW register. Add engine interrupt offset definitions to engine info as we will need this to process memory based interrupts. Bspec: 46149, 50829, 50844 Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-6-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_hw_engine.c | 28 +++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_hw_engine_types.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 1fa5cf5eea978..832989c83a253 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -34,6 +34,7 @@ struct engine_info { const char *name; unsigned int class : 8; unsigned int instance : 8; + unsigned int irq_offset : 8; enum xe_force_wake_domains domain; u32 mmio_base; }; @@ -43,6 +44,7 @@ static const struct engine_info engine_infos[] = { .name = "rcs0", .class = XE_ENGINE_CLASS_RENDER, .instance = 0, + .irq_offset = ilog2(INTR_RCS0), .domain = XE_FW_RENDER, .mmio_base = RENDER_RING_BASE, }, @@ -50,6 +52,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs0", .class = XE_ENGINE_CLASS_COPY, .instance = 0, + .irq_offset = ilog2(INTR_BCS(0)), .domain = XE_FW_RENDER, .mmio_base = BLT_RING_BASE, }, @@ -57,6 +60,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs1", .class = XE_ENGINE_CLASS_COPY, .instance = 1, + .irq_offset = ilog2(INTR_BCS(1)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS1_RING_BASE, }, @@ -64,6 +68,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs2", .class = XE_ENGINE_CLASS_COPY, .instance = 2, + .irq_offset = ilog2(INTR_BCS(2)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS2_RING_BASE, }, @@ -71,6 +76,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs3", .class = XE_ENGINE_CLASS_COPY, .instance = 3, + .irq_offset = ilog2(INTR_BCS(3)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS3_RING_BASE, }, @@ -78,6 +84,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs4", .class = XE_ENGINE_CLASS_COPY, .instance = 4, + .irq_offset = ilog2(INTR_BCS(4)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS4_RING_BASE, }, @@ -85,6 +92,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs5", .class = XE_ENGINE_CLASS_COPY, .instance = 5, + .irq_offset = ilog2(INTR_BCS(5)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS5_RING_BASE, }, @@ -92,12 +100,14 @@ static const struct engine_info engine_infos[] = { .name = "bcs6", .class = XE_ENGINE_CLASS_COPY, .instance = 6, + .irq_offset = ilog2(INTR_BCS(6)), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS6_RING_BASE, }, [XE_HW_ENGINE_BCS7] = { .name = "bcs7", .class = XE_ENGINE_CLASS_COPY, + .irq_offset = ilog2(INTR_BCS(7)), .instance = 7, .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS7_RING_BASE, @@ -106,6 +116,7 @@ static const struct engine_info engine_infos[] = { .name = "bcs8", .class = XE_ENGINE_CLASS_COPY, .instance = 8, + .irq_offset = ilog2(INTR_BCS8), .domain = XE_FW_RENDER, .mmio_base = XEHPC_BCS8_RING_BASE, }, @@ -114,6 +125,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs0", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 0, + .irq_offset = 32 + ilog2(INTR_VCS(0)), .domain = XE_FW_MEDIA_VDBOX0, .mmio_base = BSD_RING_BASE, }, @@ -121,6 +133,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs1", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 1, + .irq_offset = 32 + ilog2(INTR_VCS(1)), .domain = XE_FW_MEDIA_VDBOX1, .mmio_base = BSD2_RING_BASE, }, @@ -128,6 +141,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs2", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 2, + .irq_offset = 32 + ilog2(INTR_VCS(2)), .domain = XE_FW_MEDIA_VDBOX2, .mmio_base = BSD3_RING_BASE, }, @@ -135,6 +149,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs3", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 3, + .irq_offset = 32 + ilog2(INTR_VCS(3)), .domain = XE_FW_MEDIA_VDBOX3, .mmio_base = BSD4_RING_BASE, }, @@ -142,6 +157,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs4", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 4, + .irq_offset = 32 + ilog2(INTR_VCS(4)), .domain = XE_FW_MEDIA_VDBOX4, .mmio_base = XEHP_BSD5_RING_BASE, }, @@ -149,6 +165,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs5", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 5, + .irq_offset = 32 + ilog2(INTR_VCS(5)), .domain = XE_FW_MEDIA_VDBOX5, .mmio_base = XEHP_BSD6_RING_BASE, }, @@ -156,6 +173,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs6", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 6, + .irq_offset = 32 + ilog2(INTR_VCS(6)), .domain = XE_FW_MEDIA_VDBOX6, .mmio_base = XEHP_BSD7_RING_BASE, }, @@ -163,6 +181,7 @@ static const struct engine_info engine_infos[] = { .name = "vcs7", .class = XE_ENGINE_CLASS_VIDEO_DECODE, .instance = 7, + .irq_offset = 32 + ilog2(INTR_VCS(7)), .domain = XE_FW_MEDIA_VDBOX7, .mmio_base = XEHP_BSD8_RING_BASE, }, @@ -170,6 +189,7 @@ static const struct engine_info engine_infos[] = { .name = "vecs0", .class = XE_ENGINE_CLASS_VIDEO_ENHANCE, .instance = 0, + .irq_offset = 32 + ilog2(INTR_VECS(0)), .domain = XE_FW_MEDIA_VEBOX0, .mmio_base = VEBOX_RING_BASE, }, @@ -177,6 +197,7 @@ static const struct engine_info engine_infos[] = { .name = "vecs1", .class = XE_ENGINE_CLASS_VIDEO_ENHANCE, .instance = 1, + .irq_offset = 32 + ilog2(INTR_VECS(1)), .domain = XE_FW_MEDIA_VEBOX1, .mmio_base = VEBOX2_RING_BASE, }, @@ -184,6 +205,7 @@ static const struct engine_info engine_infos[] = { .name = "vecs2", .class = XE_ENGINE_CLASS_VIDEO_ENHANCE, .instance = 2, + .irq_offset = 32 + ilog2(INTR_VECS(2)), .domain = XE_FW_MEDIA_VEBOX2, .mmio_base = XEHP_VEBOX3_RING_BASE, }, @@ -191,6 +213,7 @@ static const struct engine_info engine_infos[] = { .name = "vecs3", .class = XE_ENGINE_CLASS_VIDEO_ENHANCE, .instance = 3, + .irq_offset = 32 + ilog2(INTR_VECS(3)), .domain = XE_FW_MEDIA_VEBOX3, .mmio_base = XEHP_VEBOX4_RING_BASE, }, @@ -198,6 +221,7 @@ static const struct engine_info engine_infos[] = { .name = "ccs0", .class = XE_ENGINE_CLASS_COMPUTE, .instance = 0, + .irq_offset = ilog2(INTR_CCS(0)), .domain = XE_FW_RENDER, .mmio_base = COMPUTE0_RING_BASE, }, @@ -205,6 +229,7 @@ static const struct engine_info engine_infos[] = { .name = "ccs1", .class = XE_ENGINE_CLASS_COMPUTE, .instance = 1, + .irq_offset = ilog2(INTR_CCS(1)), .domain = XE_FW_RENDER, .mmio_base = COMPUTE1_RING_BASE, }, @@ -212,6 +237,7 @@ static const struct engine_info engine_infos[] = { .name = "ccs2", .class = XE_ENGINE_CLASS_COMPUTE, .instance = 2, + .irq_offset = ilog2(INTR_CCS(2)), .domain = XE_FW_RENDER, .mmio_base = COMPUTE2_RING_BASE, }, @@ -219,6 +245,7 @@ static const struct engine_info engine_infos[] = { .name = "ccs3", .class = XE_ENGINE_CLASS_COMPUTE, .instance = 3, + .irq_offset = ilog2(INTR_CCS(3)), .domain = XE_FW_RENDER, .mmio_base = COMPUTE3_RING_BASE, }, @@ -397,6 +424,7 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe, hwe->class = info->class; hwe->instance = info->instance; hwe->mmio_base = info->mmio_base; + hwe->irq_offset = info->irq_offset; hwe->domain = info->domain; hwe->name = info->name; hwe->fence_irq = >->fence_irq[info->class]; diff --git a/drivers/gpu/drm/xe/xe_hw_engine_types.h b/drivers/gpu/drm/xe/xe_hw_engine_types.h index 39908dec042a4..dfeaaac08b7f9 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_types.h +++ b/drivers/gpu/drm/xe/xe_hw_engine_types.h @@ -116,6 +116,8 @@ struct xe_hw_engine { u16 instance; /** @logical_instance: logical instance of this hw engine */ u16 logical_instance; + /** @irq_offset: IRQ offset of this hw engine */ + u16 irq_offset; /** @mmio_base: MMIO base address of this hw engine*/ u32 mmio_base; /** -- GitLab From f15de1936f8d1bb5b4f7ee55da7fdba8c7540792 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:40 +0100 Subject: [PATCH 0068/1420] drm/xe: Add XE_BO_NEEDS_UC flag to force UC mode instead WB When we map BO in GGTT, then by default we are using PAT index that corresponds to XE_CACHE_WB but ppcoming feature will require use of the PAT index of the XE_CACHE_UC. Define new BO flag that could be used during BO creation to force alternate caching. Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-7-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_bo.h | 1 + drivers/gpu/drm/xe/xe_ggtt.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index 9b1279aca1272..97b32528c600f 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -44,6 +44,7 @@ #define XE_BO_FIXED_PLACEMENT_BIT BIT(11) #define XE_BO_PAGETABLE BIT(12) #define XE_BO_NEEDS_CPU_ACCESS BIT(13) +#define XE_BO_NEEDS_UC BIT(14) /* this one is trigger internally only */ #define XE_BO_INTERNAL_TEST BIT(30) #define XE_BO_INTERNAL_64K BIT(31) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 3efd2d066bf72..c639dbf3bdd27 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -334,7 +334,8 @@ int xe_ggtt_insert_special_node(struct xe_ggtt *ggtt, struct drm_mm_node *node, void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_bo *bo) { - u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[XE_CACHE_WB]; + u16 cache_mode = bo->flags & XE_BO_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB; + u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode]; u64 start = bo->ggtt_node.start; u64 offset, pte; -- GitLab From a6581ebe76856bf23d1a7f3ee95828173b560a05 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:41 +0100 Subject: [PATCH 0069/1420] drm/xe/vf: Introduce Memory Based Interrupts Handler The register based interrupts infrastructure does not scale efficiently to allow delivering interrupts to a large number of virtual machines. Memory based interrupt reporting provides an efficient and scalable infrastructure. Define handler to read and dispatch memory based interrupts. We will use this handler in upcoming patch. Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-8-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/Makefile | 4 +- drivers/gpu/drm/xe/xe_device.c | 7 + drivers/gpu/drm/xe/xe_device.h | 5 + drivers/gpu/drm/xe/xe_device_types.h | 5 + drivers/gpu/drm/xe/xe_memirq.c | 430 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_memirq.h | 26 ++ drivers/gpu/drm/xe/xe_memirq_types.h | 37 +++ 7 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/xe/xe_memirq.c create mode 100644 drivers/gpu/drm/xe/xe_memirq.h create mode 100644 drivers/gpu/drm/xe/xe_memirq_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 53bd2a8ba1ae5..9214915d9566c 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -146,7 +146,9 @@ xe-y += xe_bb.o \ xe-$(CONFIG_HWMON) += xe_hwmon.o # graphics virtualization (SR-IOV) support -xe-y += xe_sriov.o +xe-y += \ + xe_memirq.o \ + xe_sriov.o xe-$(CONFIG_PCI_IOV) += \ xe_lmtt.o \ diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index d9ae77fe7382d..86867d42d5329 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -29,12 +29,14 @@ #include "xe_gt.h" #include "xe_gt_mcr.h" #include "xe_irq.h" +#include "xe_memirq.h" #include "xe_mmio.h" #include "xe_module.h" #include "xe_pat.h" #include "xe_pcode.h" #include "xe_pm.h" #include "xe_query.h" +#include "xe_sriov.h" #include "xe_tile.h" #include "xe_ttm_stolen_mgr.h" #include "xe_ttm_sys_mgr.h" @@ -456,6 +458,11 @@ int xe_device_probe(struct xe_device *xe) err = xe_ggtt_init_early(tile->mem.ggtt); if (err) return err; + if (IS_SRIOV_VF(xe)) { + err = xe_memirq_init(&tile->sriov.vf.memirq); + if (err) + return err; + } } err = drmm_add_action_or_reset(&xe->drm, xe_driver_flr_fini, xe); diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 3da83b2332063..af8ac2e9e2709 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -168,6 +168,11 @@ static inline bool xe_device_has_sriov(struct xe_device *xe) return xe->info.has_sriov; } +static inline bool xe_device_has_memirq(struct xe_device *xe) +{ + return GRAPHICS_VERx100(xe) >= 1250; +} + u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); #endif diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index c45ef17b34732..71f23ac365e66 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -16,6 +16,7 @@ #include "xe_heci_gsc.h" #include "xe_gt_types.h" #include "xe_lmtt_types.h" +#include "xe_memirq_types.h" #include "xe_platform_types.h" #include "xe_pt_types.h" #include "xe_sriov_types.h" @@ -192,6 +193,10 @@ struct xe_tile { /** @sriov.pf.lmtt: Local Memory Translation Table. */ struct xe_lmtt lmtt; } pf; + struct { + /** @sriov.vf.memirq: Memory Based Interrupts. */ + struct xe_memirq memirq; + } vf; } sriov; /** @migrate: Migration helper for vram blits and clearing */ diff --git a/drivers/gpu/drm/xe/xe_memirq.c b/drivers/gpu/drm/xe/xe_memirq.c new file mode 100644 index 0000000000000..76e95535d7f60 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_memirq.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include "regs/xe_gt_regs.h" +#include "regs/xe_guc_regs.h" +#include "regs/xe_regs.h" + +#include "xe_assert.h" +#include "xe_bo.h" +#include "xe_device.h" +#include "xe_device_types.h" +#include "xe_gt.h" +#include "xe_gt_printk.h" +#include "xe_guc.h" +#include "xe_hw_engine.h" +#include "xe_map.h" +#include "xe_memirq.h" +#include "xe_sriov.h" +#include "xe_sriov_printk.h" + +#define memirq_assert(m, condition) xe_tile_assert(memirq_to_tile(m), condition) +#define memirq_debug(m, msg...) xe_sriov_dbg_verbose(memirq_to_xe(m), "MEMIRQ: " msg) + +static struct xe_tile *memirq_to_tile(struct xe_memirq *memirq) +{ + return container_of(memirq, struct xe_tile, sriov.vf.memirq); +} + +static struct xe_device *memirq_to_xe(struct xe_memirq *memirq) +{ + return tile_to_xe(memirq_to_tile(memirq)); +} + +static const char *guc_name(struct xe_guc *guc) +{ + return xe_gt_is_media_type(guc_to_gt(guc)) ? "media GuC" : "GuC"; +} + +/** + * DOC: Memory Based Interrupts + * + * MMIO register based interrupts infrastructure used for non-virtualized mode + * or SRIOV-8 (which supports 8 Virtual Functions) does not scale efficiently + * to allow delivering interrupts to a large number of Virtual machines or + * containers. Memory based interrupt status reporting provides an efficient + * and scalable infrastructure. + * + * For memory based interrupt status reporting hardware sequence is: + * * Engine writes the interrupt event to memory + * (Pointer to memory location is provided by SW. This memory surface must + * be mapped to system memory and must be marked as un-cacheable (UC) on + * Graphics IP Caches) + * * Engine triggers an interrupt to host. + */ + +/** + * DOC: Memory Based Interrupts Page Layout + * + * `Memory Based Interrupts`_ requires three different objects, which are + * called "page" in the specs, even if they aren't page-sized or aligned. + * + * To simplify the code we allocate a single page size object and then use + * offsets to embedded "pages". The address of those "pages" are then + * programmed in the HW via LRI and LRM in the context image. + * + * - _`Interrupt Status Report Page`: this page contains the interrupt + * status vectors for each unit. Each bit in the interrupt vectors is + * converted to a byte, with the byte being set to 0xFF when an + * interrupt is triggered; interrupt vectors are 16b big so each unit + * gets 16B. One space is reserved for each bit in one of the + * GT_INTR_DWx registers, so this object needs a total of 1024B. + * This object needs to be 4KiB aligned. + * + * - _`Interrupt Source Report Page`: this is the equivalent of the + * GEN11_GT_INTR_DWx registers, with each bit in those registers being + * mapped to a byte here. The offsets are the same, just bytes instead + * of bits. This object needs to be cacheline aligned. + * + * - Interrupt Mask: the HW needs a location to fetch the interrupt + * mask vector to be used by the LRM in the context, so we just use + * the next available space in the interrupt page. + * + * :: + * + * 0x0000 +===========+ <== Interrupt Status Report Page + * | | + * | | ____ +----+----------------+ + * | | / | 0 | USER INTERRUPT | + * +-----------+ __/ | 1 | | + * | HWE(n) | __ | | CTX SWITCH | + * +-----------+ \ | | WAIT SEMAPHORE | + * | | \____ | 15 | | + * | | +----+----------------+ + * | | + * 0x0400 +===========+ <== Interrupt Source Report Page + * | HWE(0) | + * | HWE(1) | + * | | + * | HWE(x) | + * 0x0440 +===========+ <== Interrupt Enable Mask + * | | + * | | + * +-----------+ + */ + +static void __release_xe_bo(struct drm_device *drm, void *arg) +{ + struct xe_bo *bo = arg; + + xe_bo_unpin_map_no_vm(bo); +} + +static int memirq_alloc_pages(struct xe_memirq *memirq) +{ + struct xe_device *xe = memirq_to_xe(memirq); + struct xe_tile *tile = memirq_to_tile(memirq); + struct xe_bo *bo; + int err; + + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET, SZ_64)); + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET, SZ_4K)); + + /* XXX: convert to managed bo */ + bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K, + ttm_bo_type_kernel, + XE_BO_CREATE_SYSTEM_BIT | + XE_BO_CREATE_GGTT_BIT | + XE_BO_NEEDS_UC | + XE_BO_NEEDS_CPU_ACCESS); + if (IS_ERR(bo)) { + err = PTR_ERR(bo); + goto out; + } + + memirq_assert(memirq, !xe_bo_is_vram(bo)); + memirq_assert(memirq, !memirq->bo); + + iosys_map_memset(&bo->vmap, 0, 0, SZ_4K); + + memirq->bo = bo; + memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET); + memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET); + memirq->mask = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_ENABLE_OFFSET); + + memirq_assert(memirq, !memirq->source.is_iomem); + memirq_assert(memirq, !memirq->status.is_iomem); + memirq_assert(memirq, !memirq->mask.is_iomem); + + memirq_debug(memirq, "page offsets: source %#x status %#x\n", + xe_memirq_source_ptr(memirq), xe_memirq_status_ptr(memirq)); + + return drmm_add_action_or_reset(&xe->drm, __release_xe_bo, memirq->bo); + +out: + xe_sriov_err(memirq_to_xe(memirq), + "Failed to allocate memirq page (%pe)\n", ERR_PTR(err)); + return err; +} + +static void memirq_set_enable(struct xe_memirq *memirq, bool enable) +{ + iosys_map_wr(&memirq->mask, 0, u32, enable ? GENMASK(15, 0) : 0); + + memirq->enabled = enable; +} + +/** + * xe_memirq_init - Initialize data used by `Memory Based Interrupts`_. + * @memirq: the &xe_memirq to initialize + * + * Allocate `Interrupt Source Report Page`_ and `Interrupt Status Report Page`_ + * used by `Memory Based Interrupts`_. + * + * These allocations are managed and will be implicitly released on unload. + * + * Note: This function shall be called only by the VF driver. + * + * If this function fails then VF driver won't be able to operate correctly. + * If `Memory Based Interrupts`_ are not used this function will return 0. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_memirq_init(struct xe_memirq *memirq) +{ + struct xe_device *xe = memirq_to_xe(memirq); + int err; + + memirq_assert(memirq, IS_SRIOV_VF(xe)); + + if (!xe_device_has_memirq(xe)) + return 0; + + err = memirq_alloc_pages(memirq); + if (unlikely(err)) + return err; + + /* we need to start with all irqs enabled */ + memirq_set_enable(memirq, true); + + return 0; +} + +/** + * xe_memirq_source_ptr - Get GGTT's offset of the `Interrupt Source Report Page`_. + * @memirq: the &xe_memirq to query + * + * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * and xe_memirq_init() didn't fail. + * + * Return: GGTT's offset of the `Interrupt Source Report Page`_. + */ +u32 xe_memirq_source_ptr(struct xe_memirq *memirq) +{ + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, memirq->bo); + + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET; +} + +/** + * xe_memirq_status_ptr - Get GGTT's offset of the `Interrupt Status Report Page`_. + * @memirq: the &xe_memirq to query + * + * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * and xe_memirq_init() didn't fail. + * + * Return: GGTT's offset of the `Interrupt Status Report Page`_. + */ +u32 xe_memirq_status_ptr(struct xe_memirq *memirq) +{ + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, memirq->bo); + + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET; +} + +/** + * xe_memirq_enable_ptr - Get GGTT's offset of the Interrupt Enable Mask. + * @memirq: the &xe_memirq to query + * + * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * and xe_memirq_init() didn't fail. + * + * Return: GGTT's offset of the Interrupt Enable Mask. + */ +u32 xe_memirq_enable_ptr(struct xe_memirq *memirq) +{ + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, memirq->bo); + + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_ENABLE_OFFSET; +} + +/** + * xe_memirq_init_guc - Prepare GuC for `Memory Based Interrupts`_. + * @memirq: the &xe_memirq + * @guc: the &xe_guc to setup + * + * Register `Interrupt Source Report Page`_ and `Interrupt Status Report Page`_ + * to be used by the GuC when `Memory Based Interrupts`_ are required. + * + * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * and xe_memirq_init() didn't fail. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc) +{ + bool is_media = xe_gt_is_media_type(guc_to_gt(guc)); + u32 offset = is_media ? ilog2(INTR_MGUC) : ilog2(INTR_GUC); + u32 source, status; + int err; + + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, memirq->bo); + + source = xe_memirq_source_ptr(memirq) + offset; + status = xe_memirq_status_ptr(memirq) + offset * SZ_16; + + err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY, + source); + if (unlikely(err)) + goto failed; + + err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_STATUS_ADDR_KEY, + status); + if (unlikely(err)) + goto failed; + + return 0; + +failed: + xe_sriov_err(memirq_to_xe(memirq), + "Failed to setup report pages in %s (%pe)\n", + guc_name(guc), ERR_PTR(err)); + return err; +} + +/** + * xe_memirq_reset - Disable processing of `Memory Based Interrupts`_. + * @memirq: struct xe_memirq + * + * This is part of the driver IRQ setup flow. + * + * This function shall only be used by the VF driver on platforms that use + * `Memory Based Interrupts`_. + */ +void xe_memirq_reset(struct xe_memirq *memirq) +{ + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + + if (memirq->bo) + memirq_set_enable(memirq, false); +} + +/** + * xe_memirq_postinstall - Enable processing of `Memory Based Interrupts`_. + * @memirq: the &xe_memirq + * + * This is part of the driver IRQ setup flow. + * + * This function shall only be used by the VF driver on platforms that use + * `Memory Based Interrupts`_. + */ +void xe_memirq_postinstall(struct xe_memirq *memirq) +{ + memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + + if (memirq->bo) + memirq_set_enable(memirq, true); +} + +static bool memirq_received(struct xe_memirq *memirq, struct iosys_map *vector, + u16 offset, const char *name) +{ + u8 value; + + value = iosys_map_rd(vector, offset, u8); + if (value) { + if (value != 0xff) + xe_sriov_err_ratelimited(memirq_to_xe(memirq), + "Unexpected memirq value %#x from %s at %u\n", + value, name, offset); + iosys_map_wr(vector, offset, u8, 0x00); + } + + return value; +} + +static void memirq_dispatch_engine(struct xe_memirq *memirq, struct iosys_map *status, + struct xe_hw_engine *hwe) +{ + memirq_debug(memirq, "STATUS %s %*ph\n", hwe->name, 16, status->vaddr); + + if (memirq_received(memirq, status, ilog2(GT_RENDER_USER_INTERRUPT), hwe->name)) + xe_hw_engine_handle_irq(hwe, GT_RENDER_USER_INTERRUPT); +} + +static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *status, + struct xe_guc *guc) +{ + const char *name = guc_name(guc); + + memirq_debug(memirq, "STATUS %s %*ph\n", name, 16, status->vaddr); + + if (memirq_received(memirq, status, ilog2(GUC_INTR_GUC2HOST), name)) + xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST); +} + +/** + * xe_memirq_handler - The `Memory Based Interrupts`_ Handler. + * @memirq: the &xe_memirq + * + * This function reads and dispatches `Memory Based Interrupts`. + */ +void xe_memirq_handler(struct xe_memirq *memirq) +{ + struct xe_device *xe = memirq_to_xe(memirq); + struct xe_tile *tile = memirq_to_tile(memirq); + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + struct iosys_map map; + unsigned int gtid; + struct xe_gt *gt; + + if (!memirq->bo) + return; + + memirq_assert(memirq, !memirq->source.is_iomem); + memirq_debug(memirq, "SOURCE %*ph\n", 32, memirq->source.vaddr); + memirq_debug(memirq, "SOURCE %*ph\n", 32, memirq->source.vaddr + 32); + + for_each_gt(gt, xe, gtid) { + if (gt->tile != tile) + continue; + + for_each_hw_engine(hwe, gt, id) { + if (memirq_received(memirq, &memirq->source, hwe->irq_offset, "SRC")) { + map = IOSYS_MAP_INIT_OFFSET(&memirq->status, + hwe->irq_offset * SZ_16); + memirq_dispatch_engine(memirq, &map, hwe); + } + } + } + + /* GuC and media GuC (if present) must be checked separately */ + + if (memirq_received(memirq, &memirq->source, ilog2(INTR_GUC), "SRC")) { + map = IOSYS_MAP_INIT_OFFSET(&memirq->status, ilog2(INTR_GUC) * SZ_16); + memirq_dispatch_guc(memirq, &map, &tile->primary_gt->uc.guc); + } + + if (!tile->media_gt) + return; + + if (memirq_received(memirq, &memirq->source, ilog2(INTR_MGUC), "SRC")) { + map = IOSYS_MAP_INIT_OFFSET(&memirq->status, ilog2(INTR_MGUC) * SZ_16); + memirq_dispatch_guc(memirq, &map, &tile->media_gt->uc.guc); + } +} diff --git a/drivers/gpu/drm/xe/xe_memirq.h b/drivers/gpu/drm/xe/xe_memirq.h new file mode 100644 index 0000000000000..2d40d03c30956 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_memirq.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_MEMIRQ_H_ +#define _XE_MEMIRQ_H_ + +#include + +struct xe_guc; +struct xe_memirq; + +int xe_memirq_init(struct xe_memirq *memirq); + +u32 xe_memirq_source_ptr(struct xe_memirq *memirq); +u32 xe_memirq_status_ptr(struct xe_memirq *memirq); +u32 xe_memirq_enable_ptr(struct xe_memirq *memirq); + +void xe_memirq_reset(struct xe_memirq *memirq); +void xe_memirq_postinstall(struct xe_memirq *memirq); +void xe_memirq_handler(struct xe_memirq *memirq); + +int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc); + +#endif diff --git a/drivers/gpu/drm/xe/xe_memirq_types.h b/drivers/gpu/drm/xe/xe_memirq_types.h new file mode 100644 index 0000000000000..625b6b8736cc4 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_memirq_types.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_MEMIRQ_TYPES_H_ +#define _XE_MEMIRQ_TYPES_H_ + +#include + +struct xe_bo; + +/* ISR */ +#define XE_MEMIRQ_STATUS_OFFSET 0x0 +/* IIR */ +#define XE_MEMIRQ_SOURCE_OFFSET 0x400 +/* IMR */ +#define XE_MEMIRQ_ENABLE_OFFSET 0x440 + +/** + * struct xe_memirq - Data used by the `Memory Based Interrupts`_. + * + * @bo: buffer object with `Memory Based Interrupts Page Layout`_. + * @source: iosys pointer to `Interrupt Source Report Page`_. + * @status: iosys pointer to `Interrupt Status Report Page`_. + * @mask: iosys pointer to Interrupt Enable Mask. + * @enabled: internal flag used to control processing of the interrupts. + */ +struct xe_memirq { + struct xe_bo *bo; + struct iosys_map source; + struct iosys_map status; + struct iosys_map mask; + bool enabled; +}; + +#endif -- GitLab From 9a30b04f15f043cdb5add993413a4fc5b692b25f Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:42 +0100 Subject: [PATCH 0070/1420] drm/xe/vf: Update LRC with memory based interrupts data When Memory Based Interrupts are used, the VF driver must provide in the LRC the references to the Source and Status Report Pages. Update the LRC according to the requirements. Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-9-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_lrc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index 44586e612eaf5..f17e9785355e8 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -19,6 +19,8 @@ #include "xe_gt_printk.h" #include "xe_hw_fence.h" #include "xe_map.h" +#include "xe_memirq.h" +#include "xe_sriov.h" #include "xe_vm.h" #define CTX_VALID (1 << 0) @@ -532,6 +534,27 @@ static void set_context_control(u32 *regs, struct xe_hw_engine *hwe) /* TODO: Timestamp */ } +static void set_memory_based_intr(u32 *regs, struct xe_hw_engine *hwe) +{ + struct xe_memirq *memirq = >_to_tile(hwe->gt)->sriov.vf.memirq; + struct xe_device *xe = gt_to_xe(hwe->gt); + + if (!IS_SRIOV_VF(xe) || !xe_device_has_memirq(xe)) + return; + + regs[CTX_LRM_INT_MASK_ENABLE] = MI_LOAD_REGISTER_MEM | + MI_LRI_LRM_CS_MMIO | MI_LRM_USE_GGTT; + regs[CTX_INT_MASK_ENABLE_REG] = RING_IMR(0).addr; + regs[CTX_INT_MASK_ENABLE_PTR] = xe_memirq_enable_ptr(memirq); + + regs[CTX_LRI_INT_REPORT_PTR] = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(2) | + MI_LRI_LRM_CS_MMIO | MI_LRI_FORCE_POSTED; + regs[CTX_INT_STATUS_REPORT_REG] = RING_INT_STATUS_RPT_PTR(0).addr; + regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq); + regs[CTX_INT_SRC_REPORT_REG] = RING_INT_SRC_RPT_PTR(0).addr; + regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq); +} + static int lrc_ring_mi_mode(struct xe_hw_engine *hwe) { struct xe_device *xe = gt_to_xe(hwe->gt); @@ -667,6 +690,7 @@ static void *empty_lrc_data(struct xe_hw_engine *hwe) regs = data + LRC_PPHWSP_SIZE; set_offsets(regs, reg_offsets(xe, hwe->class), hwe); set_context_control(regs, hwe); + set_memory_based_intr(regs, hwe); reset_stop_ring(regs, hwe); return data; -- GitLab From aef4eb7c7dec62f8b289651540fcc851257b1a16 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:43 +0100 Subject: [PATCH 0071/1420] drm/xe/vf: Setup memory based interrupts in GuC When Memory Based Interrupts are used, the VF driver must provide to the GuC references to the Source and Status Report Pages. Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-10-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 76b31d542e1ae..811e8b2012705 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -22,8 +22,10 @@ #include "xe_guc_log.h" #include "xe_guc_pc.h" #include "xe_guc_submit.h" +#include "xe_memirq.h" #include "xe_mmio.h" #include "xe_platform_types.h" +#include "xe_sriov.h" #include "xe_uc.h" #include "xe_uc_fw.h" #include "xe_wa.h" @@ -568,10 +570,20 @@ static void guc_enable_irq(struct xe_guc *guc) int xe_guc_enable_communication(struct xe_guc *guc) { + struct xe_device *xe = guc_to_xe(guc); int err; guc_enable_irq(guc); + if (IS_SRIOV_VF(xe) && xe_device_has_memirq(xe)) { + struct xe_gt *gt = guc_to_gt(guc); + struct xe_tile *tile = gt_to_tile(gt); + + err = xe_memirq_init_guc(&tile->sriov.vf.memirq, guc); + if (err) + return err; + } + xe_mmio_rmw32(guc_to_gt(guc), PMINTRMSK, ARAT_EXPIRED_INTRMSK, 0); -- GitLab From b130289b23244dc5bc5fcbd42ac57ad689cccae9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:44 +0100 Subject: [PATCH 0072/1420] drm/xe/vf: Add VF specific interrupt handler There are small differences in handling of the register based interrupts on the VF driver as some registers are not accessible to the VF driver. Additionally VFs must support Memory Based Interrupts. Add VF specific interrupt handler for this. Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231214185955.1791-11-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_irq.c | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index d1f5ba4bb745a..907c8ff0fa21f 100644 --- a/drivers/gpu/drm/xe/xe_irq.c +++ b/drivers/gpu/drm/xe/xe_irq.c @@ -17,7 +17,9 @@ #include "xe_gt.h" #include "xe_guc.h" #include "xe_hw_engine.h" +#include "xe_memirq.h" #include "xe_mmio.h" +#include "xe_sriov.h" /* * Interrupt registers for a unit are always consecutive and ordered @@ -498,6 +500,9 @@ static void xelp_irq_reset(struct xe_tile *tile) gt_irq_reset(tile); + if (IS_SRIOV_VF(tile_to_xe(tile))) + return; + mask_and_disable(tile, PCU_IRQ_OFFSET); } @@ -508,6 +513,9 @@ static void dg1_irq_reset(struct xe_tile *tile) gt_irq_reset(tile); + if (IS_SRIOV_VF(tile_to_xe(tile))) + return; + mask_and_disable(tile, PCU_IRQ_OFFSET); } @@ -518,11 +526,34 @@ static void dg1_irq_reset_mstr(struct xe_tile *tile) xe_mmio_write32(mmio, GFX_MSTR_IRQ, ~0); } +static void vf_irq_reset(struct xe_device *xe) +{ + struct xe_tile *tile; + unsigned int id; + + xe_assert(xe, IS_SRIOV_VF(xe)); + + if (GRAPHICS_VERx100(xe) < 1210) + xelp_intr_disable(xe); + else + xe_assert(xe, xe_device_has_memirq(xe)); + + for_each_tile(tile, xe, id) { + if (xe_device_has_memirq(xe)) + xe_memirq_reset(&tile->sriov.vf.memirq); + else + gt_irq_reset(tile); + } +} + static void xe_irq_reset(struct xe_device *xe) { struct xe_tile *tile; u8 id; + if (IS_SRIOV_VF(xe)) + return vf_irq_reset(xe); + for_each_tile(tile, xe, id) { if (GRAPHICS_VERx100(xe) >= 1210) dg1_irq_reset(tile); @@ -545,8 +576,26 @@ static void xe_irq_reset(struct xe_device *xe) } } +static void vf_irq_postinstall(struct xe_device *xe) +{ + struct xe_tile *tile; + unsigned int id; + + for_each_tile(tile, xe, id) + if (xe_device_has_memirq(xe)) + xe_memirq_postinstall(&tile->sriov.vf.memirq); + + if (GRAPHICS_VERx100(xe) < 1210) + xelp_intr_enable(xe, true); + else + xe_assert(xe, xe_device_has_memirq(xe)); +} + static void xe_irq_postinstall(struct xe_device *xe) { + if (IS_SRIOV_VF(xe)) + return vf_irq_postinstall(xe); + xe_display_irq_postinstall(xe, xe_root_mmio_gt(xe)); /* @@ -563,8 +612,30 @@ static void xe_irq_postinstall(struct xe_device *xe) xelp_intr_enable(xe, true); } +static irqreturn_t vf_mem_irq_handler(int irq, void *arg) +{ + struct xe_device *xe = arg; + struct xe_tile *tile; + unsigned int id; + + spin_lock(&xe->irq.lock); + if (!xe->irq.enabled) { + spin_unlock(&xe->irq.lock); + return IRQ_NONE; + } + spin_unlock(&xe->irq.lock); + + for_each_tile(tile, xe, id) + xe_memirq_handler(&tile->sriov.vf.memirq); + + return IRQ_HANDLED; +} + static irq_handler_t xe_irq_handler(struct xe_device *xe) { + if (IS_SRIOV_VF(xe) && xe_device_has_memirq(xe)) + return vf_mem_irq_handler; + if (GRAPHICS_VERx100(xe) >= 1210) return dg1_irq_handler; else -- GitLab From b2e1f97fb41843ddee5afbf4ba7812642f3cfab9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:20 +0100 Subject: [PATCH 0073/1420] drm/xe: Add GT oriented drm_printers Instead of using generic drm_err_printer() that just adds static prefix, or drm_info_printer() that outputs only device name, add new helpers that create dedicated drm_printers that use our GT oriented xe_gt_err() and xe_gt_info() functions. Cc: Rodrigo Vivi Cc: Matt Roper Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-2-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_gt_printk.h | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_printk.h b/drivers/gpu/drm/xe/xe_gt_printk.h index 5991bcadd47e0..c2b004d3f48e3 100644 --- a/drivers/gpu/drm/xe/xe_gt_printk.h +++ b/drivers/gpu/drm/xe/xe_gt_printk.h @@ -43,4 +43,48 @@ #define xe_gt_WARN_ON_ONCE(_gt, _condition) \ xe_gt_WARN_ONCE((_gt), _condition, "%s(%s)", "gt_WARN_ON_ONCE", __stringify(_condition)) +static inline void __xe_gt_printfn_err(struct drm_printer *p, struct va_format *vaf) +{ + struct xe_gt *gt = p->arg; + + xe_gt_err(gt, "%pV", vaf); +} + +static inline void __xe_gt_printfn_info(struct drm_printer *p, struct va_format *vaf) +{ + struct xe_gt *gt = p->arg; + + xe_gt_info(gt, "%pV", vaf); +} + +/** + * xe_gt_err_printer - Construct a &drm_printer that outputs to xe_gt_err() + * @gt: the &xe_gt pointer to use in xe_gt_err() + * + * Return: The &drm_printer object. + */ +static inline struct drm_printer xe_gt_err_printer(struct xe_gt *gt) +{ + struct drm_printer p = { + .printfn = __xe_gt_printfn_err, + .arg = gt, + }; + return p; +} + +/** + * xe_gt_info_printer - Construct a &drm_printer that outputs to xe_gt_info() + * @gt: the &xe_gt pointer to use in xe_gt_info() + * + * Return: The &drm_printer object. + */ +static inline struct drm_printer xe_gt_info_printer(struct xe_gt *gt) +{ + struct drm_printer p = { + .printfn = __xe_gt_printfn_info, + .arg = gt, + }; + return p; +} + #endif -- GitLab From e8b9b3097ca82f29d4e4e32d0ad79732ed041b7c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:21 +0100 Subject: [PATCH 0074/1420] drm/xe: Report TLB timeout using GT oriented functions We track TLB invalidation seqno per GT and we have GT oriented message helpers, so it's better to use GT oriented log functions. Cc: Matt Roper Cc: Matthew Brost Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-3-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c index 7eef23a00d77e..e3a4131ebb587 100644 --- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c +++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c @@ -8,6 +8,7 @@ #include "abi/guc_actions_abi.h" #include "xe_device.h" #include "xe_gt.h" +#include "xe_gt_printk.h" #include "xe_guc.h" #include "xe_guc_ct.h" #include "xe_trace.h" @@ -30,8 +31,8 @@ static void xe_gt_tlb_fence_timeout(struct work_struct *work) break; trace_xe_gt_tlb_invalidation_fence_timeout(fence); - drm_err(>_to_xe(gt)->drm, "gt%d: TLB invalidation fence timeout, seqno=%d recv=%d", - gt->info.id, fence->seqno, gt->tlb_invalidation.seqno_recv); + xe_gt_err(gt, "TLB invalidation fence timeout, seqno=%d recv=%d", + fence->seqno, gt->tlb_invalidation.seqno_recv); list_del(&fence->link); fence->base.error = -ETIME; @@ -312,9 +313,7 @@ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt, */ int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno) { - struct xe_device *xe = gt_to_xe(gt); struct xe_guc *guc = >->uc.guc; - struct drm_printer p = drm_err_printer(__func__); int ret; /* @@ -325,8 +324,10 @@ int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno) tlb_invalidation_seqno_past(gt, seqno), TLB_TIMEOUT); if (!ret) { - drm_err(&xe->drm, "gt%d: TLB invalidation time'd out, seqno=%d, recv=%d\n", - gt->info.id, seqno, gt->tlb_invalidation.seqno_recv); + struct drm_printer p = xe_gt_err_printer(gt); + + xe_gt_err(gt, "TLB invalidation time'd out, seqno=%d, recv=%d\n", + seqno, gt->tlb_invalidation.seqno_recv); xe_guc_ct_print(&guc->ct, &p, true); return -ETIME; } -- GitLab From 587c73343ac79000223b05e1e58a0657a0b59f01 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:22 +0100 Subject: [PATCH 0075/1420] drm/xe: Introduce GuC Doorbells Manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GFX doorbell solution provides a mechanism for submission of workload to the graphics hardware by a ring3 application without the penalty of ring transition for each workload submission. This feature is not currently used by the Linux drivers, but in SR-IOV mode the doorbells are treated as shared resource and the PF driver must be able to provision exclusive range of doorbells IDs across all enabled VFs. Introduce simple GuC doorbell ID manager that will be used by the PF driver for VFs provisioning and can later be used by submission code once we are ready to switch from H2G based notifications to doorbells mechanism. Cc: Matthew Brost Cc: Piotr Piórkowski Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20231218190629.502-4-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_guc_db_mgr.c | 257 +++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_db_mgr.h | 22 +++ drivers/gpu/drm/xe/xe_guc_types.h | 15 ++ drivers/gpu/drm/xe/xe_uc.c | 5 + 5 files changed, 300 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_guc_db_mgr.c create mode 100644 drivers/gpu/drm/xe/xe_guc_db_mgr.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 9214915d9566c..a1aa0028e153d 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -93,6 +93,7 @@ xe-y += xe_bb.o \ xe_guc.o \ xe_guc_ads.o \ xe_guc_ct.o \ + xe_guc_db_mgr.o \ xe_guc_debugfs.o \ xe_guc_hwconfig.o \ xe_guc_log.o \ diff --git a/drivers/gpu/drm/xe/xe_guc_db_mgr.c b/drivers/gpu/drm/xe/xe_guc_db_mgr.c new file mode 100644 index 0000000000000..15816f90e9605 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_db_mgr.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include + +#include + +#include "regs/xe_guc_regs.h" + +#include "xe_assert.h" +#include "xe_gt_printk.h" +#include "xe_guc.h" +#include "xe_guc_db_mgr.h" +#include "xe_guc_types.h" + +/** + * DOC: GuC Doorbells + * + * The GFX doorbell solution provides a mechanism for submission of workload + * to the graphics hardware by a ring3 application without the penalty of + * ring transition for each workload submission. + * + * In SR-IOV mode, the doorbells are treated as shared resource and PF must + * be able to provision exclusive range of IDs across VFs, which may want to + * use this feature. + */ + +static struct xe_guc *dbm_to_guc(struct xe_guc_db_mgr *dbm) +{ + return container_of(dbm, struct xe_guc, dbm); +} + +static struct xe_gt *dbm_to_gt(struct xe_guc_db_mgr *dbm) +{ + return guc_to_gt(dbm_to_guc(dbm)); +} + +static struct xe_device *dbm_to_xe(struct xe_guc_db_mgr *dbm) +{ + return gt_to_xe(dbm_to_gt(dbm)); +} + +#define dbm_assert(_dbm, _cond) xe_gt_assert(dbm_to_gt(_dbm), _cond) +#define dbm_mutex(_dbm) (&dbm_to_guc(_dbm)->submission_state.lock) + +static void __fini_dbm(struct drm_device *drm, void *arg) +{ + struct xe_guc_db_mgr *dbm = arg; + unsigned int weight; + + mutex_lock(dbm_mutex(dbm)); + + weight = bitmap_weight(dbm->bitmap, dbm->count); + if (weight) { + struct drm_printer p = xe_gt_info_printer(dbm_to_gt(dbm)); + + xe_gt_err(dbm_to_gt(dbm), "GuC doorbells manager unclean (%u/%u)\n", + weight, dbm->count); + xe_guc_db_mgr_print(dbm, &p, 1); + } + + bitmap_free(dbm->bitmap); + dbm->bitmap = NULL; + dbm->count = 0; + + mutex_unlock(dbm_mutex(dbm)); +} + +/** + * xe_guc_db_mgr_init() - Initialize GuC Doorbells Manager. + * @dbm: the &xe_guc_db_mgr to initialize + * @count: number of doorbells to manage + * + * The bare-metal or PF driver can pass ~0 as &count to indicate that all + * doorbells supported by the hardware are available for use. + * + * Only VF's drivers will have to provide explicit number of doorbells IDs + * that they can use. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_guc_db_mgr_init(struct xe_guc_db_mgr *dbm, unsigned int count) +{ + int ret; + + if (count == ~0) + count = GUC_NUM_DOORBELLS; + + dbm_assert(dbm, !dbm->bitmap); + dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); + + if (!count) + goto done; + + dbm->bitmap = bitmap_zalloc(count, GFP_KERNEL); + if (!dbm->bitmap) + return -ENOMEM; + dbm->count = count; + + ret = drmm_add_action_or_reset(&dbm_to_xe(dbm)->drm, __fini_dbm, dbm); + if (ret) + return ret; +done: + xe_gt_dbg(dbm_to_gt(dbm), "using %u doorbell(s)\n", dbm->count); + return 0; +} + +static int dbm_reserve_chunk_locked(struct xe_guc_db_mgr *dbm, + unsigned int count, unsigned int spare) +{ + unsigned int used; + int index; + + dbm_assert(dbm, count); + dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); + dbm_assert(dbm, dbm->count <= GUC_NUM_DOORBELLS); + lockdep_assert_held(dbm_mutex(dbm)); + + if (!dbm->count) + return -ENODATA; + + if (spare) { + used = bitmap_weight(dbm->bitmap, dbm->count); + if (used + count + spare > dbm->count) + return -EDQUOT; + } + + index = bitmap_find_next_zero_area(dbm->bitmap, dbm->count, 0, count, 0); + if (index >= dbm->count) + return -ENOSPC; + + bitmap_set(dbm->bitmap, index, count); + + return index; +} + +static void dbm_release_chunk_locked(struct xe_guc_db_mgr *dbm, + unsigned int start, unsigned int count) +{ + dbm_assert(dbm, count); + dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); + dbm_assert(dbm, dbm->count); + dbm_assert(dbm, dbm->count <= GUC_NUM_DOORBELLS); + lockdep_assert_held(dbm_mutex(dbm)); + + if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { + unsigned int n; + + for (n = 0; n < count; n++) + dbm_assert(dbm, test_bit(start + n, dbm->bitmap)); + } + bitmap_clear(dbm->bitmap, start, count); +} + +/** + * xe_guc_db_mgr_reserve_id_locked() - Reserve a single GuC Doorbell ID. + * @dbm: the &xe_guc_db_mgr + * + * This function expects that submission lock is already taken. + * + * Return: ID of the allocated GuC doorbell or a negative error code on failure. + */ +int xe_guc_db_mgr_reserve_id_locked(struct xe_guc_db_mgr *dbm) +{ + return dbm_reserve_chunk_locked(dbm, 1, 0); +} + +/** + * xe_guc_db_mgr_release_id_locked() - Release a single GuC Doorbell ID. + * @dbm: the &xe_guc_db_mgr + * @id: the GuC Doorbell ID to release + * + * This function expects that submission lock is already taken. + */ +void xe_guc_db_mgr_release_id_locked(struct xe_guc_db_mgr *dbm, unsigned int id) +{ + return dbm_release_chunk_locked(dbm, id, 1); +} + +/** + * xe_guc_db_mgr_reserve_range() - Reserve a range of GuC Doorbell IDs. + * @dbm: the &xe_guc_db_mgr + * @count: number of GuC doorbell IDs to reserve + * @spare: number of GuC doorbell IDs to keep available + * + * This function is dedicated for the for use by the PF which expects that + * allocated range for the VF will be contiguous and that there will be at + * least &spare IDs still available for the PF use after this reservation. + * + * Return: starting ID of the allocated GuC doorbell ID range or + * a negative error code on failure. + */ +int xe_guc_db_mgr_reserve_range(struct xe_guc_db_mgr *dbm, + unsigned int count, unsigned int spare) +{ + int ret; + + mutex_lock(dbm_mutex(dbm)); + ret = dbm_reserve_chunk_locked(dbm, count, spare); + mutex_unlock(dbm_mutex(dbm)); + + return ret; +} + +/** + * xe_guc_db_mgr_release_range() - Release a range of Doorbell IDs. + * @dbm: the &xe_guc_db_mgr + * @start: the starting ID of GuC doorbell ID range to release + * @count: number of GuC doorbell IDs to release + */ +void xe_guc_db_mgr_release_range(struct xe_guc_db_mgr *dbm, + unsigned int start, unsigned int count) +{ + mutex_lock(dbm_mutex(dbm)); + dbm_release_chunk_locked(dbm, start, count); + mutex_unlock(dbm_mutex(dbm)); +} + +/** + * xe_guc_db_mgr_print() - Print status of GuC Doorbells Manager. + * @dbm: the &xe_guc_db_mgr to print + * @p: the &drm_printer to print to + * @indent: tab indentation level + */ +void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm, + struct drm_printer *p, int indent) +{ + unsigned int rs, re; + unsigned int total; + + drm_printf_indent(p, indent, "count: %u\n", dbm->count); + if (!dbm->bitmap) + return; + + mutex_lock(dbm_mutex(dbm)); + + total = 0; + for_each_clear_bitrange(rs, re, dbm->bitmap, dbm->count) { + drm_printf_indent(p, indent, "available range: %u..%u (%u)\n", + rs, re - 1, re - rs); + total += re - rs; + } + drm_printf_indent(p, indent, "available total: %u\n", total); + + total = 0; + for_each_set_bitrange(rs, re, dbm->bitmap, dbm->count) { + drm_printf_indent(p, indent, "reserved range: %u..%u (%u)\n", + rs, re - 1, re - rs); + total += re - rs; + } + drm_printf_indent(p, indent, "reserved total: %u\n", total); + + mutex_unlock(dbm_mutex(dbm)); +} diff --git a/drivers/gpu/drm/xe/xe_guc_db_mgr.h b/drivers/gpu/drm/xe/xe_guc_db_mgr.h new file mode 100644 index 0000000000000..c250fa0ca9d63 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_db_mgr.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_GUC_DB_MGR_H_ +#define _XE_GUC_DB_MGR_H_ + +struct drm_printer; +struct xe_guc_db_mgr; + +int xe_guc_db_mgr_init(struct xe_guc_db_mgr *dbm, unsigned int count); + +int xe_guc_db_mgr_reserve_id_locked(struct xe_guc_db_mgr *dbm); +void xe_guc_db_mgr_release_id_locked(struct xe_guc_db_mgr *dbm, unsigned int id); + +int xe_guc_db_mgr_reserve_range(struct xe_guc_db_mgr *dbm, unsigned int count, unsigned int spare); +void xe_guc_db_mgr_release_range(struct xe_guc_db_mgr *dbm, unsigned int start, unsigned int count); + +void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm, struct drm_printer *p, int indent); + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h index cd80802e89189..16de203c62a7e 100644 --- a/drivers/gpu/drm/xe/xe_guc_types.h +++ b/drivers/gpu/drm/xe/xe_guc_types.h @@ -17,6 +17,19 @@ #include "xe_guc_pc_types.h" #include "xe_uc_fw_types.h" +/** + * struct xe_guc_db_mgr - GuC Doorbells Manager. + * + * Note: GuC Doorbells Manager is relying on &xe_guc::submission_state.lock + * to protect its members. + */ +struct xe_guc_db_mgr { + /** @count: number of doorbells to manage */ + unsigned int count; + /** @bitmap: bitmap to track allocated doorbells */ + unsigned long *bitmap; +}; + /** * struct xe_guc - Graphic micro controller */ @@ -31,6 +44,8 @@ struct xe_guc { struct xe_guc_ct ct; /** @pc: GuC Power Conservation */ struct xe_guc_pc pc; + /** @dbm: GuC Doorbell Manager */ + struct xe_guc_db_mgr dbm; /** @submission_state: GuC submission state */ struct { /** @exec_queue_lookup: Lookup an xe_engine from guc_id */ diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c index 25e1ddfd2f86a..4408ea1751e7e 100644 --- a/drivers/gpu/drm/xe/xe_uc.c +++ b/drivers/gpu/drm/xe/xe_uc.c @@ -9,6 +9,7 @@ #include "xe_gsc.h" #include "xe_gt.h" #include "xe_guc.h" +#include "xe_guc_db_mgr.h" #include "xe_guc_pc.h" #include "xe_guc_submit.h" #include "xe_huc.h" @@ -60,6 +61,10 @@ int xe_uc_init(struct xe_uc *uc) if (ret) goto err; + ret = xe_guc_db_mgr_init(&uc->guc.dbm, ~0); + if (ret) + goto err; + return 0; err: -- GitLab From 4ceb8645bd85aeefab0929ada82a95603c6e1f2b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:23 +0100 Subject: [PATCH 0076/1420] drm/xe/kunit: Set SR-IOV mode of the fake device We want to add code that will check the driver's SR-IOV mode. Update xe_pci_fake_device_init() and struct xe_pci_fake_data to either explicitly specify desired SR-IOV mode of the fake device or fallback to the default bare-metal mode. Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-5-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_pci.c | 3 +++ drivers/gpu/drm/xe/tests/xe_pci_test.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 602793644f61d..f62809ca8b51f 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -156,6 +156,9 @@ int xe_pci_fake_device_init(struct xe_device *xe) return -ENODEV; done: + xe->sriov.__mode = data && data->sriov_mode ? + data->sriov_mode : XE_SRIOV_MODE_NONE; + kunit_activate_static_stub(test, read_gmdid, fake_read_gmdid); xe_info_init_early(xe, desc, subplatform_desc); diff --git a/drivers/gpu/drm/xe/tests/xe_pci_test.h b/drivers/gpu/drm/xe/tests/xe_pci_test.h index 811ffe5bd9fd2..f40dcec839929 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci_test.h +++ b/drivers/gpu/drm/xe/tests/xe_pci_test.h @@ -9,6 +9,7 @@ #include #include "xe_platform_types.h" +#include "xe_sriov_types.h" struct xe_device; struct xe_graphics_desc; @@ -23,6 +24,7 @@ void xe_call_for_each_graphics_ip(xe_graphics_fn xe_fn); void xe_call_for_each_media_ip(xe_media_fn xe_fn); struct xe_pci_fake_data { + enum xe_sriov_mode sriov_mode; enum xe_platform platform; enum xe_subplatform subplatform; u32 graphics_verx100; -- GitLab From 5095d13d758b4e602eb78771abf65ee5dc867645 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:24 +0100 Subject: [PATCH 0077/1420] drm/xe/kunit: Define helper functions to allocate fake xe device There will be more KUnit tests added that will require fake device. Define generic helper functions to avoid code duplications. Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-6-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/Makefile | 3 + drivers/gpu/drm/xe/tests/xe_kunit_helpers.c | 80 +++++++++++++++++++++ drivers/gpu/drm/xe/tests/xe_kunit_helpers.h | 17 +++++ 3 files changed, 100 insertions(+) create mode 100644 drivers/gpu/drm/xe/tests/xe_kunit_helpers.c create mode 100644 drivers/gpu/drm/xe/tests/xe_kunit_helpers.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index a1aa0028e153d..df8601d6a59f0 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -156,6 +156,9 @@ xe-$(CONFIG_PCI_IOV) += \ xe_lmtt_2l.o \ xe_lmtt_ml.o +xe-$(CONFIG_DRM_XE_KUNIT_TEST) += \ + tests/xe_kunit_helpers.o + # i915 Display compat #defines and #includes subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \ -I$(srctree)/$(src)/display/ext \ diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c new file mode 100644 index 0000000000000..6d72dbf061393 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include +#include + +#include +#include + +#include "tests/xe_kunit_helpers.h" +#include "tests/xe_pci_test.h" +#include "xe_device_types.h" + +/** + * xe_kunit_helper_alloc_xe_device - Allocate a &xe_device for a KUnit test. + * @test: the &kunit where this &xe_device will be used + * @dev: The parent device object + * + * This function allocates xe_device using drm_kunit_helper_alloc_device(). + * The xe_device allocation is managed by the test. + * + * @dev should be allocated using drm_kunit_helper_alloc_device(). + * + * This function uses KUNIT_ASSERT to detect any allocation failures. + * + * Return: A pointer to the new &xe_device. + */ +struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test, + struct device *dev) +{ + struct xe_device *xe; + + xe = drm_kunit_helper_alloc_drm_device(test, dev, + struct xe_device, + drm, DRIVER_GEM); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); + return xe; +} +EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_alloc_xe_device); + +/** + * xe_kunit_helper_xe_device_test_init - Prepare a &xe_device for a KUnit test. + * @test: the &kunit where this fake &xe_device will be used + * + * This function allocates and initializes a fake &xe_device and stores its + * pointer as &kunit.priv to allow the test code to access it. + * + * This function can be directly used as custom implementation of + * &kunit_suite.init. + * + * It is possible to prepare specific variant of the fake &xe_device by passing + * in &kunit.priv pointer to the struct xe_pci_fake_data supplemented with + * desired parameters prior to calling this function. + * + * This function uses KUNIT_ASSERT to detect any failures. + * + * Return: Always 0. + */ +int xe_kunit_helper_xe_device_test_init(struct kunit *test) +{ + struct xe_device *xe; + struct device *dev; + int err; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + xe = xe_kunit_helper_alloc_xe_device(test, dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); + + err = xe_pci_fake_device_init(xe); + KUNIT_ASSERT_EQ(test, err, 0); + + test->priv = xe; + return 0; +} +EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_xe_device_test_init); diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.h b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.h new file mode 100644 index 0000000000000..067a1babf0497 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 AND MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_KUNIT_HELPERS_H_ +#define _XE_KUNIT_HELPERS_H_ + +struct device; +struct kunit; +struct xe_device; + +struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test, + struct device *dev); +int xe_kunit_helper_xe_device_test_init(struct kunit *test); + +#endif -- GitLab From 0b75475723b182400a4bfa5aaff9a969afdfdb76 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:25 +0100 Subject: [PATCH 0078/1420] drm/xe/kunit: Restore test->priv when done with fake xe device Current KUnit implementation does not reset test->priv in case of parametrized tests and that may lead to wrongly treat our output pointer to fake xe_device from first call as input pointer with xe_pci_fake_data on subsequent calls. Restore test->priv to original value to avoid invalid access. Acked-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-7-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_kunit_helpers.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c index 6d72dbf061393..fefe79b3b75a4 100644 --- a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c +++ b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c @@ -41,6 +41,13 @@ struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test, } EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_alloc_xe_device); +static void kunit_action_restore_priv(void *priv) +{ + struct kunit *test = kunit_get_current_test(); + + test->priv = priv; +} + /** * xe_kunit_helper_xe_device_test_init - Prepare a &xe_device for a KUnit test. * @test: the &kunit where this fake &xe_device will be used @@ -74,6 +81,9 @@ int xe_kunit_helper_xe_device_test_init(struct kunit *test) err = xe_pci_fake_device_init(xe); KUNIT_ASSERT_EQ(test, err, 0); + err = kunit_add_action_or_reset(test, kunit_action_restore_priv, test->priv); + KUNIT_ASSERT_EQ(test, err, 0); + test->priv = xe; return 0; } -- GitLab From d8ba1ede4cbd8df3a2a9a8a089df04398b8a7db6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:26 +0100 Subject: [PATCH 0079/1420] drm/xe/kunit: Use xe kunit helper in RTP test Replace drm_kunit_helper_alloc_drm_device with xe helper. Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-8-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_rtp_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c index 4a69728976756..21e77026518b6 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.c @@ -15,6 +15,7 @@ #include "regs/xe_reg_defs.h" #include "xe_device.h" #include "xe_device_types.h" +#include "xe_kunit_helpers.h" #include "xe_pci_test.h" #include "xe_reg_sr.h" #include "xe_rtp.h" @@ -276,9 +277,7 @@ static int xe_rtp_test_init(struct kunit *test) dev = drm_kunit_helper_alloc_device(test); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); - xe = drm_kunit_helper_alloc_drm_device(test, dev, - struct xe_device, - drm, DRIVER_GEM); + xe = xe_kunit_helper_alloc_xe_device(test, dev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); /* Initialize an empty device */ -- GitLab From 29d52c9c1b9d1abdbddc9b6cbd8eb2d70b025e6c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:27 +0100 Subject: [PATCH 0080/1420] drm/xe/kunit: Use xe kunit helper in WA test Use xe helper code to allocate fake xe device. Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-9-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_wa_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index a53c22a195824..3d7f3ef62ae93 100644 --- a/drivers/gpu/drm/xe/tests/xe_wa_test.c +++ b/drivers/gpu/drm/xe/tests/xe_wa_test.c @@ -9,6 +9,7 @@ #include #include "xe_device.h" +#include "xe_kunit_helpers.h" #include "xe_pci_test.h" #include "xe_reg_sr.h" #include "xe_tuning.h" @@ -108,9 +109,7 @@ static int xe_wa_test_init(struct kunit *test) dev = drm_kunit_helper_alloc_device(test); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); - xe = drm_kunit_helper_alloc_drm_device(test, dev, - struct xe_device, - drm, DRIVER_GEM); + xe = xe_kunit_helper_alloc_xe_device(test, dev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); test->priv = &data; -- GitLab From 90ad6f3017894860429bc1f8820024e0b177e676 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:28 +0100 Subject: [PATCH 0081/1420] drm/xe/kunit: Enable CONFIG_LOCKDEP in tests Tests might use locking, better to have LOCKDEP enabled. Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20231218190629.502-10-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/.kunitconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/.kunitconfig b/drivers/gpu/drm/xe/.kunitconfig index 9590eac91af39..ad4b9b4a9f554 100644 --- a/drivers/gpu/drm/xe/.kunitconfig +++ b/drivers/gpu/drm/xe/.kunitconfig @@ -11,3 +11,8 @@ CONFIG_DRM_XE_DISPLAY=n CONFIG_EXPERT=y CONFIG_FB=y CONFIG_DRM_XE_KUNIT_TEST=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_LOCKDEP=y +CONFIG_DEBUG_LOCKDEP=y -- GitLab From 6e2546131750a7c5e5dc668f9050d6a99c095d51 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:29 +0100 Subject: [PATCH 0082/1420] drm/xe/kunit: Add GuC Doorbells Manager tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add few tests to make sure that basic usage scenarios of the GuC Doorbells Manager are implemented correctly. Cc: Piotr Piórkowski Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20231218190629.502-11-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_guc_db_mgr_test.c | 201 ++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_db_mgr.c | 4 + 2 files changed, 205 insertions(+) create mode 100644 drivers/gpu/drm/xe/tests/xe_guc_db_mgr_test.c diff --git a/drivers/gpu/drm/xe/tests/xe_guc_db_mgr_test.c b/drivers/gpu/drm/xe/tests/xe_guc_db_mgr_test.c new file mode 100644 index 0000000000000..a87a7b4b040a2 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_guc_db_mgr_test.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include "xe_device.h" +#include "xe_kunit_helpers.h" + +static int guc_dbm_test_init(struct kunit *test) +{ + struct xe_guc_db_mgr *dbm; + + xe_kunit_helper_xe_device_test_init(test); + dbm = &xe_device_get_gt(test->priv, 0)->uc.guc.dbm; + + mutex_init(dbm_mutex(dbm)); + test->priv = dbm; + return 0; +} + +static void test_empty(struct kunit *test) +{ + struct xe_guc_db_mgr *dbm = test->priv; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, 0), 0); + KUNIT_ASSERT_EQ(test, dbm->count, 0); + + mutex_lock(dbm_mutex(dbm)); + KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0); + mutex_unlock(dbm_mutex(dbm)); + + KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); +} + +static void test_default(struct kunit *test) +{ + struct xe_guc_db_mgr *dbm = test->priv; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0); + KUNIT_ASSERT_EQ(test, dbm->count, GUC_NUM_DOORBELLS); +} + +static const unsigned int guc_dbm_params[] = { + GUC_NUM_DOORBELLS / 64, + GUC_NUM_DOORBELLS / 32, + GUC_NUM_DOORBELLS / 8, + GUC_NUM_DOORBELLS, +}; + +static void uint_param_get_desc(const unsigned int *p, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%u", *p); +} + +KUNIT_ARRAY_PARAM(guc_dbm, guc_dbm_params, uint_param_get_desc); + +static void test_size(struct kunit *test) +{ + const unsigned int *p = test->param_value; + struct xe_guc_db_mgr *dbm = test->priv; + unsigned int n; + int id; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, *p), 0); + KUNIT_ASSERT_EQ(test, dbm->count, *p); + + mutex_lock(dbm_mutex(dbm)); + for (n = 0; n < *p; n++) { + KUNIT_EXPECT_GE(test, id = xe_guc_db_mgr_reserve_id_locked(dbm), 0); + KUNIT_EXPECT_LT(test, id, dbm->count); + } + KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0); + mutex_unlock(dbm_mutex(dbm)); + + mutex_lock(dbm_mutex(dbm)); + for (n = 0; n < *p; n++) + xe_guc_db_mgr_release_id_locked(dbm, n); + mutex_unlock(dbm_mutex(dbm)); +} + +static void test_reuse(struct kunit *test) +{ + const unsigned int *p = test->param_value; + struct xe_guc_db_mgr *dbm = test->priv; + unsigned int n; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, *p), 0); + + mutex_lock(dbm_mutex(dbm)); + for (n = 0; n < *p; n++) + KUNIT_EXPECT_GE(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0); + KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0); + mutex_unlock(dbm_mutex(dbm)); + + mutex_lock(dbm_mutex(dbm)); + for (n = 0; n < *p; n++) { + xe_guc_db_mgr_release_id_locked(dbm, n); + KUNIT_EXPECT_EQ(test, xe_guc_db_mgr_reserve_id_locked(dbm), n); + } + KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0); + mutex_unlock(dbm_mutex(dbm)); + + mutex_lock(dbm_mutex(dbm)); + for (n = 0; n < *p; n++) + xe_guc_db_mgr_release_id_locked(dbm, n); + mutex_unlock(dbm_mutex(dbm)); +} + +static void test_range_overlap(struct kunit *test) +{ + const unsigned int *p = test->param_value; + struct xe_guc_db_mgr *dbm = test->priv; + int id1, id2, id3; + unsigned int n; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0); + KUNIT_ASSERT_LE(test, *p, dbm->count); + + KUNIT_ASSERT_GE(test, id1 = xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0); + for (n = 0; n < dbm->count - *p; n++) { + KUNIT_ASSERT_GE(test, id2 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + KUNIT_ASSERT_NE(test, id2, id1); + KUNIT_ASSERT_NE_MSG(test, id2 < id1, id2 > id1 + *p - 1, + "id1=%d id2=%d", id1, id2); + } + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + xe_guc_db_mgr_release_range(dbm, 0, dbm->count); + + if (*p >= 1) { + KUNIT_ASSERT_GE(test, id1 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + KUNIT_ASSERT_GE(test, id2 = xe_guc_db_mgr_reserve_range(dbm, *p - 1, 0), 0); + KUNIT_ASSERT_NE(test, id2, id1); + KUNIT_ASSERT_NE_MSG(test, id1 < id2, id1 > id2 + *p - 2, + "id1=%d id2=%d", id1, id2); + for (n = 0; n < dbm->count - *p; n++) { + KUNIT_ASSERT_GE(test, id3 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + KUNIT_ASSERT_NE(test, id3, id1); + KUNIT_ASSERT_NE(test, id3, id2); + KUNIT_ASSERT_NE_MSG(test, id3 < id2, id3 > id2 + *p - 2, + "id3=%d id2=%d", id3, id2); + } + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + xe_guc_db_mgr_release_range(dbm, 0, dbm->count); + } +} + +static void test_range_compact(struct kunit *test) +{ + const unsigned int *p = test->param_value; + struct xe_guc_db_mgr *dbm = test->priv; + unsigned int n; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0); + KUNIT_ASSERT_NE(test, *p, 0); + KUNIT_ASSERT_LE(test, *p, dbm->count); + if (dbm->count % *p) + kunit_skip(test, "must be divisible"); + + KUNIT_ASSERT_GE(test, xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0); + for (n = 1; n < dbm->count / *p; n++) + KUNIT_ASSERT_GE(test, xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0); + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0); + xe_guc_db_mgr_release_range(dbm, 0, dbm->count); +} + +static void test_range_spare(struct kunit *test) +{ + const unsigned int *p = test->param_value; + struct xe_guc_db_mgr *dbm = test->priv; + int id; + + KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0); + KUNIT_ASSERT_LE(test, *p, dbm->count); + + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count), 0); + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count - *p + 1), 0); + KUNIT_ASSERT_EQ(test, id = xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count - *p), 0); + KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, dbm->count - *p), 0); + xe_guc_db_mgr_release_range(dbm, id, *p); +} + +static struct kunit_case guc_dbm_test_cases[] = { + KUNIT_CASE(test_empty), + KUNIT_CASE(test_default), + KUNIT_CASE_PARAM(test_size, guc_dbm_gen_params), + KUNIT_CASE_PARAM(test_reuse, guc_dbm_gen_params), + KUNIT_CASE_PARAM(test_range_overlap, guc_dbm_gen_params), + KUNIT_CASE_PARAM(test_range_compact, guc_dbm_gen_params), + KUNIT_CASE_PARAM(test_range_spare, guc_dbm_gen_params), + {} +}; + +static struct kunit_suite guc_dbm_suite = { + .name = "guc_dbm", + .test_cases = guc_dbm_test_cases, + .init = guc_dbm_test_init, +}; + +kunit_test_suites(&guc_dbm_suite); diff --git a/drivers/gpu/drm/xe/xe_guc_db_mgr.c b/drivers/gpu/drm/xe/xe_guc_db_mgr.c index 15816f90e9605..c1c04575d82d9 100644 --- a/drivers/gpu/drm/xe/xe_guc_db_mgr.c +++ b/drivers/gpu/drm/xe/xe_guc_db_mgr.c @@ -255,3 +255,7 @@ void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm, mutex_unlock(dbm_mutex(dbm)); } + +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST) +#include "tests/xe_guc_db_mgr_test.c" +#endif -- GitLab From c5be725eb09de1f1083ba9b4762460ebc66b669c Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Tue, 19 Dec 2023 12:26:13 +0530 Subject: [PATCH 0083/1420] drm/xe/xelpg: Extend Wa_14019877138 for Graphics 12.70/71 Wa_14019877138 is also needed for xe_lpg graphics 12.70/71 Reviewed-by: Matt Roper Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_wa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 7d6b86d602c8a..3456ca6f7b323 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -536,6 +536,10 @@ static const struct xe_rtp_entry_sr lrc_was[] = { XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1271)), XE_RTP_ACTIONS(SET(CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE)) }, + { XE_RTP_NAME("14019877138"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1271), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) + }, /* Xe2_LPG */ -- GitLab From 0eb16fd26795639d5420b58bb12d11c7705e6dfa Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 6 Dec 2023 13:14:41 -0800 Subject: [PATCH 0084/1420] drm/xe/guc: Use FAST_REQUEST for non-blocking H2G messages We're currently sending non-blocking H2G messages using the EVENT type, which suppresses all CTB protocol replies from the GuC, including the failure cases. This might cause errors to slip through and manifest as unexpected behavior (e.g. a context state might not be what the driver thinks it is because the state change command was silently rejected by the GuC). To avoid this kind of problems, we can use the FAST_REQUEST type instead, which suppresses the reply only on success; this way we still get the advantage of not having to wait for an ack from the GuC (i.e. the H2G is still non-blocking) while still detecting errors. Since we can't escalate to the caller when a non-blocking message fails, we need to escalate to GT reset instead. Note that FAST_REQUEST failures are NOT expected and are usually a sign that the H2G was either malformed or requested an illegal operation. v2: assign fence values to FAST_REQUEST messages, fix abi doc, use xe_gt printers (Michal). v3: fix doc alignment, fix and improve prints (Michal) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Cc: Matthew Brost Cc: Michal Wajdeczko Reviewed-by: Matthew Brost #v2 Reviewed-by: Michal Wajdeczko --- drivers/gpu/drm/xe/abi/guc_messages_abi.h | 2 + drivers/gpu/drm/xe/xe_guc_ct.c | 58 ++++++++++++++++++++--- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/abi/guc_messages_abi.h b/drivers/gpu/drm/xe/abi/guc_messages_abi.h index 3d199016cf881..ff888d16bd4f1 100644 --- a/drivers/gpu/drm/xe/abi/guc_messages_abi.h +++ b/drivers/gpu/drm/xe/abi/guc_messages_abi.h @@ -24,6 +24,7 @@ * | | 30:28 | **TYPE** - message type | * | | | - _`GUC_HXG_TYPE_REQUEST` = 0 | * | | | - _`GUC_HXG_TYPE_EVENT` = 1 | + * | | | - _`GUC_HXG_TYPE_FAST_REQUEST` = 2 | * | | | - _`GUC_HXG_TYPE_NO_RESPONSE_BUSY` = 3 | * | | | - _`GUC_HXG_TYPE_NO_RESPONSE_RETRY` = 5 | * | | | - _`GUC_HXG_TYPE_RESPONSE_FAILURE` = 6 | @@ -46,6 +47,7 @@ #define GUC_HXG_MSG_0_TYPE (0x7 << 28) #define GUC_HXG_TYPE_REQUEST 0u #define GUC_HXG_TYPE_EVENT 1u +#define GUC_HXG_TYPE_FAST_REQUEST 2u #define GUC_HXG_TYPE_NO_RESPONSE_BUSY 3u #define GUC_HXG_TYPE_NO_RESPONSE_RETRY 5u #define GUC_HXG_TYPE_RESPONSE_FAILURE 6u diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 24a33fa36496a..4cde93c18a2d4 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -17,6 +17,7 @@ #include "xe_device.h" #include "xe_gt.h" #include "xe_gt_pagefault.h" +#include "xe_gt_printk.h" #include "xe_gt_tlb_invalidation.h" #include "xe_guc.h" #include "xe_guc_submit.h" @@ -448,7 +449,7 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len, GUC_HXG_EVENT_MSG_0_DATA0, action[0]); } else { cmd[1] = - FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_FAST_REQUEST) | FIELD_PREP(GUC_HXG_EVENT_MSG_0_ACTION | GUC_HXG_EVENT_MSG_0_DATA0, action[0]); } @@ -475,11 +476,31 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len, return 0; } +/* + * The CT protocol accepts a 16 bits fence. This field is fully owned by the + * driver, the GuC will just copy it to the reply message. Since we need to + * be able to distinguish between replies to REQUEST and FAST_REQUEST messages, + * we use one bit of the seqno as an indicator for that and a rolling counter + * for the remaining 15 bits. + */ +#define CT_SEQNO_MASK GENMASK(14, 0) +#define CT_SEQNO_UNTRACKED BIT(15) +static u16 next_ct_seqno(struct xe_guc_ct *ct, bool is_g2h_fence) +{ + u32 seqno = ct->fence_seqno++ & CT_SEQNO_MASK; + + if (!is_g2h_fence) + seqno |= CT_SEQNO_UNTRACKED; + + return seqno; +} + static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, u32 g2h_len, u32 num_g2h, struct g2h_fence *g2h_fence) { struct xe_device *xe = ct_to_xe(ct); + u16 seqno; int ret; xe_assert(xe, !g2h_len || !g2h_fence); @@ -505,7 +526,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, if (g2h_fence_needs_alloc(g2h_fence)) { void *ptr; - g2h_fence->seqno = (ct->fence_seqno++ & 0xffff); + g2h_fence->seqno = next_ct_seqno(ct, true); ptr = xa_store(&ct->fence_lookup, g2h_fence->seqno, g2h_fence, GFP_ATOMIC); @@ -514,6 +535,10 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, goto out; } } + + seqno = g2h_fence->seqno; + } else { + seqno = next_ct_seqno(ct, false); } if (g2h_len) @@ -523,8 +548,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, if (unlikely(ret)) goto out_unlock; - ret = h2g_write(ct, action, len, g2h_fence ? g2h_fence->seqno : 0, - !!g2h_fence); + ret = h2g_write(ct, action, len, seqno, !!g2h_fence); if (unlikely(ret)) { if (ret == -EAGAIN) goto retry; @@ -786,7 +810,8 @@ static int parse_g2h_event(struct xe_guc_ct *ct, u32 *msg, u32 len) static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) { - struct xe_device *xe = ct_to_xe(ct); + struct xe_gt *gt = ct_to_gt(ct); + struct xe_device *xe = gt_to_xe(gt); u32 response_len = len - GUC_CTB_MSG_MIN_LEN; u32 fence = FIELD_GET(GUC_CTB_MSG_0_FENCE, msg[0]); u32 type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[1]); @@ -794,10 +819,31 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) lockdep_assert_held(&ct->lock); + /* + * Fences for FAST_REQUEST messages are not tracked in ct->fence_lookup. + * Those messages should never fail, so if we do get an error back it + * means we're likely doing an illegal operation and the GuC is + * rejecting it. We have no way to inform the code that submitted the + * H2G that the message was rejected, so we need to escalate the + * failure to trigger a reset. + */ + if (fence & CT_SEQNO_UNTRACKED) { + if (type == GUC_HXG_TYPE_RESPONSE_FAILURE) + xe_gt_err(gt, "FAST_REQ H2G fence 0x%x failed! e=0x%x, h=%u\n", + fence, + FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, msg[1]), + FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, msg[1])); + else + xe_gt_err(gt, "unexpected response %u for FAST_REQ H2G fence 0x%x!\n", + type, fence); + + return -EPROTO; + } + g2h_fence = xa_erase(&ct->fence_lookup, fence); if (unlikely(!g2h_fence)) { /* Don't tear down channel, as send could've timed out */ - drm_warn(&xe->drm, "G2H fence (%u) not found!\n", fence); + xe_gt_warn(gt, "G2H fence (%u) not found!\n", fence); g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); return 0; } -- GitLab From da2d668480c37d43a423ff7822caba2e0c58c4ac Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Fri, 15 Dec 2023 10:39:16 +0530 Subject: [PATCH 0085/1420] drm/i915/hdcp: Fail Repeater authentication if Type1 device not present Fail repeater authentication step in case RX_INFO indicates HDCP1.x or HDCP2.0/2.1 device is present downstream in repeater topology and content type set by userspace is Type1. --v2 -Fix build error. --v3 -remove mst encoder check as branch device also act as repeater Signed-off-by: Suraj Kandpal Reviewed-by: Ankit Nautiyal Signed-off-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20231215050915.2070119-1-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_hdcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index ee29fcb860e46..c3e692e7f790d 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -1633,6 +1633,12 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) !HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) && !HDCP_2_2_HDCP_2_0_REP_CONNECTED(rx_info[1]); + if (!dig_port->hdcp_mst_type1_capable && hdcp->content_type) { + drm_dbg_kms(&i915->drm, + "HDCP1.x or 2.0 Legacy Device Downstream\n"); + return -EINVAL; + } + /* Converting and Storing the seq_num_v to local variable as DWORD */ seq_num_v = drm_hdcp_be24_to_cpu((const u8 *)msgs.recvid_list.seq_num_v); -- GitLab From e11300a1d8e38a2311beaebdd2169a15265de103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:03 +0200 Subject: [PATCH 0086/1420] drm/i915/display: Remove intel_crtc_state->psr_vsc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no really need to have separate vsc for psr usage. Use intel_crtc_state->infoframes.vsc instead. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 1 - drivers/gpu/drm/i915/display/intel_psr.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 3fdd8a5179831..bbdc2041a990c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1218,7 +1218,6 @@ struct intel_crtc_state { bool wm_level_disabled; u32 dc3co_exitline; u16 su_y_granularity; - struct drm_dp_vsc_sdp psr_vsc; /* * Frequence the dpll for the port should run at. Differs from the diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index b6e2e70e12904..9d5dc3fb6f20d 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1380,7 +1380,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, - &crtc_state->psr_vsc); + &crtc_state->infoframes.vsc); } void intel_psr_get_config(struct intel_encoder *encoder, @@ -1652,7 +1652,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", intel_dp->psr.psr2_enabled ? "2" : "1"); - intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc); + intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->infoframes.vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); intel_psr_enable_source(intel_dp, crtc_state); -- GitLab From 00076671a648e1d10ebbccf2fa71bf7edbedddb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:04 +0200 Subject: [PATCH 0087/1420] drm/i915/display: Move colorimetry_support from intel_psr to intel_dp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Colorimetry support is not really a PSR specific thing. Move it to intel_dp struct and use it also when preparing vsc sdp for non-PSR case. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 3 ++- drivers/gpu/drm/i915/display/intel_dp.c | 10 +++++++--- drivers/gpu/drm/i915/display/intel_psr.c | 5 +---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index bbdc2041a990c..b9b9d9f2bc0ba 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1701,7 +1701,6 @@ struct intel_psr { unsigned int busy_frontbuffer_bits; bool sink_psr2_support; bool link_standby; - bool colorimetry_support; bool psr2_enabled; bool psr2_sel_fetch_enabled; bool psr2_sel_fetch_cff_enabled; @@ -1832,6 +1831,8 @@ struct intel_dp { /* When we last wrote the OUI for eDP */ unsigned long last_oui_write; + + bool colorimetry_support; }; enum lspcon_vendor { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index dcfcc626d503f..d1cb325c64d14 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2622,7 +2622,8 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, if (crtc_state->has_psr) return; - if (!intel_dp_needs_vsc_sdp(crtc_state, conn_state)) + if (!intel_dp->colorimetry_support || + !intel_dp_needs_vsc_sdp(crtc_state, conn_state)) return; crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); @@ -2639,7 +2640,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, vsc->sdp_type = DP_SDP_VSC; if (crtc_state->has_psr2) { - if (intel_dp->psr.colorimetry_support && + if (intel_dp->colorimetry_support && intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { /* [PSR2, +Colorimetry] */ intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, @@ -2654,7 +2655,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, vsc->length = 0xe; } } else if (crtc_state->has_panel_replay) { - if (intel_dp->psr.colorimetry_support && + if (intel_dp->colorimetry_support && intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { /* [Panel Replay with colorimetry info] */ intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, @@ -6536,6 +6537,9 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } + intel_dp->colorimetry_support = + intel_dp_get_colorimetry_status(intel_dp); + intel_dp->frl.is_trained = false; intel_dp->frl.trained_rate_gbps = 0; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 9d5dc3fb6f20d..d9fffc8023357 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -560,11 +560,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (intel_dp->psr_dpcd[0]) _psr_init_dpcd(intel_dp); - if (intel_dp->psr.sink_psr2_support) { - intel_dp->psr.colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); + if (intel_dp->psr.sink_psr2_support) intel_dp_get_su_granularity(intel_dp); - } } static void hsw_psr_setup_aux(struct intel_dp *intel_dp) -- GitLab From 31a5b6ed88c79b2b80262a3060c2f13a12397ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:05 +0200 Subject: [PATCH 0088/1420] drm/i915/display: Unify VSC SPD preparation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no specific reason to prepare VSC SDP for PSR case somehow differently. Unify PSR and non-PSR preparation. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-4-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 43 ++++-------------------- drivers/gpu/drm/i915/display/intel_dp.h | 7 ---- drivers/gpu/drm/i915/display/intel_psr.c | 6 ---- 3 files changed, 6 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d1cb325c64d14..6607dba8049eb 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2616,28 +2616,17 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_dp_vsc_sdp *vsc = &crtc_state->infoframes.vsc; + struct drm_dp_vsc_sdp *vsc; - /* When a crtc state has PSR, VSC SDP will be handled by PSR routine */ - if (crtc_state->has_psr) + if ((!intel_dp->colorimetry_support || + !intel_dp_needs_vsc_sdp(crtc_state, conn_state)) && + !crtc_state->has_psr) return; - if (!intel_dp->colorimetry_support || - !intel_dp_needs_vsc_sdp(crtc_state, conn_state)) - return; + vsc = &crtc_state->infoframes.vsc; crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); vsc->sdp_type = DP_SDP_VSC; - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - &crtc_state->infoframes.vsc); -} - -void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, - struct drm_dp_vsc_sdp *vsc) -{ - vsc->sdp_type = DP_SDP_VSC; if (crtc_state->has_psr2) { if (intel_dp->colorimetry_support && @@ -4289,24 +4278,6 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder, dig_port->write_infoframe(encoder, crtc_state, type, &sdp, len); } -void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_dp_vsc_sdp *vsc) -{ - struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct dp_sdp sdp = {}; - ssize_t len; - - len = intel_dp_vsc_sdp_pack(vsc, &sdp, sizeof(sdp)); - - if (drm_WARN_ON(&dev_priv->drm, len < 0)) - return; - - dig_port->write_infoframe(encoder, crtc_state, DP_SDP_VSC, - &sdp, len); -} - void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, @@ -4333,9 +4304,7 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, if (!enable) return; - /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (!crtc_state->has_psr) - intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC); + intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC); intel_write_dp_sdp(encoder, crtc_state, HDMI_PACKET_TYPE_GAMUT_METADATA); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 05db46b111f21..b911706d2e95e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -109,13 +109,6 @@ int intel_dp_max_data_rate(int max_link_rate, int max_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); -void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, - struct drm_dp_vsc_sdp *vsc); -void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_dp_vsc_sdp *vsc); void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index d9fffc8023357..494d08817d71e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1374,10 +1374,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); - - crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); - intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, - &crtc_state->infoframes.vsc); } void intel_psr_get_config(struct intel_encoder *encoder, @@ -1621,7 +1617,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); - struct intel_encoder *encoder = &dig_port->base; u32 val; drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled); @@ -1649,7 +1644,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", intel_dp->psr.psr2_enabled ? "2" : "1"); - intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->infoframes.vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); intel_psr_enable_source(intel_dp, crtc_state); -- GitLab From fde53fa18d8e859adaadec0ecdad3d267e3b010b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:06 +0200 Subject: [PATCH 0089/1420] drm/i915/display: Fix vsc_sdp computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently colorimetry data is not added for psr1 or non-psr case. Fix this by adding it as needed. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-5-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 48 ++++++++++--------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6607dba8049eb..173562f4ec457 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2628,36 +2628,26 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); vsc->sdp_type = DP_SDP_VSC; - if (crtc_state->has_psr2) { - if (intel_dp->colorimetry_support && - intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { - /* [PSR2, +Colorimetry] */ - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - vsc); - } else { - /* - * [PSR2, -Colorimetry] - * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11 - * 3D stereo + PSR/PSR2 + Y-coordinate. - */ - vsc->revision = 0x4; - vsc->length = 0xe; - } + /* Needs colorimetry */ + if (intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { + intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, + vsc); + } else if (crtc_state->has_psr2) { + /* + * [PSR2 without colorimetry] + * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11 + * 3D stereo + PSR/PSR2 + Y-coordinate. + */ + vsc->revision = 0x4; + vsc->length = 0xe; } else if (crtc_state->has_panel_replay) { - if (intel_dp->colorimetry_support && - intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { - /* [Panel Replay with colorimetry info] */ - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - vsc); - } else { - /* - * [Panel Replay without colorimetry info] - * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 - * VSC SDP supporting 3D stereo + Panel Replay. - */ - vsc->revision = 0x6; - vsc->length = 0x10; - } + /* + * [Panel Replay without colorimetry info] + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo + Panel Replay. + */ + vsc->revision = 0x6; + vsc->length = 0x10; } else { /* * [PSR1] -- GitLab From 6b6276138450617575f1a3176de3a9e289dfa3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:07 +0200 Subject: [PATCH 0090/1420] drm/i915/display: Ignore only psr specific part of vsc sdp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pipe config check is currently ignoring vsc sdp changes completely if psr is enabled. We want to ignore only PSR part of it as there might be changes in colorimetry data. Also read back vsc_sdp when psr is used. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-6-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 9 ++++++--- drivers/gpu/drm/i915/display/intel_dp.c | 4 ---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 66b4c3f3ceb16..9b9a30c11e1c6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4764,7 +4764,11 @@ static bool intel_compare_dp_vsc_sdp(const struct drm_dp_vsc_sdp *a, const struct drm_dp_vsc_sdp *b) { - return memcmp(a, b, sizeof(*a)) == 0; + return a->pixelformat == b->pixelformat && + a->colorimetry == b->colorimetry && + a->bpc == b->bpc && + a->dynamic_range == b->dynamic_range && + a->content_type == b->content_type; } static bool @@ -5045,8 +5049,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } while (0) #define PIPE_CONF_CHECK_DP_VSC_SDP(name) do { \ - if (!current_config->has_psr && !pipe_config->has_psr && \ - !intel_compare_dp_vsc_sdp(¤t_config->infoframes.name, \ + if (!intel_compare_dp_vsc_sdp(¤t_config->infoframes.name, \ &pipe_config->infoframes.name)) { \ pipe_config_dp_vsc_sdp_mismatch(dev_priv, fastset, __stringify(name), \ ¤t_config->infoframes.name, \ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 173562f4ec457..f4a22d40eec27 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4425,10 +4425,6 @@ static void intel_read_dp_vsc_sdp(struct intel_encoder *encoder, struct dp_sdp sdp = {}; int ret; - /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (crtc_state->has_psr) - return; - if ((crtc_state->infoframes.enable & intel_hdmi_infoframe_enable(type)) == 0) return; -- GitLab From 16448cf437ea935b0b05ad4c5891b5bc430fa6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:08 +0200 Subject: [PATCH 0091/1420] drm/i915/display: Read PSR configuration before VSC SDP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VSC SDP sending is taken care by PSR HW and it's not enabled in VIDEO_DIP_CTL when PSR is enabled. Readback of VSC SDP is depending on VSC_SDP being set in intel_crtc_state->infoframes.enabled. In case of PSR setting this flag is taken care by PSR code -> read back PSR configuration before reading VSC SDP otherwise we get pipeconfig mismatch error. Signed-off-by: Jouni Högander Reviewed-by: Rodrigo Vivi Tested-by: Shawn Lee Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-7-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 12a29363e5dfe..2746655bcb264 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3941,11 +3941,11 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, if (DISPLAY_VER(dev_priv) >= 8) bdw_get_trans_port_sync_config(pipe_config); + intel_psr_get_config(encoder, pipe_config); + intel_read_dp_sdp(encoder, pipe_config, HDMI_PACKET_TYPE_GAMUT_METADATA); intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC); - intel_psr_get_config(encoder, pipe_config); - intel_audio_codec_get_config(encoder, pipe_config); } -- GitLab From bac2d7d8e64bb06522a438a79d9f12f942069b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 20 Dec 2023 12:36:09 +0200 Subject: [PATCH 0092/1420] drm/i915/display: Take care of VSC select field in video dip ctl register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to configure VSC Select field in video dip ctl if we want to have e.g. colorimetry date in our VSC SDP. Signed-off-by: Jouni Högander Acked-by: Rodrigo Vivi Tested-by: Shawn Lee Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231220103609.1384523-8-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 39e4f5f7c8171..eedef8121ff7c 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -523,10 +523,12 @@ void hsw_write_infoframe(struct intel_encoder *encoder, 0); /* Wa_14013475917 */ - if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC) - return; + if (!(IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC)) + val |= hsw_infoframe_enable(type); + + if (type == DP_SDP_VSC) + val |= VSC_DIP_HW_DATA_SW_HEA; - val |= hsw_infoframe_enable(type); intel_de_write(dev_priv, ctl_reg, val); intel_de_posting_read(dev_priv, ctl_reg); } -- GitLab From 021a81e7ac8f579b049e5bc76efabd9e67bd627c Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Thu, 21 Dec 2023 13:43:32 +0100 Subject: [PATCH 0093/1420] dt-bindings: panel: lvds: Append edt,etml0700z9ndha in panel-lvds List EDT ETML0700Z9NDHA in the LVDS panel enumeration. Signed-off-by: Raphael Gallais-Pou Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231221124339.420119-2-raphael.gallais-pou@foss.st.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231221124339.420119-2-raphael.gallais-pou@foss.st.com --- Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml index 9f1016551e0b2..3fb24393529cd 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml @@ -42,6 +42,8 @@ properties: - auo,b101ew05 # Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel - chunghwa,claa070wp03xg + # EDT ETML0700Z9NDHA 7.0" WSVGA (1024x600) color TFT LCD LVDS panel + - edt,etml0700z9ndha # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel - hannstar,hsd101pww2 # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel -- GitLab From 0c68132df6e66244acec1bb5b9e19b0751414389 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Mon, 18 Dec 2023 16:05:43 -0800 Subject: [PATCH 0094/1420] drm/i915/perf: Update handling of MMIO triggered reports On XEHP platforms user is not able to find MMIO triggered reports in the OA buffer since i915 squashes the context ID fields. These context ID fields hold the MMIO trigger markers. Update logic to not squash the context ID fields of MMIO triggered reports. Fixes: 7eeaedf79989 ("drm/i915/perf: Determine context valid in OA reports") Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Link: https://patchwork.freedesktop.org/patch/msgid/20231219000543.1087706-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 39 ++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index f92c2a464ebe7..dbbc95d185504 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -772,10 +772,6 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, * The reason field includes flags identifying what * triggered this specific report (mostly timer * triggered or e.g. due to a context switch). - * - * In MMIO triggered reports, some platforms do not set the - * reason bit in this field and it is valid to have a reason - * field of zero. */ reason = oa_report_reason(stream, report); ctx_id = oa_context_id(stream, report32); @@ -787,8 +783,41 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, * * Note: that we don't clear the valid_ctx_bit so userspace can * understand that the ID has been squashed by the kernel. + * + * Update: + * + * On XEHP platforms the behavior of context id valid bit has + * changed compared to prior platforms. To describe this, we + * define a few terms: + * + * context-switch-report: This is a report with the reason type + * being context-switch. It is generated when a context switches + * out. + * + * context-valid-bit: A bit that is set in the report ID field + * to indicate that a valid context has been loaded. + * + * gpu-idle: A condition characterized by a + * context-switch-report with context-valid-bit set to 0. + * + * On prior platforms, context-id-valid bit is set to 0 only + * when GPU goes idle. In all other reports, it is set to 1. + * + * On XEHP platforms, context-valid-bit is set to 1 in a context + * switch report if a new context switched in. For all other + * reports it is set to 0. + * + * This change in behavior causes an issue with MMIO triggered + * reports. MMIO triggered reports have the markers in the + * context ID field and the context-valid-bit is 0. The logic + * below to squash the context ID would render the report + * useless since the user will not be able to find it in the OA + * buffer. Since MMIO triggered reports exist only on XEHP, + * we should avoid squashing these for XEHP platforms. */ - if (oa_report_ctx_invalid(stream, report)) { + + if (oa_report_ctx_invalid(stream, report) && + GRAPHICS_VER_FULL(stream->engine->i915) < IP_VER(12, 50)) { ctx_id = INVALID_CTX_ID; oa_context_id_squash(stream, report32); } -- GitLab From 0e209fa7bf66e8a5b8a9efdc4d4926dcb441af18 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 21 Dec 2023 14:28:04 -0800 Subject: [PATCH 0095/1420] drm/xe: Disable 32bits build Add a dependency on CONFIG_64BIT since currently the xe driver doesn't build on 32bits. It may be enabled again after all the issues are fixed. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Reviewed-by: Rodrigo Vivi Link: https://lore.kernel.org/r/20231221222809.4123220-2-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig index 5b3da06e7ba30..a53b0fdc15a74 100644 --- a/drivers/gpu/drm/xe/Kconfig +++ b/drivers/gpu/drm/xe/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_XE tristate "Intel Xe Graphics" - depends on DRM && PCI && MMU && (m || (y && KUNIT=y)) + depends on DRM && PCI && MMU && (m || (y && KUNIT=y)) && 64BIT select INTERVAL_TREE # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs -- GitLab From f031c3a7af8ea06790dd0a71872c4f0175084baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 26 Dec 2023 08:11:14 -0800 Subject: [PATCH 0096/1420] drm/xe/uapi: Remove DRM_XE_VM_BIND_FLAG_ASYNC comment left over MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a comment left over of commit d3d767396a02 ("drm/xe/uapi: Remove sync binds"). Fixes: d3d767396a02 ("drm/xe/uapi: Remove sync binds") Reviewed-by: Rodrigo Vivi Cc: Matthew Brost Signed-off-by: José Roberto de Souza --- include/uapi/drm/xe_drm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 9fa3ae324731a..50bbea0992d9c 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -832,7 +832,6 @@ struct drm_xe_vm_destroy { * * and the @flags can be: * - %DRM_XE_VM_BIND_FLAG_READONLY - * - %DRM_XE_VM_BIND_FLAG_ASYNC * - %DRM_XE_VM_BIND_FLAG_IMMEDIATE - Valid on a faulting VM only, do the * MAP operation immediately rather than deferring the MAP to the page * fault handler. -- GitLab From 570a8fc233b2adb659015bfb09f90a46a6b594d4 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 7 Dec 2023 09:51:17 -0800 Subject: [PATCH 0097/1420] drm/xe/xe2: Add workaround 16020183090 Graphics version 20.04, used in Lunar Lake, needs WA 16020183090 for steppings A*. Set ENABLE_SEMAPHORE_POLL_BIT in INSTPM(RENDER_RING_BASE) and whitelist CSBE_DEBUG_STATUS for userspace to be able to use it and complement the workaround. Cc: Haridhar Kalvala Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231207175117.2334022-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/regs/xe_engine_regs.h | 4 ++++ drivers/gpu/drm/xe/xe_reg_whitelist.c | 8 ++++++++ drivers/gpu/drm/xe/xe_wa.c | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h index bd9c956f48a7c..0b1266c88a6af 100644 --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h @@ -83,6 +83,9 @@ #define RING_EMR(base) XE_REG((base) + 0xb4) #define RING_ESR(base) XE_REG((base) + 0xb8) +#define INSTPM(base) XE_REG((base) + 0xc0, XE_REG_OPTION_MASKED) +#define ENABLE_SEMAPHORE_POLL_BIT REG_BIT(13) + #define RING_CMD_CCTL(base) XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED) /* * CMD_CCTL read/write fields take a MOCS value and _not_ a table index. @@ -138,6 +141,7 @@ #define TAIL_ADDR 0x001FFFF8 #define RING_CTX_TIMESTAMP(base) XE_REG((base) + 0x3a8) +#define CSBE_DEBUG_STATUS(base) XE_REG((base) + 0x3fc) #define RING_FORCE_TO_NONPRIV(base, i) XE_REG(((base) + 0x4d0) + (i) * 4) #define RING_FORCE_TO_NONPRIV_DENY REG_BIT(30) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index e66ae1bdaf9c0..3fa2ece7d2289 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -7,9 +7,11 @@ #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" +#include "regs/xe_regs.h" #include "xe_gt_types.h" #include "xe_platform_types.h" #include "xe_rtp.h" +#include "xe_step.h" #undef XE_REG_MCR #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) @@ -56,6 +58,12 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { RING_FORCE_TO_NONPRIV_DENY, XE_RTP_ACTION_FLAG(ENGINE_BASE))) }, + { XE_RTP_NAME("16020183090"), + XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), + ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(WHITELIST(CSBE_DEBUG_STATUS(RENDER_RING_BASE), 0)) + }, + {} }; diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 3456ca6f7b323..b77d406e083e2 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -571,6 +571,11 @@ static const struct xe_rtp_entry_sr lrc_was[] = { XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) }, + { XE_RTP_NAME("16020183090"), + XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), + ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(INSTPM(RENDER_RING_BASE), ENABLE_SEMAPHORE_POLL_BIT)) + }, {} }; -- GitLab From a196a5166e0812db267281c32fa0724fc5be6582 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Fri, 22 Dec 2023 12:52:17 +0100 Subject: [PATCH 0098/1420] drm/tilcdc: request and mapp iomem with devres tilcdc currently just ioremaps its iomem, without doing the (a bit more robust) request on the memory first. The devm_ functions provide a handy way to both request and ioremap the memory with automatic cleanup. Replace the manual ioremap with the devm_ version. Suggested-by: Thomas Zimmermann Signed-off-by: Philipp Stanner Reviewed-by: Jyri Sarha Tested-by: Jyri Sarha Signed-off-by: Jyri Sarha Link: https://patchwork.freedesktop.org/patch/msgid/20231222115216.19218-2-pstanner@redhat.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 23bf16f596f61..cd5eefa06060d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -182,9 +182,6 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->clk) clk_put(priv->clk); - if (priv->mmio) - iounmap(priv->mmio); - if (priv->wq) destroy_workqueue(priv->wq); @@ -201,7 +198,6 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct device_node *node = dev->of_node; struct tilcdc_drm_private *priv; - struct resource *res; u32 bpp = 0; int ret; @@ -226,17 +222,10 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) goto init_failed; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get memory resource\n"); - ret = -EINVAL; - goto init_failed; - } - - priv->mmio = ioremap(res->start, resource_size(res)); - if (!priv->mmio) { - dev_err(dev, "failed to ioremap\n"); - ret = -ENOMEM; + priv->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio)) { + dev_err(dev, "failed to request / ioremap\n"); + ret = PTR_ERR(priv->mmio); goto init_failed; } -- GitLab From e7b2d82d420a389da078be315b80cc5bc18ee734 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 21 Dec 2023 12:54:14 +0200 Subject: [PATCH 0099/1420] drm/i915/bios: remove some unused leftover declarations Remove some unused declarations probably left behind after some refactoring. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231221105414.1518267-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_bios.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 49e24b7cf6753..96673dc707e75 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -246,13 +246,10 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size); bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port); -bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port); bool intel_bios_is_dsi_present(struct drm_i915_private *dev_priv, enum port *port); bool intel_bios_get_dsc_params(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int dsc_max_bpc); -bool intel_bios_port_supports_typec_usb(struct drm_i915_private *i915, enum port port); -bool intel_bios_port_supports_tbt(struct drm_i915_private *i915, enum port port); const struct intel_bios_encoder_data * intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port); -- GitLab From 7353c3d7c15017140a8b984e41f94be0bf535e73 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:29 -0800 Subject: [PATCH 0100/1420] drm/i915/gem: reconcile Excess struct member kernel-doc warnings Document nested struct members with full names as described in Documentation/doc-guide/kernel-doc.rst. i915_gem_context_types.h:420: warning: Excess struct member 'lock' description in 'i915_gem_context' Signed-off-by: Randy Dunlap Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: intel-gfx@lists.freedesktop.org Cc: Jonathan Corbet Cc: dri-devel@lists.freedesktop.org Reviewed-by: Rodrigo Vivi Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231226195432.10891-1-rdunlap@infradead.org --- drivers/gpu/drm/i915/gem/i915_gem_context_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h index c573c067779f5..03bc7f9d191b9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h @@ -412,9 +412,9 @@ struct i915_gem_context { /** @stale: tracks stale engines to be destroyed */ struct { - /** @lock: guards engines */ + /** @stale.lock: guards engines */ spinlock_t lock; - /** @engines: list of stale engines */ + /** @stale.engines: list of stale engines */ struct list_head engines; } stale; }; -- GitLab From cd1d91115ff1929ec346d85f512ef260ddf8131e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 28 Dec 2023 15:49:46 -0800 Subject: [PATCH 0101/1420] drm/i915/gt: reconcile Excess struct member kernel-doc warnings Document nested struct members with full names as described in Documentation/doc-guide/kernel-doc.rst. intel_gsc.h:34: warning: Excess struct member 'gem_obj' description in 'intel_gsc' Also add missing field member descriptions. Signed-off-by: Randy Dunlap Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: intel-gfx@lists.freedesktop.org Cc: Jonathan Corbet Cc: dri-devel@lists.freedesktop.org Reviewed-by: Rodrigo Vivi Cc: Andi Shyti Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231228234946.12405-1-rdunlap@infradead.org --- drivers/gpu/drm/i915/gt/intel_gsc.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.h b/drivers/gpu/drm/i915/gt/intel_gsc.h index 7ab3ca0f9f268..013c642514486 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.h +++ b/drivers/gpu/drm/i915/gt/intel_gsc.h @@ -21,8 +21,11 @@ struct mei_aux_device; /** * struct intel_gsc - graphics security controller * - * @gem_obj: scratch memory GSC operations - * @intf : gsc interface + * @intf: gsc interface + * @intf.adev: MEI aux. device for this @intf + * @intf.gem_obj: scratch memory GSC operations + * @intf.irq: IRQ for this device (%-1 for no IRQ) + * @intf.id: this interface's id number/index */ struct intel_gsc { struct intel_gsc_intf { -- GitLab From e4cf1a70fad3e2107503e99cfe9cc0c9cba19dad Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:31 -0800 Subject: [PATCH 0102/1420] drm/i915/guc: reconcile Excess struct member kernel-doc warnings Document nested struct members with full names as described in Documentation/doc-guide/kernel-doc.rst. intel_guc.h:305: warning: Excess struct member 'lock' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'guc_ids' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'num_guc_ids' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'guc_ids_bitmap' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'guc_id_list' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'guc_ids_in_use' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'destroyed_contexts' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'destroyed_worker' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'reset_fail_worker' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'reset_fail_mask' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'sched_disable_delay_ms' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'sched_disable_gucid_threshold' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'lock' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'gt_stamp' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'ping_delay' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'work' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'shift' description in 'intel_guc' intel_guc.h:305: warning: Excess struct member 'last_stat_jiffies' description in 'intel_guc' 18 warnings as Errors Signed-off-by: Randy Dunlap Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: intel-gfx@lists.freedesktop.org Cc: Jonathan Corbet Cc: dri-devel@lists.freedesktop.org Reviewed-by: Rodrigo Vivi Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231226195432.10891-3-rdunlap@infradead.org --- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 75 ++++++++++++++------------ 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index e22c12ce245ad..813cc888e6fae 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -105,61 +105,67 @@ struct intel_guc { */ struct { /** - * @lock: protects everything in submission_state, - * ce->guc_id.id, and ce->guc_id.ref when transitioning in and - * out of zero + * @submission_state.lock: protects everything in + * submission_state, ce->guc_id.id, and ce->guc_id.ref + * when transitioning in and out of zero */ spinlock_t lock; /** - * @guc_ids: used to allocate new guc_ids, single-lrc + * @submission_state.guc_ids: used to allocate new + * guc_ids, single-lrc */ struct ida guc_ids; /** - * @num_guc_ids: Number of guc_ids, selftest feature to be able - * to reduce this number while testing. + * @submission_state.num_guc_ids: Number of guc_ids, selftest + * feature to be able to reduce this number while testing. */ int num_guc_ids; /** - * @guc_ids_bitmap: used to allocate new guc_ids, multi-lrc + * @submission_state.guc_ids_bitmap: used to allocate + * new guc_ids, multi-lrc */ unsigned long *guc_ids_bitmap; /** - * @guc_id_list: list of intel_context with valid guc_ids but no - * refs + * @submission_state.guc_id_list: list of intel_context + * with valid guc_ids but no refs */ struct list_head guc_id_list; /** - * @guc_ids_in_use: Number single-lrc guc_ids in use + * @submission_state.guc_ids_in_use: Number single-lrc + * guc_ids in use */ unsigned int guc_ids_in_use; /** - * @destroyed_contexts: list of contexts waiting to be destroyed - * (deregistered with the GuC) + * @submission_state.destroyed_contexts: list of contexts + * waiting to be destroyed (deregistered with the GuC) */ struct list_head destroyed_contexts; /** - * @destroyed_worker: worker to deregister contexts, need as we - * need to take a GT PM reference and can't from destroy - * function as it might be in an atomic context (no sleeping) + * @submission_state.destroyed_worker: worker to deregister + * contexts, need as we need to take a GT PM reference and + * can't from destroy function as it might be in an atomic + * context (no sleeping) */ struct work_struct destroyed_worker; /** - * @reset_fail_worker: worker to trigger a GT reset after an - * engine reset fails + * @submission_state.reset_fail_worker: worker to trigger + * a GT reset after an engine reset fails */ struct work_struct reset_fail_worker; /** - * @reset_fail_mask: mask of engines that failed to reset + * @submission_state.reset_fail_mask: mask of engines that + * failed to reset */ intel_engine_mask_t reset_fail_mask; /** - * @sched_disable_delay_ms: schedule disable delay, in ms, for - * contexts + * @submission_state.sched_disable_delay_ms: schedule + * disable delay, in ms, for contexts */ unsigned int sched_disable_delay_ms; /** - * @sched_disable_gucid_threshold: threshold of min remaining available - * guc_ids before we start bypassing the schedule disable delay + * @submission_state.sched_disable_gucid_threshold: + * threshold of min remaining available guc_ids before + * we start bypassing the schedule disable delay */ unsigned int sched_disable_gucid_threshold; } submission_state; @@ -243,37 +249,40 @@ struct intel_guc { */ struct { /** - * @lock: Lock protecting the below fields and the engine stats. + * @timestamp.lock: Lock protecting the below fields and + * the engine stats. */ spinlock_t lock; /** - * @gt_stamp: 64 bit extended value of the GT timestamp. + * @timestamp.gt_stamp: 64-bit extended value of the GT + * timestamp. */ u64 gt_stamp; /** - * @ping_delay: Period for polling the GT timestamp for - * overflow. + * @timestamp.ping_delay: Period for polling the GT + * timestamp for overflow. */ unsigned long ping_delay; /** - * @work: Periodic work to adjust GT timestamp, engine and - * context usage for overflows. + * @timestamp.work: Periodic work to adjust GT timestamp, + * engine and context usage for overflows. */ struct delayed_work work; /** - * @shift: Right shift value for the gpm timestamp + * @timestamp.shift: Right shift value for the gpm timestamp */ u32 shift; /** - * @last_stat_jiffies: jiffies at last actual stats collection time - * We use this timestamp to ensure we don't oversample the - * stats because runtime power management events can trigger - * stats collection at much higher rates than required. + * @timestamp.last_stat_jiffies: jiffies at last actual + * stats collection time. We use this timestamp to ensure + * we don't oversample the stats because runtime power + * management events can trigger stats collection at much + * higher rates than required. */ unsigned long last_stat_jiffies; } timestamp; -- GitLab From aa253baca534357e033bd29b074ce1eade2a9362 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:32 -0800 Subject: [PATCH 0103/1420] drm/i915/perf: reconcile Excess struct member kernel-doc warnings Document nested struct members with full names as described in Documentation/doc-guide/kernel-doc.rst. i915_perf_types.h:341: warning: Excess struct member 'ptr_lock' description in 'i915_perf_stream' i915_perf_types.h:341: warning: Excess struct member 'head' description in 'i915_perf_stream' i915_perf_types.h:341: warning: Excess struct member 'tail' description in 'i915_perf_stream' 3 warnings as Errors Signed-off-by: Randy Dunlap Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: intel-gfx@lists.freedesktop.org Cc: Jonathan Corbet Cc: dri-devel@lists.freedesktop.org Reviewed-by: Rodrigo Vivi Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231226195432.10891-4-rdunlap@infradead.org --- drivers/gpu/drm/i915/i915_perf_types.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index 13b1ae9b96c7f..46445248d193e 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -291,7 +291,8 @@ struct i915_perf_stream { int size_exponent; /** - * @ptr_lock: Locks reads and writes to all head/tail state + * @oa_buffer.ptr_lock: Locks reads and writes to all + * head/tail state * * Consider: the head and tail pointer state needs to be read * consistently from a hrtimer callback (atomic context) and @@ -313,7 +314,8 @@ struct i915_perf_stream { spinlock_t ptr_lock; /** - * @head: Although we can always read back the head pointer register, + * @oa_buffer.head: Although we can always read back + * the head pointer register, * we prefer to avoid trusting the HW state, just to avoid any * risk that some hardware condition could * somehow bump the * head pointer unpredictably and cause us to forward the wrong @@ -322,7 +324,8 @@ struct i915_perf_stream { u32 head; /** - * @tail: The last verified tail that can be read by userspace. + * @oa_buffer.tail: The last verified tail that can be + * read by userspace. */ u32 tail; } oa_buffer; -- GitLab From 407eaa4aa64a8429094fa75fac00fff5e471138d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:53 +0100 Subject: [PATCH 0104/1420] drm/rockchip: vop: Add output selection registers for RK312x In contrast to RK3036, RK312x SoCs have multiple output channels such as RGB (i.e. LVDS TTL), LVDS, DSI and HDMI. In order to support that, this splits output from RK3036 and defines an separate one for RK3126 with the registers required to enable the appropriate output and setup the correct polarity. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-3-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 13 ++++++++++++- drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index c51ca82320cb0..b9ee02061d5bf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -227,11 +227,22 @@ static const struct vop_win_data rk3126_vop_win_data[] = { .type = DRM_PLANE_TYPE_CURSOR }, }; +static const struct vop_output rk3126_output = { + .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), + .hdmi_pin_pol = VOP_REG(RK3126_INT_SCALER, 0x7, 4), + .hdmi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 22), + .hdmi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 23), + .rgb_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 24), + .rgb_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 25), + .mipi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 28), + .mipi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 29), +}; + static const struct vop_data rk3126_vop = { .intr = &rk3036_intr, .common = &rk3036_common, .modeset = &rk3036_modeset, - .output = &rk3036_output, + .output = &rk3126_output, .win = rk3126_vop_win_data, .win_size = ARRAY_SIZE(rk3126_vop_win_data), .max_output = { 1920, 1080 }, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 406e981c75bd7..fbf1bcc686250 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -872,6 +872,9 @@ /* rk3036 register definition end */ /* rk3126 register definition */ +#define RK3126_INT_SCALER 0x0c + +/* win1 register */ #define RK3126_WIN1_MST 0x4c #define RK3126_WIN1_DSP_INFO 0x50 #define RK3126_WIN1_DSP_ST 0x54 -- GitLab From 47a145c03484d33e65d773169d5ca1b9fe2a492e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:54 +0100 Subject: [PATCH 0105/1420] drm/rockchip: inno_hdmi: Fix video timing The controller wants the difference between *total and *sync_start in the HDMI_VIDEO_EXT_*DELAY registers. Otherwise the signal is very unstable for certain non-VIC modes. See downstream commit [0]. [0] https://github.com/rockchip-linux/kernel/commit/8eb559f2502c Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support") Co-developed-by: Zheng Yang Signed-off-by: Zheng Yang Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-4-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f6d819803c0e0..50c984ac107d6 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -411,7 +411,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); - value = mode->hsync_start - mode->hdisplay; + value = mode->htotal - mode->hsync_start; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); @@ -426,7 +426,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, value = mode->vtotal - mode->vdisplay; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); - value = mode->vsync_start - mode->vdisplay; + value = mode->vtotal - mode->vsync_start; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); value = mode->vsync_end - mode->vsync_start; -- GitLab From 099be7b6718685ebafb417e74bb637abf992474a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:55 +0100 Subject: [PATCH 0106/1420] drm/rockchip: inno_hdmi: Remove useless mode_fixup The mode_fixup implementation doesn't do anything, so we can simply remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-5-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 50c984ac107d6..a50d1d7e9e06d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -516,13 +516,6 @@ static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); } -static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - return true; -} - static int inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -539,7 +532,6 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { .enable = inno_hdmi_encoder_enable, .disable = inno_hdmi_encoder_disable, - .mode_fixup = inno_hdmi_encoder_mode_fixup, .mode_set = inno_hdmi_encoder_mode_set, .atomic_check = inno_hdmi_encoder_atomic_check, }; -- GitLab From 8f0df2012b8a94aed0cc450016f7592c24e92cfb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:56 +0100 Subject: [PATCH 0107/1420] drm/rockchip: inno_hdmi: Remove useless copy of drm_display_mode The driver maintains a copy of the adjusted mode but doesn't use it anywhere. Remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-6-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index a50d1d7e9e06d..0b16e449c17bf 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -61,7 +61,6 @@ struct inno_hdmi { unsigned int tmds_rate; struct hdmi_data_info hdmi_data; - struct drm_display_mode previous_mode; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -497,9 +496,6 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_setup(hdmi, adj_mode); - - /* Store the display mode for plugin/DPMS poweron events */ - drm_mode_copy(&hdmi->previous_mode, adj_mode); } static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) -- GitLab From ff4d4fa76fcc19f7d5d261f717121f0a88ec4e30 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:57 +0100 Subject: [PATCH 0108/1420] drm/rockchip: inno_hdmi: Switch encoder hooks to atomic The inno_hdmi encoder still uses the !atomic variants of enable, disable and modeset. Convert to their atomic equivalents. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-7-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 0b16e449c17bf..4616ff8c22e77 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -490,22 +490,25 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, } static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { + struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode; struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_setup(hdmi, adj_mode); } -static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) +static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) +static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); @@ -526,10 +529,10 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, } static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { - .enable = inno_hdmi_encoder_enable, - .disable = inno_hdmi_encoder_disable, - .mode_set = inno_hdmi_encoder_mode_set, - .atomic_check = inno_hdmi_encoder_atomic_check, + .atomic_check = inno_hdmi_encoder_atomic_check, + .atomic_enable = inno_hdmi_encoder_enable, + .atomic_disable = inno_hdmi_encoder_disable, + .atomic_mode_set = inno_hdmi_encoder_mode_set, }; static enum drm_connector_status -- GitLab From d3e040f450ec8e46ff42fa495a433b976ab47686 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:58 +0100 Subject: [PATCH 0109/1420] drm/rockchip: inno_hdmi: Get rid of mode_set We're not doing anything special in atomic_mode_set so we can simply merge it into atomic_enable. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-8-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 4616ff8c22e77..38990a13ee194 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -489,21 +489,22 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, return 0; } -static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode; - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - - inno_hdmi_setup(hdmi, adj_mode); -} - static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + + conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); inno_hdmi_set_pwr_mode(hdmi, NORMAL); } @@ -532,7 +533,6 @@ static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { .atomic_check = inno_hdmi_encoder_atomic_check, .atomic_enable = inno_hdmi_encoder_enable, .atomic_disable = inno_hdmi_encoder_disable, - .atomic_mode_set = inno_hdmi_encoder_mode_set, }; static enum drm_connector_status -- GitLab From d7ba3d711cf537ef0ece14cd85d2113ca338a00b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:59 +0100 Subject: [PATCH 0110/1420] drm/rockchip: inno_hdmi: no need to store vic The mode's VIC is only ever used in the inno_hdmi_setup() function so there's no need to store it in the main structure. Signed-off-by: Maxime Ripard Tested-by: Alex Bee [made checkpatch happy] Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-9-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 38990a13ee194..437c5dcbab0da 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - int vic; bool sink_has_audio; unsigned int enc_in_format; unsigned int enc_out_format; @@ -442,16 +441,15 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; - - hdmi->hdmi_data.vic = drm_match_cea_mode(mode); + u8 vic = drm_match_cea_mode(mode); hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB; hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; - if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) || - (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) || - (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) || - (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18)) + if (vic == 6 || vic == 7 || + vic == 21 || vic == 22 || + vic == 2 || vic == 3 || + vic == 17 || vic == 18) hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; else hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; -- GitLab From f8723484e045ff2d176124484907ec0199c55a0c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:00 +0100 Subject: [PATCH 0111/1420] drm/rockchip: inno_hdmi: Remove unneeded has audio flag The sink_has_audio flag is not used anywhere in the driver so let's get rid of it. It's redundant with drm_display_info.has_audio anyway. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-10-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 437c5dcbab0da..6120ab8dd8fd1 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - bool sink_has_audio; unsigned int enc_in_format; unsigned int enc_out_format; unsigned int colorimetry; @@ -553,7 +552,6 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, hdmi->ddc); if (edid) { - hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid); drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); -- GitLab From c1ceee3248742149d1a602fd913bd88857da1d52 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:01 +0100 Subject: [PATCH 0112/1420] drm/rockchip: inno_hdmi: Remove useless input format The driver has a lot of logic to deal with multiple input formats, but hardcodes it to RGB. This means that most of that code has been dead code, so let's get rid of it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee [made checkpatch happy] Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-11-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 41 ++++++++-------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 6120ab8dd8fd1..3cb84943646f8 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - unsigned int enc_in_format; unsigned int enc_out_format; unsigned int colorimetry; }; @@ -327,47 +326,30 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (data->enc_in_format == data->enc_out_format) { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) || - (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) { - value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, - m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, - v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | - v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); - return 0; - } + if (data->enc_out_format == HDMI_COLORSPACE_RGB) { + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); + return 0; } if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && - (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { + if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; - } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && - (data->enc_out_format == HDMI_COLORSPACE_RGB)) { - csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT; - auto_csc = AUTO_CSC_ENABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_DISABLE; } } else { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && - (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { + if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; - } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && - (data->enc_out_format == HDMI_COLORSPACE_RGB)) { - csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT; - auto_csc = AUTO_CSC_ENABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_DISABLE; } } @@ -442,7 +424,6 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_info *display = &hdmi->connector.display_info; u8 vic = drm_match_cea_mode(mode); - hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB; hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; if (vic == 6 || vic == 7 || -- GitLab From 139771b8239c43ad1bd6c2976aa12788096a5483 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:02 +0100 Subject: [PATCH 0113/1420] drm/rockchip: inno_hdmi: Remove YUV-based csc coefficents Now that the unneeded support for YUV based input formats is gone, the csc coefficients for those formats can be dropped as well. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-12-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 37 ---------------------------- 1 file changed, 37 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 3cb84943646f8..b5ba5fecbec97 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -73,49 +73,12 @@ static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) } enum { - CSC_ITU601_16_235_TO_RGB_0_255_8BIT, - CSC_ITU601_0_255_TO_RGB_0_255_8BIT, - CSC_ITU709_16_235_TO_RGB_0_255_8BIT, CSC_RGB_0_255_TO_ITU601_16_235_8BIT, CSC_RGB_0_255_TO_ITU709_16_235_8BIT, CSC_RGB_0_255_TO_RGB_16_235_8BIT, }; static const char coeff_csc[][24] = { - /* - * YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]): - * R = 1.164*Y + 1.596*V - 204 - * G = 1.164*Y - 0.391*U - 0.813*V + 154 - * B = 1.164*Y + 2.018*U - 258 - */ - { - 0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc, - 0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a, - 0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02 - }, - /* - * YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]): - * R = Y + 1.402*V - 248 - * G = Y - 0.344*U - 0.714*V + 135 - * B = Y + 1.772*U - 227 - */ - { - 0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8, - 0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87, - 0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3 - }, - /* - * YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]): - * R = 1.164*Y + 1.793*V - 248 - * G = 1.164*Y - 0.213*U - 0.534*V + 77 - * B = 1.164*Y + 2.115*U - 289 - */ - { - 0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8, - 0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d, - 0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21 - }, - /* * RGB2YUV:601 SD mode: * Cb = -0.291G - 0.148R + 0.439B + 128 -- GitLab From 5f92474844a4fcb7997da20dd1de2031aed1d794 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:03 +0100 Subject: [PATCH 0114/1420] drm/rockchip: inno_hdmi: Remove tmds rate from structure The tmds_rate field in the inno_hdmi structure is used mostly to configure the internal i2c controller divider through a call to the inno_hdmi_i2c_init() function. We can simply make that rate an argument to that function, which also removes a workaround to initialize the divider at probe time when we don't have a mode yet. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-13-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index b5ba5fecbec97..682087275aeb5 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -55,8 +55,6 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; - unsigned int tmds_rate; - struct hdmi_data_info hdmi_data; }; @@ -133,11 +131,11 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, hdmi_writeb(hdmi, offset, temp); } -static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) +static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate) { - int ddc_bus_freq; + unsigned long long ddc_bus_freq = rate >> 2; - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; + do_div(ddc_bus_freq, HDMI_SCL_RATE); hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); @@ -420,8 +418,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - hdmi->tmds_rate = mode->clock * 1000; - inno_hdmi_i2c_init(hdmi); + inno_hdmi_i2c_init(hdmi, mode->clock * 1000); /* Unmute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -799,8 +796,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, * and reconfigure the DDC clock. */ - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); - inno_hdmi_i2c_init(hdmi); + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); ret = inno_hdmi_register(drm, hdmi); if (ret) -- GitLab From aa4f96e2de82f5e0dfc0102d08f66918c5e3637f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:04 +0100 Subject: [PATCH 0115/1420] drm/rockchip: inno_hdmi: Drop HDMI Vendor Infoframe support The HDMI vendor infoframe is only meant to be sent with 4k60 modes and higher, but the controller doesn't support them. Let's drop them from the kernel. Suggested-by: Johan Jonker Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-14-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 35 ++++++++-------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 682087275aeb5..08b5e4da47181 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -205,11 +205,15 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) } static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, - union hdmi_infoframe *frame, u32 frame_index, - u32 mask, u32 disable, u32 enable) + union hdmi_infoframe *frame, u32 frame_index) { - if (mask) - hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable); + struct drm_connector *connector = &hdmi->connector; + + if (frame_index != INFOFRAME_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", frame_index); + return 0; + } hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); @@ -225,28 +229,11 @@ static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, for (i = 0; i < rc; i++) hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, packed_frame[i]); - - if (mask) - hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable); } return setup_rc; } -static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - union hdmi_infoframe frame; - int rc; - - rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, - &hdmi->connector, - mode); - - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI, - m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1)); -} - static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { @@ -264,7 +251,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) @@ -407,10 +394,8 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_config_video_csc(hdmi); - if (display->is_hdmi) { + if (display->is_hdmi) inno_hdmi_config_video_avi(hdmi, mode); - inno_hdmi_config_video_vsi(hdmi, mode); - } /* * When IP controller have configured to an accurate video -- GitLab From cc9ec38cb2cd32518fe02615d004e96ce2fd0348 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:05 +0100 Subject: [PATCH 0116/1420] drm/rockchip: inno_hdmi: Move infoframe disable to separate function The code to upload infoframes to the controller uses a weird construct which, based on the previous function call return code, will either disable or enable that infoframe. In order to get rid of that argument, let's split the function to disable the infoframe into a separate function and make it obvious what we are doing in the error path. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-15-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 46 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 08b5e4da47181..90a163029773c 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -204,34 +204,44 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, - union hdmi_infoframe *frame, u32 frame_index) +static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, u32 frame_index) { struct drm_connector *connector = &hdmi->connector; if (frame_index != INFOFRAME_AVI) { drm_err(connector->dev, "Unsupported infoframe type: %u\n", frame_index); - return 0; + return; } hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); +} - if (setup_rc >= 0) { - u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; - ssize_t rc, i; - - rc = hdmi_infoframe_pack(frame, packed_frame, - sizeof(packed_frame)); - if (rc < 0) - return rc; +static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, + union hdmi_infoframe *frame, u32 frame_index) +{ + struct drm_connector *connector = &hdmi->connector; + u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; + ssize_t rc, i; - for (i = 0; i < rc; i++) - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, - packed_frame[i]); + if (frame_index != INFOFRAME_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", frame_index); + return 0; } - return setup_rc; + inno_hdmi_disable_frame(hdmi, frame_index); + + rc = hdmi_infoframe_pack(frame, packed_frame, + sizeof(packed_frame)); + if (rc < 0) + return rc; + + for (i = 0; i < rc; i++) + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, + packed_frame[i]); + + return 0; } static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, @@ -243,6 +253,10 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, &hdmi->connector, mode); + if (rc) { + inno_hdmi_disable_frame(hdmi, INFOFRAME_AVI); + return rc; + } if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) frame.avi.colorspace = HDMI_COLORSPACE_YUV444; @@ -251,7 +265,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI); + return inno_hdmi_upload_frame(hdmi, &frame, INFOFRAME_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) -- GitLab From 4278ff62b73936a9138b60cc0610381003132b77 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:06 +0100 Subject: [PATCH 0117/1420] drm/rockchip: inno_hdmi: Switch to infoframe type The inno_hdmi driver relies on its own internal infoframe type matching the hardware. This works fine, but in order to make further reworks easier, let's switch to the HDMI spec definition of those types. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-16-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 90a163029773c..bec91a14965ba 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -204,33 +204,34 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, u32 frame_index) +static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, + enum hdmi_infoframe_type type) { struct drm_connector *connector = &hdmi->connector; - if (frame_index != INFOFRAME_AVI) { + if (type != HDMI_INFOFRAME_TYPE_AVI) { drm_err(connector->dev, - "Unsupported infoframe type: %u\n", frame_index); + "Unsupported infoframe type: %u\n", type); return; } - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); } static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, - union hdmi_infoframe *frame, u32 frame_index) + union hdmi_infoframe *frame, enum hdmi_infoframe_type type) { struct drm_connector *connector = &hdmi->connector; u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; ssize_t rc, i; - if (frame_index != INFOFRAME_AVI) { + if (type != HDMI_INFOFRAME_TYPE_AVI) { drm_err(connector->dev, - "Unsupported infoframe type: %u\n", frame_index); + "Unsupported infoframe type: %u\n", type); return 0; } - inno_hdmi_disable_frame(hdmi, frame_index); + inno_hdmi_disable_frame(hdmi, type); rc = hdmi_infoframe_pack(frame, packed_frame, sizeof(packed_frame)); @@ -254,7 +255,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, &hdmi->connector, mode); if (rc) { - inno_hdmi_disable_frame(hdmi, INFOFRAME_AVI); + inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI); return rc; } @@ -265,7 +266,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, &frame, INFOFRAME_AVI); + return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) -- GitLab From 153fe8dbd866869846af3a359ecf82d5ad9fe247 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:07 +0100 Subject: [PATCH 0118/1420] drm/rockchip: inno_hdmi: Remove unused drm device pointer The drm_dev field in the inno_hdmi struct stores a pointer to the DRM device but is never used anywhere in the driver. Let's remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-17-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index bec91a14965ba..f17f0c4859d3a 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -43,7 +43,6 @@ struct inno_hdmi_i2c { struct inno_hdmi { struct device *dev; - struct drm_device *drm_dev; int irq; struct clk *pclk; @@ -756,7 +755,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return -ENOMEM; hdmi->dev = dev; - hdmi->drm_dev = drm; hdmi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdmi->regs)) -- GitLab From 073aa696f8cbc170a2c3502c2165aeb835be0156 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:08 +0100 Subject: [PATCH 0119/1420] drm/rockchip: inno_hdmi: Drop irq struct member The struct member irq isn't used anywhere. Drop it. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-18-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f17f0c4859d3a..610e7241e4f3d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -44,7 +44,6 @@ struct inno_hdmi_i2c { struct inno_hdmi { struct device *dev; - int irq; struct clk *pclk; void __iomem *regs; -- GitLab From f68a68fe9d9197ea6aa9cb461270685f370b165e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:09 +0100 Subject: [PATCH 0120/1420] drm/rockchip: inno_hdmi: Remove useless include The inclusion syscon.h isn't used anywhere. Remove it. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-19-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 610e7241e4f3d..9fb1e49bc9091 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- GitLab From ceeb0f0104a62c867656c2730a51df47e7350b8f Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:10 +0100 Subject: [PATCH 0121/1420] drm/rockchip: inno_hdmi: Subclass connector state The data which is currently hold in hdmi_data should not be part of device itself but of the connector state. Introduce a connector state subclass and move the data from hdmi_data in there. Suggested-by: Maxime Ripard Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-20-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 116 ++++++++++++++++++++------- 1 file changed, 89 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 9fb1e49bc9091..c6a4b228ea93d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,11 +25,6 @@ #include "inno_hdmi.h" -struct hdmi_data_info { - unsigned int enc_out_format; - unsigned int colorimetry; -}; - struct inno_hdmi_i2c { struct i2c_adapter adap; @@ -51,8 +46,12 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; +}; - struct hdmi_data_info hdmi_data; +struct inno_hdmi_connector_state { + struct drm_connector_state base; + unsigned int enc_out_format; + unsigned int colorimetry; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -67,6 +66,9 @@ static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) return container_of(connector, struct inno_hdmi, connector); } +#define to_inno_hdmi_conn_state(conn_state) \ + container_of_const(conn_state, struct inno_hdmi_connector_state, base) + enum { CSC_RGB_0_255_TO_ITU601_16_235_8BIT, CSC_RGB_0_255_TO_ITU709_16_235_8BIT, @@ -245,6 +247,10 @@ static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); union hdmi_infoframe frame; int rc; @@ -256,9 +262,9 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return rc; } - if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) frame.avi.colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422) + else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422) frame.avi.colorspace = HDMI_COLORSPACE_YUV422; else frame.avi.colorspace = HDMI_COLORSPACE_RGB; @@ -268,7 +274,10 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { - struct hdmi_data_info *data = &hdmi->hdmi_data; + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); int c0_c2_change = 0; int csc_enable = 0; int csc_mode = 0; @@ -286,7 +295,7 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (data->enc_out_format == HDMI_COLORSPACE_RGB) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); @@ -297,15 +306,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) return 0; } - if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; } } else { - if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; @@ -382,17 +391,6 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; - u8 vic = drm_match_cea_mode(mode); - - hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; - - if (vic == 6 || vic == 7 || - vic == 21 || vic == 22 || - vic == 2 || vic == 3 || - vic == 17 || vic == 18) - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; - else - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; /* Mute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -457,10 +455,24 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + u8 vic = drm_match_cea_mode(mode); + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); s->output_mode = ROCKCHIP_OUT_MODE_P888; s->output_type = DRM_MODE_CONNECTOR_HDMIA; + if (vic == 6 || vic == 7 || + vic == 21 || vic == 22 || + vic == 2 || vic == 3 || + vic == 17 || vic == 18) + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; + else + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + return 0; } @@ -518,13 +530,63 @@ static void inno_hdmi_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +static void +inno_hdmi_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(state); + + __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base); + kfree(inno_conn_state); +} + +static void inno_hdmi_connector_reset(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (connector->state) { + inno_hdmi_connector_destroy_state(connector, connector->state); + connector->state = NULL; + } + + inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); + if (!inno_conn_state) + return; + + __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); + + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; +} + +static struct drm_connector_state * +inno_hdmi_connector_duplicate_state(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (WARN_ON(!connector->state)) + return NULL; + + inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state), + sizeof(*inno_conn_state), GFP_KERNEL); + + if (!inno_conn_state) + return NULL; + + __drm_atomic_helper_connector_duplicate_state(connector, + &inno_conn_state->base); + + return &inno_conn_state->base; +} + static const struct drm_connector_funcs inno_hdmi_connector_funcs = { .fill_modes = inno_hdmi_probe_single_connector_modes, .detect = inno_hdmi_connector_detect, .destroy = inno_hdmi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .reset = inno_hdmi_connector_reset, + .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, + .atomic_destroy_state = inno_hdmi_connector_destroy_state, }; static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { -- GitLab From 164abbd2b7ef62aae6fc80450a2d085acdc3da3e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:11 +0100 Subject: [PATCH 0122/1420] drm/rockchip: inno_hdmi: Correctly setup HDMI quantization range The display controller will always give full range RGB regardless of the mode set, but HDMI requires certain modes to be transmitted in limited range RGB. This is especially required for HDMI sinks which do not support non-standard quantization ranges. This enables color space conversion for those modes and sets the quantization range accordingly in the AVI infoframe. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-21-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 60 +++++++++++++++++++--------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index c6a4b228ea93d..fbf73f6b99ca8 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -52,6 +52,7 @@ struct inno_hdmi_connector_state { struct drm_connector_state base; unsigned int enc_out_format; unsigned int colorimetry; + bool rgb_limited_range; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -269,6 +270,18 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + connector, mode, + inno_conn_state->rgb_limited_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); + } else { + frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + frame.avi.ycc_quantization_range = + HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + } + return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); } @@ -296,29 +309,37 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, - m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, - v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | - v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); - return 0; - } - - if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; + if (inno_conn_state->rgb_limited_range) { + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; + + } else { + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); + return 0; } } else { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; - auto_csc = AUTO_CSC_DISABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_ENABLE; + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } + } else { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } } } @@ -472,6 +493,8 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; return 0; } @@ -558,6 +581,7 @@ static void inno_hdmi_connector_reset(struct drm_connector *connector) inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = false; } static struct drm_connector_state * -- GitLab From 71892cee6ceb3e1b88e0bb44b05c8397d8261a85 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:12 +0100 Subject: [PATCH 0123/1420] drm/rockchip: inno_hdmi: Don't power up the phy after resetting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inno_hdmi_reset is only ever called when initializing the controller. At this point it’s completely uneccessary to power up the PHY, since all what has to work at this point is the DDC bus. The phy will be powered up correctly when a mode is set in inno_hdmi_encoder_enable and disabled in inno_hdmi_encoder_disable. Set it to LOWER_PWR after resetting the controller. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-22-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index fbf73f6b99ca8..763d61704ee61 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -201,7 +201,7 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); - inno_hdmi_set_pwr_mode(hdmi, NORMAL); + inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); } static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, -- GitLab From f01e33cb586b5fd354cba73052f82c3b4246109d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:13 +0100 Subject: [PATCH 0124/1420] drm/rockchip: inno_hdmi: Split power mode setting This splits setting the power mode of the controller / phy in two functions. It's done in preparation of setting up the phy based on the pixelclock. No functional changes intended. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-23-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 54 +++++++++++++--------------- drivers/gpu/drm/rockchip/inno_hdmi.h | 5 --- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 763d61704ee61..da77171b2b42f 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -153,38 +153,31 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF); } -static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) +static void inno_hdmi_standby(struct inno_hdmi *hdmi) { - switch (mode) { - case NORMAL: - inno_hdmi_sys_power(hdmi, false); + inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); - - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); - - inno_hdmi_sys_power(hdmi, true); - break; + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +}; - case LOWER_PWR: - inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +static void inno_hdmi_power_up(struct inno_hdmi *hdmi) +{ + inno_hdmi_sys_power(hdmi, false); - break; + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); - default: - DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode); - } -} + inno_hdmi_sys_power(hdmi, true); +}; static void inno_hdmi_reset(struct inno_hdmi *hdmi) { @@ -201,7 +194,7 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); - inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + inno_hdmi_standby(hdmi); } static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, @@ -440,6 +433,8 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + inno_hdmi_power_up(hdmi); + return 0; } @@ -459,7 +454,6 @@ static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, return; inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); - inno_hdmi_set_pwr_mode(hdmi, NORMAL); } static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, @@ -467,7 +461,7 @@ static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + inno_hdmi_standby(hdmi); } static int diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h index 93245b55f9670..a7edf3559e606 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.h +++ b/drivers/gpu/drm/rockchip/inno_hdmi.h @@ -10,11 +10,6 @@ #define DDC_SEGMENT_ADDR 0x30 -enum PWR_MODE { - NORMAL, - LOWER_PWR, -}; - #define HDMI_SCL_RATE (100*1000) #define DDC_BUS_FREQ_L 0x4b #define DDC_BUS_FREQ_H 0x4c -- GitLab From a72aa8985c41ec241263b802857d84f4c90a8694 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:18 +0100 Subject: [PATCH 0125/1420] dt-bindings: display: ssd1307fb: Add vendor prefix to width and height The commit 591825fba8a2 ("dt-bindings: display: ssd1307fb: Remove default width and height values") used the wrong properties for width and height, instead of the correct "solomon,width" and "solomon,height" properties. Fix this by adding the vendor prefix to the width and height properties. Fixes: 591825fba8a2 ("dt-bindings: display: ssd1307fb: Remove default width and height values") Reported-by: Conor Dooley Closes: https://lore.kernel.org/dri-devel/20231218-example-envision-b41ca8efa251@spud/ Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-2-javierm@redhat.com --- .../bindings/display/solomon,ssd1307fb.yaml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml index 3afbb52d1b7fe..153ff86fb4059 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml @@ -131,9 +131,9 @@ allOf: const: sinowealth,sh1106 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -149,9 +149,9 @@ allOf: - solomon,ssd1305 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -167,9 +167,9 @@ allOf: - solomon,ssd1306 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -185,9 +185,9 @@ allOf: - solomon,ssd1307 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 39 solomon,dclk-div: default: 2 @@ -205,9 +205,9 @@ allOf: - solomon,ssd1309 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 -- GitLab From 95ea83829e5f406b15175eb445b89000c2558168 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:19 +0100 Subject: [PATCH 0126/1420] dt-bindings: display: ssd132x: Add vendor prefix to width and height Commit 2d23e7d6bacb ("dt-bindings: display: Add SSD132x OLED controllers") used the wrong properties for width and height, instead of the correct "solomon,width" and "solomon,height" properties. Fix this by adding the vendor prefix to the width and height properties. Fixes: 2d23e7d6bacb ("dt-bindings: display: Add SSD132x OLED controllers") Reported-by: Conor Dooley Closes: https://lore.kernel.org/dri-devel/20231218-example-envision-b41ca8efa251@spud/ Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-3-javierm@redhat.com --- .../devicetree/bindings/display/solomon,ssd132x.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml index 37975ee61c5ad..dd7939989cf4f 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml @@ -30,9 +30,9 @@ allOf: const: solomon,ssd1322 then: properties: - width: + solomon,width: default: 480 - height: + solomon,height: default: 128 - if: @@ -42,9 +42,9 @@ allOf: const: solomon,ssd1325 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 80 - if: @@ -54,9 +54,9 @@ allOf: const: solomon,ssd1327 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 128 unevaluatedProperties: false -- GitLab From e06b7373cfb96b73d05712fbd15b6d6a78ce9b9d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:20 +0100 Subject: [PATCH 0127/1420] dt-bindings: display: Add SSD133x OLED controllers Add a Device Tree binding schema for the OLED panels based on the Solomon SSD133x family of controllers. Signed-off-by: Javier Martinez Canillas Reviewed-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-4-javierm@redhat.com --- .../bindings/display/solomon,ssd133x.yaml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/solomon,ssd133x.yaml diff --git a/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml new file mode 100644 index 0000000000000..b7780038a34b4 --- /dev/null +++ b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/solomon,ssd133x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Solomon SSD133x OLED Display Controllers + +maintainers: + - Javier Martinez Canillas + +allOf: + - $ref: solomon,ssd-common.yaml# + +properties: + compatible: + enum: + - solomon,ssd1331 + + solomon,width: + default: 96 + + solomon,height: + default: 64 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + oled@0 { + compatible = "solomon,ssd1331"; + reg = <0x0>; + reset-gpios = <&gpio2 7>; + dc-gpios = <&gpio2 8>; + spi-max-frequency = <10000000>; + }; + }; -- GitLab From b4299c936d8fd62b75621cad8dbf8aa9178e7c0e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:21 +0100 Subject: [PATCH 0128/1420] drm/ssd130x: Add support for the SSD133x OLED controller family The Solomon SSD133x controllers (such as the SSD1331) are used by RGB dot matrix OLED panels, add a modesetting pipeline to support the chip family. The SSD133x controllers support 256 (8-bit) and 65k (16-bit) color depths but only the 256-color mode (DRM_FORMAT_RGB332) is implemented for now. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-5-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x-spi.c | 7 + drivers/gpu/drm/solomon/ssd130x.c | 370 ++++++++++++++++++++++++++ drivers/gpu/drm/solomon/ssd130x.h | 5 +- 3 files changed, 381 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 84e035a7ab3f5..84bfde31d1724 100644 --- a/drivers/gpu/drm/solomon/ssd130x-spi.c +++ b/drivers/gpu/drm/solomon/ssd130x-spi.c @@ -142,6 +142,11 @@ static const struct of_device_id ssd130x_of_match[] = { .compatible = "solomon,ssd1327", .data = &ssd130x_variants[SSD1327_ID], }, + /* ssd133x family */ + { + .compatible = "solomon,ssd1331", + .data = &ssd130x_variants[SSD1331_ID], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ssd130x_of_match); @@ -166,6 +171,8 @@ static const struct spi_device_id ssd130x_spi_table[] = { { "ssd1322", SSD1322_ID }, { "ssd1325", SSD1325_ID }, { "ssd1327", SSD1327_ID }, + /* ssd133x family */ + { "ssd1331", SSD1331_ID }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, ssd130x_spi_table); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index bef293922b98f..447d0c7c88c63 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -119,6 +119,26 @@ #define SSD130X_SET_VCOMH_VOLTAGE 0xbe #define SSD132X_SET_FUNCTION_SELECT_B 0xd5 +/* ssd133x commands */ +#define SSD133X_SET_COL_RANGE 0x15 +#define SSD133X_SET_ROW_RANGE 0x75 +#define SSD133X_CONTRAST_A 0x81 +#define SSD133X_CONTRAST_B 0x82 +#define SSD133X_CONTRAST_C 0x83 +#define SSD133X_SET_MASTER_CURRENT 0x87 +#define SSD132X_SET_PRECHARGE_A 0x8a +#define SSD132X_SET_PRECHARGE_B 0x8b +#define SSD132X_SET_PRECHARGE_C 0x8c +#define SSD133X_SET_DISPLAY_START 0xa1 +#define SSD133X_SET_DISPLAY_OFFSET 0xa2 +#define SSD133X_SET_DISPLAY_NORMAL 0xa4 +#define SSD133X_SET_MASTER_CONFIG 0xad +#define SSD133X_POWER_SAVE_MODE 0xb0 +#define SSD133X_PHASES_PERIOD 0xb1 +#define SSD133X_SET_CLOCK_FREQ 0xb3 +#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb +#define SSD133X_SET_VCOMH_VOLTAGE 0xbe + #define MAX_CONTRAST 255 const struct ssd130x_deviceinfo ssd130x_variants[] = { @@ -180,6 +200,12 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = { .default_width = 128, .default_height = 128, .family_id = SSD132X_FAMILY, + }, + /* ssd133x family */ + [SSD1331_ID] = { + .default_width = 96, + .default_height = 64, + .family_id = SSD133X_FAMILY, } }; EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X); @@ -589,6 +615,117 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) return 0; } +static int ssd133x_init(struct ssd130x_device *ssd130x) +{ + int ret; + + /* Set color A contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91); + if (ret < 0) + return ret; + + /* Set color B contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_B, 0x50); + if (ret < 0) + return ret; + + /* Set color C contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_C, 0x7d); + if (ret < 0) + return ret; + + /* Set master current */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CURRENT, 0x06); + if (ret < 0) + return ret; + + /* Set column start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1); + if (ret < 0) + return ret; + + /* Set row start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1); + if (ret < 0) + return ret; + + /* + * Horizontal Address Increment + * Normal order SA,SB,SC (e.g. RGB) + * COM Split Odd Even + * 256 color format + */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x20); + if (ret < 0) + return ret; + + /* Set display start and offset */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_START, 0x00); + if (ret < 0) + return ret; + + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_OFFSET, 0x00); + if (ret < 0) + return ret; + + /* Set display mode normal */ + ret = ssd130x_write_cmd(ssd130x, 1, SSD133X_SET_DISPLAY_NORMAL); + if (ret < 0) + return ret; + + /* Set multiplex ratio value */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1); + if (ret < 0) + return ret; + + /* Set master configuration */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CONFIG, 0x8e); + if (ret < 0) + return ret; + + /* Set power mode */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_POWER_SAVE_MODE, 0x0b); + if (ret < 0) + return ret; + + /* Set Phase 1 and 2 period */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_PHASES_PERIOD, 0x31); + if (ret < 0) + return ret; + + /* Set clock divider */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_CLOCK_FREQ, 0xf0); + if (ret < 0) + return ret; + + /* Set pre-charge A */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_A, 0x64); + if (ret < 0) + return ret; + + /* Set pre-charge B */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_B, 0x78); + if (ret < 0) + return ret; + + /* Set pre-charge C */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_C, 0x64); + if (ret < 0) + return ret; + + /* Set pre-charge level */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_PRECHARGE_VOLTAGE, 0x3a); + if (ret < 0) + return ret; + + /* Set VCOMH voltage */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_VCOMH_VOLTAGE, 0x3e); + if (ret < 0) + return ret; + + return 0; +} + static int ssd130x_update_rect(struct ssd130x_device *ssd130x, struct drm_rect *rect, u8 *buf, u8 *data_array) @@ -753,6 +890,47 @@ static int ssd132x_update_rect(struct ssd130x_device *ssd130x, return ret; } +static int ssd133x_update_rect(struct ssd130x_device *ssd130x, + struct drm_rect *rect, u8 *data_array, + unsigned int pitch) +{ + unsigned int x = rect->x1; + unsigned int y = rect->y1; + unsigned int columns = drm_rect_width(rect); + unsigned int rows = drm_rect_height(rect); + int ret; + + /* + * The screen is divided in Segment and Common outputs, where + * COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are + * the columns. + * + * Each Segment has a 8-bit pixel and each Common output has a + * row of pixels. When using the (default) horizontal address + * increment mode, each byte of data sent to the controller has + * a Segment (e.g: SEG0). + * + * When using the 256 color depth format, each pixel contains 3 + * sub-pixels for color A, B and C. These have 3 bit, 3 bit and + * 2 bits respectively. + */ + + /* Set column start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, x, columns - 1); + if (ret < 0) + return ret; + + /* Set row start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, y, rows - 1); + if (ret < 0) + return ret; + + /* Write out update in one go since horizontal addressing mode is used */ + ret = ssd130x_write_data(ssd130x, data_array, pitch * rows); + + return ret; +} + static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) { unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT); @@ -805,6 +983,22 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) ssd130x_write_data(ssd130x, data_array, columns * height); } +static void ssd133x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) +{ + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int pitch; + + if (!fi) + return; + + pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + + memset(data_array, 0, pitch * ssd130x->height); + + /* Write out update in one go since horizontal addressing mode is used */ + ssd130x_write_data(ssd130x, data_array, pitch * ssd130x->height); +} + static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, struct drm_rect *rect, @@ -866,6 +1060,36 @@ static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb, return ret; } +static int ssd133x_fb_blit_rect(struct drm_framebuffer *fb, + const struct iosys_map *vmap, + struct drm_rect *rect, u8 *data_array, + struct drm_format_conv_state *fmtcnv_state) +{ + struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int dst_pitch; + struct iosys_map dst; + int ret = 0; + + if (!fi) + return -EINVAL; + + dst_pitch = drm_format_info_min_pitch(fi, 0, drm_rect_width(rect)); + + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; + + iosys_map_set_vaddr(&dst, data_array); + drm_fb_xrgb8888_to_rgb332(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state); + + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); + + ssd133x_update_rect(ssd130x, rect, data_array, dst_pitch); + + return ret; +} + static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -964,6 +1188,29 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane, return 0; } +static int ssd133x_primary_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!plane_state->visible) + return 0; + + return 0; +} + static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -1034,6 +1281,39 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane, drm_dev_exit(idx); } +static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + struct ssd130x_crtc_state *ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_atomic_helper_damage_iter iter; + struct drm_device *drm = plane->dev; + struct drm_rect dst_clip; + struct drm_rect damage; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + dst_clip = plane_state->dst; + + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; + + ssd133x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip, + ssd130x_crtc_state->data_array, + &shadow_plane_state->fmtcnv_state); + } + + drm_dev_exit(idx); +} + static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -1082,6 +1362,30 @@ static void ssd132x_primary_plane_atomic_disable(struct drm_plane *plane, drm_dev_exit(idx); } +static void ssd133x_primary_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_device *drm = plane->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *crtc_state; + struct ssd130x_crtc_state *ssd130x_crtc_state; + int idx; + + if (!plane_state->crtc) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + + if (!drm_dev_enter(drm, &idx)) + return; + + ssd133x_clear_screen(ssd130x, ssd130x_crtc_state->data_array); + + drm_dev_exit(idx); +} + /* Called during init to allocate the plane's atomic state. */ static void ssd130x_primary_plane_reset(struct drm_plane *plane) { @@ -1144,6 +1448,12 @@ static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs[] .atomic_check = ssd132x_primary_plane_atomic_check, .atomic_update = ssd132x_primary_plane_atomic_update, .atomic_disable = ssd132x_primary_plane_atomic_disable, + }, + [SSD133X_FAMILY] = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = ssd133x_primary_plane_atomic_check, + .atomic_update = ssd133x_primary_plane_atomic_update, + .atomic_disable = ssd133x_primary_plane_atomic_disable, } }; @@ -1214,6 +1524,33 @@ static int ssd132x_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static int ssd133x_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state); + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int pitch; + int ret; + + if (!fi) + return -EINVAL; + + ret = drm_crtc_helper_atomic_check(crtc, state); + if (ret) + return ret; + + pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + + ssd130x_state->data_array = kmalloc(pitch * ssd130x->height, GFP_KERNEL); + if (!ssd130x_state->data_array) + return -ENOMEM; + + return 0; +} + /* Called during init to allocate the CRTC's atomic state. */ static void ssd130x_crtc_reset(struct drm_crtc *crtc) { @@ -1275,6 +1612,10 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs[] = { .mode_valid = ssd130x_crtc_mode_valid, .atomic_check = ssd132x_crtc_atomic_check, }, + [SSD133X_FAMILY] = { + .mode_valid = ssd130x_crtc_mode_valid, + .atomic_check = ssd133x_crtc_atomic_check, + }, }; static const struct drm_crtc_funcs ssd130x_crtc_funcs = { @@ -1337,6 +1678,31 @@ static void ssd132x_encoder_atomic_enable(struct drm_encoder *encoder, ssd130x_power_off(ssd130x); } +static void ssd133x_encoder_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *drm = encoder->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + int ret; + + ret = ssd130x_power_on(ssd130x); + if (ret) + return; + + ret = ssd133x_init(ssd130x); + if (ret) + goto power_off; + + ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON); + + backlight_enable(ssd130x->bl_dev); + + return; + +power_off: + ssd130x_power_off(ssd130x); +} + static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -1358,6 +1724,10 @@ static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs[] = { [SSD132X_FAMILY] = { .atomic_enable = ssd132x_encoder_atomic_enable, .atomic_disable = ssd130x_encoder_atomic_disable, + }, + [SSD133X_FAMILY] = { + .atomic_enable = ssd133x_encoder_atomic_enable, + .atomic_disable = ssd130x_encoder_atomic_disable, } }; diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index 075c5c3ee75ac..a4554018bb2a4 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -25,7 +25,8 @@ enum ssd130x_family_ids { SSD130X_FAMILY, - SSD132X_FAMILY + SSD132X_FAMILY, + SSD133X_FAMILY }; enum ssd130x_variants { @@ -39,6 +40,8 @@ enum ssd130x_variants { SSD1322_ID, SSD1325_ID, SSD1327_ID, + /* ssd133x family */ + SSD1331_ID, NR_SSD130X_VARIANTS }; -- GitLab From b8a5d1f4a08751031a18621ce1b59fc49d042494 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 16 Dec 2023 14:15:27 +0000 Subject: [PATCH 0129/1420] drm/vc4: plane: check drm_gem_plane_helper_prepare_fb() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bubble up any error to the caller. Signed-off-by: Simon Ser Cc: Maxime Ripard Cc: Kees Cook Cc: Dave Stevenson Reviewed-by: Maíra Canal Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231216141518.242811-1-contact@emersion.fr --- drivers/gpu/drm/vc4/vc4_plane.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 00e713faecd5a..b8184374332ce 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1497,13 +1497,16 @@ static int vc4_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { struct vc4_bo *bo; + int ret; if (!state->fb) return 0; bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); - drm_gem_plane_helper_prepare_fb(plane, state); + ret = drm_gem_plane_helper_prepare_fb(plane, state); + if (ret) + return ret; if (plane->state->fb == state->fb) return 0; -- GitLab From cf8837d7204481026335461629b84ac7f4538fa5 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:20 -0500 Subject: [PATCH 0130/1420] drm: Don't treat 0 as -1 in drm_fixp2int_ceil Unit testing this in VKMS shows that passing 0 into this function returns -1, which is highly counter- intuitive. Fix it by checking whether the input is >= 0 instead of > 0. Fixes: 64566b5e767f ("drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil") Signed-off-by: Harry Wentland Reviewed-by: Simon Ser Reviewed-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-2-harry.wentland@amd.com --- include/drm/drm_fixed.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index 6ea339d5de088..0c9f917a4d4be 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h @@ -95,7 +95,7 @@ static inline int drm_fixp2int_round(s64 a) static inline int drm_fixp2int_ceil(s64 a) { - if (a > 0) + if (a >= 0) return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE); else return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE); -- GitLab From ffcc67cd79ff2e93fd0bdb837c99cbab6c59d38c Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:22 -0500 Subject: [PATCH 0131/1420] drm/vkms: Create separate Kconfig file for VKMS This aligns with most other DRM drivers and will allow us to add new VKMS config options without polluting the DRM Kconfig. v3: - Change SPDX to GPL-2.0-only to match DRM KConfig SPDX (Simon) Signed-off-by: Harry Wentland Reviewed-by: Simon Ser Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-4-harry.wentland@amd.com --- drivers/gpu/drm/Kconfig | 14 +------------- drivers/gpu/drm/vkms/Kconfig | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/vkms/Kconfig diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4b8b8f8a0e72b..628f90ed8a9be 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -287,19 +287,7 @@ config DRM_VGEM as used by Mesa's software renderer for enhanced performance. If M is selected the module will be called vgem. -config DRM_VKMS - tristate "Virtual KMS (EXPERIMENTAL)" - depends on DRM && MMU - select DRM_KMS_HELPER - select DRM_GEM_SHMEM_HELPER - select CRC32 - default n - help - Virtual Kernel Mode-Setting (VKMS) is used for testing or for - running GPU in a headless machines. Choose this option to get - a VKMS. - - If M is selected the module will be called vkms. +source "drivers/gpu/drm/vkms/Kconfig" source "drivers/gpu/drm/exynos/Kconfig" diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig new file mode 100644 index 0000000000000..b9ecdebecb0b6 --- /dev/null +++ b/drivers/gpu/drm/vkms/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config DRM_VKMS + tristate "Virtual KMS (EXPERIMENTAL)" + depends on DRM && MMU + select DRM_KMS_HELPER + select DRM_GEM_SHMEM_HELPER + select CRC32 + default n + help + Virtual Kernel Mode-Setting (VKMS) is used for testing or for + running GPU in a headless machines. Choose this option to get + a VKMS. + + If M is selected the module will be called vkms. -- GitLab From 2fee84030d12d9fddfa874e4562d71761a129277 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:24 -0500 Subject: [PATCH 0132/1420] drm/vkms: Avoid reading beyond LUT array When the floor LUT index (drm_fixp2int(lut_index) is the last index of the array the ceil LUT index will point to an entry beyond the array. Make sure we guard against it and use the value of the floor LUT index. v3: - Drop bits from commit description that didn't contribute anything of value Fixes: db1f254f2cfa ("drm/vkms: Add support to 1D gamma LUT") Signed-off-by: Harry Wentland Cc: Arthur Grillo Reviewed-by: Arthur Grillo Reviewed-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-6-harry.wentland@amd.com --- drivers/gpu/drm/vkms/vkms_composer.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 3c99fb8b54e2d..e7441b227b3ce 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan enum lut_channel channel) { s64 lut_index = get_lut_index(lut, channel_value); + u16 *floor_lut_value, *ceil_lut_value; + u16 floor_channel_value, ceil_channel_value; /* * This checks if `struct drm_color_lut` has any gap added by the compiler @@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan */ static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); - u16 *floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; - u16 *ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; + floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; + if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) + /* We're at the end of the LUT array, use same value for ceil and floor */ + ceil_lut_value = floor_lut_value; + else + ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; - u16 floor_channel_value = floor_lut_value[channel]; - u16 ceil_channel_value = ceil_lut_value[channel]; + floor_channel_value = floor_lut_value[channel]; + ceil_channel_value = ceil_lut_value[channel]; return lerp_u16(floor_channel_value, ceil_channel_value, lut_index & DRM_FIXED_DECIMAL_MASK); -- GitLab From 0c75d52190b8bfa22cdb66e07148aea599c4535d Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sat, 23 Dec 2023 19:32:48 +0100 Subject: [PATCH 0133/1420] drm/debugfs: drop unneeded DEBUG_FS guard The Makefile enables/disables the file compilation depending on CONFIG_DEBUG_FS. Signed-off-by: Dario Binacchi Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231223183301.78332-1-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/drm_debugfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f4715a67e340d..08fcefd804bc0 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -45,8 +45,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#if defined(CONFIG_DEBUG_FS) - /*************************************************** * Initialization, etc. **************************************************/ @@ -647,5 +645,3 @@ void drm_debugfs_encoder_remove(struct drm_encoder *encoder) debugfs_remove_recursive(encoder->debugfs_entry); encoder->debugfs_entry = NULL; } - -#endif /* CONFIG_DEBUG_FS */ -- GitLab From 835e4d9bb3a13879031942ca6692d5a82ec00158 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 2 Jan 2024 01:02:31 +0000 Subject: [PATCH 0134/1420] drm/i915/guc: Change wa and EU_PERF_CNTL registers to MCR type Some of the wa registers are MCR register, and EU_PERF_CNTL registers are MCR register. MCR register needs extra process for read/write. As normal MMIO register also could work with the MCR register process, change all wa registers to MCR type for code simplicity. Signed-off-by: Shuicheng Lin Cc: Matt Roper Cc: Umesh Nerlige Ramappa Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240102010231.843778-1-shuicheng.lin@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 63724e17829a7..f7372f736a776 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -377,8 +377,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset, CCS_MASK(engine->gt)) ret |= GUC_MMIO_REG_ADD(gt, regset, GEN12_RCU_MODE, true); + /* + * some of the WA registers are MCR registers. As it is safe to + * use MCR form for non-MCR registers, for code simplicity, all + * WA registers are added with MCR form. + */ for (i = 0, wa = wal->list; i < wal->count; i++, wa++) - ret |= GUC_MMIO_REG_ADD(gt, regset, wa->reg, wa->masked_reg); + ret |= GUC_MCR_REG_ADD(gt, regset, wa->mcr_reg, wa->masked_reg); /* Be extra paranoid and include all whitelist registers. */ for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) @@ -394,13 +399,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset, ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); if (GRAPHICS_VER(engine->i915) >= 12) { - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL0, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL1, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL2, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL3, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL4, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL5, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL6, false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL0)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL1)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL2)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL3)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL4)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL5)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL6)), false); } return ret ? -1 : 0; -- GitLab From 93cbc1accbcec2740231755774420934658e2b18 Mon Sep 17 00:00:00 2001 From: Haridhar Kalvala Date: Wed, 20 Dec 2023 00:22:33 +0530 Subject: [PATCH 0135/1420] drm/i915/mtl: Add fake PCH for Meteor Lake Correct the implementation trying to detect MTL PCH with the MTL fake PCH id. On MTL, both the North Display (NDE) and South Display (SDE) functionality reside on the same die (the SoC die in this case), unlike many past platforms where the SDE was on a separate PCH die. The code is (badly) structured today in a way that assumes the SDE is always on the PCH for modern platforms, so on platforms where we don't actually need to identify the PCH to figure out how the SDE behaves (i.e., all DG1/2 GPUs as well as MTL and LNL),we've been assigning a "fake PCH" as a quickhack that allows us to avoid restructuring a bunch of the code.we've been assigning a "fake PCH" as a quick hack that allows us to avoid restructuring a bunch of the code. Removed unused macros of LNL amd MTL as well. v2: Reorder PCH_MTL conditional check (Matt Roper) Reverting to PCH_MTL for PICA interrupt(Matt Roper) Signed-off-by: Haridhar Kalvala Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231219185233.1469675-1-haridhar.kalvala@intel.com --- drivers/gpu/drm/i915/display/intel_backlight.c | 2 +- drivers/gpu/drm/i915/display/intel_bios.c | 3 +-- drivers/gpu/drm/i915/display/intel_cdclk.c | 6 +++--- drivers/gpu/drm/i915/display/intel_display_irq.c | 2 +- drivers/gpu/drm/i915/display/intel_gmbus.c | 5 +---- drivers/gpu/drm/i915/display/intel_hotplug_irq.c | 6 ++---- drivers/gpu/drm/i915/display/intel_pps.c | 2 +- drivers/gpu/drm/i915/soc/intel_pch.c | 16 ++++++++-------- drivers/gpu/drm/i915/soc/intel_pch.h | 6 +----- 9 files changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 612d4cd9dacba..696ae59874a9f 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -1465,7 +1465,7 @@ static bool cnp_backlight_controller_is_valid(struct drm_i915_private *i915, int if (controller == 1 && INTEL_PCH_TYPE(i915) >= PCH_ICP && - INTEL_PCH_TYPE(i915) < PCH_MTP) + INTEL_PCH_TYPE(i915) <= PCH_ADP) return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT; return true; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index aa169b0055e97..0e61e424802e7 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2204,8 +2204,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) if (IS_DGFX(i915)) return vbt_pin; - if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || - IS_ALDERLAKE_P(i915)) { + if (INTEL_PCH_TYPE(i915) >= PCH_MTL || IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; n_entries = ARRAY_SIZE(adlp_ddc_pin_map); } else if (IS_ALDERLAKE_S(i915)) { diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0da9bcce25b17..c5fecde7afa88 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -3466,15 +3466,15 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) { u32 freq; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) - freq = dg1_rawclk(dev_priv); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL) /* * MTL always uses a 38.4 MHz rawclk. The bspec tells us * "RAWCLK_FREQ defaults to the values for 38.4 and does * not need to be programmed." */ freq = 38400; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + freq = dg1_rawclk(dev_priv); else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) freq = cnp_rawclk(dev_priv); else if (HAS_PCH_SPLIT(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index a7d8f3fc98de9..6964f4b95865f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -986,7 +986,7 @@ static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_i * their flags both in the PICA and SDE IIR. */ if (*pch_iir & SDE_PICAINTERRUPT) { - drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); + drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTL); pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 40d7b6f3f4891..854566ba54149 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -155,7 +155,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, const struct gmbus_pin *pins; size_t size; - if (INTEL_PCH_TYPE(i915) >= PCH_LNL) { + if (INTEL_PCH_TYPE(i915) >= PCH_MTL) { pins = gmbus_pins_mtp; size = ARRAY_SIZE(gmbus_pins_mtp); } else if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { @@ -164,9 +164,6 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { pins = gmbus_pins_dg1; size = ARRAY_SIZE(gmbus_pins_dg1); - } else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) { - pins = gmbus_pins_mtp; - size = ARRAY_SIZE(gmbus_pins_mtp); } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) { pins = gmbus_pins_icp; size = ARRAY_SIZE(gmbus_pins_icp); diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 04f62f27ad74b..76076509f7717 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -163,12 +163,10 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))) return; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_LNL) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL) hpd->pch_hpd = hpd_mtp; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) hpd->pch_hpd = hpd_sde_dg1; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) - hpd->pch_hpd = hpd_mtp; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) hpd->pch_hpd = hpd_icp; else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) @@ -1139,7 +1137,7 @@ static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) if (INTEL_PCH_TYPE(i915) >= PCH_LNL) xe2lpd_sde_hpd_irq_setup(i915); - else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) + else if (INTEL_PCH_TYPE(i915) >= PCH_MTL) mtp_hpd_irq_setup(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index a8fa3a20990e7..2d65a538f83e4 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -366,7 +366,7 @@ static bool intel_pps_is_valid(struct intel_dp *intel_dp) if (intel_dp->pps.pps_idx == 1 && INTEL_PCH_TYPE(i915) >= PCH_ICP && - INTEL_PCH_TYPE(i915) < PCH_MTP) + INTEL_PCH_TYPE(i915) <= PCH_ADP) return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT; return true; diff --git a/drivers/gpu/drm/i915/soc/intel_pch.c b/drivers/gpu/drm/i915/soc/intel_pch.c index 240beafb38ed9..3cad6dac06b01 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.c +++ b/drivers/gpu/drm/i915/soc/intel_pch.c @@ -140,11 +140,6 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv) && !IS_ALDERLAKE_P(dev_priv)); return PCH_ADP; - case INTEL_PCH_MTP_DEVICE_ID_TYPE: - case INTEL_PCH_MTP2_DEVICE_ID_TYPE: - drm_dbg_kms(&dev_priv->drm, "Found Meteor Lake PCH\n"); - drm_WARN_ON(&dev_priv->drm, !IS_METEORLAKE(dev_priv)); - return PCH_MTP; default: return PCH_NONE; } @@ -173,9 +168,7 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv, * make an educated guess as to which PCH is really there. */ - if (IS_METEORLAKE(dev_priv)) - id = INTEL_PCH_MTP_DEVICE_ID_TYPE; - else if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) id = INTEL_PCH_ADP_DEVICE_ID_TYPE; else if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) id = INTEL_PCH_TGP_DEVICE_ID_TYPE; @@ -225,6 +218,13 @@ void intel_detect_pch(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 20) { dev_priv->pch_type = PCH_LNL; return; + } else if (IS_METEORLAKE(dev_priv)) { + /* + * Both north display and south display are on the SoC die. + * The real PCH is uninvolved in display. + */ + dev_priv->pch_type = PCH_MTL; + return; } else if (IS_DG2(dev_priv)) { dev_priv->pch_type = PCH_DG2; return; diff --git a/drivers/gpu/drm/i915/soc/intel_pch.h b/drivers/gpu/drm/i915/soc/intel_pch.h index 1b03ea60a7a87..89e89ede265db 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.h +++ b/drivers/gpu/drm/i915/soc/intel_pch.h @@ -25,11 +25,11 @@ enum intel_pch { PCH_ICP, /* Ice Lake/Jasper Lake PCH */ PCH_TGP, /* Tiger Lake/Mule Creek Canyon PCH */ PCH_ADP, /* Alder Lake PCH */ - PCH_MTP, /* Meteor Lake PCH */ /* Fake PCHs, functionality handled on the same PCI dev */ PCH_DG1 = 1024, PCH_DG2, + PCH_MTL, PCH_LNL, }; @@ -59,16 +59,12 @@ enum intel_pch { #define INTEL_PCH_ADP2_DEVICE_ID_TYPE 0x5180 #define INTEL_PCH_ADP3_DEVICE_ID_TYPE 0x7A00 #define INTEL_PCH_ADP4_DEVICE_ID_TYPE 0x5480 -#define INTEL_PCH_MTP_DEVICE_ID_TYPE 0x7E00 -#define INTEL_PCH_MTP2_DEVICE_ID_TYPE 0xAE00 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type) #define INTEL_PCH_ID(dev_priv) ((dev_priv)->pch_id) -#define HAS_PCH_LNL(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_LNL) -#define HAS_PCH_MTP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_MTP) #define HAS_PCH_DG2(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG2) #define HAS_PCH_ADP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ADP) #define HAS_PCH_DG1(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG1) -- GitLab From 09d015deddd6234430c04a1eddaa8a28fd621dec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Dec 2023 17:19:55 +0200 Subject: [PATCH 0136/1420] drm/virtio: Spelling fixes While making a spelling mistake myself for `git grep kvalloc` I found that the only file has such a typo. Fix it and update to the standard de facto of how we refer to the functions. Also spell usr-out as user-out, it seems this driver uses its own terminology nobody else can decypher, make it more readable. Signed-off-by: Andy Shevchenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20231219151955.2477488-1-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/virtio/virtgpu_submit.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c index 5c514946bbad9..1c7c7f61a2228 100644 --- a/drivers/gpu/drm/virtio/virtgpu_submit.c +++ b/drivers/gpu/drm/virtio/virtgpu_submit.c @@ -99,8 +99,8 @@ virtio_gpu_parse_deps(struct virtio_gpu_submit *submit) return 0; /* - * kvalloc at first tries to allocate memory using kmalloc and - * falls back to vmalloc only on failure. It also uses __GFP_NOWARN + * kvmalloc() at first tries to allocate memory using kmalloc() and + * falls back to vmalloc() only on failure. It also uses __GFP_NOWARN * internally for allocations larger than a page size, preventing * storm of KMSG warnings. */ @@ -529,7 +529,7 @@ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, virtio_gpu_submit(&submit); /* - * Set up usr-out data after submitting the job to optimize + * Set up user-out data after submitting the job to optimize * the job submission path. */ virtio_gpu_install_out_fence_fd(&submit); -- GitLab From ecc8271f56d317627b5875918f2ac7e94242ea6d Mon Sep 17 00:00:00 2001 From: Ghanshyam Agrawal Date: Fri, 15 Dec 2023 11:00:16 +0530 Subject: [PATCH 0137/1420] drm/vmwgfx: Fix typos in vmwgfx_execbuf.c Fix typos in vmwgfx_execbuf.c. Signed-off-by: Ghanshyam Agrawal Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215053016.552019-1-ghanshyam1898@gmail.com --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 36987ef3fc300..272141b6164c6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -621,10 +621,10 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) * @sw_context: Pointer to the software context. * @res_type: Resource type. * @dirty: Whether to change dirty status. - * @converter: User-space visisble type specific information. + * @converter: User-space visible type specific information. * @id_loc: Pointer to the location in the command buffer currently being parsed * from where the user-space resource id handle is located. - * @p_res: Pointer to pointer to resource validalidation node. Populated on + * @p_res: Pointer to pointer to resource validation node. Populated on * exit. */ static int -- GitLab From 834b1d72051145e553222926b1a375f5441b24eb Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:41:02 -0800 Subject: [PATCH 0138/1420] drm/vmwgfx: fix all kernel-doc warnings in stdu kernel test robot reports one kernel-doc warning in stdu, but running scripts/kernel-doc in -Wall mode reports several more, so fix all of them at one time: vmwgfx_stdu.c:76: warning: Excess struct member 'transfer' description in 'vmw_stdu_dirty' vmwgfx_stdu.c:103: warning: missing initial short description on line: * struct vmw_screen_target_display_unit vmwgfx_stdu.c:215: warning: No description found for return value of 'vmw_stdu_bind_st' vmwgfx_stdu.c:320: warning: No description found for return value of 'vmw_stdu_destroy_st' vmwgfx_stdu.c:551: warning: No description found for return value of 'vmw_kms_stdu_readback' vmwgfx_stdu.c:719: warning: No description found for return value of 'vmw_kms_stdu_surface_dirty' vmwgfx_stdu.c:895: warning: No description found for return value of 'vmw_stdu_primary_plane_prepare_fb' vmwgfx_stdu.c:1470: warning: No description found for return value of 'vmw_stdu_init' Signed-off-by: Randy Dunlap Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312150347.5icezNlK-lkp@intel.com/ Cc: Zack Rusin Cc: VMware Graphics Reviewers Cc: dri-devel@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215234102.16574-1-rdunlap@infradead.org --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ba0c0e12cfe9d..6bc23bdf32c24 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -53,7 +53,6 @@ enum stdu_content_type { * struct vmw_stdu_dirty - closure structure for the update functions * * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). - * @transfer: Transfer direction for DMA command. * @left: Left side of bounding box. * @right: Right side of bounding box. * @top: Top side of bounding box. @@ -100,7 +99,7 @@ struct vmw_stdu_update_gb_image { }; /** - * struct vmw_screen_target_display_unit + * struct vmw_screen_target_display_unit - conglomerated STDU structure * * @base: VMW specific DU structure * @display_srf: surface to be displayed. The dimension of this will always @@ -208,6 +207,8 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, * @res: Buffer to bind to the screen target. Set to NULL to blank screen. * * Binding a surface to a Screen Target the same as flipping + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu, @@ -314,6 +315,9 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, * * @dev_priv: VMW DRM device * @stdu: display unit to destroy + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. */ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu) @@ -536,7 +540,8 @@ static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) * If DMA-ing till the screen target system, the function will also notify * the screen target system that a bounding box of the cliprects has been * updated. - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ int vmw_kms_stdu_readback(struct vmw_private *dev_priv, @@ -703,7 +708,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) * case the device has already synchronized. * @crtc: If crtc is passed, perform surface dirty on that crtc only. * - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, @@ -887,7 +892,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, * backed by a buffer object. The display surface is pinned here, and it'll * be unpinned in .cleanup_fb() * - * Returns 0 on success + * Returns: %0 on success */ static int vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, @@ -1465,6 +1470,8 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { * This function is called once per CRTC, and allocates one Screen Target * display unit to represent that CRTC. Since the SVGA device does not separate * out encoder and connector, they are represented as part of the STDU as well. + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) { -- GitLab From 89709105a6091948ffb6ec2427954cbfe45358ce Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 4 Dec 2023 17:14:16 +0800 Subject: [PATCH 0139/1420] drm/vmwgfx: fix a memleak in vmw_gmrid_man_get_node When ida_alloc_max fails, resources allocated before should be freed, including *res allocated by kmalloc and ttm_resource_init. Fixes: d3bcb4b02fe9 ("drm/vmwgfx: switch the TTM backends to self alloc") Signed-off-by: Zhipeng Lu Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231204091416.3308430-1-alexious@zju.edu.cn --- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index ceb4d3d3b965a..a0b47c9b33f55 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -64,8 +64,11 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, ttm_resource_init(bo, place, *res); id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); - if (id < 0) + if (id < 0) { + ttm_resource_fini(man, *res); + kfree(*res); return id; + } spin_lock(&gman->lock); -- GitLab From 85110d04688d7a12ff594f1152c0ae85f3b90bbe Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:56:38 -0800 Subject: [PATCH 0140/1420] drm/vmwgfx: fix kernel-doc Excess struct member 'base' Fix a new kernel-doc warning reported by kernel test robot: vmwgfx_surface.c:55: warning: Excess struct member 'base' description in 'vmw_user_surface' The other warning is not correct: it is confused by "__counted_by". Kees has made a separate patch for that. In -Wall mode, kernel-doc still reports 20 warnings of this nature: vmwgfx_surface.c:198: warning: No description found for return value of 'vmw_surface_dma_size' but I am not addressing those. Signed-off-by: Randy Dunlap Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312150701.kNI9LuM3-lkp@intel.com/ Cc: Kees Cook Cc: Zack Rusin Cc: VMware Graphics Reviewers Cc: dri-devel@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215235638.19189-1-rdunlap@infradead.org --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 680441bb1786d..10498725034cb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -44,7 +44,6 @@ * struct vmw_user_surface - User-space visible surface resource * * @prime: The TTM prime object. - * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. * @master: Master of the creating client. Used for security check. */ -- GitLab From 27571c64f1855881753e6f33c3186573afbab7ba Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sun, 24 Dec 2023 00:25:40 -0500 Subject: [PATCH 0141/1420] drm/vmwgfx: Unmap the surface before resetting it on a plane state Switch to a new plane state requires unreferencing of all held surfaces. In the work required for mob cursors the mapped surfaces started being cached but the variable indicating whether the surface is currently mapped was not being reset. This leads to crashes as the duplicated state, incorrectly, indicates the that surface is mapped even when no surface is present. That's because after unreferencing the surface it's perfectly possible for the plane to be backed by a bo instead of a surface. Reset the surface mapped flag when unreferencing the plane state surface to fix null derefs in cleanup. Fixes crashes in KDE KWin 6.0 on Wayland: Oops: 0000 [#1] PREEMPT SMP PTI CPU: 4 PID: 2533 Comm: kwin_wayland Not tainted 6.7.0-rc3-vmwgfx #2 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] Code: 00 00 00 75 3a 48 83 c4 10 5b 5d c3 cc cc cc cc 48 8b b3 a8 00 00 00 48 c7 c7 99 90 43 c0 e8 93 c5 db ca 48 8b 83 a8 00 00 00 <48> 8b 78 28 e8 e3 f> RSP: 0018:ffffb6b98216fa80 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff969d84cdcb00 RCX: 0000000000000027 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff969e75f21600 RBP: ffff969d4143dc50 R08: 0000000000000000 R09: ffffb6b98216f920 R10: 0000000000000003 R11: ffff969e7feb3b10 R12: 0000000000000000 R13: 0000000000000000 R14: 000000000000027b R15: ffff969d49c9fc00 FS: 00007f1e8f1b4180(0000) GS:ffff969e75f00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000028 CR3: 0000000104006004 CR4: 00000000003706f0 Call Trace: ? __die+0x23/0x70 ? page_fault_oops+0x171/0x4e0 ? exc_page_fault+0x7f/0x180 ? asm_exc_page_fault+0x26/0x30 ? vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] drm_atomic_helper_cleanup_planes+0x9b/0xc0 commit_tail+0xd1/0x130 drm_atomic_helper_commit+0x11a/0x140 drm_atomic_commit+0x97/0xd0 ? __pfx___drm_printfn_info+0x10/0x10 drm_atomic_helper_update_plane+0xf5/0x160 drm_mode_cursor_universal+0x10e/0x270 drm_mode_cursor_common+0x102/0x230 ? __pfx_drm_mode_cursor2_ioctl+0x10/0x10 drm_ioctl_kernel+0xb2/0x110 drm_ioctl+0x26d/0x4b0 ? __pfx_drm_mode_cursor2_ioctl+0x10/0x10 ? __pfx_drm_ioctl+0x10/0x10 vmw_generic_ioctl+0xa4/0x110 [vmwgfx] __x64_sys_ioctl+0x94/0xd0 do_syscall_64+0x61/0xe0 ? __x64_sys_ioctl+0xaf/0xd0 ? syscall_exit_to_user_mode+0x2b/0x40 ? do_syscall_64+0x70/0xe0 ? __x64_sys_ioctl+0xaf/0xd0 ? syscall_exit_to_user_mode+0x2b/0x40 ? do_syscall_64+0x70/0xe0 ? exc_page_fault+0x7f/0x180 entry_SYSCALL_64_after_hwframe+0x6e/0x76 RIP: 0033:0x7f1e93f279ed Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff f> RSP: 002b:00007ffca0faf600 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 000055db876ed2c0 RCX: 00007f1e93f279ed RDX: 00007ffca0faf6c0 RSI: 00000000c02464bb RDI: 0000000000000015 RBP: 00007ffca0faf650 R08: 000055db87184010 R09: 0000000000000007 R10: 000055db886471a0 R11: 0000000000000246 R12: 00007ffca0faf6c0 R13: 00000000c02464bb R14: 0000000000000015 R15: 00007ffca0faf790 Modules linked in: snd_seq_dummy snd_hrtimer nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_ine> CR2: 0000000000000028 ---[ end trace 0000000000000000 ]--- RIP: 0010:vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] Code: 00 00 00 75 3a 48 83 c4 10 5b 5d c3 cc cc cc cc 48 8b b3 a8 00 00 00 48 c7 c7 99 90 43 c0 e8 93 c5 db ca 48 8b 83 a8 00 00 00 <48> 8b 78 28 e8 e3 f> RSP: 0018:ffffb6b98216fa80 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff969d84cdcb00 RCX: 0000000000000027 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff969e75f21600 RBP: ffff969d4143dc50 R08: 0000000000000000 R09: ffffb6b98216f920 R10: 0000000000000003 R11: ffff969e7feb3b10 R12: 0000000000000000 R13: 0000000000000000 R14: 000000000000027b R15: ffff969d49c9fc00 FS: 00007f1e8f1b4180(0000) GS:ffff969e75f00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000028 CR3: 0000000104006004 CR4: 00000000003706f0 Signed-off-by: Zack Rusin Fixes: 485d98d472d5 ("drm/vmwgfx: Add support for CursorMob and CursorBypass 4") Reported-by: Stefan Hoffmeister Closes: https://gitlab.freedesktop.org/drm/misc/-/issues/34 Cc: Martin Krastev Cc: Maaz Mombasawala Cc: Ian Forbes Cc: Broadcom internal kernel review list Cc: dri-devel@lists.freedesktop.org Cc: # v5.19+ Acked-by: Javier Martinez Canillas Reviewed-by: Maaz Mombasawala Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20231224052540.605040-1-zack.rusin@broadcom.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5fd0ccaa0b41b..8589a1c3cc36b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -694,6 +694,10 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, int ret = 0; if (vps->surf) { + if (vps->surf_mapped) { + vmw_bo_unmap(vps->surf->res.guest_memory_bo); + vps->surf_mapped = false; + } vmw_surface_unreference(&vps->surf); vps->surf = NULL; } -- GitLab From bb056046c2139c72e20a5b6fc39c9caaf9eac2b8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 3 Jan 2024 19:13:01 +0100 Subject: [PATCH 0142/1420] drm/rockchip: analogix_dp: get encoder port ID from DT The VOP2 driver needs this port ID to properly configure the display data routing. Signed-off-by: Lucas Stach Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240103181301.3339595-1-l.stach@pengutronix.de --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index bd08d57486fef..7069a3d4d5811 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -343,6 +343,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, return ret; } + rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, + dev->of_node, 0, 0); + dp->plat_data.encoder = &dp->encoder.encoder; ret = analogix_dp_bind(dp->adp, drm_dev); -- GitLab From 5f2e93e6719701a91307090f8f7696fd6b3bffdf Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:14 +0100 Subject: [PATCH 0143/1420] drm/rockchip: inno_hdmi: Add variant support In preparation to support RK3128's integration of the controller, this patch adds a simple variant implementation. They mainly differ in the phy configuration required, so those are part of the match_data. The values have been taken from downstream. The pixelclocks in there are meant to be max-inclusive. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-24-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 74 ++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index da77171b2b42f..676c1cd73862b 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,6 +25,17 @@ #include "inno_hdmi.h" +struct inno_hdmi_phy_config { + unsigned long pixelclock; + u8 pre_emphasis; + u8 voltage_level_control; +}; + +struct inno_hdmi_variant { + struct inno_hdmi_phy_config *phy_configs; + struct inno_hdmi_phy_config *default_phy_config; +}; + struct inno_hdmi_i2c { struct i2c_adapter adap; @@ -46,6 +57,8 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; + + const struct inno_hdmi_variant *variant; }; struct inno_hdmi_connector_state { @@ -112,6 +125,30 @@ static const char coeff_csc[][24] = { }, }; +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xbb }, + { 165000000, 0x6f, 0xbb }, + { ~0UL, 0x00, 0x00 } +}; + +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, + unsigned long pixelclk) +{ + const struct inno_hdmi_phy_config *phy_configs = + hdmi->variant->phy_configs; + int i; + + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) { + if (pixelclk <= phy_configs[i].pixelclock) + return i; + } + + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n", + pixelclk); + + return -EINVAL; +} + static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) { return readl_relaxed(hdmi->regs + (offset) * 0x04); @@ -163,12 +200,25 @@ static void inno_hdmi_standby(struct inno_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); }; -static void inno_hdmi_power_up(struct inno_hdmi *hdmi) +static void inno_hdmi_power_up(struct inno_hdmi *hdmi, + unsigned long mpixelclock) { + struct inno_hdmi_phy_config *phy_config; + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock); + + if (ret < 0) { + phy_config = hdmi->variant->default_phy_config; + DRM_DEV_ERROR(hdmi->dev, + "Using default phy configuration for TMDS rate %lu", + mpixelclock); + } else { + phy_config = &hdmi->variant->phy_configs[ret]; + } + inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); @@ -405,6 +455,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; + unsigned long mpixelclock = mode->clock * 1000; /* Mute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -427,13 +478,13 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - inno_hdmi_i2c_init(hdmi, mode->clock * 1000); + inno_hdmi_i2c_init(hdmi, mpixelclock); /* Unmute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); - inno_hdmi_power_up(hdmi); + inno_hdmi_power_up(hdmi, mpixelclock); return 0; } @@ -825,6 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct inno_hdmi *hdmi; + const struct inno_hdmi_variant *variant; int irq; int ret; @@ -834,6 +886,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, hdmi->dev = dev; + variant = of_device_get_match_data(hdmi->dev); + if (!variant) + return -EINVAL; + + hdmi->variant = variant; + hdmi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); @@ -927,8 +985,14 @@ static void inno_hdmi_remove(struct platform_device *pdev) component_del(&pdev->dev, &inno_hdmi_ops); } +static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { + .phy_configs = rk3036_hdmi_phy_configs, + .default_phy_config = &rk3036_hdmi_phy_configs[1], +}; + static const struct of_device_id inno_hdmi_dt_ids[] = { { .compatible = "rockchip,rk3036-inno-hdmi", + .data = &rk3036_inno_hdmi_variant, }, {}, }; -- GitLab From aa54f334c291effe321aa4b9ac0e67a895fd7b58 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:15 +0100 Subject: [PATCH 0144/1420] drm/rockchip: inno_hdmi: Add RK3128 support This variant requires the phy reference clock to be enabled before the DDC block can work and the (initial) DDC bus frequency is calculated based on the rate of this clock. Besides the only difference is phy configuration required to make the driver working for this variant as well. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-25-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 46 +++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 676c1cd73862b..5045836993b5c 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -50,6 +50,7 @@ struct inno_hdmi { struct device *dev; struct clk *pclk; + struct clk *refclk; void __iomem *regs; struct drm_connector connector; @@ -131,6 +132,12 @@ static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { { ~0UL, 0x00, 0x00 } }; +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xaa }, + { 165000000, 0x5f, 0xaa }, + { ~0UL, 0x00, 0x00 } +}; + static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, unsigned long pixelclk) { @@ -909,6 +916,20 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return ret; } + hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); + if (IS_ERR(hdmi->refclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n"); + ret = PTR_ERR(hdmi->refclk); + goto err_disable_pclk; + } + + ret = clk_prepare_enable(hdmi->refclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI reference clock: %d\n", ret); + goto err_disable_pclk; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; @@ -925,12 +946,16 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, } /* - * When IP controller haven't configured to an accurate video - * timing, then the TMDS clock source would be switched to - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, - * and reconfigure the DDC clock. + * When the controller isn't configured to an accurate + * video timing and there is no reference clock available, + * then the TMDS clock source would be switched to PCLK_HDMI, + * so we need to init the TMDS rate to PCLK rate, and + * reconfigure the DDC clock. */ - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); + if (hdmi->refclk) + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk)); + else + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); ret = inno_hdmi_register(drm, hdmi); if (ret) @@ -954,6 +979,8 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, err_put_adapter: i2c_put_adapter(hdmi->ddc); err_disable_clk: + clk_disable_unprepare(hdmi->refclk); +err_disable_pclk: clk_disable_unprepare(hdmi->pclk); return ret; } @@ -967,6 +994,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(hdmi->refclk); clk_disable_unprepare(hdmi->pclk); } @@ -990,10 +1018,18 @@ static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { .default_phy_config = &rk3036_hdmi_phy_configs[1], }; +static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { + .phy_configs = rk3128_hdmi_phy_configs, + .default_phy_config = &rk3128_hdmi_phy_configs[1], +}; + static const struct of_device_id inno_hdmi_dt_ids[] = { { .compatible = "rockchip,rk3036-inno-hdmi", .data = &rk3036_inno_hdmi_variant, }, + { .compatible = "rockchip,rk3128-inno-hdmi", + .data = &rk3128_inno_hdmi_variant, + }, {}, }; MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); -- GitLab From 701029621d4141d0c9f8b81a88a37b95ec84ce65 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:16 +0100 Subject: [PATCH 0145/1420] drm/rockchip: inno_hdmi: Add basic mode validation As per TRM this controller supports pixelclocks starting from 25 MHz. The maximum supported pixelclocks are defined by the phy configurations we have. Also it can't support modes that require doubled clocks. If the variant has a phy reference clock we can additionally validate against VESA DMT'srecommendations. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-26-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 42 ++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 5045836993b5c..22697e714b236 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,6 +25,8 @@ #include "inno_hdmi.h" +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U + struct inno_hdmi_phy_config { unsigned long pixelclock; u8 pre_emphasis; @@ -496,6 +498,38 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, return 0; } +static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, + struct drm_display_mode *mode) +{ + unsigned long mpixelclk, max_tolerance; + long rounded_refclk; + + /* No support for double-clock modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + + mpixelclk = mode->clock * 1000; + + if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK) + return MODE_CLOCK_LOW; + + if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0) + return MODE_CLOCK_HIGH; + + if (hdmi->refclk) { + rounded_refclk = clk_round_rate(hdmi->refclk, mpixelclk); + if (rounded_refclk < 0) + return MODE_BAD; + + /* Vesa DMT standard mentions +/- 0.5% max tolerance */ + max_tolerance = mpixelclk / 200; + if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance) + return MODE_NOCLOCK; + } + + return MODE_OK; +} + static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -528,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); struct drm_display_mode *mode = &crtc_state->adjusted_mode; u8 vic = drm_match_cea_mode(mode); struct inno_hdmi_connector_state *inno_conn_state = @@ -548,7 +583,8 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, inno_conn_state->rgb_limited_range = drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; - return 0; + return inno_hdmi_display_mode_valid(hdmi, + &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; } static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { @@ -589,7 +625,9 @@ static enum drm_mode_status inno_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - return MODE_OK; + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + + return inno_hdmi_display_mode_valid(hdmi, mode); } static int -- GitLab From 50a3c772bd927dd409c484832ddd9f6bf00b7389 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:17 +0100 Subject: [PATCH 0146/1420] drm/rockchip: inno_hdmi: Drop custom fill_modes hook Now that we have proper pixelclock-based mode validation we can drop the custom fill_modes hook. CRTC size validation for the display controller has been added with Commit 8e140cb60270 ("drm/rockchip: vop: limit maximum resolution to hardware capabilities") Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-27-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 22697e714b236..925320fef0a80 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -630,13 +630,6 @@ inno_hdmi_connector_mode_valid(struct drm_connector *connector, return inno_hdmi_display_mode_valid(hdmi, mode); } -static int -inno_hdmi_probe_single_connector_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) -{ - return drm_helper_probe_single_connector_modes(connector, 1920, 1080); -} - static void inno_hdmi_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); @@ -695,7 +688,7 @@ inno_hdmi_connector_duplicate_state(struct drm_connector *connector) } static const struct drm_connector_funcs inno_hdmi_connector_funcs = { - .fill_modes = inno_hdmi_probe_single_connector_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .detect = inno_hdmi_connector_detect, .destroy = inno_hdmi_connector_destroy, .reset = inno_hdmi_connector_reset, -- GitLab From f4304beadd88d074333b23fdc7f35d00ee763e14 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:39 +0200 Subject: [PATCH 0147/1420] drm/i915/display: Fix C20 pll selection for state verification Add pll selection check for C20 as well as clock state verification0. We have been relying on sw state to select A or B pll's. This is incorrect as the hw might see this selection differently. This patch fixes this shortcoming by reading pll selection for both sw and hw states and compares if these two selections match. Fixes: 59be90248b42 ("drm/i915/mtl: C20 state verification") v2: reword commit message and include fix to a original commit (Imre) Compare pll selection (Jani) Signed-off-by: Mika Kahola Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20240102115741.118525-2-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 25 ++++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 884a1da360893..6b25e195232f1 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -3067,24 +3067,29 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state, { struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20; - bool use_mplla; + bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB; + bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB; int i; - use_mplla = intel_c20_use_mplla(mpll_hw_state->clock); - if (use_mplla) { - for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) { - I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i], - "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)", - crtc->base.base.id, crtc->base.name, i, - mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]); - } - } else { + I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb, + "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)", + crtc->base.base.id, crtc->base.name, + sw_use_mpllb, hw_use_mpllb); + + if (hw_use_mpllb) { for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) { I915_STATE_WARN(i915, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i], "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)", crtc->base.base.id, crtc->base.name, i, mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]); } + } else { + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) { + I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i], + "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]); + } } for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) { -- GitLab From 172516e153c9269e02cfd64f11df7142c482ffe2 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:40 +0200 Subject: [PATCH 0148/1420] drm/i915/display: Store hw clock for C20 We can calculate the hw port clock during the hw readout and store it as pll_state->clock for C20 state verification. In order to do that we need to move intel_c20pll_calc_port_clock() function. Signed-off-by: Mika Kahola Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20240102115741.118525-3-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 97 +++++++++++--------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6b25e195232f1..fc7211675b2f5 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2105,6 +2105,51 @@ static bool intel_c20_use_mplla(u32 clock) return false; } +static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) +{ + unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; + unsigned int multiplier, refclk = 38400; + unsigned int tx_clk_div; + unsigned int ref_clk_mpllb_div; + unsigned int fb_clk_div4_en; + unsigned int ref, vco; + unsigned int tx_rate_mult; + unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); + + if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + tx_rate_mult = 1; + frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); + frac_quot = pll_state->mpllb[8]; + frac_rem = pll_state->mpllb[9]; + frac_den = pll_state->mpllb[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); + fb_clk_div4_en = 0; + } else { + tx_rate_mult = 2; + frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); + frac_quot = pll_state->mplla[8]; + frac_rem = pll_state->mplla[9]; + frac_den = pll_state->mplla[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); + fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); + } + + if (frac_en) + frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); + else + frac = 0; + + ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); + vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); + + return vco << tx_rate_mult >> tx_clk_div >> tx_rate; +} + static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c20pll_state *pll_state) { @@ -2160,6 +2205,8 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, } } + pll_state->clock = intel_c20pll_calc_port_clock(encoder, pll_state); + intel_cx0_phy_transaction_end(encoder, wakeref); } @@ -2408,51 +2455,6 @@ static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } -static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) -{ - unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; - unsigned int multiplier, refclk = 38400; - unsigned int tx_clk_div; - unsigned int ref_clk_mpllb_div; - unsigned int fb_clk_div4_en; - unsigned int ref, vco; - unsigned int tx_rate_mult; - unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); - - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { - tx_rate_mult = 1; - frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); - frac_quot = pll_state->mpllb[8]; - frac_rem = pll_state->mpllb[9]; - frac_den = pll_state->mpllb[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); - fb_clk_div4_en = 0; - } else { - tx_rate_mult = 2; - frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); - frac_quot = pll_state->mplla[8]; - frac_rem = pll_state->mplla[9]; - frac_den = pll_state->mplla[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); - fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); - } - - if (frac_en) - frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); - else - frac = 0; - - ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); - vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); - - return vco << tx_rate_mult >> tx_clk_div >> tx_rate; -} - static void intel_program_port_clock_ctl(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, bool lane_reversal) @@ -3071,6 +3073,11 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state, bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB; int i; + I915_STATE_WARN(i915, mpll_hw_state->clock != mpll_sw_state->clock, + "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)", + crtc->base.base.id, crtc->base.name, + mpll_sw_state->clock, mpll_hw_state->clock); + I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb, "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)", crtc->base.base.id, crtc->base.name, -- GitLab From 2e13b5bb5e28a098eecd2b5f00d745b27f87e2e8 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:41 +0200 Subject: [PATCH 0149/1420] drm/i915/display: Cleanup mplla/mpllb selection The function intel_c20_use_mplla() is not really widely used and can be replaced with the more suitable pll->tx[0] & C20_PHY_USE_MPLLB expression. Let's remove the intel_c20_use_mplla() alltogether and replace mplla/mpllb selection by checking mpllb bit. Signed-off-by: Mika Kahola Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20240102115741.118525-4-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 39 ++++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index fc7211675b2f5..d0b6b4e439e15 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2096,15 +2096,6 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, return intel_c20pll_calc_state(crtc_state, encoder); } -static bool intel_c20_use_mplla(u32 clock) -{ - /* 10G and 20G rates use MPLLA */ - if (clock == 1000000 || clock == 2000000) - return true; - - return false; -} - static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_c20pll_state *pll_state) { @@ -2221,12 +2212,12 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n", hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]); - if (intel_c20_use_mplla(hw_state->clock)) { - for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) - drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); - } else { + if (hw_state->tx[0] & C20_PHY_USE_MPLLB) { for (i = 0; i < ARRAY_SIZE(hw_state->mpllb); i++) drm_dbg_kms(&i915->drm, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]); + } else { + for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) + drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); } } @@ -2373,27 +2364,27 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, } /* 3.3 mpllb or mplla configuration */ - if (intel_c20_use_mplla(clock)) { - for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { + if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_A_MPLLA_CNTX_CFG(i), - pll_state->mplla[i]); + PHY_C20_A_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); else intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_B_MPLLA_CNTX_CFG(i), - pll_state->mplla[i]); + PHY_C20_B_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); } } else { - for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { + for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_A_MPLLB_CNTX_CFG(i), - pll_state->mpllb[i]); + PHY_C20_A_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); else intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_B_MPLLB_CNTX_CFG(i), - pll_state->mpllb[i]); + PHY_C20_B_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); } } -- GitLab From 79b09453c4e369ca81cfb670d0136d089e3b92f0 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:48 +0100 Subject: [PATCH 0150/1420] drm/rockchip: lvds: do not overwrite error code ret variable stores the return value of drm_of_find_panel_or_bridge which can return error codes different from EPROBE_DEFER. Therefore, let's just return that error code instead of forcing it to EPROBE_DEFER. Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Cc: Quentin Schulz Signed-off-by: Quentin Schulz Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231120-rk-lvds-defer-msg-v2-1-9c59a5779cf9@theobroma-systems.com --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 59341654ec32b..6ecb6b8a1dcde 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -577,7 +577,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, goto err_put_port; } else if (ret) { DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); - ret = -EPROBE_DEFER; goto err_put_port; } if (lvds->panel) -- GitLab From 52d11c863ac92e36a0365249f7f6d27ac48c78bc Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:49 +0100 Subject: [PATCH 0151/1420] drm/rockchip: lvds: do not print scary message when probing defer This scary message can misled the user into thinking something bad has happened and needs to be fixed, however it could simply be part of a normal boot process where EPROBE_DEFER is taken into account. Therefore, let's use dev_err_probe so that this message doesn't get shown (by default) when the return code is EPROBE_DEFER. Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Cc: Quentin Schulz Signed-off-by: Quentin Schulz Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231120-rk-lvds-defer-msg-v2-2-9c59a5779cf9@theobroma-systems.com --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 6ecb6b8a1dcde..77b76cff1adb9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -576,7 +576,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, ret = -EINVAL; goto err_put_port; } else if (ret) { - DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); + dev_err_probe(dev, ret, "failed to find panel and bridge node\n"); goto err_put_port; } if (lvds->panel) -- GitLab From a1d91c6e989d0e66b89aa911f2cd459d7bdebbe5 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 19 Dec 2023 14:32:46 +0200 Subject: [PATCH 0152/1420] drm/i915/display: Skip C10 state verification in case of fastset PLL's are not programmed in case of fastset so the state verification compares bios programmed PLL values against sw PLL values. To overcome this limitation, we can skip the state verification for C10 in fastset case as the driver is not writing PLL values. Signed-off-by: Mika Kahola Reviewed-by: Radhakrishna Sripada Link: https://patchwork.freedesktop.org/patch/msgid/20231219123246.832245-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index d0b6b4e439e15..ce1bddf74a82d 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -3009,6 +3009,9 @@ static void intel_c10pll_state_verify(const struct intel_crtc_state *state, const struct intel_c10pll_state *mpllb_sw_state = &state->cx0pll_state.c10; int i; + if (intel_crtc_needs_fastset(state)) + return; + for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { u8 expected = mpllb_sw_state->pll[i]; -- GitLab From 65afd91e8d70e10c7f99126d61bf0045ef52d271 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:57 +0100 Subject: [PATCH 0153/1420] drm/panel: ltk050h3146w: only print message when GPIO getting is not EPROBE_DEFER devm_gpiod_get_optional may return EPROBE_DEFER in case the GPIO controller isn't yet probed when the panel driver is being probed. In that case, a spurious and confusing error message about not being able to get the reset GPIO is printed even though later on the device actually manages to get probed. Use dev_err_probe instead so that the message is only printed when it truly matters. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Christophe JAILLET Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240104-ltk-dev_err_probe-v1-1-8ef3c0b585d8@theobroma-systems.com --- drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 6e3670508e3a5..69e4b4c975581 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -646,10 +646,8 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return -EINVAL; ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ctx->reset_gpio); - } + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); if (IS_ERR(ctx->vci)) { -- GitLab From 056a9965e58e47928e8afd4dc017221f9221b3d3 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:58 +0100 Subject: [PATCH 0154/1420] drm/panel: ltk050h3146w: use dev_err_probe wherever possible This is only a cosmetic change. This replaces a hand-crafted EPROBE_DEFER handling for deciding to print an error message with dev_err_probe. A side-effect is that dev_err_probe also adds a debug message when it's not EPROBE_DEFER, but this is seen as an improvement. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Christophe JAILLET Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240104-ltk-dev_err_probe-v1-2-8ef3c0b585d8@theobroma-systems.com --- .../gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 69e4b4c975581..32ebedadbcdc3 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -650,20 +650,13 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); - if (IS_ERR(ctx->vci)) { - ret = PTR_ERR(ctx->vci); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request vci regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->vci)) + return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n"); ctx->iovcc = devm_regulator_get(dev, "iovcc"); - if (IS_ERR(ctx->iovcc)) { - ret = PTR_ERR(ctx->iovcc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(dev, PTR_ERR(ctx->iovcc), + "Failed to request iovcc regulator\n"); mipi_dsi_set_drvdata(dsi, ctx); -- GitLab From 9b0b61c5bc08e1aa55a0c1e7cda28f952b2d02cc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 3 Jan 2024 17:26:09 +0200 Subject: [PATCH 0155/1420] drm/i915/dp: Fix the PSR debugfs entries wrt. MST connectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MST connectors don't have a static attached encoder, as their encoder can change depending on the pipe they use; so the encoder for an MST connector can't be retrieved using intel_dp_attached_encoder() (which may return NULL for MST). Most of the PSR debugfs entries depend on a static connector -> encoder mapping which is only true for eDP and SST DP connectors and not for MST. These debugfs entries were enabled for MST connectors as well recently to provide PR information for them, but handling MST connectors needs more changes. Fix this by not adding for now the PSR entries on MST connectors. To make things more uniform add the entries for SST connectors on all platforms, not just on platforms supporting DP2.0. v2: - Keep adding the entries for SST connectors. (Jouni) - Add a TODO: comment for MST support. Fixes: ef75c25e8fed ("drm/i915/panelreplay: Debugfs support for panel replay") Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9850 Cc: Animesh Manna Cc: Jouni Högander Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20240103152609.2434100-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 494d08817d71e..54120b45958b0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -3310,11 +3310,11 @@ void intel_psr_connector_debugfs_add(struct intel_connector *connector) struct drm_i915_private *i915 = to_i915(connector->base.dev); struct dentry *root = connector->base.debugfs_entry; - if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) { - if (!(HAS_DP20(i915) && - connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort)) - return; - } + /* TODO: Add support for MST connectors as well. */ + if ((connector->base.connector_type != DRM_MODE_CONNECTOR_eDP && + connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) || + connector->mst_port) + return; debugfs_create_file("i915_psr_sink_status", 0444, root, connector, &i915_psr_sink_status_fops); -- GitLab From e130ba220da559a8eac60eb5ff60b0774ea17009 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 23:10:28 +0200 Subject: [PATCH 0156/1420] drm/edid: prefer forward declarations over includes in drm_edid.h There's no need to include either linux/hdmi.h or drm/drm_mode.h. They can be removed by using forward declarations. While at it, group the forward declarations together, and remove the unnecessary ones. Signed-off-by: Jani Nikula Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20240104211028.1129606-1-jani.nikula@intel.com --- include/drm/drm_edid.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 54cc6f04a7086..86c1812a8034e 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -24,11 +24,14 @@ #define __DRM_EDID_H__ #include -#include -#include +enum hdmi_quantization_range; +struct drm_connector; struct drm_device; +struct drm_display_mode; struct drm_edid; +struct hdmi_avi_infoframe; +struct hdmi_vendor_infoframe; struct i2c_adapter; #define EDID_LENGTH 128 @@ -319,11 +322,6 @@ struct cea_sad { u8 byte2; /* meaning depends on format */ }; -struct drm_encoder; -struct drm_connector; -struct drm_connector_state; -struct drm_display_mode; - int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads); int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb); int drm_av_sync_delay(struct drm_connector *connector, -- GitLab From de06b42edc5bf05aefbb7e2f59475d6022ed57e1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 18:46:00 +0200 Subject: [PATCH 0157/1420] drm/i915: don't make assumptions about intel_wakeref_t type intel_wakeref_t is supposed to be a mostly opaque cookie to its users. It should only be checked for being non-zero and set to zero. Debug logging its actual value is meaningless. Switch to just debug logging whether the async_put_wakeref is non-zero. The issue dates back to much earlier than commit b49e894c3fd8 ("drm/i915: Replace custom intel runtime_pm tracker with ref_tracker library"), but this is the one that brought about a build failure due to the printf format. Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/r/20240102111222.2db11208@canb.auug.org.au Fixes: b49e894c3fd8 ("drm/i915: Replace custom intel runtime_pm tracker with ref_tracker library") Cc: Andrzej Hajda Cc: Imre Deak Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Reviewed-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20240104164600.783371-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index f78bfcf2ce000..42da2af809769 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -405,8 +405,8 @@ print_async_put_domains_state(struct i915_power_domains *power_domains) struct drm_i915_private, display.power.domains); - drm_dbg(&i915->drm, "async_put_wakeref %lu\n", - power_domains->async_put_wakeref); + drm_dbg(&i915->drm, "async_put_wakeref: %s\n", + str_yes_no(power_domains->async_put_wakeref)); print_power_domains(power_domains, "async_put_domains[0]", &power_domains->async_put_domains[0]); -- GitLab From a133e35bc65007379b8fd58c02d8035396fe4be4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:46 +0200 Subject: [PATCH 0158/1420] drm/i915/irq: use DISPLAY_VER instead of GRAPHICS_VER Display code should not care about graphics version. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240104174350.823605-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 6964f4b95865f..99843883cef7c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1587,7 +1587,7 @@ void ilk_de_irq_postinstall(struct drm_i915_private *i915) struct intel_uncore *uncore = &i915->uncore; u32 display_mask, extra_mask; - if (GRAPHICS_VER(i915) >= 7) { + if (DISPLAY_VER(i915) >= 7) { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB); extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | -- GitLab From 102971422e578c55381e0f5e38577293bbf8d919 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:47 +0200 Subject: [PATCH 0159/1420] drm/i915/dmc: use DISPLAY_VER instead of GRAPHICS_VER Display code should not care about graphics version. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240104174350.823605-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b70502586ab98..8357816244829 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1158,7 +1158,7 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) str_yes_no(intel_dmc_has_payload(i915))); seq_printf(m, "path: %s\n", dmc ? dmc->fw_path : "N/A"); seq_printf(m, "Pipe A fw needed: %s\n", - str_yes_no(GRAPHICS_VER(i915) >= 12)); + str_yes_no(DISPLAY_VER(i915) >= 12)); seq_printf(m, "Pipe A fw loaded: %s\n", str_yes_no(has_dmc_id_fw(i915, DMC_FW_PIPEA))); seq_printf(m, "Pipe B fw needed: %s\n", -- GitLab From fbfb125c849282b00c130f5497bd51e1a76037c8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:48 +0200 Subject: [PATCH 0160/1420] drm/i915/hdcp: use DISPLAY_VER instead of GRAPHICS_VER Display code should not care about graphics version. While at it, abstract the version check to a separate macro. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240104174350.823605-3-jani.nikula@intel.com --- .../gpu/drm/i915/display/intel_hdcp_regs.h | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h index 8023c85c7fa0e..a568a457e5326 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h @@ -8,6 +8,8 @@ #include "intel_display_reg_defs.h" +#define TRANS_HDCP(__i915) (DISPLAY_VER(__i915) >= 12) + /* HDCP Key Registers */ #define HDCP_KEY_CONF _MMIO(0x66c00) #define HDCP_AKSV_SEND_TRIGGER REG_BIT(31) @@ -82,7 +84,7 @@ #define TRANS_HDCP_CONF(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_CONF, \ _TRANSB_HDCP_CONF) #define HDCP_CONF(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_CONF(trans) : \ PORT_HDCP_CONF(port)) @@ -95,7 +97,7 @@ _TRANSA_HDCP_ANINIT, \ _TRANSB_HDCP_ANINIT) #define HDCP_ANINIT(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANINIT(trans) : \ PORT_HDCP_ANINIT(port)) @@ -105,7 +107,7 @@ #define TRANS_HDCP_ANLO(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANLO, \ _TRANSB_HDCP_ANLO) #define HDCP_ANLO(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANLO(trans) : \ PORT_HDCP_ANLO(port)) @@ -115,7 +117,7 @@ #define TRANS_HDCP_ANHI(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANHI, \ _TRANSB_HDCP_ANHI) #define HDCP_ANHI(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANHI(trans) : \ PORT_HDCP_ANHI(port)) @@ -126,7 +128,7 @@ _TRANSA_HDCP_BKSVLO, \ _TRANSB_HDCP_BKSVLO) #define HDCP_BKSVLO(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_BKSVLO(trans) : \ PORT_HDCP_BKSVLO(port)) @@ -137,7 +139,7 @@ _TRANSA_HDCP_BKSVHI, \ _TRANSB_HDCP_BKSVHI) #define HDCP_BKSVHI(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_BKSVHI(trans) : \ PORT_HDCP_BKSVHI(port)) @@ -148,7 +150,7 @@ _TRANSA_HDCP_RPRIME, \ _TRANSB_HDCP_RPRIME) #define HDCP_RPRIME(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_RPRIME(trans) : \ PORT_HDCP_RPRIME(port)) @@ -159,7 +161,7 @@ _TRANSA_HDCP_STATUS, \ _TRANSB_HDCP_STATUS) #define HDCP_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_STATUS(trans) : \ PORT_HDCP_STATUS(port)) @@ -200,7 +202,7 @@ #define AUTH_FORCE_CLR_INPUTCTR REG_BIT(19) #define AUTH_CLR_KEYS REG_BIT(18) #define HDCP2_AUTH(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_AUTH(trans) : \ PORT_HDCP2_AUTH(port)) @@ -211,7 +213,7 @@ _TRANSB_HDCP2_CTL) #define CTL_LINK_ENCRYPTION_REQ REG_BIT(31) #define HDCP2_CTL(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_CTL(trans) : \ PORT_HDCP2_CTL(port)) @@ -225,7 +227,7 @@ #define LINK_AUTH_STATUS REG_BIT(21) #define LINK_ENCRYPTION_STATUS REG_BIT(20) #define HDCP2_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_STATUS(trans) : \ PORT_HDCP2_STATUS(port)) @@ -247,7 +249,7 @@ #define STREAM_ENCRYPTION_STATUS REG_BIT(31) #define STREAM_TYPE_STATUS REG_BIT(30) #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_STREAM_STATUS(trans) : \ PIPE_HDCP2_STREAM_STATUS(pipe)) @@ -263,7 +265,7 @@ _TRANSB_HDCP2_AUTH_STREAM) #define AUTH_STREAM_TYPE REG_BIT(31) #define HDCP2_AUTH_STREAM(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_AUTH_STREAM(trans) : \ PORT_HDCP2_AUTH_STREAM(port)) -- GitLab From ee3c386e4bee2cae6fc88defd15052e3f4c3e18b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:49 +0200 Subject: [PATCH 0161/1420] drm/i915/display: use IS_DISPLAY_VER instead of IS_GRAPHICS_VER Display code should not care about graphics version. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240104174350.823605-4-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 0b522c6a8d6f5..c02d79b50006c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1012,7 +1012,7 @@ static void __intel_display_device_info_runtime_init(struct drm_i915_private *i9 goto display_fused_off; } - if (IS_GRAPHICS_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) { + if (IS_DISPLAY_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) { u32 fuse_strap = intel_de_read(i915, FUSE_STRAP); u32 sfuse_strap = intel_de_read(i915, SFUSE_STRAP); -- GitLab From 39c9f38e1ad36d4f87e5506806001543cf4274ec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:50 +0200 Subject: [PATCH 0162/1420] drm/i915/tv: use DISPLAY_VER instead of GRAPHICS_VER Display code should not care about graphics version. It's only comments here, but update anyway. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240104174350.823605-5-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_tv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index d4386cb3569e0..9a217805d2f6f 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1327,7 +1327,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, * the active portion. Hence following this formula seems * more trouble that it's worth. * - * if (GRAPHICS_VER(dev_priv) == 4) { + * if (DISPLAY_VER(dev_priv) == 4) { * num = cdclk * (tv_mode->oversample >> !tv_mode->progressive); * den = tv_mode->clock; * } else { -- GitLab From c27f010aa1884276ee5dae72034d84987060c769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 4 Jan 2024 08:24:09 -0800 Subject: [PATCH 0163/1420] drm/i915: Disable DSB in Xe KMD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Often getting DSB overflows when starting Xorg or Wayland compositors when running Xe KMD. Issue was reported but nothing was done, so disabling DSB as whole until properly fixed in Xe KMD. v2: - move check to HAS_DSB(Jani) v3: - use IS_ENABLED(I915) check in intel_dsb_prepare() Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/989 Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/1031 Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/1072 Cc: Animesh Manna Cc: Rodrigo Vivi Cc: Jani Nikula Cc: Francois Dugast Reviewed-by: Jani Nikula Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20240104162411.56085-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_dsb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 482c28b5c2de5..a6c7122fd671d 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -453,6 +453,10 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, if (!HAS_DSB(i915)) return NULL; + /* TODO: DSB is broken in Xe KMD, so disabling it until fixed */ + if (!IS_ENABLED(I915)) + return NULL; + dsb = kzalloc(sizeof(*dsb), GFP_KERNEL); if (!dsb) goto out; -- GitLab From fe761f3465c00f372cb4acb004579c7c377ae08b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 18:46:00 +0200 Subject: [PATCH 0164/1420] drm/i915: don't make assumptions about intel_wakeref_t type intel_wakeref_t is supposed to be a mostly opaque cookie to its users. It should only be checked for being non-zero and set to zero. Debug logging its actual value is meaningless. Switch to just debug logging whether the async_put_wakeref is non-zero. The issue dates back to much earlier than commit b49e894c3fd8 ("drm/i915: Replace custom intel runtime_pm tracker with ref_tracker library"), but this is the one that brought about a build failure due to the printf format. Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/r/20240102111222.2db11208@canb.auug.org.au Fixes: b49e894c3fd8 ("drm/i915: Replace custom intel runtime_pm tracker with ref_tracker library") Cc: Andrzej Hajda Cc: Imre Deak Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Reviewed-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20240104164600.783371-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index f23080a4368dd..6fd4fa52253a3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -405,8 +405,8 @@ print_async_put_domains_state(struct i915_power_domains *power_domains) struct drm_i915_private, display.power.domains); - drm_dbg(&i915->drm, "async_put_wakeref %u\n", - power_domains->async_put_wakeref); + drm_dbg(&i915->drm, "async_put_wakeref: %s\n", + str_yes_no(power_domains->async_put_wakeref)); print_power_domains(power_domains, "async_put_domains[0]", &power_domains->async_put_domains[0]); -- GitLab From fdbadf504375886a0320ac6f84c850322a6b32e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 4 Jan 2024 08:18:32 -0800 Subject: [PATCH 0165/1420] drm/xe: Fix definition of intel_wakeref_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915 defines it as unsigned long so Xe should do the same to avoid compilation warnings: CC [M] drivers/gpu/drm/i915/i915_gem.o CC [M] drivers/gpu/drm/xe/i915-display/intel_display_power_well.o In file included from ./include/drm/drm_mm.h:51, from drivers/gpu/drm/xe/xe_bo_types.h:11, from drivers/gpu/drm/xe/xe_bo.h:11, from ./drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h:11, from ./drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h:15, from drivers/gpu/drm/i915/display/intel_display_power.c:8: drivers/gpu/drm/i915/display/intel_display_power.c: In function ‘print_async_put_domains_state’: drivers/gpu/drm/i915/display/intel_display_power.c:408:29: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 5 has type ‘int’ [-Wformat=] 408 | drm_dbg(&i915->drm, "async_put_wakeref %lu\n", | ^~~~~~~~~~~~~~~~~~~~~~~~~ 409 | power_domains->async_put_wakeref); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | int ./include/drm/drm_print.h:410:39: note: in definition of macro ‘drm_dev_dbg’ 410 | __drm_dev_dbg(NULL, dev, cat, fmt, ##__VA_ARGS__) | ^~~ ./include/drm/drm_print.h:510:33: note: in expansion of macro ‘drm_dbg_driver’ 510 | #define drm_dbg(drm, fmt, ...) drm_dbg_driver(drm, fmt, ##__VA_ARGS__) | ^~~~~~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_power.c:408:9: note: in expansion of macro ‘drm_dbg’ 408 | drm_dbg(&i915->drm, "async_put_wakeref %lu\n", | ^~~~~~~ drivers/gpu/drm/i915/display/intel_display_power.c:408:50: note: format string is defined here 408 | drm_dbg(&i915->drm, "async_put_wakeref %lu\n", | ~~^ | | | long unsigned int | %u CC [M] drivers/gpu/drm/i915/i915_gem_evict.o CC [M] drivers/gpu/drm/i915/i915_gem_gtt.o CC [M] drivers/gpu/drm/xe/i915-display/intel_display_trace.o CC [M] drivers/gpu/drm/xe/i915-display/intel_display_wa.o CC [M] drivers/gpu/drm/i915/i915_query.o Fixes: 44e694958b95 ("drm/xe/display: Implement display support") Cc: Maarten Lankhorst Reviewed-by: Jani Nikula Signed-off-by: José Roberto de Souza --- drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h index 1c5e30cf10caa..ecb1c07077069 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h @@ -5,4 +5,4 @@ #include -typedef bool intel_wakeref_t; +typedef unsigned long intel_wakeref_t; -- GitLab From 9bab383d47c934ff550f31b3e05b4509fa6136bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 4 Jan 2024 08:18:41 -0800 Subject: [PATCH 0166/1420] drm/xe: Use intel_wakeref_t in intel_runtime_pm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now intel_wakeref_t is a unsigned long and Xe KMD version of those functions should use the same type, so changing from bool to intel_wakeref_t. Cc: Maarten Lankhorst Reviewed-by: Jani Nikula Signed-off-by: José Roberto de Souza --- drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h index 5d2a77b52db41..420eba0e4be00 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h @@ -162,18 +162,18 @@ static inline struct drm_i915_private *kdev_to_i915(struct device *kdev) #include "intel_wakeref.h" -static inline bool intel_runtime_pm_get(struct xe_runtime_pm *pm) +static inline intel_wakeref_t intel_runtime_pm_get(struct xe_runtime_pm *pm) { struct xe_device *xe = container_of(pm, struct xe_device, runtime_pm); if (xe_pm_runtime_get(xe) < 0) { xe_pm_runtime_put(xe); - return false; + return 0; } - return true; + return 1; } -static inline bool intel_runtime_pm_get_if_in_use(struct xe_runtime_pm *pm) +static inline intel_wakeref_t intel_runtime_pm_get_if_in_use(struct xe_runtime_pm *pm) { struct xe_device *xe = container_of(pm, struct xe_device, runtime_pm); @@ -187,7 +187,7 @@ static inline void intel_runtime_pm_put_unchecked(struct xe_runtime_pm *pm) xe_pm_runtime_put(xe); } -static inline void intel_runtime_pm_put(struct xe_runtime_pm *pm, bool wakeref) +static inline void intel_runtime_pm_put(struct xe_runtime_pm *pm, intel_wakeref_t wakeref) { if (wakeref) intel_runtime_pm_put_unchecked(pm); -- GitLab From 0cfb7caefabd740a13ae0c26d092641a5ac7e785 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:22 +0100 Subject: [PATCH 0167/1420] drm/xe: Allocate dedicated workqueue for SR-IOV workers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We plan to use several workers where we might be running long operations. Allocate dedicated workqueue to avoid undesired interaction with non-virtualized workers. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-2-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_device.c | 4 ++++ drivers/gpu/drm/xe/xe_device_types.h | 2 ++ drivers/gpu/drm/xe/xe_sriov.c | 32 ++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_sriov.h | 1 + 4 files changed, 39 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 86867d42d5329..004e65544e8d8 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -438,6 +438,10 @@ int xe_device_probe(struct xe_device *xe) xe_pat_init_early(xe); + err = xe_sriov_init(xe); + if (err) + return err; + xe->info.mem_region_mask = 1; err = xe_display_init_nommio(xe); if (err) diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 71f23ac365e66..163d889d407bc 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -321,6 +321,8 @@ struct xe_device { struct { /** @sriov.__mode: SR-IOV mode (Don't access directly!) */ enum xe_sriov_mode __mode; + /** @sriov.wq: workqueue used by the virtualization workers */ + struct workqueue_struct *wq; } sriov; /** @clients: drm clients info */ diff --git a/drivers/gpu/drm/xe/xe_sriov.c b/drivers/gpu/drm/xe/xe_sriov.c index 42a0e0c917a09..f295d91886b12 100644 --- a/drivers/gpu/drm/xe/xe_sriov.c +++ b/drivers/gpu/drm/xe/xe_sriov.c @@ -3,6 +3,8 @@ * Copyright © 2023 Intel Corporation */ +#include + #include "xe_assert.h" #include "xe_sriov.h" @@ -53,3 +55,33 @@ void xe_sriov_probe_early(struct xe_device *xe, bool has_sriov) drm_info(&xe->drm, "Running in %s mode\n", xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); } + +static void fini_sriov(struct drm_device *drm, void *arg) +{ + struct xe_device *xe = arg; + + destroy_workqueue(xe->sriov.wq); + xe->sriov.wq = NULL; +} + +/** + * xe_sriov_init - Initialize SR-IOV specific data. + * @xe: the &xe_device to initialize + * + * In this function we create dedicated workqueue that will be used + * by the SR-IOV specific workers. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_sriov_init(struct xe_device *xe) +{ + if (!IS_SRIOV(xe)) + return 0; + + xe_assert(xe, !xe->sriov.wq); + xe->sriov.wq = alloc_workqueue("xe-sriov-wq", 0, 0); + if (!xe->sriov.wq) + return -ENOMEM; + + return drmm_add_action_or_reset(&xe->drm, fini_sriov, xe); +} diff --git a/drivers/gpu/drm/xe/xe_sriov.h b/drivers/gpu/drm/xe/xe_sriov.h index 5af73a3172b03..1545552162c9e 100644 --- a/drivers/gpu/drm/xe/xe_sriov.h +++ b/drivers/gpu/drm/xe/xe_sriov.h @@ -13,6 +13,7 @@ const char *xe_sriov_mode_to_string(enum xe_sriov_mode mode); void xe_sriov_probe_early(struct xe_device *xe, bool has_sriov); +int xe_sriov_init(struct xe_device *xe); static inline enum xe_sriov_mode xe_device_sriov_mode(struct xe_device *xe) { -- GitLab From b97d87039fe5a2fc91feb9f42c5b443ad0927864 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:23 +0100 Subject: [PATCH 0168/1420] drm/xe: Define Virtual Function Identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the PCI Express specification, the SR-IOV Virtual Functions (VFs) are numbered starting with 1 (VF1, VF2, ...). Additionally, both driver and GuC will refer to Physical Function (PF) as VF0. Define helper macro to represent VFn and PF. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-3-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_sriov_types.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_sriov_types.h b/drivers/gpu/drm/xe/xe_sriov_types.h index 999a4311b98bf..1a138108d1395 100644 --- a/drivers/gpu/drm/xe/xe_sriov_types.h +++ b/drivers/gpu/drm/xe/xe_sriov_types.h @@ -8,6 +8,18 @@ #include +/** + * VFID - Virtual Function Identifier + * @n: VF number + * + * Helper macro to represent Virtual Function (VF) Identifier. + * VFID(0) is used as alias to the PFID that represents Physical Function. + * + * Note: According to PCI spec, SR-IOV VF's numbers are 1-based (VF1, VF2, ...). + */ +#define VFID(n) (n) +#define PFID VFID(0) + /** * enum xe_sriov_mode - SR-IOV mode * @XE_SRIOV_MODE_NONE: bare-metal mode (non-virtualized) -- GitLab From 13f976ea62208d64d2f324bce27f79c574394caf Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:24 +0100 Subject: [PATCH 0169/1420] drm/xe: Introduce GT-oriented SR-IOV logging macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify logging and help identify SR-IOV specific messages related to the GT, define set of helper macros that will add prefix to the messages based on the current SR-IOV mode. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-4-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_gt_sriov_printk.h | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_gt_sriov_printk.h diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_printk.h b/drivers/gpu/drm/xe/xe_gt_sriov_printk.h new file mode 100644 index 0000000000000..17624b16300ad --- /dev/null +++ b/drivers/gpu/drm/xe/xe_gt_sriov_printk.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_GT_SRIOV_PRINTK_H_ +#define _XE_GT_SRIOV_PRINTK_H_ + +#include "xe_gt_printk.h" +#include "xe_sriov_printk.h" + +#define __xe_gt_sriov_printk(gt, _level, fmt, ...) \ + xe_gt_printk((gt), _level, "%s" fmt, xe_sriov_printk_prefix(gt_to_xe(gt)), ##__VA_ARGS__) + +#define xe_gt_sriov_err(_gt, _fmt, ...) \ + __xe_gt_sriov_printk(_gt, err, _fmt, ##__VA_ARGS__) + +#define xe_gt_sriov_notice(_gt, _fmt, ...) \ + __xe_gt_sriov_printk(_gt, notice, _fmt, ##__VA_ARGS__) + +#define xe_gt_sriov_info(_gt, _fmt, ...) \ + __xe_gt_sriov_printk(_gt, info, _fmt, ##__VA_ARGS__) + +#define xe_gt_sriov_dbg(_gt, _fmt, ...) \ + __xe_gt_sriov_printk(_gt, dbg, _fmt, ##__VA_ARGS__) + +/* for low level noisy debug messages */ +#ifdef CONFIG_DRM_XE_DEBUG_SRIOV +#define xe_gt_sriov_dbg_verbose(_gt, _fmt, ...) xe_gt_sriov_dbg(_gt, _fmt, ##__VA_ARGS__) +#else +#define xe_gt_sriov_dbg_verbose(_gt, _fmt, ...) typecheck(struct xe_gt *, (_gt)) +#endif + +#endif -- GitLab From e6cbc458b4f875ce35610af635911d6926804c4c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:25 +0100 Subject: [PATCH 0170/1420] drm/xe/guc: Add helpers for HXG messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition to MMIO and CTB communication between the host driver and the GUC firmware, we will start using GuC HXG message protocol in communication between SR-IOV VFs and PF. Define helpers related to HXG message protocol to minimize code duplication. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-5-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_hxg_helpers.h | 108 ++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_guc_hxg_helpers.h diff --git a/drivers/gpu/drm/xe/xe_guc_hxg_helpers.h b/drivers/gpu/drm/xe/xe_guc_hxg_helpers.h new file mode 100644 index 0000000000000..aeeb573c6842e --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_hxg_helpers.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_GUC_HXG_HELPERS_H_ +#define _XE_GUC_HXG_HELPERS_H_ + +#include +#include + +#include "abi/guc_messages_abi.h" + +/** + * hxg_sizeof - Queries size of the object or type (in HXG units). + * @T: the object or type + * + * Force a compilation error if actual size is not aligned to HXG unit (u32). + * + * Return: size in dwords (u32). + */ +#define hxg_sizeof(T) (sizeof(T) / sizeof(u32) + BUILD_BUG_ON_ZERO(sizeof(T) % sizeof(u32))) + +static inline const char *guc_hxg_type_to_string(unsigned int type) +{ + switch (type) { + case GUC_HXG_TYPE_REQUEST: + return "request"; + case GUC_HXG_TYPE_FAST_REQUEST: + return "fast-request"; + case GUC_HXG_TYPE_EVENT: + return "event"; + case GUC_HXG_TYPE_NO_RESPONSE_BUSY: + return "busy"; + case GUC_HXG_TYPE_NO_RESPONSE_RETRY: + return "retry"; + case GUC_HXG_TYPE_RESPONSE_FAILURE: + return "failure"; + case GUC_HXG_TYPE_RESPONSE_SUCCESS: + return "response"; + default: + return ""; + } +} + +static inline bool guc_hxg_type_is_action(unsigned int type) +{ + switch (type) { + case GUC_HXG_TYPE_REQUEST: + case GUC_HXG_TYPE_FAST_REQUEST: + case GUC_HXG_TYPE_EVENT: + return true; + default: + return false; + } +} + +static inline bool guc_hxg_type_is_reply(unsigned int type) +{ + switch (type) { + case GUC_HXG_TYPE_NO_RESPONSE_BUSY: + case GUC_HXG_TYPE_NO_RESPONSE_RETRY: + case GUC_HXG_TYPE_RESPONSE_FAILURE: + case GUC_HXG_TYPE_RESPONSE_SUCCESS: + return true; + default: + return false; + } +} + +static inline u32 guc_hxg_msg_encode_success(u32 *msg, u32 data0) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) | + FIELD_PREP(GUC_HXG_RESPONSE_MSG_0_DATA0, data0); + + return GUC_HXG_RESPONSE_MSG_MIN_LEN; +} + +static inline u32 guc_hxg_msg_encode_failure(u32 *msg, u32 error, u32 hint) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_FAILURE) | + FIELD_PREP(GUC_HXG_FAILURE_MSG_0_HINT, hint) | + FIELD_PREP(GUC_HXG_FAILURE_MSG_0_ERROR, error); + + return GUC_HXG_FAILURE_MSG_LEN; +} + +static inline u32 guc_hxg_msg_encode_busy(u32 *msg, u32 counter) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_NO_RESPONSE_BUSY) | + FIELD_PREP(GUC_HXG_BUSY_MSG_0_COUNTER, counter); + + return GUC_HXG_BUSY_MSG_LEN; +} + +static inline u32 guc_hxg_msg_encode_retry(u32 *msg, u32 reason) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_NO_RESPONSE_RETRY) | + FIELD_PREP(GUC_HXG_RETRY_MSG_0_REASON, reason); + + return GUC_HXG_RETRY_MSG_LEN; +} + +#endif -- GitLab From e83679985ac73cca54259abaf7d55835c150bbe4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:26 +0100 Subject: [PATCH 0171/1420] drm/xe/guc: Update few GuC CTB ABI definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In upcoming new GuC ABI definitions we will want to refer to max number of dwords that could fit into CTB HXG message. Add explicit definition named as GUC_CTB_MAX_DWORDS and start using it. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-6-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h b/drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h index 3b83f907ece46..4aaed1cb4e125 100644 --- a/drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h +++ b/drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h @@ -81,12 +81,13 @@ static_assert(sizeof(struct guc_ct_buffer_desc) == 64); #define GUC_CTB_HDR_LEN 1u #define GUC_CTB_MSG_MIN_LEN GUC_CTB_HDR_LEN -#define GUC_CTB_MSG_MAX_LEN 256u +#define GUC_CTB_MSG_MAX_LEN (GUC_CTB_MSG_MIN_LEN + GUC_CTB_MAX_DWORDS) #define GUC_CTB_MSG_0_FENCE (0xffff << 16) #define GUC_CTB_MSG_0_FORMAT (0xf << 12) #define GUC_CTB_FORMAT_HXG 0u #define GUC_CTB_MSG_0_RESERVED (0xf << 8) #define GUC_CTB_MSG_0_NUM_DWORDS (0xff << 0) +#define GUC_CTB_MAX_DWORDS 255 /** * DOC: CTB HXG Message -- GitLab From fa6c12e036c9450c43782d52648bf0fb915a7bbb Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:27 +0100 Subject: [PATCH 0172/1420] drm/xe/guc: Add Relay Communication ABI definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The communication between Virtual Function (VF) drivers and Physical Function (PF) drivers is based on the GuC firmware acting as a proxy (relay) agent. Add related ABI definitions that we will be using in upcoming patches with our GuC Relay implementation. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-7-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- .../gpu/drm/xe/abi/guc_actions_sriov_abi.h | 174 ++++++++++++++++++ .../gpu/drm/xe/abi/guc_relay_actions_abi.h | 79 ++++++++ .../drm/xe/abi/guc_relay_communication_abi.h | 118 ++++++++++++ 3 files changed, 371 insertions(+) create mode 100644 drivers/gpu/drm/xe/abi/guc_actions_sriov_abi.h create mode 100644 drivers/gpu/drm/xe/abi/guc_relay_actions_abi.h create mode 100644 drivers/gpu/drm/xe/abi/guc_relay_communication_abi.h diff --git a/drivers/gpu/drm/xe/abi/guc_actions_sriov_abi.h b/drivers/gpu/drm/xe/abi/guc_actions_sriov_abi.h new file mode 100644 index 0000000000000..5496a5890847d --- /dev/null +++ b/drivers/gpu/drm/xe/abi/guc_actions_sriov_abi.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _GUC_ACTIONS_PF_ABI_H +#define _GUC_ACTIONS_PF_ABI_H + +#include "guc_communication_ctb_abi.h" + +/** + * DOC: GUC2PF_RELAY_FROM_VF + * + * This message is used by the GuC firmware to forward a VF2PF `Relay Message`_ + * received from the Virtual Function (VF) driver to this Physical Function (PF) + * driver. + * + * This message is always sent as `CTB HXG Message`_. + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:16 | MBZ | + * | +-------+--------------------------------------------------------------+ + * | | 15:0 | ACTION = _`XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF` = 0x5100 | + * +---+-------+--------------------------------------------------------------+ + * | 1 | 31:0 | **VFID** - source VF identifier | + * +---+-------+--------------------------------------------------------------+ + * | 2 | 31:0 | **RELAY_ID** - VF/PF message ID | + * +---+-------+-----------------+--------------------------------------------+ + * | 3 | 31:0 | **RELAY_DATA1** | | + * +---+-------+-----------------+ | + * |...| | | [Embedded `Relay Message`_] | + * +---+-------+-----------------+ | + * | n | 31:0 | **RELAY_DATAx** | | + * +---+-------+-----------------+--------------------------------------------+ + */ +#define XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF 0x5100 + +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 2u) +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN \ + (GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN) +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0 +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_2_RELAY_ID GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_3_RELAY_DATA1 GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_n_RELAY_DATAx GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN + +/** + * DOC: PF2GUC_RELAY_TO_VF + * + * This H2G message is used by the Physical Function (PF) driver to send embedded + * VF2PF `Relay Message`_ to the VF. + * + * This action message must be sent over CTB as `CTB HXG Message`_. + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = `GUC_HXG_TYPE_FAST_REQUEST`_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:16 | MBZ | + * | +-------+--------------------------------------------------------------+ + * | | 15:0 | ACTION = _`XE_GUC_ACTION_PF2GUC_RELAY_TO_VF` = 0x5101 | + * +---+-------+--------------------------------------------------------------+ + * | 1 | 31:0 | **VFID** - target VF identifier | + * +---+-------+--------------------------------------------------------------+ + * | 2 | 31:0 | **RELAY_ID** - VF/PF message ID | + * +---+-------+-----------------+--------------------------------------------+ + * | 3 | 31:0 | **RELAY_DATA1** | | + * +---+-------+-----------------+ | + * |...| | | [Embedded `Relay Message`_] | + * +---+-------+-----------------+ | + * | n | 31:0 | **RELAY_DATAx** | | + * +---+-------+-----------------+--------------------------------------------+ + */ +#define XE_GUC_ACTION_PF2GUC_RELAY_TO_VF 0x5101 + +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 2u) +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_MAX_LEN \ + (PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN) +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0 +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_1_VFID GUC_HXG_REQUEST_MSG_n_DATAn +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_2_RELAY_ID GUC_HXG_REQUEST_MSG_n_DATAn +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_3_RELAY_DATA1 GUC_HXG_REQUEST_MSG_n_DATAn +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_n_RELAY_DATAx GUC_HXG_REQUEST_MSG_n_DATAn +#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN + +/** + * DOC: GUC2VF_RELAY_FROM_PF + * + * This message is used by the GuC firmware to deliver `Relay Message`_ from the + * Physical Function (PF) driver to this Virtual Function (VF) driver. + * See `GuC Relay Communication`_ for details. + * + * This message is always sent over CTB. + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:16 | MBZ | + * | +-------+--------------------------------------------------------------+ + * | | 15:0 | ACTION = _`XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF` = 0x5102 | + * +---+-------+--------------------------------------------------------------+ + * | 1 | 31:0 | **RELAY_ID** - VF/PF message ID | + * +---+-------+-----------------+--------------------------------------------+ + * | 2 | 31:0 | **RELAY_DATA1** | | + * +---+-------+-----------------+ | + * |...| | | [Embedded `Relay Message`_] | + * +---+-------+-----------------+ | + * | n | 31:0 | **RELAY_DATAx** | | + * +---+-------+-----------------+--------------------------------------------+ + */ +#define XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF 0x5102 + +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 1u) +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN \ + (GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN) +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0 +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_1_RELAY_ID GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_n_RELAY_DATAx GUC_HXG_EVENT_MSG_n_DATAn +#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN + +/** + * DOC: VF2GUC_RELAY_TO_PF + * + * This message is used by the Virtual Function (VF) drivers to communicate with + * the Physical Function (PF) driver and send `Relay Message`_ to the PF driver. + * See `GuC Relay Communication`_ for details. + * + * This message must be sent over CTB. + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ or GUC_HXG_TYPE_FAST_REQUEST_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:16 | MBZ | + * | +-------+--------------------------------------------------------------+ + * | | 15:0 | ACTION = _`XE_GUC_ACTION_VF2GUC_RELAY_TO_PF` = 0x5103 | + * +---+-------+--------------------------------------------------------------+ + * | 1 | 31:0 | **RELAY_ID** - VF/PF message ID | + * +---+-------+-----------------+--------------------------------------------+ + * | 2 | 31:0 | **RELAY_DATA1** | | + * +---+-------+-----------------+ | + * |...| | | [Embedded `Relay Message`_] | + * +---+-------+-----------------+ | + * | n | 31:0 | **RELAY_DATAx** | | + * +---+-------+-----------------+--------------------------------------------+ + */ +#define XE_GUC_ACTION_VF2GUC_RELAY_TO_PF 0x5103 + +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 1u) +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_MAX_LEN \ + (VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN) +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0 +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_1_RELAY_ID GUC_HXG_REQUEST_MSG_n_DATAn +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_n_RELAY_DATAx GUC_HXG_REQUEST_MSG_n_DATAn +#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN + +#endif diff --git a/drivers/gpu/drm/xe/abi/guc_relay_actions_abi.h b/drivers/gpu/drm/xe/abi/guc_relay_actions_abi.h new file mode 100644 index 0000000000000..747e428de421f --- /dev/null +++ b/drivers/gpu/drm/xe/abi/guc_relay_actions_abi.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _ABI_GUC_RELAY_ACTIONS_ABI_H_ +#define _ABI_GUC_RELAY_ACTIONS_ABI_H_ + +/** + * DOC: GuC Relay Debug Actions + * + * This range of action codes is reserved for debugging purposes only and should + * be used only on debug builds. These actions may not be supported by the + * production drivers. Their definitions could be changed in the future. + * + * _`GUC_RELAY_ACTION_DEBUG_ONLY_START` = 0xDEB0 + * _`GUC_RELAY_ACTION_DEBUG_ONLY_END` = 0xDEFF + */ + +#define GUC_RELAY_ACTION_DEBUG_ONLY_START 0xDEB0 +#define GUC_RELAY_ACTION_DEBUG_ONLY_END 0xDEFF + +/** + * DOC: VFXPF_TESTLOOP + * + * This `Relay Message`_ is used to selftest the `GuC Relay Communication`_. + * + * The following opcodes are defined: + * VFXPF_TESTLOOP_OPCODE_NOP_ will return no data. + * VFXPF_TESTLOOP_OPCODE_BUSY_ will reply with BUSY response first. + * VFXPF_TESTLOOP_OPCODE_RETRY_ will reply with RETRY response instead. + * VFXPF_TESTLOOP_OPCODE_ECHO_ will return same data as received. + * VFXPF_TESTLOOP_OPCODE_FAIL_ will always fail with error. + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ or GUC_HXG_TYPE_FAST_REQUEST_ | + * | | | or GUC_HXG_TYPE_EVENT_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:16 | **OPCODE** | + * | | | - _`VFXPF_TESTLOOP_OPCODE_NOP` = 0x0 | + * | | | - _`VFXPF_TESTLOOP_OPCODE_BUSY` = 0xB | + * | | | - _`VFXPF_TESTLOOP_OPCODE_RETRY` = 0xD | + * | | | - _`VFXPF_TESTLOOP_OPCODE_ECHO` = 0xE | + * | | | - _`VFXPF_TESTLOOP_OPCODE_FAIL` = 0xF | + * | +-------+--------------------------------------------------------------+ + * | | 15:0 | ACTION = _`IOV_ACTION_SELFTEST_RELAY` | + * +---+-------+--------------------------------------------------------------+ + * | 1 | 31:0 | **DATA1** = optional, depends on **OPCODE**: | + * | | | for VFXPF_TESTLOOP_OPCODE_BUSY_: time in ms for reply | + * | | | for VFXPF_TESTLOOP_OPCODE_FAIL_: expected error | + * | | | for VFXPF_TESTLOOP_OPCODE_ECHO_: payload | + * +---+-------+--------------------------------------------------------------+ + * |...| 31:0 | **DATAn** = only for **OPCODE** VFXPF_TESTLOOP_OPCODE_ECHO_ | + * +---+-------+--------------------------------------------------------------+ + * + * +---+-------+--------------------------------------------------------------+ + * | | Bits | Description | + * +===+=======+==============================================================+ + * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ | + * | +-------+--------------------------------------------------------------+ + * | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ | + * | +-------+--------------------------------------------------------------+ + * | | 27:0 | DATA0 = MBZ | + * +---+-------+--------------------------------------------------------------+ + * |...| 31:0 | DATAn = only for **OPCODE** VFXPF_TESTLOOP_OPCODE_ECHO_ | + * +---+-------+--------------------------------------------------------------+ + */ +#define GUC_RELAY_ACTION_VFXPF_TESTLOOP (GUC_RELAY_ACTION_DEBUG_ONLY_START + 1) +#define VFXPF_TESTLOOP_OPCODE_NOP 0x0 +#define VFXPF_TESTLOOP_OPCODE_BUSY 0xB +#define VFXPF_TESTLOOP_OPCODE_RETRY 0xD +#define VFXPF_TESTLOOP_OPCODE_ECHO 0xE +#define VFXPF_TESTLOOP_OPCODE_FAIL 0xF + +#endif diff --git a/drivers/gpu/drm/xe/abi/guc_relay_communication_abi.h b/drivers/gpu/drm/xe/abi/guc_relay_communication_abi.h new file mode 100644 index 0000000000000..f92625f047967 --- /dev/null +++ b/drivers/gpu/drm/xe/abi/guc_relay_communication_abi.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _ABI_GUC_RELAY_COMMUNICATION_ABI_H +#define _ABI_GUC_RELAY_COMMUNICATION_ABI_H + +#include + +#include "guc_actions_sriov_abi.h" +#include "guc_communication_ctb_abi.h" +#include "guc_messages_abi.h" + +/** + * DOC: GuC Relay Communication + * + * The communication between Virtual Function (VF) drivers and Physical Function + * (PF) drivers is based on the GuC firmware acting as a proxy (relay) agent. + * + * To communicate with the PF driver, VF's drivers use `VF2GUC_RELAY_TO_PF`_ + * action that takes the `Relay Message`_ as opaque payload and requires the + * relay message identifier (RID) as additional parameter. + * + * This identifier is used by the drivers to match related messages. + * + * The GuC forwards this `Relay Message`_ and its identifier to the PF driver + * in `GUC2PF_RELAY_FROM_VF`_ action. This event message additionally contains + * the identifier of the origin VF (VFID). + * + * Likewise, to communicate with the VF drivers, PF driver use + * `VF2GUC_RELAY_TO_PF`_ action that in addition to the `Relay Message`_ + * and the relay message identifier (RID) also takes the target VF identifier. + * + * The GuC uses this target VFID from the message to select where to send the + * `GUC2VF_RELAY_FROM_PF`_ with the embedded `Relay Message`_ with response:: + * + * VF GuC PF + * | | | + * [ ] VF2GUC_RELAY_TO_PF | | + * [ ]---------------------------> [ ] | + * [ ] { rid, msg } [ ] | + * [ ] [ ] GUC2PF_RELAY_FROM_VF | + * [ ] [ ]---------------------------> [ ] + * [ ] | { VFID, rid, msg } [ ] + * [ ] | [ ] + * [ ] | PF2GUC_RELAY_TO_VF [ ] + * [ ] [ ] <---------------------------[ ] + * [ ] [ ] { VFID, rid, reply } | + * [ ] GUC2VF_RELAY_FROM_PF [ ] | + * [ ] <---------------------------[ ] | + * | { rid, reply } | | + * | | | + * + * It is also possible that PF driver will initiate communication with the + * selected VF driver. The same GuC action messages will be used:: + * + * VF GuC PF + * | | | + * | | PF2GUC_RELAY_TO_VF [ ] + * | [ ] <---------------------------[ ] + * | [ ] { VFID, rid, msg } [ ] + * | GUC2VF_RELAY_FROM_PF [ ] [ ] + * [ ] <---------------------------[ ] [ ] + * [ ] { rid, msg } | [ ] + * [ ] | [ ] + * [ ] VF2GUC_RELAY_TO_PF | [ ] + * [ ]---------------------------> [ ] [ ] + * | { rid, reply } [ ] [ ] + * | [ ] GUC2PF_RELAY_FROM_VF [ ] + * | [ ]---------------------------> [ ] + * | | { VFID, rid, reply } | + * | | | + */ + +/** + * DOC: Relay Message + * + * The `Relay Message`_ is used by Physical Function (PF) driver and Virtual + * Function (VF) drivers to communicate using `GuC Relay Communication`_. + * + * Format of the `Relay Message`_ follows format of the generic `HXG Message`_. + * + * +--------------------------------------------------------------------------+ + * | `Relay Message`_ | + * +==========================================================================+ + * | `HXG Message`_ | + * +--------------------------------------------------------------------------+ + * + * Maximum length of the `Relay Message`_ is limited by the maximum length of + * the `CTB HXG Message`_ and format of the `GUC2PF_RELAY_FROM_VF`_ message. + */ + +#define GUC_RELAY_MSG_MIN_LEN GUC_HXG_MSG_MIN_LEN +#define GUC_RELAY_MSG_MAX_LEN \ + (GUC_CTB_MAX_DWORDS - GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN) + +static_assert(PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN > + VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN); + +/** + * DOC: Relay Error Codes + * + * The `GuC Relay Communication`_ can be used to pass `Relay Message`_ between + * drivers that run on different Operating Systems. To help in troubleshooting, + * `GuC Relay Communication`_ uses error codes that mostly match errno values. + */ + +#define GUC_RELAY_ERROR_UNDISCLOSED 0 +#define GUC_RELAY_ERROR_OPERATION_NOT_PERMITTED 1 /* EPERM */ +#define GUC_RELAY_ERROR_PERMISSION_DENIED 13 /* EACCES */ +#define GUC_RELAY_ERROR_INVALID_ARGUMENT 22 /* EINVAL */ +#define GUC_RELAY_ERROR_INVALID_REQUEST_CODE 56 /* EBADRQC */ +#define GUC_RELAY_ERROR_NO_DATA_AVAILABLE 61 /* ENODATA */ +#define GUC_RELAY_ERROR_PROTOCOL_ERROR 71 /* EPROTO */ +#define GUC_RELAY_ERROR_MESSAGE_SIZE 90 /* EMSGSIZE */ + +#endif -- GitLab From 811fe9f556fcb281ea2db1b0fff3bab20f0a4d42 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:28 +0100 Subject: [PATCH 0173/1420] drm/xe/guc: Introduce Relay Communication for SR-IOV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are scenarios where SR-IOV Virtual Function (VF) driver will need to get additional data that is not available over VF MMIO BAR nor could be queried from the GuC firmware and must be obtained from the Physical Function (PF) driver. To allow such communication between VF and PF drivers, GuC supports set of H2G and G2H actions which allows relaying embedded messages, that are otherwise opaque for the GuC. To allow use of this communication mechanism, provide functions for sending requests and handling replies and placeholder where we will put handlers for incoming requests. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-8-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_guc.c | 5 + drivers/gpu/drm/xe/xe_guc_relay.c | 925 ++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_relay.h | 37 + drivers/gpu/drm/xe/xe_guc_relay_types.h | 36 + drivers/gpu/drm/xe/xe_guc_types.h | 4 + 6 files changed, 1008 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_guc_relay.c create mode 100644 drivers/gpu/drm/xe/xe_guc_relay.h create mode 100644 drivers/gpu/drm/xe/xe_guc_relay_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index df8601d6a59f0..6952da8979ea7 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -148,6 +148,7 @@ xe-$(CONFIG_HWMON) += xe_hwmon.o # graphics virtualization (SR-IOV) support xe-y += \ + xe_guc_relay.o \ xe_memirq.o \ xe_sriov.o diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 811e8b2012705..311a0364bff15 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -21,6 +21,7 @@ #include "xe_guc_hwconfig.h" #include "xe_guc_log.h" #include "xe_guc_pc.h" +#include "xe_guc_relay.h" #include "xe_guc_submit.h" #include "xe_memirq.h" #include "xe_mmio.h" @@ -263,6 +264,10 @@ int xe_guc_init(struct xe_guc *guc) if (ret) goto out; + ret = xe_guc_relay_init(&guc->relay); + if (ret) + goto out; + ret = xe_guc_pc_init(&guc->pc); if (ret) goto out; diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c new file mode 100644 index 0000000000000..0e73832564082 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -0,0 +1,925 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include + +#include + +#include "abi/guc_actions_sriov_abi.h" +#include "abi/guc_relay_actions_abi.h" +#include "abi/guc_relay_communication_abi.h" + +#include "xe_assert.h" +#include "xe_device.h" +#include "xe_gt.h" +#include "xe_gt_sriov_printk.h" +#include "xe_guc.h" +#include "xe_guc_ct.h" +#include "xe_guc_hxg_helpers.h" +#include "xe_guc_relay.h" +#include "xe_guc_relay_types.h" +#include "xe_sriov.h" + +/* + * How long should we wait for the response? + * XXX this value is subject for the profiling. + */ +#define RELAY_TIMEOUT_MSEC (2500) + +static void relays_worker_fn(struct work_struct *w); + +static struct xe_guc *relay_to_guc(struct xe_guc_relay *relay) +{ + return container_of(relay, struct xe_guc, relay); +} + +static struct xe_guc_ct *relay_to_ct(struct xe_guc_relay *relay) +{ + return &relay_to_guc(relay)->ct; +} + +static struct xe_gt *relay_to_gt(struct xe_guc_relay *relay) +{ + return guc_to_gt(relay_to_guc(relay)); +} + +static struct xe_device *relay_to_xe(struct xe_guc_relay *relay) +{ + return gt_to_xe(relay_to_gt(relay)); +} + +#define relay_assert(relay, condition) xe_gt_assert(relay_to_gt(relay), condition) +#define relay_notice(relay, msg...) xe_gt_sriov_notice(relay_to_gt(relay), "relay: " msg) +#define relay_debug(relay, msg...) xe_gt_sriov_dbg_verbose(relay_to_gt(relay), "relay: " msg) + +static int relay_get_totalvfs(struct xe_guc_relay *relay) +{ + struct xe_device *xe = relay_to_xe(relay); + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + + return IS_SRIOV_VF(xe) ? 0 : pci_sriov_get_totalvfs(pdev); +} + +static bool relay_is_ready(struct xe_guc_relay *relay) +{ + return mempool_initialized(&relay->pool); +} + +static u32 relay_get_next_rid(struct xe_guc_relay *relay) +{ + u32 rid; + + spin_lock(&relay->lock); + rid = ++relay->last_rid; + spin_unlock(&relay->lock); + + return rid; +} + +/** + * struct relay_transaction - internal data used to handle transactions + * + * Relation between struct relay_transaction members:: + * + * <-------------------- GUC_CTB_MAX_DWORDS --------------> + * <-------- GUC_RELAY_MSG_MAX_LEN ---> + * <--- offset ---> <--- request_len -------> + * +----------------+-------------------------+----------+--+ + * | | | | | + * +----------------+-------------------------+----------+--+ + * ^ ^ + * / / + * request_buf request + * + * <-------------------- GUC_CTB_MAX_DWORDS --------------> + * <-------- GUC_RELAY_MSG_MAX_LEN ---> + * <--- offset ---> <--- response_len ---> + * +----------------+----------------------+-------------+--+ + * | | | | | + * +----------------+----------------------+-------------+--+ + * ^ ^ + * / / + * response_buf response + */ +struct relay_transaction { + /** + * @incoming: indicates whether this transaction represents an incoming + * request from the remote VF/PF or this transaction + * represents outgoing request to the remote VF/PF. + */ + bool incoming; + + /** + * @remote: PF/VF identifier of the origin (or target) of the relay + * request message. + */ + u32 remote; + + /** @rid: identifier of the VF/PF relay message. */ + u32 rid; + + /** + * @request: points to the inner VF/PF request message, copied to the + * #response_buf starting at #offset. + */ + u32 *request; + + /** @request_len: length of the inner VF/PF request message. */ + u32 request_len; + + /** + * @response: points to the placeholder buffer where inner VF/PF + * response will be located, for outgoing transaction + * this could be caller's buffer (if provided) otherwise + * it points to the #response_buf starting at #offset. + */ + u32 *response; + + /** + * @response_len: length of the inner VF/PF response message (only + * if #status is 0), initially set to the size of the + * placeholder buffer where response message will be + * copied. + */ + u32 response_len; + + /** + * @offset: offset to the start of the inner VF/PF relay message inside + * buffers; this offset is equal the length of the outer GuC + * relay header message. + */ + u32 offset; + + /** + * @request_buf: buffer with VF/PF request message including outer + * transport message. + */ + u32 request_buf[GUC_CTB_MAX_DWORDS]; + + /** + * @response_buf: buffer with VF/PF response message including outer + * transport message. + */ + u32 response_buf[GUC_CTB_MAX_DWORDS]; + + /** + * @reply: status of the reply, 0 means that data pointed by the + * #response is valid. + */ + int reply; + + /** @done: completion of the outgoing transaction. */ + struct completion done; + + /** @link: transaction list link */ + struct list_head link; +}; + +static u32 prepare_pf2guc(u32 *msg, u32 target, u32 rid) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, XE_GUC_ACTION_PF2GUC_RELAY_TO_VF); + msg[1] = FIELD_PREP(PF2GUC_RELAY_TO_VF_REQUEST_MSG_1_VFID, target); + msg[2] = FIELD_PREP(PF2GUC_RELAY_TO_VF_REQUEST_MSG_2_RELAY_ID, rid); + + return PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN; +} + +static u32 prepare_vf2guc(u32 *msg, u32 rid) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, XE_GUC_ACTION_VF2GUC_RELAY_TO_PF); + msg[1] = FIELD_PREP(VF2GUC_RELAY_TO_PF_REQUEST_MSG_1_RELAY_ID, rid); + + return VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN; +} + +static struct relay_transaction * +__relay_get_transaction(struct xe_guc_relay *relay, bool incoming, u32 remote, u32 rid, + const u32 *action, u32 action_len, u32 *resp, u32 resp_size) +{ + struct relay_transaction *txn; + + relay_assert(relay, action_len >= GUC_RELAY_MSG_MIN_LEN); + relay_assert(relay, action_len <= GUC_RELAY_MSG_MAX_LEN); + relay_assert(relay, !(!!resp ^ !!resp_size)); + relay_assert(relay, resp_size <= GUC_RELAY_MSG_MAX_LEN); + relay_assert(relay, resp_size == 0 || resp_size >= GUC_RELAY_MSG_MIN_LEN); + + if (unlikely(!relay_is_ready(relay))) + return ERR_PTR(-ENODEV); + + /* + * For incoming requests we can't use GFP_KERNEL as those are delivered + * with CTB lock held which is marked as used in the reclaim path. + * Btw, that's one of the reason why we use mempool here! + */ + txn = mempool_alloc(&relay->pool, incoming ? GFP_ATOMIC : GFP_KERNEL); + if (!txn) + return ERR_PTR(-ENOMEM); + + txn->incoming = incoming; + txn->remote = remote; + txn->rid = rid; + txn->offset = remote ? + prepare_pf2guc(incoming ? txn->response_buf : txn->request_buf, remote, rid) : + prepare_vf2guc(incoming ? txn->response_buf : txn->request_buf, rid); + + relay_assert(relay, txn->offset); + relay_assert(relay, txn->offset + GUC_RELAY_MSG_MAX_LEN <= ARRAY_SIZE(txn->request_buf)); + relay_assert(relay, txn->offset + GUC_RELAY_MSG_MAX_LEN <= ARRAY_SIZE(txn->response_buf)); + + txn->request = txn->request_buf + txn->offset; + memcpy(&txn->request_buf[txn->offset], action, sizeof(u32) * action_len); + txn->request_len = action_len; + + txn->response = resp ?: txn->response_buf + txn->offset; + txn->response_len = resp_size ?: GUC_RELAY_MSG_MAX_LEN; + txn->reply = -ENOMSG; + INIT_LIST_HEAD(&txn->link); + init_completion(&txn->done); + + return txn; +} + +static struct relay_transaction * +relay_new_transaction(struct xe_guc_relay *relay, u32 target, const u32 *action, u32 len, + u32 *resp, u32 resp_size) +{ + u32 rid = relay_get_next_rid(relay); + + return __relay_get_transaction(relay, false, target, rid, action, len, resp, resp_size); +} + +static struct relay_transaction * +relay_new_incoming_transaction(struct xe_guc_relay *relay, u32 origin, u32 rid, + const u32 *action, u32 len) +{ + return __relay_get_transaction(relay, true, origin, rid, action, len, NULL, 0); +} + +static void relay_release_transaction(struct xe_guc_relay *relay, struct relay_transaction *txn) +{ + relay_assert(relay, list_empty(&txn->link)); + + txn->offset = 0; + txn->response = NULL; + txn->reply = -ESTALE; + mempool_free(txn, &relay->pool); +} + +static int relay_send_transaction(struct xe_guc_relay *relay, struct relay_transaction *txn) +{ + u32 len = txn->incoming ? txn->response_len : txn->request_len; + u32 *buf = txn->incoming ? txn->response_buf : txn->request_buf; + u32 *msg = buf + txn->offset; + int ret; + + relay_assert(relay, txn->offset); + relay_assert(relay, txn->offset + len <= GUC_CTB_MAX_DWORDS); + relay_assert(relay, len >= GUC_RELAY_MSG_MIN_LEN); + relay_assert(relay, len <= GUC_RELAY_MSG_MAX_LEN); + + relay_debug(relay, "sending %s.%u to %u = %*ph\n", + guc_hxg_type_to_string(FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0])), + txn->rid, txn->remote, (int)sizeof(u32) * len, msg); + + ret = xe_guc_ct_send_block(relay_to_ct(relay), buf, len + txn->offset); + + if (unlikely(ret > 0)) { + relay_notice(relay, "Unexpected data=%d from GuC, wrong ABI?\n", ret); + ret = -EPROTO; + } + if (unlikely(ret < 0)) { + relay_notice(relay, "Failed to send %s.%x to GuC (%pe) %*ph ...\n", + guc_hxg_type_to_string(FIELD_GET(GUC_HXG_MSG_0_TYPE, buf[0])), + FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, buf[0]), + ERR_PTR(ret), (int)sizeof(u32) * txn->offset, buf); + relay_notice(relay, "Failed to send %s.%u to %u (%pe) %*ph\n", + guc_hxg_type_to_string(FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0])), + txn->rid, txn->remote, ERR_PTR(ret), (int)sizeof(u32) * len, msg); + } + + return ret; +} + +static void __fini_relay(struct drm_device *drm, void *arg) +{ + struct xe_guc_relay *relay = arg; + + mempool_exit(&relay->pool); +} + +/** + * xe_guc_relay_init - Initialize a &xe_guc_relay + * @relay: the &xe_guc_relay to initialize + * + * Initialize remaining members of &xe_guc_relay that may depend + * on the SR-IOV mode. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_guc_relay_init(struct xe_guc_relay *relay) +{ + const int XE_RELAY_MEMPOOL_MIN_NUM = 1; + struct xe_device *xe = relay_to_xe(relay); + int err; + + relay_assert(relay, !relay_is_ready(relay)); + + if (!IS_SRIOV(xe)) + return 0; + + spin_lock_init(&relay->lock); + INIT_WORK(&relay->worker, relays_worker_fn); + INIT_LIST_HEAD(&relay->pending_relays); + INIT_LIST_HEAD(&relay->incoming_actions); + + err = mempool_init_kmalloc_pool(&relay->pool, XE_RELAY_MEMPOOL_MIN_NUM + + relay_get_totalvfs(relay), + sizeof(struct relay_transaction)); + if (err) + return err; + + relay_debug(relay, "using mempool with %d elements\n", relay->pool.min_nr); + + return drmm_add_action_or_reset(&xe->drm, __fini_relay, relay); +} + +static u32 to_relay_error(int err) +{ + /* XXX: assume that relay errors match errno codes */ + return err < 0 ? -err : GUC_RELAY_ERROR_UNDISCLOSED; +} + +static int from_relay_error(u32 error) +{ + /* XXX: assume that relay errors match errno codes */ + return error ? -error : -ENODATA; +} + +static u32 sanitize_relay_error(u32 error) +{ + /* XXX TBD if generic error codes will be allowed */ + if (!IS_ENABLED(CONFIG_DRM_XE_DEBUG)) + error = GUC_RELAY_ERROR_UNDISCLOSED; + return error; +} + +static u32 sanitize_relay_error_hint(u32 hint) +{ + /* XXX TBD if generic error codes will be allowed */ + if (!IS_ENABLED(CONFIG_DRM_XE_DEBUG)) + hint = 0; + return hint; +} + +static u32 prepare_error_reply(u32 *msg, u32 error, u32 hint) +{ + msg[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_FAILURE) | + FIELD_PREP(GUC_HXG_FAILURE_MSG_0_HINT, hint) | + FIELD_PREP(GUC_HXG_FAILURE_MSG_0_ERROR, error); + + XE_WARN_ON(!FIELD_FIT(GUC_HXG_FAILURE_MSG_0_ERROR, error)); + XE_WARN_ON(!FIELD_FIT(GUC_HXG_FAILURE_MSG_0_HINT, hint)); + + return GUC_HXG_FAILURE_MSG_LEN; +} + +static int relay_send_message_and_wait(struct xe_guc_relay *relay, + struct relay_transaction *txn, + u32 *buf, u32 buf_size) +{ + unsigned long timeout = msecs_to_jiffies(RELAY_TIMEOUT_MSEC); + u32 *msg = &txn->request_buf[txn->offset]; + u32 len = txn->request_len; + u32 type, action, data0; + int ret; + long n; + + type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + action = FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]); + data0 = FIELD_GET(GUC_HXG_REQUEST_MSG_0_DATA0, msg[0]); + + relay_debug(relay, "%s.%u to %u action %#x:%u\n", + guc_hxg_type_to_string(type), + txn->rid, txn->remote, action, data0); + + /* list ordering does not need to match RID ordering */ + spin_lock(&relay->lock); + list_add_tail(&txn->link, &relay->pending_relays); + spin_unlock(&relay->lock); + +resend: + ret = relay_send_transaction(relay, txn); + if (unlikely(ret < 0)) + goto unlink; + +wait: + n = wait_for_completion_timeout(&txn->done, timeout); + if (unlikely(n == 0 && txn->reply)) { + ret = -ETIME; + goto unlink; + } + + relay_debug(relay, "%u.%u reply %d after %u msec\n", + txn->remote, txn->rid, txn->reply, jiffies_to_msecs(timeout - n)); + if (unlikely(txn->reply)) { + reinit_completion(&txn->done); + if (txn->reply == -EAGAIN) + goto resend; + if (txn->reply == -EBUSY) + goto wait; + if (txn->reply > 0) + ret = from_relay_error(txn->reply); + else + ret = txn->reply; + goto unlink; + } + + relay_debug(relay, "%u.%u response %*ph\n", txn->remote, txn->rid, + (int)sizeof(u32) * txn->response_len, txn->response); + relay_assert(relay, txn->response_len >= GUC_RELAY_MSG_MIN_LEN); + ret = txn->response_len; + +unlink: + spin_lock(&relay->lock); + list_del_init(&txn->link); + spin_unlock(&relay->lock); + + if (unlikely(ret < 0)) { + relay_notice(relay, "Unsuccessful %s.%u %#x:%u to %u (%pe) %*ph\n", + guc_hxg_type_to_string(type), txn->rid, + action, data0, txn->remote, ERR_PTR(ret), + (int)sizeof(u32) * len, msg); + } + + return ret; +} + +static int relay_send_to(struct xe_guc_relay *relay, u32 target, + const u32 *msg, u32 len, u32 *buf, u32 buf_size) +{ + struct relay_transaction *txn; + int ret; + + relay_assert(relay, len >= GUC_RELAY_MSG_MIN_LEN); + relay_assert(relay, len <= GUC_RELAY_MSG_MAX_LEN); + relay_assert(relay, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]) == GUC_HXG_ORIGIN_HOST); + relay_assert(relay, guc_hxg_type_is_action(FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]))); + + if (unlikely(!relay_is_ready(relay))) + return -ENODEV; + + txn = relay_new_transaction(relay, target, msg, len, buf, buf_size); + if (IS_ERR(txn)) + return PTR_ERR(txn); + + switch (FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0])) { + case GUC_HXG_TYPE_REQUEST: + ret = relay_send_message_and_wait(relay, txn, buf, buf_size); + break; + case GUC_HXG_TYPE_FAST_REQUEST: + relay_assert(relay, !GUC_HXG_TYPE_FAST_REQUEST); + fallthrough; + case GUC_HXG_TYPE_EVENT: + ret = relay_send_transaction(relay, txn); + break; + default: + ret = -EINVAL; + break; + } + + relay_release_transaction(relay, txn); + return ret; +} + +#ifdef CONFIG_PCI_IOV +/** + * xe_guc_relay_send_to_vf - Send a message to the VF. + * @relay: the &xe_guc_relay which will send the message + * @target: target VF number + * @msg: request message to be sent + * @len: length of the request message (in dwords, can't be 0) + * @buf: placeholder for the response message + * @buf_size: size of the response message placeholder (in dwords) + * + * This function can only be used by the driver running in the SR-IOV PF mode. + * + * Return: Non-negative response length (in dwords) or + * a negative error code on failure. + */ +int xe_guc_relay_send_to_vf(struct xe_guc_relay *relay, u32 target, + const u32 *msg, u32 len, u32 *buf, u32 buf_size) +{ + relay_assert(relay, IS_SRIOV_PF(relay_to_xe(relay))); + + return relay_send_to(relay, target, msg, len, buf, buf_size); +} +#endif + +/** + * xe_guc_relay_send_to_pf - Send a message to the PF. + * @relay: the &xe_guc_relay which will send the message + * @msg: request message to be sent + * @len: length of the message (in dwords, can't be 0) + * @buf: placeholder for the response message + * @buf_size: size of the response message placeholder (in dwords) + * + * This function can only be used by driver running in SR-IOV VF mode. + * + * Return: Non-negative response length (in dwords) or + * a negative error code on failure. + */ +int xe_guc_relay_send_to_pf(struct xe_guc_relay *relay, + const u32 *msg, u32 len, u32 *buf, u32 buf_size) +{ + relay_assert(relay, IS_SRIOV_VF(relay_to_xe(relay))); + + return relay_send_to(relay, PFID, msg, len, buf, buf_size); +} + +static int relay_handle_reply(struct xe_guc_relay *relay, u32 origin, + u32 rid, int reply, const u32 *msg, u32 len) +{ + struct relay_transaction *pending; + int err = -ESRCH; + + spin_lock(&relay->lock); + list_for_each_entry(pending, &relay->pending_relays, link) { + if (pending->remote != origin || pending->rid != rid) { + relay_debug(relay, "%u.%u still awaits response\n", + pending->remote, pending->rid); + continue; + } + err = 0; /* found! */ + if (reply == 0) { + if (len > pending->response_len) { + reply = -ENOBUFS; + err = -ENOBUFS; + } else { + memcpy(pending->response, msg, 4 * len); + pending->response_len = len; + } + } + pending->reply = reply; + complete_all(&pending->done); + break; + } + spin_unlock(&relay->lock); + + return err; +} + +static int relay_handle_failure(struct xe_guc_relay *relay, u32 origin, + u32 rid, const u32 *msg, u32 len) +{ + int error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, msg[0]); + u32 hint __maybe_unused = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, msg[0]); + + relay_assert(relay, len); + relay_debug(relay, "%u.%u error %#x (%pe) hint %u debug %*ph\n", + origin, rid, error, ERR_PTR(-error), hint, 4 * (len - 1), msg + 1); + + return relay_handle_reply(relay, origin, rid, error ?: -EREMOTEIO, NULL, 0); +} + +static int relay_testloop_action_handler(struct xe_guc_relay *relay, u32 origin, + const u32 *msg, u32 len, u32 *response, u32 size) +{ + static ktime_t last_reply = 0; + u32 type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + u32 action = FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]); + u32 opcode = FIELD_GET(GUC_HXG_REQUEST_MSG_0_DATA0, msg[0]); + ktime_t now = ktime_get(); + bool busy; + int ret; + + relay_assert(relay, guc_hxg_type_is_action(type)); + relay_assert(relay, action == GUC_RELAY_ACTION_VFXPF_TESTLOOP); + + if (!IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) + return -ECONNREFUSED; + + if (!last_reply) + last_reply = now; + busy = ktime_before(now, ktime_add_ms(last_reply, 2 * RELAY_TIMEOUT_MSEC)); + if (!busy) + last_reply = now; + + switch (opcode) { + case VFXPF_TESTLOOP_OPCODE_NOP: + if (type == GUC_HXG_TYPE_EVENT) + return 0; + return guc_hxg_msg_encode_success(response, 0); + case VFXPF_TESTLOOP_OPCODE_BUSY: + if (type == GUC_HXG_TYPE_EVENT) + return -EPROTO; + msleep(RELAY_TIMEOUT_MSEC / 8); + if (busy) + return -EINPROGRESS; + return guc_hxg_msg_encode_success(response, 0); + case VFXPF_TESTLOOP_OPCODE_RETRY: + if (type == GUC_HXG_TYPE_EVENT) + return -EPROTO; + msleep(RELAY_TIMEOUT_MSEC / 8); + if (busy) + return guc_hxg_msg_encode_retry(response, 0); + return guc_hxg_msg_encode_success(response, 0); + case VFXPF_TESTLOOP_OPCODE_ECHO: + if (type == GUC_HXG_TYPE_EVENT) + return -EPROTO; + if (size < len) + return -ENOBUFS; + ret = guc_hxg_msg_encode_success(response, len); + memcpy(response + ret, msg + ret, (len - ret) * sizeof(u32)); + return len; + case VFXPF_TESTLOOP_OPCODE_FAIL: + return -EHWPOISON; + default: + break; + } + + relay_notice(relay, "Unexpected action %#x opcode %#x\n", action, opcode); + return -EBADRQC; +} + +static int relay_action_handler(struct xe_guc_relay *relay, u32 origin, + const u32 *msg, u32 len, u32 *response, u32 size) +{ + u32 type; + int ret; + + relay_assert(relay, len >= GUC_HXG_MSG_MIN_LEN); + + if (FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]) == GUC_RELAY_ACTION_VFXPF_TESTLOOP) + return relay_testloop_action_handler(relay, origin, msg, len, response, size); + + type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + + /* XXX: PF services will be added later */ + ret = -EOPNOTSUPP; + + if (type == GUC_HXG_TYPE_EVENT) + relay_assert(relay, ret <= 0); + + return ret; +} + +static struct relay_transaction *relay_dequeue_transaction(struct xe_guc_relay *relay) +{ + struct relay_transaction *txn; + + spin_lock(&relay->lock); + txn = list_first_entry_or_null(&relay->incoming_actions, struct relay_transaction, link); + if (txn) + list_del_init(&txn->link); + spin_unlock(&relay->lock); + + return txn; +} + +static void relay_process_incoming_action(struct xe_guc_relay *relay) +{ + struct relay_transaction *txn; + bool again = false; + u32 type; + int ret; + + txn = relay_dequeue_transaction(relay); + if (!txn) + return; + + type = FIELD_GET(GUC_HXG_MSG_0_TYPE, txn->request_buf[txn->offset]); + + ret = relay_action_handler(relay, txn->remote, + txn->request_buf + txn->offset, txn->request_len, + txn->response_buf + txn->offset, + ARRAY_SIZE(txn->response_buf) - txn->offset); + + if (ret == -EINPROGRESS) { + again = true; + ret = guc_hxg_msg_encode_busy(txn->response_buf + txn->offset, 0); + } + + if (ret > 0) { + txn->response_len = ret; + ret = relay_send_transaction(relay, txn); + } + + if (ret < 0) { + u32 error = to_relay_error(ret); + + relay_notice(relay, "Failed to handle %s.%u from %u (%pe) %*ph\n", + guc_hxg_type_to_string(type), txn->rid, txn->remote, + ERR_PTR(ret), 4 * txn->request_len, txn->request_buf + txn->offset); + + txn->response_len = prepare_error_reply(txn->response_buf + txn->offset, + txn->remote ? + sanitize_relay_error(error) : error, + txn->remote ? + sanitize_relay_error_hint(-ret) : -ret); + ret = relay_send_transaction(relay, txn); + again = false; + } + + if (again) { + spin_lock(&relay->lock); + list_add(&txn->link, &relay->incoming_actions); + spin_unlock(&relay->lock); + return; + } + + if (unlikely(ret < 0)) + relay_notice(relay, "Failed to process action.%u (%pe) %*ph\n", + txn->rid, ERR_PTR(ret), 4 * txn->request_len, + txn->request_buf + txn->offset); + + relay_release_transaction(relay, txn); +} + +static bool relay_needs_worker(struct xe_guc_relay *relay) +{ + return !list_empty(&relay->incoming_actions); +} + +static void relay_kick_worker(struct xe_guc_relay *relay) +{ + queue_work(relay_to_xe(relay)->sriov.wq, &relay->worker); +} + +static void relays_worker_fn(struct work_struct *w) +{ + struct xe_guc_relay *relay = container_of(w, struct xe_guc_relay, worker); + + relay_process_incoming_action(relay); + + if (relay_needs_worker(relay)) + relay_kick_worker(relay); +} + +static int relay_queue_action_msg(struct xe_guc_relay *relay, u32 origin, u32 rid, + const u32 *msg, u32 len) +{ + struct relay_transaction *txn; + + txn = relay_new_incoming_transaction(relay, origin, rid, msg, len); + if (IS_ERR(txn)) + return PTR_ERR(txn); + + spin_lock(&relay->lock); + list_add_tail(&txn->link, &relay->incoming_actions); + spin_unlock(&relay->lock); + + relay_kick_worker(relay); + return 0; +} + +static int relay_process_msg(struct xe_guc_relay *relay, u32 origin, u32 rid, + const u32 *msg, u32 len) +{ + u32 type; + int err; + + if (unlikely(len < GUC_HXG_MSG_MIN_LEN)) + return -EPROTO; + + if (FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]) != GUC_HXG_ORIGIN_HOST) + return -EPROTO; + + type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + relay_debug(relay, "received %s.%u from %u = %*ph\n", + guc_hxg_type_to_string(type), rid, origin, 4 * len, msg); + + switch (type) { + case GUC_HXG_TYPE_REQUEST: + case GUC_HXG_TYPE_FAST_REQUEST: + case GUC_HXG_TYPE_EVENT: + err = relay_queue_action_msg(relay, origin, rid, msg, len); + break; + case GUC_HXG_TYPE_RESPONSE_SUCCESS: + err = relay_handle_reply(relay, origin, rid, 0, msg, len); + break; + case GUC_HXG_TYPE_NO_RESPONSE_BUSY: + err = relay_handle_reply(relay, origin, rid, -EBUSY, NULL, 0); + break; + case GUC_HXG_TYPE_NO_RESPONSE_RETRY: + err = relay_handle_reply(relay, origin, rid, -EAGAIN, NULL, 0); + break; + case GUC_HXG_TYPE_RESPONSE_FAILURE: + err = relay_handle_failure(relay, origin, rid, msg, len); + break; + default: + err = -EBADRQC; + } + + if (unlikely(err)) + relay_notice(relay, "Failed to process %s.%u from %u (%pe) %*ph\n", + guc_hxg_type_to_string(type), rid, origin, + ERR_PTR(err), 4 * len, msg); + + return err; +} + +/** + * xe_guc_relay_process_guc2vf - Handle relay notification message from the GuC. + * @relay: the &xe_guc_relay which will handle the message + * @msg: message to be handled + * @len: length of the message (in dwords) + * + * This function will handle relay messages received from the GuC. + * + * This function is can only be used if driver is running in SR-IOV mode. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_guc_relay_process_guc2vf(struct xe_guc_relay *relay, const u32 *msg, u32 len) +{ + u32 rid; + + relay_assert(relay, len >= GUC_HXG_MSG_MIN_LEN); + relay_assert(relay, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]) == GUC_HXG_ORIGIN_GUC); + relay_assert(relay, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_EVENT); + relay_assert(relay, FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[0]) == + XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF); + + if (unlikely(!IS_SRIOV_VF(relay_to_xe(relay)))) + return -EPERM; + + if (unlikely(!relay_is_ready(relay))) + return -ENODEV; + + if (unlikely(len < GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN)) + return -EPROTO; + + if (unlikely(len > GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN)) + return -EMSGSIZE; + + if (unlikely(FIELD_GET(GUC_HXG_EVENT_MSG_0_DATA0, msg[0]))) + return -EPFNOSUPPORT; + + rid = FIELD_GET(GUC2VF_RELAY_FROM_PF_EVENT_MSG_1_RELAY_ID, msg[1]); + + return relay_process_msg(relay, PFID, rid, + msg + GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN, + len - GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN); +} + +#ifdef CONFIG_PCI_IOV +/** + * xe_guc_relay_process_guc2pf - Handle relay notification message from the GuC. + * @relay: the &xe_guc_relay which will handle the message + * @msg: message to be handled + * @len: length of the message (in dwords) + * + * This function will handle relay messages received from the GuC. + * + * This function can only be used if driver is running in SR-IOV PF mode. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_guc_relay_process_guc2pf(struct xe_guc_relay *relay, const u32 *msg, u32 len) +{ + u32 origin, rid; + int err; + + relay_assert(relay, len >= GUC_HXG_EVENT_MSG_MIN_LEN); + relay_assert(relay, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]) == GUC_HXG_ORIGIN_GUC); + relay_assert(relay, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_EVENT); + relay_assert(relay, FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[0]) == + XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF); + + if (unlikely(!IS_SRIOV_PF(relay_to_xe(relay)))) + return -EPERM; + + if (unlikely(!relay_is_ready(relay))) + return -ENODEV; + + if (unlikely(len < GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN)) + return -EPROTO; + + if (unlikely(len > GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN)) + return -EMSGSIZE; + + if (unlikely(FIELD_GET(GUC_HXG_EVENT_MSG_0_DATA0, msg[0]))) + return -EPFNOSUPPORT; + + origin = FIELD_GET(GUC2PF_RELAY_FROM_VF_EVENT_MSG_1_VFID, msg[1]); + rid = FIELD_GET(GUC2PF_RELAY_FROM_VF_EVENT_MSG_2_RELAY_ID, msg[2]); + + if (unlikely(origin > relay_get_totalvfs(relay))) + return -ENOENT; + + err = relay_process_msg(relay, origin, rid, + msg + GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN, + len - GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN); + + return err; +} +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_relay.h b/drivers/gpu/drm/xe/xe_guc_relay.h new file mode 100644 index 0000000000000..385429aa188ab --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_relay.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_GUC_RELAY_H_ +#define _XE_GUC_RELAY_H_ + +#include +#include + +struct xe_guc_relay; + +int xe_guc_relay_init(struct xe_guc_relay *relay); + +int xe_guc_relay_send_to_pf(struct xe_guc_relay *relay, + const u32 *msg, u32 len, u32 *buf, u32 buf_size); + +int xe_guc_relay_process_guc2vf(struct xe_guc_relay *relay, const u32 *msg, u32 len); + +#ifdef CONFIG_PCI_IOV +int xe_guc_relay_send_to_vf(struct xe_guc_relay *relay, u32 target, + const u32 *msg, u32 len, u32 *buf, u32 buf_size); +int xe_guc_relay_process_guc2pf(struct xe_guc_relay *relay, const u32 *msg, u32 len); +#else +static inline int xe_guc_relay_send_to_vf(struct xe_guc_relay *relay, u32 target, + const u32 *msg, u32 len, u32 *buf, u32 buf_size) +{ + return -ENODEV; +} +static inline int xe_guc_relay_process_guc2pf(struct xe_guc_relay *relay, const u32 *msg, u32 len) +{ + return -ENODEV; +} +#endif + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_relay_types.h b/drivers/gpu/drm/xe/xe_guc_relay_types.h new file mode 100644 index 0000000000000..5999fcb77e96c --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_relay_types.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_GUC_RELAY_TYPES_H_ +#define _XE_GUC_RELAY_TYPES_H_ + +#include +#include +#include + +/** + * struct xe_guc_relay - Data used by the VF-PF Relay Communication over GuC. + */ +struct xe_guc_relay { + /**@lock: protects all internal data. */ + spinlock_t lock; + + /** @worker: dispatches incoming action messages. */ + struct work_struct worker; + + /** @pending_relays: list of sent requests that await a response. */ + struct list_head pending_relays; + + /** @incoming_actions: list of incoming relay action messages to process. */ + struct list_head incoming_actions; + + /** @pool: pool of the relay message buffers. */ + mempool_t pool; + + /** @last_rid: last Relay-ID used while sending a message. */ + u32 last_rid; +}; + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h index 16de203c62a7e..dc6059de669c3 100644 --- a/drivers/gpu/drm/xe/xe_guc_types.h +++ b/drivers/gpu/drm/xe/xe_guc_types.h @@ -15,6 +15,7 @@ #include "xe_guc_fwif.h" #include "xe_guc_log_types.h" #include "xe_guc_pc_types.h" +#include "xe_guc_relay_types.h" #include "xe_uc_fw_types.h" /** @@ -85,6 +86,9 @@ struct xe_guc { u32 size; } hwconfig; + /** @relay: GuC Relay Communication used in SR-IOV */ + struct xe_guc_relay relay; + /** * @notify_reg: Register which is written to notify GuC of H2G messages */ -- GitLab From 4469eae6bc52b3746b39941f90b9213bcef0255a Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:29 +0100 Subject: [PATCH 0174/1420] drm/xe/kunit: Allow to replace xe_guc_ct_send_recv() with stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to use replacement functions in upcoming kunit tests. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-9-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_ct.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 4cde93c18a2d4..8f208267ffc63 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -9,6 +9,8 @@ #include #include +#include + #include #include "abi/guc_actions_abi.h" @@ -782,6 +784,7 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, int xe_guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, u32 *response_buffer) { + KUNIT_STATIC_STUB_REDIRECT(xe_guc_ct_send_recv, ct, action, len, response_buffer); return guc_ct_send_recv(ct, action, len, response_buffer, false); } -- GitLab From 927b042a8daf2c773fd1802b388e22ca6087235c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:30 +0100 Subject: [PATCH 0175/1420] drm/xe/kunit: Add GuC Relay kunit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add few tests to make sure that some negative and normal use scenarios of the GuC Relay are implemented correctly. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-10-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/tests/xe_guc_relay_test.c | 522 +++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_relay.c | 21 +- 2 files changed, 540 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/xe/tests/xe_guc_relay_test.c diff --git a/drivers/gpu/drm/xe/tests/xe_guc_relay_test.c b/drivers/gpu/drm/xe/tests/xe_guc_relay_test.c new file mode 100644 index 0000000000000..13701451b9235 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_guc_relay_test.c @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include +#include + +#include "xe_device.h" +#include "xe_kunit_helpers.h" +#include "xe_pci_test.h" + +#define TEST_RID 1234 +#define TEST_VFID 5 +#define TEST_LEN 6 +#define TEST_ACTION 0xa +#define TEST_DATA(n) (0xd0 + (n)) + +static int replacement_relay_get_totalvfs(struct xe_guc_relay *relay) +{ + return TEST_VFID; +} + +static int relay_test_init(struct kunit *test) +{ + struct xe_pci_fake_data fake = { + .sriov_mode = XE_SRIOV_MODE_PF, + .platform = XE_TIGERLAKE, /* some random platform */ + .subplatform = XE_SUBPLATFORM_NONE, + }; + struct xe_guc_relay *relay; + struct xe_device *xe; + + test->priv = &fake; + xe_kunit_helper_xe_device_test_init(test); + + xe = test->priv; + KUNIT_ASSERT_EQ(test, xe_sriov_init(xe), 0); + + relay = &xe_device_get_gt(xe, 0)->uc.guc.relay; + kunit_activate_static_stub(test, relay_get_totalvfs, + replacement_relay_get_totalvfs); + + KUNIT_ASSERT_EQ(test, xe_guc_relay_init(relay), 0); + KUNIT_EXPECT_TRUE(test, relay_is_ready(relay)); + relay->last_rid = TEST_RID - 1; + + test->priv = relay; + return 0; +} + +static const u32 TEST_MSG[TEST_LEN] = { + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) | + FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, TEST_ACTION) | + FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_DATA0, TEST_DATA(0)), + TEST_DATA(1), TEST_DATA(2), TEST_DATA(3), TEST_DATA(4), +}; + +static int replacement_xe_guc_ct_send_recv_always_fails(struct xe_guc_ct *ct, + const u32 *msg, u32 len, + u32 *response_buffer) +{ + struct kunit *test = kunit_get_current_test(); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg); + KUNIT_ASSERT_GE(test, len, GUC_HXG_MSG_MIN_LEN); + + return -ECOMM; +} + +static int replacement_xe_guc_ct_send_recv_expects_pf2guc_relay(struct xe_guc_ct *ct, + const u32 *msg, u32 len, + u32 *response_buffer) +{ + struct kunit *test = kunit_get_current_test(); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg); + KUNIT_ASSERT_GE(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN); + KUNIT_ASSERT_EQ(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN + TEST_LEN); + KUNIT_EXPECT_EQ(test, GUC_HXG_ORIGIN_HOST, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0])); + KUNIT_EXPECT_EQ(test, GUC_HXG_TYPE_REQUEST, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0])); + KUNIT_EXPECT_EQ(test, XE_GUC_ACTION_PF2GUC_RELAY_TO_VF, + FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0])); + KUNIT_EXPECT_EQ(test, TEST_VFID, + FIELD_GET(PF2GUC_RELAY_TO_VF_REQUEST_MSG_1_VFID, msg[1])); + KUNIT_EXPECT_EQ(test, TEST_RID, + FIELD_GET(PF2GUC_RELAY_TO_VF_REQUEST_MSG_2_RELAY_ID, msg[2])); + KUNIT_EXPECT_MEMEQ(test, TEST_MSG, msg + PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN, + sizeof(u32) * TEST_LEN); + return 0; +} + +static const u32 test_guc2pf[GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN] = { + /* transport */ + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) | + FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF), + FIELD_PREP_CONST(GUC2PF_RELAY_FROM_VF_EVENT_MSG_1_VFID, TEST_VFID), + FIELD_PREP_CONST(GUC2PF_RELAY_FROM_VF_EVENT_MSG_2_RELAY_ID, TEST_RID), + /* payload */ + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS), +}; + +static const u32 test_guc2vf[GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN] = { + /* transport */ + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) | + FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF), + FIELD_PREP_CONST(GUC2VF_RELAY_FROM_PF_EVENT_MSG_1_RELAY_ID, TEST_RID), + /* payload */ + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS), +}; + +static void pf_rejects_guc2pf_too_short(struct kunit *test) +{ + const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN - 1; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2pf; + + KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2pf(relay, msg, len)); +} + +static void pf_rejects_guc2pf_too_long(struct kunit *test) +{ + const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN + 1; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2pf; + + KUNIT_ASSERT_EQ(test, -EMSGSIZE, xe_guc_relay_process_guc2pf(relay, msg, len)); +} + +static void pf_rejects_guc2pf_no_payload(struct kunit *test) +{ + const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2pf; + + KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2pf(relay, msg, len)); +} + +static void pf_fails_no_payload(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + const u32 msg = 0; + + KUNIT_ASSERT_EQ(test, -EPROTO, relay_process_msg(relay, TEST_VFID, TEST_RID, &msg, 0)); +} + +static void pf_fails_bad_origin(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + static const u32 msg[] = { + FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) | + FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS), + }; + u32 len = ARRAY_SIZE(msg); + + KUNIT_ASSERT_EQ(test, -EPROTO, relay_process_msg(relay, TEST_VFID, TEST_RID, msg, len)); +} + +static void pf_fails_bad_type(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + const u32 msg[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, 4), /* only 4 is undefined */ + }; + u32 len = ARRAY_SIZE(msg); + + KUNIT_ASSERT_EQ(test, -EBADRQC, relay_process_msg(relay, TEST_VFID, TEST_RID, msg, len)); +} + +static void pf_txn_reports_error(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + struct relay_transaction *txn; + + txn = __relay_get_transaction(relay, false, TEST_VFID, TEST_RID, + TEST_MSG, TEST_LEN, NULL, 0); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txn); + + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_always_fails); + KUNIT_EXPECT_EQ(test, -ECOMM, relay_send_transaction(relay, txn)); + + relay_release_transaction(relay, txn); +} + +static void pf_txn_sends_pf2guc(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + struct relay_transaction *txn; + + txn = __relay_get_transaction(relay, false, TEST_VFID, TEST_RID, + TEST_MSG, TEST_LEN, NULL, 0); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txn); + + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_expects_pf2guc_relay); + KUNIT_ASSERT_EQ(test, 0, relay_send_transaction(relay, txn)); + + relay_release_transaction(relay, txn); +} + +static void pf_sends_pf2guc(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_expects_pf2guc_relay); + KUNIT_ASSERT_EQ(test, 0, + xe_guc_relay_send_to_vf(relay, TEST_VFID, + TEST_MSG, TEST_LEN, NULL, 0)); +} + +static int replacement_xe_guc_ct_send_recv_loopback_relay(struct xe_guc_ct *ct, + const u32 *msg, u32 len, + u32 *response_buffer) +{ + struct kunit *test = kunit_get_current_test(); + struct xe_guc_relay *relay = test->priv; + u32 *reply = kunit_kzalloc(test, len * sizeof(u32), GFP_KERNEL); + int (*guc2relay)(struct xe_guc_relay *, const u32 *, u32); + u32 action; + int err; + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg); + KUNIT_ASSERT_GE(test, len, GUC_HXG_MSG_MIN_LEN); + KUNIT_ASSERT_EQ(test, GUC_HXG_TYPE_REQUEST, + FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0])); + KUNIT_ASSERT_GE(test, len, GUC_HXG_REQUEST_MSG_MIN_LEN); + KUNIT_ASSERT_NOT_NULL(test, reply); + + switch (FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0])) { + case XE_GUC_ACTION_PF2GUC_RELAY_TO_VF: + KUNIT_ASSERT_GE(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN); + action = XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF; + guc2relay = xe_guc_relay_process_guc2pf; + break; + case XE_GUC_ACTION_VF2GUC_RELAY_TO_PF: + KUNIT_ASSERT_GE(test, len, VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN); + action = XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF; + guc2relay = xe_guc_relay_process_guc2vf; + break; + default: + KUNIT_FAIL(test, "bad RELAY action %#x", msg[0]); + return -EINVAL; + } + + reply[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) | + FIELD_PREP(GUC_HXG_EVENT_MSG_0_ACTION, action); + memcpy(reply + 1, msg + 1, sizeof(u32) * (len - 1)); + + err = guc2relay(relay, reply, len); + KUNIT_EXPECT_EQ(test, err, 0); + + return err; +} + +static void test_requires_relay_testloop(struct kunit *test) +{ + /* + * The debug relay action GUC_RELAY_ACTION_VFXPF_TESTLOOP is available + * only on builds with CONFIG_DRM_XE_DEBUG_SRIOV enabled. + * See "kunit.py --kconfig_add" option if it's missing. + */ + if (!IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) + kunit_skip(test, "requires %s\n", __stringify(CONFIG_DRM_XE_DEBUG_SRIOV)); +} + +static void pf_loopback_nop(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + u32 request[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_NOP), + }; + u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN]; + int ret; + + test_requires_relay_testloop(test); + + kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action); + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_loopback_relay); + ret = xe_guc_relay_send_to_vf(relay, TEST_VFID, + request, ARRAY_SIZE(request), + response, ARRAY_SIZE(response)); + KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, response[0]), + GUC_HXG_ORIGIN_HOST); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_TYPE, response[0]), + GUC_HXG_TYPE_RESPONSE_SUCCESS); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, response[0]), 0); +} + +static void pf_loopback_echo(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + u32 request[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_ECHO), + TEST_DATA(1), TEST_DATA(2), TEST_DATA(3), TEST_DATA(4), + }; + u32 response[ARRAY_SIZE(request)]; + unsigned int n; + int ret; + + test_requires_relay_testloop(test); + + kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action); + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_loopback_relay); + ret = xe_guc_relay_send_to_vf(relay, TEST_VFID, + request, ARRAY_SIZE(request), + response, ARRAY_SIZE(response)); + KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(response)); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, response[0]), + GUC_HXG_ORIGIN_HOST); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_TYPE, response[0]), + GUC_HXG_TYPE_RESPONSE_SUCCESS); + KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, response[0]), + ARRAY_SIZE(response)); + for (n = GUC_HXG_RESPONSE_MSG_MIN_LEN; n < ret; n++) + KUNIT_EXPECT_EQ(test, request[n], response[n]); +} + +static void pf_loopback_fail(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + u32 request[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_FAIL), + }; + u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN]; + int ret; + + test_requires_relay_testloop(test); + + kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action); + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_loopback_relay); + ret = xe_guc_relay_send_to_vf(relay, TEST_VFID, + request, ARRAY_SIZE(request), + response, ARRAY_SIZE(response)); + KUNIT_ASSERT_EQ(test, ret, -EREMOTEIO); +} + +static void pf_loopback_busy(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + u32 request[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_BUSY), + TEST_DATA(0xb), + }; + u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN]; + int ret; + + test_requires_relay_testloop(test); + + kunit_activate_static_stub(test, relay_testonly_nop, relay_process_incoming_action); + kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action); + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_loopback_relay); + ret = xe_guc_relay_send_to_vf(relay, TEST_VFID, + request, ARRAY_SIZE(request), + response, ARRAY_SIZE(response)); + KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN); +} + +static void pf_loopback_retry(struct kunit *test) +{ + struct xe_guc_relay *relay = test->priv; + u32 request[] = { + FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | + FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) | + FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_RETRY), + TEST_DATA(0xd), TEST_DATA(0xd), + }; + u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN]; + int ret; + + test_requires_relay_testloop(test); + + kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action); + kunit_activate_static_stub(test, xe_guc_ct_send_recv, + replacement_xe_guc_ct_send_recv_loopback_relay); + ret = xe_guc_relay_send_to_vf(relay, TEST_VFID, + request, ARRAY_SIZE(request), + response, ARRAY_SIZE(response)); + KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN); +} + +static struct kunit_case pf_relay_test_cases[] = { + KUNIT_CASE(pf_rejects_guc2pf_too_short), + KUNIT_CASE(pf_rejects_guc2pf_too_long), + KUNIT_CASE(pf_rejects_guc2pf_no_payload), + KUNIT_CASE(pf_fails_no_payload), + KUNIT_CASE(pf_fails_bad_origin), + KUNIT_CASE(pf_fails_bad_type), + KUNIT_CASE(pf_txn_reports_error), + KUNIT_CASE(pf_txn_sends_pf2guc), + KUNIT_CASE(pf_sends_pf2guc), + KUNIT_CASE(pf_loopback_nop), + KUNIT_CASE(pf_loopback_echo), + KUNIT_CASE(pf_loopback_fail), + KUNIT_CASE_SLOW(pf_loopback_busy), + KUNIT_CASE_SLOW(pf_loopback_retry), + {} +}; + +static struct kunit_suite pf_relay_suite = { + .name = "pf_relay", + .test_cases = pf_relay_test_cases, + .init = relay_test_init, +}; + +static void vf_rejects_guc2vf_too_short(struct kunit *test) +{ + const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN - 1; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2vf; + + KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2vf(relay, msg, len)); +} + +static void vf_rejects_guc2vf_too_long(struct kunit *test) +{ + const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN + 1; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2vf; + + KUNIT_ASSERT_EQ(test, -EMSGSIZE, xe_guc_relay_process_guc2vf(relay, msg, len)); +} + +static void vf_rejects_guc2vf_no_payload(struct kunit *test) +{ + const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN; + struct xe_guc_relay *relay = test->priv; + const u32 *msg = test_guc2vf; + + KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2vf(relay, msg, len)); +} + +static struct kunit_case vf_relay_test_cases[] = { + KUNIT_CASE(vf_rejects_guc2vf_too_short), + KUNIT_CASE(vf_rejects_guc2vf_too_long), + KUNIT_CASE(vf_rejects_guc2vf_no_payload), + {} +}; + +static struct kunit_suite vf_relay_suite = { + .name = "vf_relay", + .test_cases = vf_relay_test_cases, + .init = relay_test_init, +}; + +static void xe_drops_guc2pf_if_not_ready(struct kunit *test) +{ + struct xe_device *xe = test->priv; + struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay; + const u32 *msg = test_guc2pf; + u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MIN_LEN; + + KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_process_guc2pf(relay, msg, len)); +} + +static void xe_drops_guc2vf_if_not_ready(struct kunit *test) +{ + struct xe_device *xe = test->priv; + struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay; + const u32 *msg = test_guc2vf; + u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MIN_LEN; + + KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_process_guc2vf(relay, msg, len)); +} + +static void xe_rejects_send_if_not_ready(struct kunit *test) +{ + struct xe_device *xe = test->priv; + struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay; + u32 msg[GUC_RELAY_MSG_MIN_LEN]; + u32 len = ARRAY_SIZE(msg); + + KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_send_to_pf(relay, msg, len, NULL, 0)); + KUNIT_ASSERT_EQ(test, -ENODEV, relay_send_to(relay, TEST_VFID, msg, len, NULL, 0)); +} + +static struct kunit_case no_relay_test_cases[] = { + KUNIT_CASE(xe_drops_guc2pf_if_not_ready), + KUNIT_CASE(xe_drops_guc2vf_if_not_ready), + KUNIT_CASE(xe_rejects_send_if_not_ready), + {} +}; + +static struct kunit_suite no_relay_suite = { + .name = "no_relay", + .test_cases = no_relay_test_cases, + .init = xe_kunit_helper_xe_device_test_init, +}; + +kunit_test_suites(&no_relay_suite, + &pf_relay_suite, + &vf_relay_suite); diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index 0e73832564082..b772088979bdd 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -8,6 +8,8 @@ #include +#include + #include "abi/guc_actions_sriov_abi.h" #include "abi/guc_relay_actions_abi.h" #include "abi/guc_relay_communication_abi.h" @@ -60,6 +62,7 @@ static int relay_get_totalvfs(struct xe_guc_relay *relay) struct xe_device *xe = relay_to_xe(relay); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + KUNIT_STATIC_STUB_REDIRECT(relay_get_totalvfs, relay); return IS_SRIOV_VF(xe) ? 0 : pci_sriov_get_totalvfs(pdev); } @@ -392,6 +395,11 @@ static u32 prepare_error_reply(u32 *msg, u32 error, u32 hint) return GUC_HXG_FAILURE_MSG_LEN; } +static void relay_testonly_nop(struct xe_guc_relay *relay) +{ + KUNIT_STATIC_STUB_REDIRECT(relay_testonly_nop, relay); +} + static int relay_send_message_and_wait(struct xe_guc_relay *relay, struct relay_transaction *txn, u32 *buf, u32 buf_size) @@ -434,8 +442,10 @@ static int relay_send_message_and_wait(struct xe_guc_relay *relay, reinit_completion(&txn->done); if (txn->reply == -EAGAIN) goto resend; - if (txn->reply == -EBUSY) + if (txn->reply == -EBUSY) { + relay_testonly_nop(relay); goto wait; + } if (txn->reply > 0) ret = from_relay_error(txn->reply); else @@ -751,6 +761,7 @@ static bool relay_needs_worker(struct xe_guc_relay *relay) static void relay_kick_worker(struct xe_guc_relay *relay) { + KUNIT_STATIC_STUB_REDIRECT(relay_kick_worker, relay); queue_work(relay_to_xe(relay)->sriov.wq, &relay->worker); } @@ -849,7 +860,7 @@ int xe_guc_relay_process_guc2vf(struct xe_guc_relay *relay, const u32 *msg, u32 relay_assert(relay, FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[0]) == XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF); - if (unlikely(!IS_SRIOV_VF(relay_to_xe(relay)))) + if (unlikely(!IS_SRIOV_VF(relay_to_xe(relay)) && !kunit_get_current_test())) return -EPERM; if (unlikely(!relay_is_ready(relay))) @@ -895,7 +906,7 @@ int xe_guc_relay_process_guc2pf(struct xe_guc_relay *relay, const u32 *msg, u32 relay_assert(relay, FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[0]) == XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF); - if (unlikely(!IS_SRIOV_PF(relay_to_xe(relay)))) + if (unlikely(!IS_SRIOV_PF(relay_to_xe(relay)) && !kunit_get_current_test())) return -EPERM; if (unlikely(!relay_is_ready(relay))) @@ -923,3 +934,7 @@ int xe_guc_relay_process_guc2pf(struct xe_guc_relay *relay, const u32 *msg, u32 return err; } #endif + +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST) +#include "tests/xe_guc_relay_test.c" +#endif -- GitLab From 26d4481ac23fe16bb7d64d2b43db250bcb65003e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:31 +0100 Subject: [PATCH 0176/1420] drm/xe/guc: Start handling GuC Relay event messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GuC Relay infrastructure is ready, start handling relay messages from the GuC to unblock testing on the live system. Reviewed-by: Piotr Piórkowski Link: https://lore.kernel.org/r/20240104222031.277-11-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_ct.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 8f208267ffc63..c29f095aa1b98 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -14,6 +14,7 @@ #include #include "abi/guc_actions_abi.h" +#include "abi/guc_actions_sriov_abi.h" #include "abi/guc_klvs_abi.h" #include "xe_bo.h" #include "xe_device.h" @@ -22,6 +23,7 @@ #include "xe_gt_printk.h" #include "xe_gt_tlb_invalidation.h" #include "xe_guc.h" +#include "xe_guc_relay.h" #include "xe_guc_submit.h" #include "xe_map.h" #include "xe_pm.h" @@ -969,6 +971,12 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) ret = xe_guc_access_counter_notify_handler(guc, payload, adj_len); break; + case XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF: + ret = xe_guc_relay_process_guc2pf(&guc->relay, payload, adj_len); + break; + case XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF: + ret = xe_guc_relay_process_guc2vf(&guc->relay, payload, adj_len); + break; default: drm_err(&xe->drm, "unexpected action 0x%04x\n", action); } -- GitLab From 0d68d06553ee9ad6d4ffc000599765211cad4930 Mon Sep 17 00:00:00 2001 From: Ruthuvikas Ravikumar Date: Sat, 23 Dec 2023 00:53:52 +0530 Subject: [PATCH 0177/1420] drm/xe: Add mocs reset kunit This kunit verifies the mocs registers content with the KMD programmed values before and after GT reset. v2: Remove extra blank lines between the local variables definitions (Matt Roper) Cc: Matt Roper Signed-off-by: Ruthuvikas Ravikumar Signed-off-by: Janga Rahul Kumar Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231222192352.927101-1-janga.rahul.kumar@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_mocs.c | 36 +++++++++++++++++++++++++ drivers/gpu/drm/xe/tests/xe_mocs_test.c | 1 + drivers/gpu/drm/xe/tests/xe_mocs_test.h | 1 + 3 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/xe/tests/xe_mocs.c b/drivers/gpu/drm/xe/tests/xe_mocs.c index 7dd34f94e8094..df5c36b70ab45 100644 --- a/drivers/gpu/drm/xe/tests/xe_mocs.c +++ b/drivers/gpu/drm/xe/tests/xe_mocs.c @@ -128,3 +128,39 @@ void xe_live_mocs_kernel_kunit(struct kunit *test) xe_call_for_each_device(mocs_kernel_test_run_device); } EXPORT_SYMBOL_IF_KUNIT(xe_live_mocs_kernel_kunit); + +static int mocs_reset_test_run_device(struct xe_device *xe) +{ + /* Check the mocs setup is retained over GT reset */ + + struct live_mocs mocs; + struct xe_gt *gt; + unsigned int flags; + int id; + struct kunit *test = xe_cur_kunit(); + + for_each_gt(gt, xe, id) { + flags = live_mocs_init(&mocs, gt); + kunit_info(test, "mocs_reset_test before reset\n"); + if (flags & HAS_GLOBAL_MOCS) + read_mocs_table(gt, &mocs.table); + if (flags & HAS_LNCF_MOCS) + read_l3cc_table(gt, &mocs.table); + + xe_gt_reset_async(gt); + flush_work(>->reset.worker); + + kunit_info(test, "mocs_reset_test after reset\n"); + if (flags & HAS_GLOBAL_MOCS) + read_mocs_table(gt, &mocs.table); + if (flags & HAS_LNCF_MOCS) + read_l3cc_table(gt, &mocs.table); + } + return 0; +} + +void xe_live_mocs_reset_kunit(struct kunit *test) +{ + xe_call_for_each_device(mocs_reset_test_run_device); +} +EXPORT_SYMBOL_IF_KUNIT(xe_live_mocs_reset_kunit); diff --git a/drivers/gpu/drm/xe/tests/xe_mocs_test.c b/drivers/gpu/drm/xe/tests/xe_mocs_test.c index ef56bd517b28c..4f62e7a4270bd 100644 --- a/drivers/gpu/drm/xe/tests/xe_mocs_test.c +++ b/drivers/gpu/drm/xe/tests/xe_mocs_test.c @@ -9,6 +9,7 @@ static struct kunit_case xe_mocs_tests[] = { KUNIT_CASE(xe_live_mocs_kernel_kunit), + KUNIT_CASE(xe_live_mocs_reset_kunit), {} }; diff --git a/drivers/gpu/drm/xe/tests/xe_mocs_test.h b/drivers/gpu/drm/xe/tests/xe_mocs_test.h index 7faa3575e6c3a..e7699d4954115 100644 --- a/drivers/gpu/drm/xe/tests/xe_mocs_test.h +++ b/drivers/gpu/drm/xe/tests/xe_mocs_test.h @@ -9,5 +9,6 @@ struct kunit; void xe_live_mocs_kernel_kunit(struct kunit *test); +void xe_live_mocs_reset_kunit(struct kunit *test); #endif -- GitLab From c5b32a41946139b9f4f7a087fda2355a90f671cb Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Wed, 3 Jan 2024 11:01:11 +0530 Subject: [PATCH 0178/1420] drm/i915/xelpg: Add workaround 14019877138 WA 14019877138 needed for Graphics 12.70/71 both V2(Jani): - Use drm/i915 Signed-off-by: Tejas Upadhyay Reviewed-by: Matt Roper Reviewed-by: Andi Shyti Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240103053111.763172-1-tejas.upadhyay@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 3eacbc50caf8d..270b56fc85e2f 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -820,6 +820,9 @@ static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_18019271663 */ wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); + + /* Wa_14019877138 */ + wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT); } static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine, -- GitLab From 5343f29b3dc534be01b45cd3a3e43572996f96f8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 2 Jan 2024 13:21:58 +0100 Subject: [PATCH 0179/1420] drm: Move drm_set_preferred_mode() helper from drm_edid to drm_modes The helper is generic, it doesn't use the opaque EDID type struct drm_edid and is also used by drivers that only support non-probeable displays such as fixed panels. These drivers add a list of modes using drm_mode_probed_add() and then set a preferred mode using the drm_set_preferred_mode() helper. It seems more logical to have the helper definition in drm_modes.o instead of drm_edid.o, since the former contains modes helper while the latter has helpers to manage the EDID information. Since both drm_edid.o and drm_modes.o object files are built-in the drm.o object, there are no functional changes. But besides being a more logical place for this helper, it could also allow to eventually make drm_edid.o optional and not included in drm.o if only fixed panels must be supported in a given system. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20240102122208.3103597-1-javierm@redhat.com --- drivers/gpu/drm/drm_edid.c | 22 ---------------------- drivers/gpu/drm/drm_modes.c | 22 ++++++++++++++++++++++ include/drm/drm_edid.h | 2 -- include/drm/drm_modes.h | 2 ++ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cb4031d5dcbba..e677dc8eb7a97 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6989,28 +6989,6 @@ int drm_add_modes_noedid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_add_modes_noedid); -/** - * drm_set_preferred_mode - Sets the preferred mode of a connector - * @connector: connector whose mode list should be processed - * @hpref: horizontal resolution of preferred mode - * @vpref: vertical resolution of preferred mode - * - * Marks a mode as preferred if it matches the resolution specified by @hpref - * and @vpref. - */ -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref) -{ - struct drm_display_mode *mode; - - list_for_each_entry(mode, &connector->probed_modes, head) { - if (mode->hdisplay == hpref && - mode->vdisplay == vpref) - mode->type |= DRM_MODE_TYPE_PREFERRED; - } -} -EXPORT_SYMBOL(drm_set_preferred_mode); - static bool is_hdmi2_sink(const struct drm_connector *connector) { /* diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac9a406250c56..45238ec5df1b7 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2754,3 +2754,25 @@ bool drm_mode_is_420(const struct drm_display_info *display, drm_mode_is_420_also(display, mode); } EXPORT_SYMBOL(drm_mode_is_420); + +/** + * drm_set_preferred_mode - Sets the preferred mode of a connector + * @connector: connector whose mode list should be processed + * @hpref: horizontal resolution of preferred mode + * @vpref: vertical resolution of preferred mode + * + * Marks a mode as preferred if it matches the resolution specified by @hpref + * and @vpref. + */ +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref) +{ + struct drm_display_mode *mode; + + list_for_each_entry(mode, &connector->probed_modes, head) { + if (mode->hdisplay == hpref && + mode->vdisplay == vpref) + mode->type |= DRM_MODE_TYPE_PREFERRED; + } +} +EXPORT_SYMBOL(drm_set_preferred_mode); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 86c1812a8034e..7923bc00dc7a4 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -424,8 +424,6 @@ enum hdmi_quantization_range drm_default_rgb_quant_range(const struct drm_display_mode *mode); int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref); int drm_edid_header_is_valid(const void *edid); bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index c613f0abe9dce..b9bb92e4b0295 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -467,6 +467,8 @@ bool drm_mode_is_420_also(const struct drm_display_info *display, const struct drm_display_mode *mode); bool drm_mode_is_420(const struct drm_display_info *display, const struct drm_display_mode *mode); +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref); struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev, enum drm_connector_tv_mode mode, -- GitLab From 2b35ae108c7f5486adbc9e70377110ab8c91f61b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 5 Jan 2024 18:19:47 +0100 Subject: [PATCH 0180/1420] drm/xe: Fix compilation without CONFIG_KUNIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks that declaration of kunit_get_current_test() was available in xe_guc_relay.c only with CONFIG_KUNIT enabled. If CONFIG_KUNIT is disabled we fail with: In file included from ../include/linux/build_bug.h:5, from ../include/linux/bitfield.h:10, from ../drivers/gpu/drm/xe/xe_guc_relay.c:6: ../drivers/gpu/drm/xe/xe_guc_relay.c: In function ‘xe_guc_relay_process_guc2vf’: ../drivers/gpu/drm/xe/xe_guc_relay.c:863:52: error: implicit declaration of function ‘kunit_get_current_test’ [-Werror=implicit-function-declaration] 863 | if (unlikely(!IS_SRIOV_VF(relay_to_xe(relay)) && !kunit_get_current_test())) | ^~~~~~~~~~~~~~~~~~~~~~ ../include/linux/compiler.h:77:42: note: in definition of macro ‘unlikely’ 77 | # define unlikely(x) __builtin_expect(!!(x), 0) | ^ Reported-by: Mika Kuoppala Fixes: 811fe9f556fc ("drm/xe/guc: Introduce Relay Communication for SR-IOV") Reviewed-by: José Roberto de Souza Tested-by: Vinay Belgaumkar Link: https://lore.kernel.org/r/20240105171947.321-1-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_relay.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index b772088979bdd..c0a2d8d5d3b3c 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -9,6 +9,7 @@ #include #include +#include #include "abi/guc_actions_sriov_abi.h" #include "abi/guc_relay_actions_abi.h" -- GitLab From a797099562267ebb281acd59750f1a8dbba36eef Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 2 Jan 2024 14:22:02 -0800 Subject: [PATCH 0181/1420] drm/i915/huc: Allow for very slow HuC loading A failure to load the HuC is occasionally observed where the cause is believed to be a low GT frequency leading to very long load times. So a) increase the timeout so that the user still gets a working system even in the case of slow load. And b) report the frequency during the load to see if that is the cause of the slow down. Also update the similar code on the GuC load to not use uncore->gt when there is a local gt available. The two should match, but no need for unnecessary de-referencing. Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20240102222202.310495-1-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c | 10 ++-- drivers/gpu/drm/i915/gt/uc/intel_huc.c | 64 ++++++++++++++++++++--- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index 0f79cb6585182..52332bb143395 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -184,7 +184,7 @@ static int guc_wait_ucode(struct intel_guc *guc) * in the seconds range. However, there is a limit on how long an * individual wait_for() can wait. So wrap it in a loop. */ - before_freq = intel_rps_read_actual_frequency(&uncore->gt->rps); + before_freq = intel_rps_read_actual_frequency(>->rps); before = ktime_get(); for (count = 0; count < GUC_LOAD_RETRY_LIMIT; count++) { ret = wait_for(guc_load_done(uncore, &status, &success), 1000); @@ -192,7 +192,7 @@ static int guc_wait_ucode(struct intel_guc *guc) break; guc_dbg(guc, "load still in progress, count = %d, freq = %dMHz, status = 0x%08X [0x%02X/%02X]\n", - count, intel_rps_read_actual_frequency(&uncore->gt->rps), status, + count, intel_rps_read_actual_frequency(>->rps), status, REG_FIELD_GET(GS_BOOTROM_MASK, status), REG_FIELD_GET(GS_UKERNEL_MASK, status)); } @@ -204,7 +204,7 @@ static int guc_wait_ucode(struct intel_guc *guc) u32 bootrom = REG_FIELD_GET(GS_BOOTROM_MASK, status); guc_info(guc, "load failed: status = 0x%08X, time = %lldms, freq = %dMHz, ret = %d\n", - status, delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps), ret); + status, delta_ms, intel_rps_read_actual_frequency(>->rps), ret); guc_info(guc, "load failed: status: Reset = %d, BootROM = 0x%02X, UKernel = 0x%02X, MIA = 0x%02X, Auth = 0x%02X\n", REG_FIELD_GET(GS_MIA_IN_RESET, status), bootrom, ukernel, @@ -254,11 +254,11 @@ static int guc_wait_ucode(struct intel_guc *guc) guc_warn(guc, "excessive init time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n", delta_ms, status, count, ret); guc_warn(guc, "excessive init time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n", - intel_rps_read_actual_frequency(&uncore->gt->rps), before_freq, + intel_rps_read_actual_frequency(>->rps), before_freq, intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt))); } else { guc_dbg(guc, "init took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n", - delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps), + delta_ms, intel_rps_read_actual_frequency(>->rps), before_freq, status, count, ret); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index ba9e07fc2b577..0945b177d5f97 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -6,6 +6,7 @@ #include #include "gt/intel_gt.h" +#include "gt/intel_rps.h" #include "intel_guc_reg.h" #include "intel_huc.h" #include "intel_huc_print.h" @@ -447,17 +448,68 @@ static const char *auth_mode_string(struct intel_huc *huc, return partial ? "clear media" : "all workloads"; } +/* + * Use a longer timeout for debug builds so that problems can be detected + * and analysed. But a shorter timeout for releases so that user's don't + * wait forever to find out there is a problem. Note that the only reason + * an end user should hit the timeout is in case of extreme thermal throttling. + * And a system that is that hot during boot is probably dead anyway! + */ +#if defined(CONFIG_DRM_I915_DEBUG_GEM) +#define HUC_LOAD_RETRY_LIMIT 20 +#else +#define HUC_LOAD_RETRY_LIMIT 3 +#endif + int intel_huc_wait_for_auth_complete(struct intel_huc *huc, enum intel_huc_authentication_type type) { struct intel_gt *gt = huc_to_gt(huc); - int ret; + struct intel_uncore *uncore = gt->uncore; + ktime_t before, after, delta; + int ret, count; + u64 delta_ms; + u32 before_freq; - ret = __intel_wait_for_register(gt->uncore, - huc->status[type].reg, - huc->status[type].mask, - huc->status[type].value, - 2, 50, NULL); + /* + * The KMD requests maximum frequency during driver load, however thermal + * throttling can force the frequency down to minimum (although the board + * really should never get that hot in real life!). IFWI issues have been + * seen to cause sporadic failures to grant the higher frequency. And at + * minimum frequency, the authentication time can be in the seconds range. + * Note that there is a limit on how long an individual wait_for() can wait. + * So wrap it in a loop. + */ + before_freq = intel_rps_read_actual_frequency(>->rps); + before = ktime_get(); + for (count = 0; count < HUC_LOAD_RETRY_LIMIT; count++) { + ret = __intel_wait_for_register(gt->uncore, + huc->status[type].reg, + huc->status[type].mask, + huc->status[type].value, + 2, 1000, NULL); + if (!ret) + break; + + huc_dbg(huc, "auth still in progress, count = %d, freq = %dMHz, status = 0x%08X\n", + count, intel_rps_read_actual_frequency(>->rps), + huc->status[type].reg.reg); + } + after = ktime_get(); + delta = ktime_sub(after, before); + delta_ms = ktime_to_ms(delta); + + if (delta_ms > 50) { + huc_warn(huc, "excessive auth time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n", + delta_ms, huc->status[type].reg.reg, count, ret); + huc_warn(huc, "excessive auth time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n", + intel_rps_read_actual_frequency(>->rps), before_freq, + intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt))); + } else { + huc_dbg(huc, "auth took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n", + delta_ms, intel_rps_read_actual_frequency(>->rps), + before_freq, huc->status[type].reg.reg, count, ret); + } /* mark the load process as complete even if the wait failed */ delayed_huc_load_complete(huc); -- GitLab From 3bb45618061c0e1838e99ad246d7342727396451 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:30:25 +0100 Subject: [PATCH 0182/1420] drm/sched: One function call less in drm_sched_init() after error detection The kfree() function was called in one case by the drm_sched_init() function during error handling even if the passed data structure member contained a null pointer. This issue was detected by using the Coccinelle software. Thus adjust a jump target. Signed-off-by: Markus Elfring Link: https://patchwork.freedesktop.org/patch/msgid/85066512-983d-480c-a44d-32405ab1b80e@web.de Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 550492a7a031d..b99d4e9ff1094 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1289,7 +1289,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq), GFP_KERNEL | __GFP_ZERO); if (!sched->sched_rq) - goto Out_free; + goto Out_check_own; sched->num_rqs = num_rqs; for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL); @@ -1314,9 +1314,10 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, Out_unroll: for (--i ; i >= DRM_SCHED_PRIORITY_KERNEL; i--) kfree(sched->sched_rq[i]); -Out_free: + kfree(sched->sched_rq); sched->sched_rq = NULL; +Out_check_own: if (sched->own_submit_wq) destroy_workqueue(sched->submit_wq); drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__); -- GitLab From 26a4591b31916e1c53a7c64fa3ba3fc7cc5d549f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:37:37 +0100 Subject: [PATCH 0183/1420] drm/sched: Return an error code only as a constant in drm_sched_init() Return an error code without storing it in an intermediate variable. Signed-off-by: Markus Elfring Link: https://patchwork.freedesktop.org/patch/msgid/85f8004e-f0c9-42d9-8c59-30f1b4e0b89e@web.de Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index b99d4e9ff1094..1abbcdf38430e 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1249,7 +1249,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev) { - int i, ret; + int i; sched->ops = ops; sched->credit_limit = credit_limit; @@ -1285,7 +1285,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->own_submit_wq = true; } - ret = -ENOMEM; + sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq), GFP_KERNEL | __GFP_ZERO); if (!sched->sched_rq) @@ -1321,7 +1321,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, if (sched->own_submit_wq) destroy_workqueue(sched->submit_wq); drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__); - return ret; + return -ENOMEM; } EXPORT_SYMBOL(drm_sched_init); -- GitLab From 0fa647659c492c0a4342f7da70f5f946a40df250 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 5 Jan 2024 13:22:43 +0200 Subject: [PATCH 0184/1420] drm/i915/display: Use helper to select C20 MPLLA/B We used to select between MPLLA/B with the following state->tx[0] & C20_PHY_USE_MPLLB Since this is used a few places within C20 PLL setting, let's introduce a helper function to clean up the code a bit. Signed-off-by: Mika Kahola Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20240105112243.224199-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index ce1bddf74a82d..e67c259759478 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2096,6 +2096,11 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, return intel_c20pll_calc_state(crtc_state, encoder); } +static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state) +{ + return state->tx[0] & C20_PHY_USE_MPLLB; +} + static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_c20pll_state *pll_state) { @@ -2108,7 +2113,7 @@ static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, unsigned int tx_rate_mult; unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + if (intel_c20phy_use_mpllb(pll_state)) { tx_rate_mult = 1; frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); frac_quot = pll_state->mpllb[8]; @@ -2174,7 +2179,7 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, PHY_C20_A_CMN_CNTX_CFG(i)); } - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + if (intel_c20phy_use_mpllb(pll_state)) { /* MPLLB configuration */ for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { if (cntx) @@ -2212,7 +2217,7 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n", hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]); - if (hw_state->tx[0] & C20_PHY_USE_MPLLB) { + if (intel_c20phy_use_mpllb(hw_state)) { for (i = 0; i < ARRAY_SIZE(hw_state->mpllb); i++) drm_dbg_kms(&i915->drm, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]); } else { @@ -2364,7 +2369,7 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, } /* 3.3 mpllb or mplla configuration */ - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + if (intel_c20phy_use_mpllb(pll_state)) { for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, @@ -3063,8 +3068,8 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state, { struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20; - bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB; - bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB; + bool sw_use_mpllb = intel_c20phy_use_mpllb(mpll_sw_state); + bool hw_use_mpllb = intel_c20phy_use_mpllb(mpll_hw_state); int i; I915_STATE_WARN(i915, mpll_hw_state->clock != mpll_sw_state->clock, -- GitLab From f5b6fd4ea320176468597afd8343e4b94544f986 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 5 Jan 2024 09:25:17 +0100 Subject: [PATCH 0185/1420] drm/mgag200: Fix caching setup for remapped video memory I/O video memory for the framebuffer supports write-combine caching mode. Simplify the driver's code that sets up the caching mode. * Map video memory with ioremap_wc(), which automatically sets up the PAT entry with write-combine caching. * Remove the now obsolete call to devm_arch_io_reserve_memtype_wc(). It is only required to mmap the video memory to user space, which the driver doesn't do. * According to the PAT documentation, arch_phys_wc_add() is best called after remapping I/O memory, so move it after ioremap. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20240105082714.21881-1-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 2fb18b782b053..54fce00e2136e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -146,14 +146,13 @@ int mgag200_device_preinit(struct mga_device *mdev) } mdev->vram_res = res; - /* Don't fail on errors, but performance might be reduced. */ - devm_arch_io_reserve_memtype_wc(dev->dev, res->start, resource_size(res)); - devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res)); - - mdev->vram = devm_ioremap(dev->dev, res->start, resource_size(res)); + mdev->vram = devm_ioremap_wc(dev->dev, res->start, resource_size(res)); if (!mdev->vram) return -ENOMEM; + /* Don't fail on errors, but performance might be reduced. */ + devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res)); + return 0; } -- GitLab From 2e367ad4da3339e2763a32592cba4f6e1ab53f59 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Jan 2024 18:57:48 +0200 Subject: [PATCH 0186/1420] drm/mgag200: convert get modes to struct drm_edid Convert mgag200_vga_connector_helper_get_modes() to use struct drm_edid based functions directly. Suggested-by: Thomas Zimmermann Signed-off-by: Jani Nikula Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/19a453c725fc27bd890f8fc73104f43a376dfce0.1704473654.git.jani.nikula@intel.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af3ce5a6a636a..1596937bb5ad7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -14,13 +14,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include "mgag200_drv.h" @@ -717,17 +717,23 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { struct mga_device *mdev = to_mga_device(connector->dev); - int ret; + const struct drm_edid *drm_edid; + int count; /* * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ mutex_lock(&mdev->rmmio_lock); - ret = drm_connector_helper_get_modes_from_ddc(connector); + + drm_edid = drm_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); + mutex_unlock(&mdev->rmmio_lock); - return ret; + return count; } /* -- GitLab From babebd1dc1279027206583a9921e05657f97da87 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Jan 2024 18:57:49 +0200 Subject: [PATCH 0187/1420] drm/probe-helper: remove unused drm_connector_helper_get_modes_from_ddc() Remove the unused drm_connector_helper_get_modes_from_ddc() function. Most drivers should probably have this functionality split to detect and get modes parts, so the helper is not the best abstraction. Suggested-by: Thomas Zimmermann Signed-off-by: Jani Nikula Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/60eb6b2db16747d3f9c12604b197f33da585c16e.1704473654.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_probe_helper.c | 36 ------------------------------ include/drm/drm_probe_helper.h | 1 - 2 files changed, 37 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3f479483d7d80..d1e1ade66f81c 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -1100,42 +1100,6 @@ enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_crtc_helper_mode_valid_fixed); -/** - * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID - * property from the connector's - * DDC channel - * @connector: The connector - * - * Returns: - * The number of detected display modes. - * - * Uses a connector's DDC channel to retrieve EDID data and update the - * connector's EDID property and display modes. Drivers can use this - * function to implement struct &drm_connector_helper_funcs.get_modes - * for connectors with a DDC channel. - */ -int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector) -{ - struct edid *edid; - int count = 0; - - if (!connector->ddc) - return 0; - - edid = drm_get_edid(connector, connector->ddc); - - // clears property if EDID is NULL - drm_connector_update_edid_property(connector, edid); - - if (edid) { - count = drm_add_edid_modes(connector, edid); - kfree(edid); - } - - return count; -} -EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc); - /** * drm_connector_helper_get_modes_fixed - Duplicates a display mode for a connector * @connector: the connector diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h index fad3c4003b2b5..62741a88796bb 100644 --- a/include/drm/drm_probe_helper.h +++ b/include/drm/drm_probe_helper.h @@ -32,7 +32,6 @@ enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc, const struct drm_display_mode *mode, const struct drm_display_mode *fixed_mode); -int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector); int drm_connector_helper_get_modes_fixed(struct drm_connector *connector, const struct drm_display_mode *fixed_mode); int drm_connector_helper_get_modes(struct drm_connector *connector); -- GitLab From 264ed178781c05f87735e2712a34c4ab35b0c91c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Jan 2024 09:20:14 +0000 Subject: [PATCH 0188/1420] drm/xe: Fix spelling mistake "gueue" -> "queue" There is a spelling mistake in a drm_info message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://lore.kernel.org/r/20240102092014.3347566-1-colin.i.king@gmail.com --- drivers/gpu/drm/xe/xe_wait_user_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c index a75eeba7bfe58..f69721339201d 100644 --- a/drivers/gpu/drm/xe/xe_wait_user_fence.c +++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c @@ -148,7 +148,7 @@ int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data, if (q) { if (q->ops->reset_status(q)) { - drm_info(&xe->drm, "exec gueue reset detected\n"); + drm_info(&xe->drm, "exec queue reset detected\n"); err = -EIO; break; } -- GitLab From 289d4180bda98bfd47e0dac402a1caf2a8f50cf7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:57 +0200 Subject: [PATCH 0189/1420] drm/i915: Init DRM connector polled field early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After an HPD IRQ storm on a connector intel_hpd_irq_storm_detect() will set the connector's HPD pin state to HPD_MARK_DISABLED and the IRQ gets disabled. Subsequently intel_hpd_irq_storm_switch_to_polling() will enable polling for these connectors, setting the pin state to HPD_DISABLED, but only if the connector's base.polled field is set to DRM_CONNECTOR_POLL_HPD. intel_hpd_irq_storm_reenable_work() will reenable the IRQ - after 2 minutes - if the pin state is HPD_DISABLED. The connectors will be created with their base.polled field set to 0, which gets initialized only later in i915_hpd_poll_init_work() (using intel_connector::polled). If a storm is detected on a connector after it's created and IRQs are enabled on it - by intel_hpd_init() - and before its bease.polled field is initialized in the above work, the connector's HPD pin will stay in the HPD_MARK_DISABLED state - leaving the IRQ disabled indefinitely - and polling will not get enabled on it as intended. I can't see a reason for initializing base.polled in a delayed manner, so do this already when creating the connector, to prevent the above race condition. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-2-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_dvo.c | 1 + drivers/gpu/drm/i915/display/intel_hdmi.c | 1 + drivers/gpu/drm/i915/display/intel_sdvo.c | 2 ++ drivers/gpu/drm/i915/display/intel_tv.c | 1 + 6 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index abaacea5c2cc4..b330337b842a4 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -1069,6 +1069,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; } + intel_connector->base.polled = intel_connector->polled; if (HAS_DDI(dev_priv)) { assert_port_valid(dev_priv, PORT_E); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f4a22d40eec27..8803a93233533 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6462,6 +6462,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, connector->interlace_allowed = true; intel_connector->polled = DRM_CONNECTOR_POLL_HPD; + intel_connector->base.polled = intel_connector->polled; intel_connector_attach_encoder(intel_connector, intel_encoder); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 9111e9d46486d..83898ba493d16 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -536,6 +536,7 @@ void intel_dvo_init(struct drm_i915_private *i915) if (intel_dvo->dev.type == INTEL_DVO_CHIP_TMDS) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->base.polled = connector->polled; drm_connector_init_with_ddc(&i915->drm, &connector->base, &intel_dvo_connector_funcs, diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index eedef8121ff7c..55048c56bc527 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3017,6 +3017,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, connector->ycbcr_420_allowed = true; intel_connector->polled = DRM_CONNECTOR_POLL_HPD; + intel_connector->base.polled = intel_connector->polled; if (HAS_DDI(dev_priv)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 0362d02d70b6a..c660dd88dec70 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2804,6 +2804,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type) } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } + intel_connector->base.polled = intel_connector->polled; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2879,6 +2880,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->base.polled = intel_connector->polled; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 9a217805d2f6f..1b19443739c33 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1990,6 +1990,7 @@ intel_tv_init(struct drm_i915_private *dev_priv) * More recent chipsets favour HDMI rather than integrated S-Video. */ intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->base.polled = intel_connector->polled; drm_connector_init(&dev_priv->drm, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); -- GitLab From f7d16a538ad226d8b60990f8628e1c81787ee62c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:58 +0200 Subject: [PATCH 0190/1420] drm/i915: Keep the connector polled state disabled after storm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an HPD IRQ storm is detected on a connector during driver loading or system suspend/resume - disabling the IRQ and switching to polling - the polling may get disabled too early - before the intended 2 minute HPD_STORM_REENABLE_DELAY - with the HPD IRQ staying disabled for this duration. One such sequence is: Thread#1 Thread#2 intel_display_driver_probe()-> intel_hpd_init()-> (HPD IRQ gets enabled) . intel_hpd_irq_handler()-> . intel_hpd_irq_storm_detect() . intel_hpd_irq_setup()-> . (HPD IRQ gets disabled) . queue_delayed_work(hotplug.hotplug_work) . ... . i915_hotplug_work_func()-> . intel_hpd_irq_storm_switch_to_polling()-> . (polling enabled) . intel_hpd_poll_disable()-> queue_work(hotplug.poll_init_work) ... i915_hpd_poll_init_work()-> (polling gets disabled, HPD IRQ is still disabled) ... (Connector is neither polled or detected via HPD IRQs for 2 minutes) intel_hpd_irq_storm_reenable_work()-> (HPD IRQ gets enabled) To avoid the above 2 minute state without either polling or enabled HPD IRQ, leave the connector's polling mode unchanged in i915_hpd_poll_init_work() if its HPD IRQ got disabled after an IRQ storm indicated by the connector's HPD_DISABLED pin state. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-3-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_hotplug.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 0c0700c6ec66d..74513c3d3690b 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -710,6 +710,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work) cancel_work(&dev_priv->display.hotplug.poll_init_work); } + spin_lock_irq(&dev_priv->irq_lock); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { enum hpd_pin pin; @@ -718,6 +720,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work) if (pin == HPD_NONE) continue; + if (dev_priv->display.hotplug.stats[pin].state == HPD_DISABLED) + continue; + connector->base.polled = connector->polled; if (enabled && connector->base.polled == DRM_CONNECTOR_POLL_HPD) @@ -726,6 +731,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work) } drm_connector_list_iter_end(&conn_iter); + spin_unlock_irq(&dev_priv->irq_lock); + if (enabled) drm_kms_helper_poll_reschedule(&dev_priv->drm); -- GitLab From a1a0e8630711e404952e8d6485715183676b99f9 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:59 +0200 Subject: [PATCH 0191/1420] drm/i915: Move audio deinit after disabling polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deinitialize audio during driver unload after disabling polling. This is in preparation to do all the display HW init/deinit steps at a point where no HPD IRQ or polling initiated connector detection or modeset can change the HW state. This may still happen here via an HPD IRQ -> hotplug detection work or a connector sysfs (state/detect) access, but these will be prevented by later changes in this patchset. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-4-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_display_driver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 9df9097a0255a..da549962feccd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -486,14 +486,15 @@ void intel_display_driver_unregister(struct drm_i915_private *i915) return; intel_fbdev_unregister(i915); - intel_audio_deinit(i915); - /* * After flushing the fbdev (incl. a late async config which * will have delayed queuing of a hotplug event), then flush * the hotplug events. */ drm_kms_helper_poll_fini(&i915->drm); + + intel_audio_deinit(i915); + drm_atomic_helper_shutdown(&i915->drm); acpi_video_unregister(); -- GitLab From 24b412b1bfebb29ffca93bec215d26fd3a85a405 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:00 +0200 Subject: [PATCH 0192/1420] drm/i915: Disable intel HPD poll after DRM poll init/enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only purpose of intel_hpd_poll_disable() during driver loading and system resume - at which point polling should be disabled anyway, except for connectors in an IRQ storm, for which the polling will stay enabled - is to force-detect all the connectors. However this detection in i915_hpd_poll_init_work() depends on drm.mode_config.poll_enabled, which will get set in drm_kms_helper_poll_init(), possibly after i915_hpd_poll_init_work() is scheduled. Hence the initial detection of connectors during driver loading may not happen. Fix the above by moving intel_hpd_poll_disable() after i915_hpd_poll_init_work(), the proper place anyway for doing the above detection after all the HW initialization steps are complete. Change the order the same way during system resume as well. The above race condition shouldn't matter here - as drm.mode_config.poll_enabled will be set - but the detection should happen here as well after the HW init steps are done. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-5-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_display_driver.c | 2 +- drivers/gpu/drm/i915/i915_driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index da549962feccd..1974f2394a518 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -374,7 +374,6 @@ int intel_display_driver_probe(struct drm_i915_private *i915) /* Only enable hotplug handling once the fbdev is fully set up. */ intel_hpd_init(i915); - intel_hpd_poll_disable(i915); skl_watermark_ipc_init(i915); @@ -412,6 +411,7 @@ void intel_display_driver_register(struct drm_i915_private *i915) * fbdev->async_cookie. */ drm_kms_helper_poll_init(&i915->drm); + intel_hpd_poll_disable(i915); intel_display_device_info_print(DISPLAY_INFO(i915), DISPLAY_RUNTIME_INFO(i915), &p); diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 8dead878e51ab..55badc20a10f4 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1248,9 +1248,9 @@ static int i915_drm_resume(struct drm_device *dev) intel_dp_mst_resume(dev_priv); intel_display_driver_resume(dev_priv); - intel_hpd_poll_disable(dev_priv); if (HAS_DISPLAY(dev_priv)) drm_kms_helper_poll_enable(dev); + intel_hpd_poll_disable(dev_priv); intel_opregion_resume(dev_priv); -- GitLab From f4ed123ae295e3ce6f52d054540fdce258ea47e1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:01 +0200 Subject: [PATCH 0193/1420] drm/i915: Suspend the framebuffer console during driver shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suspend the FB console during driver shutdown the same way this is done during system resume. This should prevent any HPD event to trigger a new FB probe/modeset cycle happening in parallel with the display HW disable/uninitialize steps. A preceding FB HPD event handling may be still pending, resulting in a probe/modeset like the above, these will be prevented by a later change in this patchset. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-6-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/i915_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 55badc20a10f4..0d78df3e7eff4 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1002,6 +1002,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_runtime_pm_disable(&i915->runtime_pm); intel_power_domains_disable(i915); + intel_fbdev_set_suspend(&i915->drm, FBINFO_STATE_SUSPENDED, true); if (HAS_DISPLAY(i915)) { drm_kms_helper_poll_disable(&i915->drm); -- GitLab From 1ef28d86bea92503341215fcc7d934d6156b9ba0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:02 +0200 Subject: [PATCH 0194/1420] drm/i915: Suspend the framebuffer console earlier during system suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suspend the FB console early during system suspend to prevent new FB probe/modeset cycles interfering with the HW uninitialization steps in a similar way as during driver shutdown as described in the previous patch. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-7-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/i915_driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 0d78df3e7eff4..8005a29e78ca7 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1080,6 +1080,7 @@ static int i915_drm_suspend(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ intel_power_domains_disable(dev_priv); + intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); if (HAS_DISPLAY(dev_priv)) drm_kms_helper_poll_disable(dev); @@ -1103,8 +1104,6 @@ static int i915_drm_suspend(struct drm_device *dev) opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; intel_opregion_suspend(dev_priv, opregion_target_state); - intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); - dev_priv->suspend_count++; intel_dmc_suspend(dev_priv); -- GitLab From bd738d859e71acb9315634cf38676fd0585d4668 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 15:23:35 +0200 Subject: [PATCH 0195/1420] drm/i915: Prevent modesets during driver init/shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An unexpected modeset or connector detection by a user (user space or FB console) during the initialization/shutdown sequence is possible either via a hotplug IRQ handling work or via the connector sysfs (status/detect) interface. These modesets/detections should be prevented by disabling/flushing all related hotplug handling work and unregistering the interfaces that can start them at the beginning of the shutdown sequence. Some of this - disabling all related intel_hotplug work - will be done by the next patch, but others - for instance disabling the MST hotplug works - require a bigger rework. It makes sense - for diagnostic purpose, even with all the above work and interface disabled - to detect and reject any such user access. This patch does that for modeset accesses and a follow-up patch for connector detection. During driver loading/unloading/system suspend/shutdown and during system resume after calling intel_display_driver_disable_user_access() or intel_display_driver_resume_access() correspondigly, the current thread is allowed to modeset (as this thread requires to do an initial/restoring modeset or a disabling modeset), other threads (the user threads) are not allowed to modeset. During driver loading/system resume after calling intel_display_driver_enable_user_access() all threads are allowed to modeset. During driver unloading/system suspend/shutdown after calling intel_display_driver_suspend_access() no threads are allowed to modeset (as the HW got disabled and should stay in this state). v2: Call intel_display_driver_suspend_access()/resume_access() only for HAS_DISPLAY(). (CI) v3: (Jouni) - Add commit log comments explaining how the permission of modeset changes during HW init/deinit wrt. to the current and other user processes. Link: https://patchwork.freedesktop.org/patch/msgid/20240104132335.2766434-1-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_display.c | 3 + .../gpu/drm/i915/display/intel_display_core.h | 7 + .../drm/i915/display/intel_display_driver.c | 138 ++++++++++++++++++ .../drm/i915/display/intel_display_driver.h | 6 + drivers/gpu/drm/i915/i915_driver.c | 19 ++- 5 files changed, 171 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9b9a30c11e1c6..4a1d0613dfe7b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6310,6 +6310,9 @@ int intel_atomic_check(struct drm_device *dev, int ret, i; bool any_ms = false; + if (!intel_display_driver_check_access(dev_priv)) + return -ENODEV; + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { /* diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 7349a2b928c07..cd3b34459b875 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -28,6 +28,8 @@ #include "intel_opregion.h" #include "intel_wm_types.h" +struct task_struct; + struct drm_i915_private; struct drm_property; struct drm_property_blob; @@ -295,6 +297,11 @@ struct intel_display { const struct intel_audio_funcs *audio; } funcs; + struct { + bool any_task_allowed; + struct task_struct *allowed_task; + } access; + struct { /* backlight registers and fields in struct intel_panel */ struct mutex lock; diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 1974f2394a518..dcdd26eefaaf4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -45,6 +45,7 @@ #include "intel_hdcp.h" #include "intel_hotplug.h" #include "intel_hti.h" +#include "intel_modeset_lock.h" #include "intel_modeset_setup.h" #include "intel_opregion.h" #include "intel_overlay.h" @@ -276,6 +277,135 @@ int intel_display_driver_probe_noirq(struct drm_i915_private *i915) return ret; } +static void set_display_access(struct drm_i915_private *i915, + bool any_task_allowed, + struct task_struct *allowed_task) +{ + struct drm_modeset_acquire_ctx ctx; + int err; + + intel_modeset_lock_ctx_retry(&ctx, NULL, 0, err) { + err = drm_modeset_lock_all_ctx(&i915->drm, &ctx); + if (err) + continue; + + i915->display.access.any_task_allowed = any_task_allowed; + i915->display.access.allowed_task = allowed_task; + } + + drm_WARN_ON(&i915->drm, err); +} + +/** + * intel_display_driver_enable_user_access - Enable display HW access for all threads + * @i915: i915 device instance + * + * Enable the display HW access for all threads. Examples for such accesses + * are modeset commits and connector probing. + * + * This function should be called during driver loading and system resume once + * all the HW initialization steps are done. + */ +void intel_display_driver_enable_user_access(struct drm_i915_private *i915) +{ + set_display_access(i915, true, NULL); +} + +/** + * intel_display_driver_disable_user_access - Disable display HW access for user threads + * @i915: i915 device instance + * + * Disable the display HW access for user threads. Examples for such accesses + * are modeset commits and connector probing. For the current thread the + * access is still enabled, which should only perform HW init/deinit + * programming (as the initial modeset during driver loading or the disabling + * modeset during driver unloading and system suspend/shutdown). This function + * should be followed by calling either intel_display_driver_enable_user_access() + * after completing the HW init programming or + * intel_display_driver_suspend_access() after completing the HW deinit + * programming. + * + * This function should be called during driver loading/unloading and system + * suspend/shutdown before starting the HW init/deinit programming. + */ +void intel_display_driver_disable_user_access(struct drm_i915_private *i915) +{ + set_display_access(i915, false, current); +} + +/** + * intel_display_driver_suspend_access - Suspend display HW access for all threads + * @i915: i915 device instance + * + * Disable the display HW access for all threads. Examples for such accesses + * are modeset commits and connector probing. This call should be either + * followed by calling intel_display_driver_resume_access(), or the driver + * should be unloaded/shutdown. + * + * This function should be called during driver unloading and system + * suspend/shutdown after completing the HW deinit programming. + */ +void intel_display_driver_suspend_access(struct drm_i915_private *i915) +{ + set_display_access(i915, false, NULL); +} + +/** + * intel_display_driver_resume_access - Resume display HW access for the resume thread + * @i915: i915 device instance + * + * Enable the display HW access for the current resume thread, keeping the + * access disabled for all other (user) threads. Examples for such accesses + * are modeset commits and connector probing. The resume thread should only + * perform HW init programming (as the restoring modeset). This function + * should be followed by calling intel_display_driver_enable_user_access(), + * after completing the HW init programming steps. + * + * This function should be called during system resume before starting the HW + * init steps. + */ +void intel_display_driver_resume_access(struct drm_i915_private *i915) +{ + set_display_access(i915, false, current); +} + +/** + * intel_display_driver_check_access - Check if the current thread has disaplay HW access + * @i915: i915 device instance + * + * Check whether the current thread has display HW access, print a debug + * message if it doesn't. Such accesses are modeset commits and connector + * probing. If the function returns %false any HW access should be prevented. + * + * Returns %true if the current thread has display HW access, %false + * otherwise. + */ +bool intel_display_driver_check_access(struct drm_i915_private *i915) +{ + char comm[TASK_COMM_LEN]; + char current_task[TASK_COMM_LEN + 16]; + char allowed_task[TASK_COMM_LEN + 16] = "none"; + + if (i915->display.access.any_task_allowed || + i915->display.access.allowed_task == current) + return true; + + snprintf(current_task, sizeof(current_task), "%s[%d]", + get_task_comm(comm, current), + task_pid_vnr(current)); + + if (i915->display.access.allowed_task) + snprintf(allowed_task, sizeof(allowed_task), "%s[%d]", + get_task_comm(comm, i915->display.access.allowed_task), + task_pid_vnr(i915->display.access.allowed_task)); + + drm_dbg_kms(&i915->drm, + "Reject display access from task %s (allowed to %s)\n", + current_task, allowed_task); + + return false; +} + /* part #2: call after irq install, but before gem init */ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) { @@ -326,6 +456,8 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) intel_vga_disable(i915); intel_setup_outputs(i915); + intel_display_driver_disable_user_access(i915); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(i915, dev->mode_config.acquire_ctx); intel_acpi_assign_connector_fwnodes(i915); @@ -393,6 +525,8 @@ void intel_display_driver_register(struct drm_i915_private *i915) intel_audio_init(i915); + intel_display_driver_enable_user_access(i915); + intel_display_debugfs_register(i915); /* @@ -440,6 +574,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return; + intel_display_driver_suspend_access(i915); + /* * Due to the hpd irq storm handling the hotplug work can re-arm the * poll handlers. Hence disable polling after hpd handling is shut down. @@ -493,6 +629,8 @@ void intel_display_driver_unregister(struct drm_i915_private *i915) */ drm_kms_helper_poll_fini(&i915->drm); + intel_display_driver_disable_user_access(i915); + intel_audio_deinit(i915); drm_atomic_helper_shutdown(&i915->drm); diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.h b/drivers/gpu/drm/i915/display/intel_display_driver.h index c276a58ee3293..42cc4af6d3fd5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.h +++ b/drivers/gpu/drm/i915/display/intel_display_driver.h @@ -32,5 +32,11 @@ int __intel_display_driver_resume(struct drm_i915_private *i915, struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); +void intel_display_driver_enable_user_access(struct drm_i915_private *i915); +void intel_display_driver_disable_user_access(struct drm_i915_private *i915); +void intel_display_driver_suspend_access(struct drm_i915_private *i915); +void intel_display_driver_resume_access(struct drm_i915_private *i915); +bool intel_display_driver_check_access(struct drm_i915_private *i915); + #endif /* __INTEL_DISPLAY_DRIVER_H__ */ diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 8005a29e78ca7..7603771ae107b 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1005,6 +1005,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_fbdev_set_suspend(&i915->drm, FBINFO_STATE_SUSPENDED, true); if (HAS_DISPLAY(i915)) { drm_kms_helper_poll_disable(&i915->drm); + intel_display_driver_disable_user_access(i915); drm_atomic_helper_shutdown(&i915->drm); } @@ -1014,6 +1015,9 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_runtime_pm_disable_interrupts(i915); intel_hpd_cancel_work(i915); + if (HAS_DISPLAY(i915)) + intel_display_driver_suspend_access(i915); + intel_suspend_encoders(i915); intel_shutdown_encoders(i915); @@ -1081,8 +1085,10 @@ static int i915_drm_suspend(struct drm_device *dev) * properly. */ intel_power_domains_disable(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); - if (HAS_DISPLAY(dev_priv)) + if (HAS_DISPLAY(dev_priv)) { drm_kms_helper_poll_disable(dev); + intel_display_driver_disable_user_access(dev_priv); + } pci_save_state(pdev); @@ -1093,6 +1099,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_runtime_pm_disable_interrupts(dev_priv); intel_hpd_cancel_work(dev_priv); + if (HAS_DISPLAY(dev_priv)) + intel_display_driver_suspend_access(dev_priv); + intel_suspend_encoders(dev_priv); /* Must be called before GGTT is suspended. */ @@ -1242,14 +1251,20 @@ static int i915_drm_resume(struct drm_device *dev) intel_display_driver_init_hw(dev_priv); intel_clock_gating_init(dev_priv); + + if (HAS_DISPLAY(dev_priv)) + intel_display_driver_resume_access(dev_priv); + intel_hpd_init(dev_priv); /* MST sideband requires HPD interrupts enabled */ intel_dp_mst_resume(dev_priv); intel_display_driver_resume(dev_priv); - if (HAS_DISPLAY(dev_priv)) + if (HAS_DISPLAY(dev_priv)) { + intel_display_driver_enable_user_access(dev_priv); drm_kms_helper_poll_enable(dev); + } intel_hpd_poll_disable(dev_priv); intel_opregion_resume(dev_priv); -- GitLab From cd572b3bb27e86f4a4c814acabbf1f197259c011 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:04 +0200 Subject: [PATCH 0196/1420] drm/i915: Disable hotplug detection works during driver init/shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the previous patch, an unexpected connector detection/modeset started from the intel_hotplug::hotplug_work can happen during the driver init/shutdown sequence. Prevent these by disabling the queuing of and flushing all the intel_hotplug work that can start them at the beginning of the init/shutdown sequence and allow the queuing only while the display is in the initialized state. Other work items - like the intel_connector::modeset_retry_work or the MST probe works - are still enabled and can start a detection/modeset, but after the previous patch these will be rejected. Disabling these works as well is for a follow-up patchset. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-9-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- .../gpu/drm/i915/display/intel_display_core.h | 6 + .../drm/i915/display/intel_display_driver.c | 4 + drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_hotplug.c | 158 +++++++++++++++--- drivers/gpu/drm/i915/display/intel_hotplug.h | 4 + 5 files changed, 154 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index cd3b34459b875..54278db823dfd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -174,6 +174,12 @@ struct intel_hotplug { struct work_struct poll_init_work; bool poll_enabled; + /* + * Queuing of hotplug_work, reenable_work and poll_init_work is + * enabled. Protected by drm_i915_private::irq_lock. + */ + bool detection_work_enabled; + unsigned int hpd_storm_threshold; /* Whether or not to count short HPD IRQs in HPD storms */ u8 hpd_short_storm_enabled; diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index dcdd26eefaaf4..ecf9cb74734b6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -309,6 +309,8 @@ static void set_display_access(struct drm_i915_private *i915, void intel_display_driver_enable_user_access(struct drm_i915_private *i915) { set_display_access(i915, true, NULL); + + intel_hpd_enable_detection_work(i915); } /** @@ -330,6 +332,8 @@ void intel_display_driver_enable_user_access(struct drm_i915_private *i915) */ void intel_display_driver_disable_user_access(struct drm_i915_private *i915) { + intel_hpd_disable_detection_work(i915); + set_display_access(i915, false, current); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8803a93233533..6ce003b97dcce 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6019,7 +6019,7 @@ static void intel_dp_oob_hotplug_event(struct drm_connector *connector) spin_lock_irq(&i915->irq_lock); i915->display.hotplug.event_bits |= BIT(encoder->hpd_pin); spin_unlock_irq(&i915->irq_lock); - queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); + intel_hpd_schedule_detection(i915); } static const struct drm_connector_funcs intel_dp_connector_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 74513c3d3690b..d9ec349f3c8c3 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -177,6 +177,46 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, return storm; } +static bool detection_work_enabled(struct drm_i915_private *i915) +{ + lockdep_assert_held(&i915->irq_lock); + + return i915->display.hotplug.detection_work_enabled; +} + +static bool +mod_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return mod_delayed_work(i915->unordered_wq, work, delay); +} + +static bool +queue_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return queue_delayed_work(i915->unordered_wq, work, delay); +} + +static bool +queue_detection_work(struct drm_i915_private *i915, struct work_struct *work) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return queue_work(i915->unordered_wq, work); +} + static void intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) { @@ -213,9 +253,9 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) /* Enable polling and queue hotplug re-enabling. */ if (hpd_disabled) { drm_kms_helper_poll_reschedule(&dev_priv->drm); - mod_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.reenable_work, - msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); + mod_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.reenable_work, + msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); } } @@ -348,9 +388,9 @@ static void i915_digport_work_func(struct work_struct *work) if (old_bits) { spin_lock_irq(&dev_priv->irq_lock); dev_priv->display.hotplug.event_bits |= old_bits; + queue_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, 0); spin_unlock_irq(&dev_priv->irq_lock); - queue_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, 0); } } @@ -467,11 +507,11 @@ static void i915_hotplug_work_func(struct work_struct *work) if (retry) { spin_lock_irq(&dev_priv->irq_lock); dev_priv->display.hotplug.retry_bits |= retry; - spin_unlock_irq(&dev_priv->irq_lock); - mod_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, - msecs_to_jiffies(HPD_RETRY_DELAY)); + mod_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, + msecs_to_jiffies(HPD_RETRY_DELAY)); + spin_unlock_irq(&dev_priv->irq_lock); } } @@ -590,7 +630,6 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, */ if (storm_detected) intel_hpd_irq_setup(dev_priv); - spin_unlock(&dev_priv->irq_lock); /* * Our hotplug handler can grab modeset locks (by calling down into the @@ -601,8 +640,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, if (queue_dig) queue_work(dev_priv->display.hotplug.dp_wq, &dev_priv->display.hotplug.dig_port_work); if (queue_hp) - queue_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, 0); + queue_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, 0); + + spin_unlock(&dev_priv->irq_lock); } /** @@ -781,8 +822,10 @@ void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) * As well, there's no issue if we race here since we always reschedule * this worker anyway */ - queue_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.poll_init_work); + spin_lock_irq(&dev_priv->irq_lock); + queue_detection_work(dev_priv, + &dev_priv->display.hotplug.poll_init_work); + spin_unlock_irq(&dev_priv->irq_lock); } /** @@ -810,8 +853,11 @@ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv) return; WRITE_ONCE(dev_priv->display.hotplug.poll_enabled, false); - queue_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.poll_init_work); + + spin_lock_irq(&dev_priv->irq_lock); + queue_detection_work(dev_priv, + &dev_priv->display.hotplug.poll_init_work); + spin_unlock_irq(&dev_priv->irq_lock); } void intel_hpd_init_early(struct drm_i915_private *i915) @@ -833,6 +879,20 @@ void intel_hpd_init_early(struct drm_i915_private *i915) i915->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(i915); } +static bool cancel_all_detection_work(struct drm_i915_private *i915) +{ + bool was_pending = false; + + if (cancel_delayed_work_sync(&i915->display.hotplug.hotplug_work)) + was_pending = true; + if (cancel_work_sync(&i915->display.hotplug.poll_init_work)) + was_pending = true; + if (cancel_delayed_work_sync(&i915->display.hotplug.reenable_work)) + was_pending = true; + + return was_pending; +} + void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) { if (!HAS_DISPLAY(dev_priv)) @@ -848,9 +908,13 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); cancel_work_sync(&dev_priv->display.hotplug.dig_port_work); - cancel_delayed_work_sync(&dev_priv->display.hotplug.hotplug_work); - cancel_work_sync(&dev_priv->display.hotplug.poll_init_work); - cancel_delayed_work_sync(&dev_priv->display.hotplug.reenable_work); + + /* + * All other work triggered by hotplug events should be canceled by + * now. + */ + if (cancel_all_detection_work(dev_priv)) + drm_dbg_kms(&dev_priv->drm, "Hotplug detection work still active\n"); } bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin) @@ -880,6 +944,62 @@ void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin) spin_unlock_irq(&dev_priv->irq_lock); } +static void queue_work_for_missed_irqs(struct drm_i915_private *i915) +{ + bool queue_work = false; + enum hpd_pin pin; + + lockdep_assert_held(&i915->irq_lock); + + if (i915->display.hotplug.event_bits || + i915->display.hotplug.retry_bits) + queue_work = true; + + for_each_hpd_pin(pin) { + switch (i915->display.hotplug.stats[pin].state) { + case HPD_MARK_DISABLED: + queue_work = true; + break; + case HPD_ENABLED: + break; + default: + MISSING_CASE(i915->display.hotplug.stats[pin].state); + } + } + + if (queue_work) + queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0); +} + +void intel_hpd_enable_detection_work(struct drm_i915_private *i915) +{ + spin_lock_irq(&i915->irq_lock); + i915->display.hotplug.detection_work_enabled = true; + queue_work_for_missed_irqs(i915); + spin_unlock_irq(&i915->irq_lock); +} + +void intel_hpd_disable_detection_work(struct drm_i915_private *i915) +{ + spin_lock_irq(&i915->irq_lock); + i915->display.hotplug.detection_work_enabled = false; + spin_unlock_irq(&i915->irq_lock); + + cancel_all_detection_work(i915); +} + +bool intel_hpd_schedule_detection(struct drm_i915_private *i915) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&i915->irq_lock, flags); + ret = queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0); + spin_unlock_irqrestore(&i915->irq_lock, flags); + + return ret; +} + static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = m->private; diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h index 424ae5dbf5a0e..a17253ddec83a 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.h +++ b/drivers/gpu/drm/i915/display/intel_hotplug.h @@ -30,4 +30,8 @@ bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_debugfs_register(struct drm_i915_private *i915); +void intel_hpd_enable_detection_work(struct drm_i915_private *i915); +void intel_hpd_disable_detection_work(struct drm_i915_private *i915); +bool intel_hpd_schedule_detection(struct drm_i915_private *i915); + #endif /* __INTEL_HOTPLUG_H__ */ -- GitLab From bab87ef4db9aafeb8f95b7bfa5c12b187c01d13e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:05 +0200 Subject: [PATCH 0197/1420] drm/i915: Disable hotplug detection handlers during driver init/shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the previous two patches an unexpected connector detection can happen during the init/shutdown sequences. Prevent these by returning the connector's current status from the detection handlers. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-10-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_crt.c | 4 ++++ drivers/gpu/drm/i915/display/intel_dp.c | 8 ++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 ++++ drivers/gpu/drm/i915/display/intel_dvo.c | 4 ++++ drivers/gpu/drm/i915/display/intel_hdmi.c | 7 +++++++ drivers/gpu/drm/i915/display/intel_panel.c | 4 ++++ drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++ drivers/gpu/drm/i915/display/intel_tv.c | 4 ++++ 8 files changed, 39 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index b330337b842a4..b9733a73e21d4 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -42,6 +42,7 @@ #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" @@ -846,6 +847,9 @@ intel_crt_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + if (dev_priv->display.params.load_detect_test) { wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6ce003b97dcce..b2591148670b7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -56,6 +56,7 @@ #include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux.h" @@ -5646,6 +5647,9 @@ intel_dp_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + /* Can't disconnect eDP */ if (intel_dp_is_edp(intel_dp)) status = edp_detect(intel_dp); @@ -5746,6 +5750,10 @@ intel_dp_force(struct drm_connector *connector) drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + + if (!intel_display_driver_check_access(dev_priv)) + return; + intel_dp_unset_edid(intel_dp); if (connector->status != connector_status_connected) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 8a94323350303..5fa25a5a36b55 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -37,6 +37,7 @@ #include "intel_crtc.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_hdcp.h" @@ -1410,6 +1411,9 @@ intel_dp_mst_detect(struct drm_connector *connector, if (drm_connector_is_unregistered(connector)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + return drm_dp_mst_detect_port(connector, ctx, &intel_dp->mst_mgr, intel_connector->port); } diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 83898ba493d16..8ca9ae4798a89 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -35,6 +35,7 @@ #include "i915_reg.h" #include "intel_connector.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dvo.h" #include "intel_dvo_dev.h" @@ -328,6 +329,9 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->base.status; + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 55048c56bc527..7020e58061092 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -49,6 +49,7 @@ #include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_gmbus.h" @@ -2505,6 +2506,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); if (DISPLAY_VER(dev_priv) >= 11 && @@ -2533,6 +2537,9 @@ intel_hdmi_force(struct drm_connector *connector) drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + if (!intel_display_driver_check_access(i915)) + return; + intel_hdmi_unset_edid(connector); if (connector->status != connector_status_connected) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 0d8e5320a4f88..073ea3166c360 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -37,6 +37,7 @@ #include "intel_backlight.h" #include "intel_connector.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_drrs.h" #include "intel_lvds_regs.h" @@ -683,6 +684,9 @@ intel_panel_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + return connector_status_connected; } diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index c660dd88dec70..cea909046ccd2 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -43,6 +43,7 @@ #include "intel_connector.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" @@ -2139,6 +2140,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo_connector->output_flag)) return connector_status_unknown; diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 1b19443739c33..a96bcfcf90a3d 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -40,6 +40,7 @@ #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_irq.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dpll.h" #include "intel_hotplug.h" @@ -1723,6 +1724,9 @@ intel_tv_detect(struct drm_connector *connector, if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + if (force) { struct drm_atomic_state *state; -- GitLab From 9210e94a5a3bf7fc84b3d94dd5d2099ca434931b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:06 +0200 Subject: [PATCH 0198/1420] drm/i915: Add intel_digital_port lock/unlock hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add hooks to intel_digital_port to lock and unlock the port and add a helper to check the connector's detect status while the port is locked already. This simplifies checking the connector detect status in intel_dp_aux_xfer() and intel_digital_port_connected() in the next two patches aborting AUX transfers on all DP connectors (except eDP) and filtering HPD glitches. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-11-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 3 ++ .../drm/i915/display/intel_display_types.h | 3 ++ drivers/gpu/drm/i915/display/intel_dp.c | 34 +++++++++++++++++-- drivers/gpu/drm/i915/display/intel_dp.h | 3 ++ drivers/gpu/drm/i915/display/intel_dp_aux.c | 28 +++++++-------- drivers/gpu/drm/i915/display/intel_tc.c | 15 +------- drivers/gpu/drm/i915/display/intel_tc.h | 1 - 7 files changed, 56 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2746655bcb264..922194b957be2 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -5117,6 +5117,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, encoder->suspend_complete = intel_ddi_tc_encoder_suspend_complete; encoder->shutdown_complete = intel_ddi_tc_encoder_shutdown_complete; + dig_port->lock = intel_tc_port_lock; + dig_port->unlock = intel_tc_port_unlock; + if (intel_tc_port_init(dig_port, is_legacy) < 0) goto err; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index b9b9d9f2bc0ba..3556ccedbe4c1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1890,6 +1890,9 @@ struct intel_digital_port { u32 (*infoframes_enabled)(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config); bool (*connected)(struct intel_encoder *encoder); + + void (*lock)(struct intel_digital_port *dig_port); + void (*unlock)(struct intel_digital_port *dig_port); }; struct intel_dp_mst_encoder { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index b2591148670b7..a320bb0292d98 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5426,8 +5426,24 @@ edp_detect(struct intel_dp *intel_dp) return connector_status_connected; } +void intel_digital_port_lock(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (dig_port->lock) + dig_port->lock(dig_port); +} + +void intel_digital_port_unlock(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (dig_port->unlock) + dig_port->unlock(dig_port); +} + /* - * intel_digital_port_connected - is the specified port connected? + * intel_digital_port_connected_locked - is the specified port connected? * @encoder: intel_encoder * * In cases where there's a connector physically connected but it can't be used @@ -5435,9 +5451,12 @@ edp_detect(struct intel_dp *intel_dp) * pretty much treat the port as disconnected. This is relevant for type-C * (starting on ICL) where there's ownership involved. * + * The caller must hold the lock acquired by calling intel_digital_port_lock() + * when calling this function. + * * Return %true if port is connected, %false otherwise. */ -bool intel_digital_port_connected(struct intel_encoder *encoder) +bool intel_digital_port_connected_locked(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); @@ -5450,6 +5469,17 @@ bool intel_digital_port_connected(struct intel_encoder *encoder) return is_connected; } +bool intel_digital_port_connected(struct intel_encoder *encoder) +{ + bool ret; + + intel_digital_port_lock(encoder); + ret = intel_digital_port_connected_locked(encoder); + intel_digital_port_unlock(encoder); + + return ret; +} + static const struct drm_edid * intel_dp_get_edid(struct intel_dp *intel_dp) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index b911706d2e95e..530cc97bc42f4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -115,7 +115,10 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, void intel_read_dp_sdp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, unsigned int type); +void intel_digital_port_lock(struct intel_encoder *encoder); +void intel_digital_port_unlock(struct intel_encoder *encoder); bool intel_digital_port_connected(struct intel_encoder *encoder); +bool intel_digital_port_connected_locked(struct intel_encoder *encoder); int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector, u8 dsc_max_bpc); u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 2e2af71bcd5a8..b36ef321e835e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -9,6 +9,7 @@ #include "intel_bios.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_dp_aux.h" #include "intel_dp_aux_regs.h" #include "intel_pps.h" @@ -228,6 +229,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, u32 aux_send_ctl_flags) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *encoder = &dig_port->base; struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); enum phy phy = intel_port_to_phy(i915, dig_port->base.port); bool is_tc_port = intel_phy_is_tc(i915, phy); @@ -245,18 +247,17 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, for (i = 0; i < ARRAY_SIZE(ch_data); i++) ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i); - if (is_tc_port) { - intel_tc_port_lock(dig_port); - /* - * Abort transfers on a disconnected port as required by - * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX - * timeouts that would otherwise happen. - * TODO: abort the transfer on non-TC ports as well. - */ - if (!intel_tc_port_connected_locked(&dig_port->base)) { - ret = -ENXIO; - goto out_unlock; - } + intel_digital_port_lock(encoder); + /* + * Abort transfers on a disconnected port as required by + * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX + * timeouts that would otherwise happen. + * TODO: abort the transfer on non-TC ports as well. + */ + if (is_tc_port && + !intel_digital_port_connected_locked(&dig_port->base)) { + ret = -ENXIO; + goto out_unlock; } aux_domain = intel_aux_power_domain(dig_port); @@ -423,8 +424,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, intel_pps_unlock(intel_dp, pps_wakeref); intel_display_power_put_async(i915, aux_domain, aux_wakeref); out_unlock: - if (is_tc_port) - intel_tc_port_unlock(dig_port); + intel_digital_port_unlock(encoder); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index dcf05e00e5052..80aed9e87927a 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -1590,7 +1590,7 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port, * connected ports are usable, and avoids exposing to the users objects they * can't really use. */ -bool intel_tc_port_connected_locked(struct intel_encoder *encoder) +bool intel_tc_port_connected(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); @@ -1605,19 +1605,6 @@ bool intel_tc_port_connected_locked(struct intel_encoder *encoder) return tc_phy_hpd_live_status(tc) & mask; } -bool intel_tc_port_connected(struct intel_encoder *encoder) -{ - struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - struct intel_tc_port *tc = to_tc_port(dig_port); - bool is_connected; - - mutex_lock(&tc->lock); - is_connected = intel_tc_port_connected_locked(encoder); - mutex_unlock(&tc->lock); - - return is_connected; -} - static bool __intel_tc_port_link_needs_reset(struct intel_tc_port *tc) { bool ret; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 80a61e52850ee..936fa2daaa74a 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -17,7 +17,6 @@ bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); -bool intel_tc_port_connected_locked(struct intel_encoder *encoder); u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port); -- GitLab From 2e4b90fbe75536c978218bb3eb1d04f8988e13cd Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:07 +0200 Subject: [PATCH 0199/1420] drm/i915: Filter out glitches on HPD lines during hotplug detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Glitches deasserting the connector HPD line can lead to incorrectly detecting a disconnect event (a glitch asserting the line will only cause a redundant connect->disconnect transition). The source of such a glitch can be noise on the line or a 0.5ms-1ms MST IRQ_HPD pulse. TypeC ports in the DP-alt or TBT-alt mode filter out these glitches inernally, but for others the driver has to do this. Make it so by polling the HPD line on these connectors for 4 ms. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-12-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp.c | 13 +++++++++++-- drivers/gpu/drm/i915/display/intel_tc.c | 9 +++++++++ drivers/gpu/drm/i915/display/intel_tc.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a320bb0292d98..93f9985ef75c3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5460,11 +5460,20 @@ bool intel_digital_port_connected_locked(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool is_glitch_free = intel_tc_port_handles_hpd_glitches(dig_port); bool is_connected = false; intel_wakeref_t wakeref; - with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - is_connected = dig_port->connected(encoder); + with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) { + unsigned long wait_expires = jiffies + msecs_to_jiffies_timeout(4); + + do { + is_connected = dig_port->connected(encoder); + if (is_connected || is_glitch_free) + break; + usleep_range(10, 30); + } while (time_before(jiffies, wait_expires)); + } return is_connected; } diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 80aed9e87927a..f34743e6eeed2 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -122,6 +122,15 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port) return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY); } +bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + struct intel_tc_port *tc = to_tc_port(dig_port); + + return intel_phy_is_tc(i915, phy) && !tc->legacy_port; +} + /* * The display power domains used for TC ports depending on the * platform and TC mode (legacy, DP-alt, TBT): diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 936fa2daaa74a..26c4265368c1a 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -15,6 +15,7 @@ struct intel_encoder; bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); +bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); -- GitLab From d544d000a3cbf845825508dafe0aebe7f93f0e04 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:08 +0200 Subject: [PATCH 0200/1420] drm/i915/dp: Abort AUX on disconnected native DP ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An AUX transfer on any disconnected DP port results in long timeout/retry delays the same way as this is described for TypeC port in commit a972cd3f0eb5 ("drm/i915/tc: Abort DP AUX transfer on a disconnected TC port") Prevent the delay on non-TypeC ports as well by aborting the transfer if the port is disconnected. For eDP keep the current behavior as the support for HPD signaling is optional for it. Link: https://patchwork.freedesktop.org/patch/msgid/20240104083008.2715733-13-imre.deak@intel.com Reviewed-by: Jouni Högander Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp_aux.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index b36ef321e835e..4f4a0e3b31140 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -231,8 +231,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); - bool is_tc_port = intel_phy_is_tc(i915, phy); i915_reg_t ch_ctl, ch_data[5]; u32 aux_clock_divider; enum intel_display_power_domain aux_domain; @@ -252,9 +250,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, * Abort transfers on a disconnected port as required by * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX * timeouts that would otherwise happen. - * TODO: abort the transfer on non-TC ports as well. */ - if (is_tc_port && + if (!intel_dp_is_edp(intel_dp) && !intel_digital_port_connected_locked(&dig_port->base)) { ret = -ENXIO; goto out_unlock; -- GitLab From 5f807f00b5f5de849e7a790864ec1d398cd1222e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 16 Dec 2023 12:11:52 -0800 Subject: [PATCH 0201/1420] drm/nouveau/bios/init: drop kernel-doc notation The "/**" comments in this file are not kernel-doc comments. They are used on static functions which can have kernel-doc comments, but that is not the primary focus of kernel-doc comments. Since these comments are incomplete for kernel-doc notation, remove the kernel-doc "/**" markers and make them common comments. This prevents scripts/kernel-doc from issuing 68 warnings: init.c:584: warning: Function parameter or member 'init' not described in 'init_reserved' and 67 warnings like this one: init.c:611: warning: expecting prototype for INIT_DONE(). Prototype was for init_done() instead Signed-off-by: Randy Dunlap Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: dri-devel@lists.freedesktop.org Cc: nouveau@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231216201152.31376-1-rdunlap@infradead.org --- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 1420794038642..b54f044c4483b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -575,7 +575,7 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds) * init opcode handlers *****************************************************************************/ -/** +/* * init_reserved - stub for various unknown/unused single-byte opcodes * */ @@ -602,7 +602,7 @@ init_reserved(struct nvbios_init *init) init->offset += length; } -/** +/* * INIT_DONE - opcode 0x71 * */ @@ -613,7 +613,7 @@ init_done(struct nvbios_init *init) init->offset = 0x0000; } -/** +/* * INIT_IO_RESTRICT_PROG - opcode 0x32 * */ @@ -650,7 +650,7 @@ init_io_restrict_prog(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_REPEAT - opcode 0x33 * */ @@ -676,7 +676,7 @@ init_repeat(struct nvbios_init *init) init->repeat = repeat; } -/** +/* * INIT_IO_RESTRICT_PLL - opcode 0x34 * */ @@ -716,7 +716,7 @@ init_io_restrict_pll(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_END_REPEAT - opcode 0x36 * */ @@ -732,7 +732,7 @@ init_end_repeat(struct nvbios_init *init) } } -/** +/* * INIT_COPY - opcode 0x37 * */ @@ -759,7 +759,7 @@ init_copy(struct nvbios_init *init) init_wrvgai(init, port, index, data); } -/** +/* * INIT_NOT - opcode 0x38 * */ @@ -771,7 +771,7 @@ init_not(struct nvbios_init *init) init_exec_inv(init); } -/** +/* * INIT_IO_FLAG_CONDITION - opcode 0x39 * */ @@ -788,7 +788,7 @@ init_io_flag_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_GENERIC_CONDITION - opcode 0x3a * */ @@ -840,7 +840,7 @@ init_generic_condition(struct nvbios_init *init) } } -/** +/* * INIT_IO_MASK_OR - opcode 0x3b * */ @@ -859,7 +859,7 @@ init_io_mask_or(struct nvbios_init *init) init_wrvgai(init, 0x03d4, index, data &= ~(1 << or)); } -/** +/* * INIT_IO_OR - opcode 0x3c * */ @@ -878,7 +878,7 @@ init_io_or(struct nvbios_init *init) init_wrvgai(init, 0x03d4, index, data | (1 << or)); } -/** +/* * INIT_ANDN_REG - opcode 0x47 * */ @@ -895,7 +895,7 @@ init_andn_reg(struct nvbios_init *init) init_mask(init, reg, mask, 0); } -/** +/* * INIT_OR_REG - opcode 0x48 * */ @@ -912,7 +912,7 @@ init_or_reg(struct nvbios_init *init) init_mask(init, reg, 0, mask); } -/** +/* * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49 * */ @@ -942,7 +942,7 @@ init_idx_addr_latched(struct nvbios_init *init) } } -/** +/* * INIT_IO_RESTRICT_PLL2 - opcode 0x4a * */ @@ -977,7 +977,7 @@ init_io_restrict_pll2(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_PLL2 - opcode 0x4b * */ @@ -994,7 +994,7 @@ init_pll2(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_I2C_BYTE - opcode 0x4c * */ @@ -1025,7 +1025,7 @@ init_i2c_byte(struct nvbios_init *init) } } -/** +/* * INIT_ZM_I2C_BYTE - opcode 0x4d * */ @@ -1051,7 +1051,7 @@ init_zm_i2c_byte(struct nvbios_init *init) } } -/** +/* * INIT_ZM_I2C - opcode 0x4e * */ @@ -1085,7 +1085,7 @@ init_zm_i2c(struct nvbios_init *init) } } -/** +/* * INIT_TMDS - opcode 0x4f * */ @@ -1111,7 +1111,7 @@ init_tmds(struct nvbios_init *init) init_wr32(init, reg + 0, addr); } -/** +/* * INIT_ZM_TMDS_GROUP - opcode 0x50 * */ @@ -1138,7 +1138,7 @@ init_zm_tmds_group(struct nvbios_init *init) } } -/** +/* * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51 * */ @@ -1168,7 +1168,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr0, save0); } -/** +/* * INIT_CR - opcode 0x52 * */ @@ -1188,7 +1188,7 @@ init_cr(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr, val | data); } -/** +/* * INIT_ZM_CR - opcode 0x53 * */ @@ -1205,7 +1205,7 @@ init_zm_cr(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr, data); } -/** +/* * INIT_ZM_CR_GROUP - opcode 0x54 * */ @@ -1229,7 +1229,7 @@ init_zm_cr_group(struct nvbios_init *init) } } -/** +/* * INIT_CONDITION_TIME - opcode 0x56 * */ @@ -1256,7 +1256,7 @@ init_condition_time(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_LTIME - opcode 0x57 * */ @@ -1273,7 +1273,7 @@ init_ltime(struct nvbios_init *init) mdelay(msec); } -/** +/* * INIT_ZM_REG_SEQUENCE - opcode 0x58 * */ @@ -1298,7 +1298,7 @@ init_zm_reg_sequence(struct nvbios_init *init) } } -/** +/* * INIT_PLL_INDIRECT - opcode 0x59 * */ @@ -1317,7 +1317,7 @@ init_pll_indirect(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_ZM_REG_INDIRECT - opcode 0x5a * */ @@ -1336,7 +1336,7 @@ init_zm_reg_indirect(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_SUB_DIRECT - opcode 0x5b * */ @@ -1362,7 +1362,7 @@ init_sub_direct(struct nvbios_init *init) init->offset += 3; } -/** +/* * INIT_JUMP - opcode 0x5c * */ @@ -1380,7 +1380,7 @@ init_jump(struct nvbios_init *init) init->offset += 3; } -/** +/* * INIT_I2C_IF - opcode 0x5e * */ @@ -1407,7 +1407,7 @@ init_i2c_if(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_COPY_NV_REG - opcode 0x5f * */ @@ -1433,7 +1433,7 @@ init_copy_nv_reg(struct nvbios_init *init) init_mask(init, dreg, ~dmask, (data & smask) ^ sxor); } -/** +/* * INIT_ZM_INDEX_IO - opcode 0x62 * */ @@ -1451,7 +1451,7 @@ init_zm_index_io(struct nvbios_init *init) init_wrvgai(init, port, index, data); } -/** +/* * INIT_COMPUTE_MEM - opcode 0x63 * */ @@ -1469,7 +1469,7 @@ init_compute_mem(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_RESET - opcode 0x65 * */ @@ -1496,7 +1496,7 @@ init_reset(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_MEM - opcode 0x66 * */ @@ -1555,7 +1555,7 @@ init_configure_mem(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_CLK - opcode 0x67 * */ @@ -1589,7 +1589,7 @@ init_configure_clk(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_PREINIT - opcode 0x68 * */ @@ -1615,7 +1615,7 @@ init_configure_preinit(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_IO - opcode 0x69 * */ @@ -1655,7 +1655,7 @@ init_io(struct nvbios_init *init) init_wrport(init, port, data | value); } -/** +/* * INIT_SUB - opcode 0x6b * */ @@ -1682,7 +1682,7 @@ init_sub(struct nvbios_init *init) init->offset += 2; } -/** +/* * INIT_RAM_CONDITION - opcode 0x6d * */ @@ -1701,7 +1701,7 @@ init_ram_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_NV_REG - opcode 0x6e * */ @@ -1719,7 +1719,7 @@ init_nv_reg(struct nvbios_init *init) init_mask(init, reg, ~mask, data); } -/** +/* * INIT_MACRO - opcode 0x6f * */ @@ -1743,7 +1743,7 @@ init_macro(struct nvbios_init *init) init->offset += 2; } -/** +/* * INIT_RESUME - opcode 0x72 * */ @@ -1755,7 +1755,7 @@ init_resume(struct nvbios_init *init) init_exec_set(init, true); } -/** +/* * INIT_STRAP_CONDITION - opcode 0x73 * */ @@ -1773,7 +1773,7 @@ init_strap_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_TIME - opcode 0x74 * */ @@ -1794,7 +1794,7 @@ init_time(struct nvbios_init *init) } } -/** +/* * INIT_CONDITION - opcode 0x75 * */ @@ -1811,7 +1811,7 @@ init_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_IO_CONDITION - opcode 0x76 * */ @@ -1828,7 +1828,7 @@ init_io_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_ZM_REG16 - opcode 0x77 * */ @@ -1845,7 +1845,7 @@ init_zm_reg16(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_INDEX_IO - opcode 0x78 * */ @@ -1867,7 +1867,7 @@ init_index_io(struct nvbios_init *init) init_wrvgai(init, port, index, data | value); } -/** +/* * INIT_PLL - opcode 0x79 * */ @@ -1884,7 +1884,7 @@ init_pll(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_ZM_REG - opcode 0x7a * */ @@ -1904,7 +1904,7 @@ init_zm_reg(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_RAM_RESTRICT_PLL - opcde 0x87 * */ @@ -1934,7 +1934,7 @@ init_ram_restrict_pll(struct nvbios_init *init) } } -/** +/* * INIT_RESET_BEGUN - opcode 0x8c * */ @@ -1945,7 +1945,7 @@ init_reset_begun(struct nvbios_init *init) init->offset += 1; } -/** +/* * INIT_RESET_END - opcode 0x8d * */ @@ -1956,7 +1956,7 @@ init_reset_end(struct nvbios_init *init) init->offset += 1; } -/** +/* * INIT_GPIO - opcode 0x8e * */ @@ -1972,7 +1972,7 @@ init_gpio(struct nvbios_init *init) nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); } -/** +/* * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f * */ @@ -2010,7 +2010,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) } } -/** +/* * INIT_COPY_ZM_REG - opcode 0x90 * */ @@ -2027,7 +2027,7 @@ init_copy_zm_reg(struct nvbios_init *init) init_wr32(init, dreg, init_rd32(init, sreg)); } -/** +/* * INIT_ZM_REG_GROUP - opcode 0x91 * */ @@ -2049,7 +2049,7 @@ init_zm_reg_group(struct nvbios_init *init) } } -/** +/* * INIT_XLAT - opcode 0x96 * */ @@ -2077,7 +2077,7 @@ init_xlat(struct nvbios_init *init) init_mask(init, daddr, ~dmask, data); } -/** +/* * INIT_ZM_MASK_ADD - opcode 0x97 * */ @@ -2098,7 +2098,7 @@ init_zm_mask_add(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_AUXCH - opcode 0x98 * */ @@ -2122,7 +2122,7 @@ init_auxch(struct nvbios_init *init) } } -/** +/* * INIT_AUXCH - opcode 0x99 * */ @@ -2144,7 +2144,7 @@ init_zm_auxch(struct nvbios_init *init) } } -/** +/* * INIT_I2C_LONG_IF - opcode 0x9a * */ @@ -2183,7 +2183,7 @@ init_i2c_long_if(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_GPIO_NE - opcode 0xa9 * */ -- GitLab From 648c3814dcf6fde9e654da01d2963e73077d07fd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:30 -0800 Subject: [PATCH 0202/1420] drm/nouveau/disp: don't misuse kernel-doc comments Change kernel-doc "/**" comments to common "/*" comments to prevent kernel-doc warnings: crtc.c:453: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Sets up registers for the given mode/adjusted_mode pair. crtc.c:453: warning: missing initial short description on line: * Sets up registers for the given mode/adjusted_mode pair. crtc.c:629: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Sets up registers for the given mode/adjusted_mode pair. crtc.c:629: warning: missing initial short description on line: * Sets up registers for the given mode/adjusted_mode pair. Signed-off-by: Randy Dunlap Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: nouveau@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231231233633.6596-1-rdunlap@infradead.org --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index a34917b048f96..4310ad71870b1 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -449,7 +449,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) regp->Attribute[NV_CIO_AR_CSEL_INDEX] = 0x00; } -/** +/* * Sets up registers for the given mode/adjusted_mode pair. * * The clocks, CRTCs and outputs attached to this CRTC must be off. @@ -625,7 +625,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) return ret; } -/** +/* * Sets up registers for the given mode/adjusted_mode pair. * * The clocks, CRTCs and outputs attached to this CRTC must be off. -- GitLab From 607a9b29ef813f95c8879a45bfb7401ba7df48b5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:31 -0800 Subject: [PATCH 0203/1420] drm/nouveau: don't misuse kernel-doc comments Change kernel-doc "/**" comments to common "/*" comments to prevent kernel-doc warnings: nouveau_ioc32.c:2: warning: Cannot understand * \file mga_ioc32.c on line 2 - I thought it was a doc line nouveau_ioc32.c:52: warning: Function parameter or member 'filp' not described in 'nouveau_compat_ioctl' nouveau_ioc32.c:52: warning: Function parameter or member 'cmd' not described in 'nouveau_compat_ioctl' nouveau_ioc32.c:52: warning: Function parameter or member 'arg' not described in 'nouveau_compat_ioctl' nouveau_ioc32.c:52: warning: expecting prototype for Called whenever a 32-bit process running under a 64(). Prototype was for nouveau_compat_ioctl() instead Signed-off-by: Randy Dunlap Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: nouveau@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231231233633.6596-2-rdunlap@infradead.org --- drivers/gpu/drm/nouveau/nouveau_ioc32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c index adf01ca9e035d..2af3615c5205c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ioc32.c +++ b/drivers/gpu/drm/nouveau/nouveau_ioc32.c @@ -1,4 +1,4 @@ -/** +/* * \file mga_ioc32.c * * 32-bit ioctl compatibility routines for the MGA DRM. @@ -38,7 +38,7 @@ #include "nouveau_ioctl.h" -/** +/* * Called whenever a 32-bit process running under a 64-bit kernel * performs an ioctl on /dev/dri/card. * -- GitLab From ce6106ffa9f4ddc3757dd9ad1be321e8b8b3278e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:32 -0800 Subject: [PATCH 0204/1420] drm/nouveau/gr/gf100: don't misuse kernel-doc comments Change kernel-doc "/**" comments to common "/*" comments to prevent kernel-doc warnings: gf100.c:1044: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Wait until GR goes idle. GR is considered idle if it is disabled by the gf100.c:1044: warning: missing initial short description on line: * Wait until GR goes idle. GR is considered idle if it is disabled by the Signed-off-by: Randy Dunlap Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: nouveau@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231231233633.6596-3-rdunlap@infradead.org --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index c494a1ff2d572..986e8d547c942 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1040,7 +1040,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr) } } -/** +/* * Wait until GR goes idle. GR is considered idle if it is disabled by the * MC (0x200) register, or GR is not busy and a context switch is not in * progress. -- GitLab From eeb8e8d9f124f279e80ae679f4ba6e822ce4f95f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:33 -0800 Subject: [PATCH 0205/1420] drm/nouveau/volt/gk20a: don't misuse kernel-doc comments Change kernel-doc "/**" comments to common "/*" comments to prevent kernel-doc warnings: gk20a.c:49: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) gk20a.c:49: warning: missing initial short description on line: * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) gk20a.c:62: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * cvb_t_mv = gk20a.c:62: warning: missing initial short description on line: * cvb_t_mv = Signed-off-by: Randy Dunlap Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: nouveau@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231231233633.6596-4-rdunlap@infradead.org --- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 8c2faa9645111..ccac88da88648 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -45,7 +45,7 @@ static const struct cvb_coef gk20a_cvb_coef[] = { /* 852 */ { 1608418, -21643, -269, 0, 763, -48}, }; -/** +/* * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) */ static inline int @@ -58,7 +58,7 @@ gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef) return mv; } -/** +/* * cvb_t_mv = * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) + * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale) -- GitLab From 251ba4583f750db2a89c464ed15682028c215688 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Mon, 25 Dec 2023 07:51:45 +0100 Subject: [PATCH 0206/1420] drm/nouveau: uapi: fix kerneldoc warnings As of commit b77fdd6a48e6 ("scripts/kernel-doc: restore warning for Excess struct/union"), we see the following warnings when running 'make htmldocs': ./include/uapi/drm/nouveau_drm.h:292: warning: Excess struct member 'DRM_NOUVEAU_VM_BIND_OP_MAP' description in 'drm_nouveau_vm_bind_op' ./include/uapi/drm/nouveau_drm.h:292: warning: Excess struct member 'DRM_NOUVEAU_VM_BIND_OP_UNMAP' description in 'drm_nouveau_vm_bind_op' ./include/uapi/drm/nouveau_drm.h:292: warning: Excess struct member 'DRM_NOUVEAU_VM_BIND_SPARSE' description in 'drm_nouveau_vm_bind_op' ./include/uapi/drm/nouveau_drm.h:336: warning: Excess struct member 'DRM_NOUVEAU_VM_BIND_RUN_ASYNC' description in 'drm_nouveau_vm_bind' The problem is that these values are #define constants, but had kerneldoc comments attached to them as if they were actual struct members. There are a number of ways we could fix this, but I chose to draw inspiration from include/uapi/drm/i915_drm.h, which pulls them into the corresponding kerneldoc comment for the struct member that they are intended to be used with. To keep the diff readable, there are a number of things I _didn't_ do in this patch, but which we should also consider: - This is pretty good documentation, but it ends up in gpu/driver-uapi, which is part of subsystem-apis/ when it really ought to display under userspace-api/ (the "Linux kernel user-space API guide" book of the documentation). - More generally, we might want a warning if include/uapi/ files are kerneldoc'd outside userspace-api/. - I'd consider it cleaner if the #defines appeared between the kerneldoc for the member and the member itself (which is something other DRM- related UAPI docs do). - The %IDENTIFIER kerneldoc syntax is intended for "constants", and is more appropriate in this context than ``IDENTIFIER`` or &IDENTIFIER. The DRM docs aren't very consistent on this. Cc: Randy Dunlap Cc: Jonathan Corbet Signed-off-by: Vegard Nossum Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231225065145.3060754-1-vegard.nossum@oracle.com --- include/uapi/drm/nouveau_drm.h | 56 ++++++++++++++++------------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h index 0bade1592f34f..c95ef8a4d94a4 100644 --- a/include/uapi/drm/nouveau_drm.h +++ b/include/uapi/drm/nouveau_drm.h @@ -238,34 +238,32 @@ struct drm_nouveau_vm_init { struct drm_nouveau_vm_bind_op { /** * @op: the operation type + * + * Supported values: + * + * %DRM_NOUVEAU_VM_BIND_OP_MAP - Map a GEM object to the GPU's VA + * space. Optionally, the &DRM_NOUVEAU_VM_BIND_SPARSE flag can be + * passed to instruct the kernel to create sparse mappings for the + * given range. + * + * %DRM_NOUVEAU_VM_BIND_OP_UNMAP - Unmap an existing mapping in the + * GPU's VA space. If the region the mapping is located in is a + * sparse region, new sparse mappings are created where the unmapped + * (memory backed) mapping was mapped previously. To remove a sparse + * region the &DRM_NOUVEAU_VM_BIND_SPARSE must be set. */ __u32 op; -/** - * @DRM_NOUVEAU_VM_BIND_OP_MAP: - * - * Map a GEM object to the GPU's VA space. Optionally, the - * &DRM_NOUVEAU_VM_BIND_SPARSE flag can be passed to instruct the kernel to - * create sparse mappings for the given range. - */ #define DRM_NOUVEAU_VM_BIND_OP_MAP 0x0 -/** - * @DRM_NOUVEAU_VM_BIND_OP_UNMAP: - * - * Unmap an existing mapping in the GPU's VA space. If the region the mapping - * is located in is a sparse region, new sparse mappings are created where the - * unmapped (memory backed) mapping was mapped previously. To remove a sparse - * region the &DRM_NOUVEAU_VM_BIND_SPARSE must be set. - */ #define DRM_NOUVEAU_VM_BIND_OP_UNMAP 0x1 /** * @flags: the flags for a &drm_nouveau_vm_bind_op + * + * Supported values: + * + * %DRM_NOUVEAU_VM_BIND_SPARSE - Indicates that an allocated VA + * space region should be sparse. */ __u32 flags; -/** - * @DRM_NOUVEAU_VM_BIND_SPARSE: - * - * Indicates that an allocated VA space region should be sparse. - */ #define DRM_NOUVEAU_VM_BIND_SPARSE (1 << 8) /** * @handle: the handle of the DRM GEM object to map @@ -301,17 +299,17 @@ struct drm_nouveau_vm_bind { __u32 op_count; /** * @flags: the flags for a &drm_nouveau_vm_bind ioctl + * + * Supported values: + * + * %DRM_NOUVEAU_VM_BIND_RUN_ASYNC - Indicates that the given VM_BIND + * operation should be executed asynchronously by the kernel. + * + * If this flag is not supplied the kernel executes the associated + * operations synchronously and doesn't accept any &drm_nouveau_sync + * objects. */ __u32 flags; -/** - * @DRM_NOUVEAU_VM_BIND_RUN_ASYNC: - * - * Indicates that the given VM_BIND operation should be executed asynchronously - * by the kernel. - * - * If this flag is not supplied the kernel executes the associated operations - * synchronously and doesn't accept any &drm_nouveau_sync objects. - */ #define DRM_NOUVEAU_VM_BIND_RUN_ASYNC 0x1 /** * @wait_count: the number of wait &drm_nouveau_syncs -- GitLab From be8755a0a81866bbf89bf3fb03ae180978b5a91f Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 21 Dec 2023 08:32:13 -0800 Subject: [PATCH 0207/1420] drm/xe/kunit: Drop xe_wa tests for pre-production DG2 As workarounds for pre-production DG2 were dropped in commit 707d1b992cfe ("drm/xe/dg2: Drop pre-production workarounds"), there's no point running the kunit tests for them. Drop those steppings from kunit. Cc: Gustavo Sousa Cc: Matt Roper Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20231221163213.3849523-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/tests/xe_wa_test.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index 3d7f3ef62ae93..5cfd5844c17b3 100644 --- a/drivers/gpu/drm/xe/tests/xe_wa_test.c +++ b/drivers/gpu/drm/xe/tests/xe_wa_test.c @@ -66,14 +66,8 @@ static const struct platform_test_case cases[] = { PLATFORM_CASE(ALDERLAKE_P, C0), SUBPLATFORM_CASE(ALDERLAKE_S, RPLS, D0), SUBPLATFORM_CASE(ALDERLAKE_P, RPLU, E0), - SUBPLATFORM_CASE(DG2, G10, A0), - SUBPLATFORM_CASE(DG2, G10, A1), - SUBPLATFORM_CASE(DG2, G10, B0), SUBPLATFORM_CASE(DG2, G10, C0), - SUBPLATFORM_CASE(DG2, G11, A0), - SUBPLATFORM_CASE(DG2, G11, B0), SUBPLATFORM_CASE(DG2, G11, B1), - SUBPLATFORM_CASE(DG2, G12, A0), SUBPLATFORM_CASE(DG2, G12, A1), PLATFORM_CASE(PVC, B0), PLATFORM_CASE(PVC, B1), -- GitLab From bdb7a38a8f409cdc3acdfc1935d09e31735e3ab4 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:35 -0300 Subject: [PATCH 0208/1420] drm/i915/xe2lpd: Update bxt_sanitize_cdclk() With Xe2_LPD, there were changes to the way CDCLK_CTL must be programmed. Those were reflected on _bxt_set_cdclk() with commit 3d3696c0fed1 ("drm/i915/lnl: Start using CDCLK through PLL"), but bxt_sanitize_cdclk() was left out. This was causing some issues when loading the driver with a pre-existing active display configuration: the driver would mistakenly take the current value of CDCLK_CTL as wrong and the sanitization would be triggered. In a scenario where the display was already configured with a high CDCLKC and had plane(s) enabled, FIFO underrun errors were reported, because the current sanitization code selects the minimum possible CDCLK. Fix that by updating bxt_sanitize_cdclk() to match the changes made in _bxt_set_cdclk(). Ideally, we would have a common function to derive the value for CDCLK_CTL, but that can be done in a future change. Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240105140538.183553-2-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c5fecde7afa88..0012e3171f3f7 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2071,7 +2071,10 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) if (vco != dev_priv->display.cdclk.hw.vco) goto sanitize; - expected = skl_cdclk_decimal(cdclk); + if (DISPLAY_VER(dev_priv) >= 20) + expected = MDCLK_SOURCE_SEL_CDCLK_PLL; + else + expected = skl_cdclk_decimal(cdclk); /* Figure out what CD2X divider we should be using for this cdclk */ if (HAS_CDCLK_SQUASH(dev_priv)) -- GitLab From 7af2f3e55c1ec09bfa04963f4a8d0ef052be22bb Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:36 -0300 Subject: [PATCH 0209/1420] drm/i915/cdclk: Extract bxt_cdclk_ctl() Extract logic for deriving the value for CDCLK_CTL into bxt_cdclk_ctl(). This makes the code better readable and will be used later in bxt_sanitize_cdclk(). v2: - Improve body of commit message to be more self-contained. Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240105140538.183553-3-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 57 +++++++++++++--------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0012e3171f3f7..b9354ad46fee9 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1900,15 +1900,47 @@ static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv) dev_priv->display.cdclk.hw.vco > 0; } +static u32 bxt_cdclk_ctl(struct drm_i915_private *i915, + const struct intel_cdclk_config *cdclk_config, + enum pipe pipe) +{ + int cdclk = cdclk_config->cdclk; + int vco = cdclk_config->vco; + int unsquashed_cdclk; + u16 waveform; + u32 val; + + waveform = cdclk_squash_waveform(i915, cdclk); + + unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len, + cdclk_squash_divider(waveform)); + + val = bxt_cdclk_cd2x_div_sel(i915, unsquashed_cdclk, vco) | + bxt_cdclk_cd2x_pipe(i915, pipe); + + /* + * Disable SSA Precharge when CD clock frequency < 500 MHz, + * enable otherwise. + */ + if ((IS_GEMINILAKE(i915) || IS_BROXTON(i915)) && + cdclk >= 500000) + val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + + if (DISPLAY_VER(i915) >= 20) + val |= MDCLK_SOURCE_SEL_CDCLK_PLL; + else + val |= skl_cdclk_decimal(cdclk); + + return val; +} + static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; - int unsquashed_cdclk; u16 waveform; - u32 val; if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0 && !cdclk_pll_is_unknown(dev_priv->display.cdclk.hw.vco)) { @@ -1925,29 +1957,10 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, waveform = cdclk_squash_waveform(dev_priv, cdclk); - unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len, - cdclk_squash_divider(waveform)); - if (HAS_CDCLK_SQUASH(dev_priv)) dg2_cdclk_squash_program(dev_priv, waveform); - val = bxt_cdclk_cd2x_div_sel(dev_priv, unsquashed_cdclk, vco) | - bxt_cdclk_cd2x_pipe(dev_priv, pipe); - - /* - * Disable SSA Precharge when CD clock frequency < 500 MHz, - * enable otherwise. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - cdclk >= 500000) - val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; - - if (DISPLAY_VER(dev_priv) >= 20) - val |= MDCLK_SOURCE_SEL_CDCLK_PLL; - else - val |= skl_cdclk_decimal(cdclk); - - intel_de_write(dev_priv, CDCLK_CTL, val); + intel_de_write(dev_priv, CDCLK_CTL, bxt_cdclk_ctl(dev_priv, cdclk_config, pipe)); if (pipe != INVALID_PIPE) intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe)); -- GitLab From ebb9c4240deaaa54b70926bdc4d4ceb22518c0cb Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:37 -0300 Subject: [PATCH 0210/1420] drm/i915/cdclk: Reorder bxt_sanitize_cdclk() Make the sequence of steps in bxt_sanitize_cdclk() more logical by grouping things related to the check on the value of CDCLK_CTL into a single "block". Also, this will make an upcoming change replacing that block with a single function call easier to follow. v2: - Improve body of commit message to be more self-contained. Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240105140538.183553-4-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index b9354ad46fee9..fbe9aba41c35d 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2060,13 +2060,23 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) dev_priv->display.cdclk.hw.cdclk == dev_priv->display.cdclk.hw.bypass) goto sanitize; - /* DPLL okay; verify the cdclock - * + /* Make sure this is a legal cdclk value for the platform */ + cdclk = bxt_calc_cdclk(dev_priv, dev_priv->display.cdclk.hw.cdclk); + if (cdclk != dev_priv->display.cdclk.hw.cdclk) + goto sanitize; + + /* Make sure the VCO is correct for the cdclk */ + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk); + if (vco != dev_priv->display.cdclk.hw.vco) + goto sanitize; + + /* * Some BIOS versions leave an incorrect decimal frequency value and * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, * so sanitize this register. */ cdctl = intel_de_read(dev_priv, CDCLK_CTL); + /* * Let's ignore the pipe field, since BIOS could have configured the * dividers both synching to an active pipe, or asynchronously @@ -2074,16 +2084,6 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) */ cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); - /* Make sure this is a legal cdclk value for the platform */ - cdclk = bxt_calc_cdclk(dev_priv, dev_priv->display.cdclk.hw.cdclk); - if (cdclk != dev_priv->display.cdclk.hw.cdclk) - goto sanitize; - - /* Make sure the VCO is correct for the cdclk */ - vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk); - if (vco != dev_priv->display.cdclk.hw.vco) - goto sanitize; - if (DISPLAY_VER(dev_priv) >= 20) expected = MDCLK_SOURCE_SEL_CDCLK_PLL; else -- GitLab From 935e486b718fc1c98191137cbf09b05ca5d8b9d6 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:38 -0300 Subject: [PATCH 0211/1420] drm/i915/cdclk: Re-use bxt_cdclk_ctl() when sanitizing The function bxt_cdclk_ctl() is responsible for deriving the value for CDCLK_CTL; use it instead of repeating the same logic. v2: - Use a better commit message body by making it more self-contained and not referring to stuff from the subject line. (Matt) Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240105140538.183553-5-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 26 +++------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index fbe9aba41c35d..26200ee3e23f9 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2051,7 +2051,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) { u32 cdctl, expected; - int cdclk, clock, vco; + int cdclk, vco; intel_update_cdclk(dev_priv); intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "Current CDCLK"); @@ -2076,6 +2076,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) * so sanitize this register. */ cdctl = intel_de_read(dev_priv, CDCLK_CTL); + expected = bxt_cdclk_ctl(dev_priv, &dev_priv->display.cdclk.hw, INVALID_PIPE); /* * Let's ignore the pipe field, since BIOS could have configured the @@ -2083,28 +2084,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) * (PIPE_NONE). */ cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); - - if (DISPLAY_VER(dev_priv) >= 20) - expected = MDCLK_SOURCE_SEL_CDCLK_PLL; - else - expected = skl_cdclk_decimal(cdclk); - - /* Figure out what CD2X divider we should be using for this cdclk */ - if (HAS_CDCLK_SQUASH(dev_priv)) - clock = dev_priv->display.cdclk.hw.vco / 2; - else - clock = dev_priv->display.cdclk.hw.cdclk; - - expected |= bxt_cdclk_cd2x_div_sel(dev_priv, clock, - dev_priv->display.cdclk.hw.vco); - - /* - * Disable SSA Precharge when CD clock frequency < 500 MHz, - * enable otherwise. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - dev_priv->display.cdclk.hw.cdclk >= 500000) - expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + expected &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); if (cdctl == expected) /* All well; nothing to sanitize */ -- GitLab From ddb5bade29de7a3e1e1ce42df33f4a98f8a9f323 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Thu, 4 Jan 2024 19:26:15 +0100 Subject: [PATCH 0212/1420] drm/xe/xe2: synchronise CS_CHICKEN1 with WMTP support Recommendation is to read FUSE4 register to check if WMTP has been enabled/disabled by HW. If enabled we don't need to do anything special, however if disabled recommendation is to also disable the WMTP mode in the FF_SLICE_CS_CHICKEN2 register, falling back to thread-group and mid-batch preemption only. However on Linux, the per-context CS_CHICKEN1 is how userspace controls pre-emption, so instead use the default lrc to disable WMTP using CS_CHICKEN1, if disabled by HW. Userspace is still free to set CS_CHICKEN1 to whatever they want later. v2: remove redundant version check and also add descriptive name(Matt) v3: remove usage of REG_FIELD_GET(Matt) Cc: Matt Roper Co-developed-by: Matthew Auld Signed-off-by: Matthew Auld Signed-off-by: Nirmoy Das Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20240104182615.21327-1-nirmoy.das@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 1 + drivers/gpu/drm/xe/xe_hw_engine.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 6aaaf1f63c728..6dfad86aaea64 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -146,6 +146,7 @@ /* Fuse readout registers for GT */ #define XEHP_FUSE4 XE_REG(0x9114) +#define CFEG_WMTP_DISABLE REG_BIT(20) #define CCS_EN_MASK REG_GENMASK(19, 16) #define GT_L3_EXC_MASK REG_GENMASK(6, 4) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 832989c83a253..e279ef6c527cd 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -316,6 +316,19 @@ static bool xe_hw_engine_match_fixed_cslice_mode(const struct xe_gt *gt, xe_rtp_match_first_render_or_compute(gt, hwe); } +static bool xe_rtp_cfeg_wmtp_disabled(const struct xe_gt *gt, + const struct xe_hw_engine *hwe) +{ + if (GRAPHICS_VER(gt_to_xe(gt)) < 20) + return false; + + if (hwe->class != XE_ENGINE_CLASS_COMPUTE && + hwe->class != XE_ENGINE_CLASS_RENDER) + return false; + + return xe_mmio_read32(hwe->gt, XEHP_FUSE4) & CFEG_WMTP_DISABLE; +} + void xe_hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) { @@ -346,6 +359,14 @@ xe_hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) XE_RTP_ACTIONS(FIELD_SET(RCU_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE)) }, + /* Disable WMTP if HW doesn't support it */ + { XE_RTP_NAME("DISABLE_WMTP_ON_UNSUPPORTED_HW"), + XE_RTP_RULES(FUNC(xe_rtp_cfeg_wmtp_disabled)), + XE_RTP_ACTIONS(FIELD_SET(CS_CHICKEN1(0), + PREEMPT_GPGPU_LEVEL_MASK, + PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) + }, {} }; -- GitLab From 49ddab089611ae5ddd0201ddbbf633da75bfcc25 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Wed, 20 Dec 2023 14:13:11 -0800 Subject: [PATCH 0213/1420] drm/panel-edp: use put_sync in unprepare Some edp panel requires T10 (Delay from end of valid video data transmitted by the Source device to power-off) less than 500ms. Using autosuspend with delay set as 1000 violates this requirement. Use put_sync_suspend in unprepare to meet the spec. For other cases (such as getting EDID), it still uses autosuspend. Suggested-by: Douglas Anderson Fixes: 3235b0f20a0a ("drm/panel: panel-simple: Use runtime pm to avoid excessive unprepare / prepare") Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231220221418.2610185-1-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index cd05c76868e3c..7d556b1bfa82c 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -429,8 +429,7 @@ static int panel_edp_unprepare(struct drm_panel *panel) if (!p->prepared) return 0; - pm_runtime_mark_last_busy(panel->dev); - ret = pm_runtime_put_autosuspend(panel->dev); + ret = pm_runtime_put_sync_suspend(panel->dev); if (ret < 0) return ret; p->prepared = false; -- GitLab From fa78e188d8d1df850eb232a2631012093aeeb0e0 Mon Sep 17 00:00:00 2001 From: Badal Nilawar Date: Thu, 4 Jan 2024 18:37:02 +0530 Subject: [PATCH 0214/1420] drm/xe/dgfx: Release mmap mappings on rpm suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Release all mmap mappings for all vram objects which are associated with userfault such that, while pcie function in D3hot, any access to memory mappings will raise a userfault. Upon userfault, in order to access memory mappings, if graphics function is in D3 then runtime resume of dgpu will be triggered to transition to D0. v2: - Avoid iomem check before bo migration check as bo can migrate to system memory (Matthew Auld) v3: - Delete bo userfault link during bo destroy - Upon bo move (vram-smem), do bo userfault link deletion in xe_bo_move_notify instead of xe_bo_move (Thomas Hellström) - Grab lock in rpm hook while deleting bo userfault link (Matthew Auld) v4: - Add kernel doc and wrap vram_userfault related stuff in the structure (Matthew Auld) - Get rpm wakeref before taking dma reserve lock (Matthew Auld) - In suspend path apply lock for entire list op including list iteration (Matthew Auld) v5: - Use mutex lock instead of spin lock v6: - Fix review comments (Matthew Auld) Cc: Rodrigo Vivi Cc: Matthew Auld Cc: Anshuman Gupta Signed-off-by: Badal Nilawar Acked-by: Thomas Hellström #For the xe_bo_move_notify() changes Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20240104130702.950078-1-badal.nilawar@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_bo.c | 56 ++++++++++++++++++++++++++-- drivers/gpu/drm/xe/xe_bo.h | 2 + drivers/gpu/drm/xe/xe_bo_types.h | 3 ++ drivers/gpu/drm/xe/xe_device_types.h | 16 ++++++++ drivers/gpu/drm/xe/xe_pci.c | 2 + drivers/gpu/drm/xe/xe_pm.c | 17 +++++++++ drivers/gpu/drm/xe/xe_pm.h | 1 + 7 files changed, 93 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8e4a3b1f6b938..2e4d2157179c8 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -586,6 +586,8 @@ static int xe_bo_move_notify(struct xe_bo *bo, { struct ttm_buffer_object *ttm_bo = &bo->ttm; struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev); + struct ttm_resource *old_mem = ttm_bo->resource; + u32 old_mem_type = old_mem ? old_mem->mem_type : XE_PL_SYSTEM; int ret; /* @@ -605,6 +607,18 @@ static int xe_bo_move_notify(struct xe_bo *bo, if (ttm_bo->base.dma_buf && !ttm_bo->base.import_attach) dma_buf_move_notify(ttm_bo->base.dma_buf); + /* + * TTM has already nuked the mmap for us (see ttm_bo_unmap_virtual), + * so if we moved from VRAM make sure to unlink this from the userfault + * tracking. + */ + if (mem_type_is_vram(old_mem_type)) { + mutex_lock(&xe->mem_access.vram_userfault.lock); + if (!list_empty(&bo->vram_userfault_link)) + list_del_init(&bo->vram_userfault_link); + mutex_unlock(&xe->mem_access.vram_userfault.lock); + } + return 0; } @@ -1063,6 +1077,11 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo) if (bo->vm && xe_bo_is_user(bo)) xe_vm_put(bo->vm); + mutex_lock(&xe->mem_access.vram_userfault.lock); + if (!list_empty(&bo->vram_userfault_link)) + list_del(&bo->vram_userfault_link); + mutex_unlock(&xe->mem_access.vram_userfault.lock); + kfree(bo); } @@ -1110,16 +1129,20 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf) { struct ttm_buffer_object *tbo = vmf->vma->vm_private_data; struct drm_device *ddev = tbo->base.dev; + struct xe_device *xe = to_xe_device(ddev); + struct xe_bo *bo = ttm_to_xe_bo(tbo); + bool needs_rpm = bo->flags & XE_BO_CREATE_VRAM_MASK; vm_fault_t ret; int idx, r = 0; + if (needs_rpm) + xe_device_mem_access_get(xe); + ret = ttm_bo_vm_reserve(tbo, vmf); if (ret) - return ret; + goto out; if (drm_dev_enter(ddev, &idx)) { - struct xe_bo *bo = ttm_to_xe_bo(tbo); - trace_xe_bo_cpu_fault(bo); if (should_migrate_to_system(bo)) { @@ -1137,10 +1160,24 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf) } else { ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); } + if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) - return ret; + goto out; + /* + * ttm_bo_vm_reserve() already has dma_resv_lock. + */ + if (ret == VM_FAULT_NOPAGE && mem_type_is_vram(tbo->resource->mem_type)) { + mutex_lock(&xe->mem_access.vram_userfault.lock); + if (list_empty(&bo->vram_userfault_link)) + list_add(&bo->vram_userfault_link, &xe->mem_access.vram_userfault.list); + mutex_unlock(&xe->mem_access.vram_userfault.lock); + } dma_resv_unlock(tbo->base.resv); +out: + if (needs_rpm) + xe_device_mem_access_put(xe); + return ret; } @@ -1254,6 +1291,7 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo, #ifdef CONFIG_PROC_FS INIT_LIST_HEAD(&bo->client_link); #endif + INIT_LIST_HEAD(&bo->vram_userfault_link); drm_gem_private_object_init(&xe->drm, &bo->ttm.base, size); @@ -2264,6 +2302,16 @@ int xe_bo_dumb_create(struct drm_file *file_priv, return err; } +void xe_bo_runtime_pm_release_mmap_offset(struct xe_bo *bo) +{ + struct ttm_buffer_object *tbo = &bo->ttm; + struct ttm_device *bdev = tbo->bdev; + + drm_vma_node_unmap(&tbo->base.vma_node, bdev->dev_mapping); + + list_del_init(&bo->vram_userfault_link); +} + #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) #include "tests/xe_bo.c" #endif diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index 97b32528c600f..350cc73cadf8d 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -249,6 +249,8 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int xe_gem_mmap_offset_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +void xe_bo_runtime_pm_release_mmap_offset(struct xe_bo *bo); + int xe_bo_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h index 64c2249a4e407..14ef13b7b421f 100644 --- a/drivers/gpu/drm/xe/xe_bo_types.h +++ b/drivers/gpu/drm/xe/xe_bo_types.h @@ -88,6 +88,9 @@ struct xe_bo { * objects. */ u16 cpu_caching; + + /** @vram_userfault_link: Link into @mem_access.vram_userfault.list */ + struct list_head vram_userfault_link; }; #define intel_bo_to_drm_bo(bo) (&(bo)->ttm.base) diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 163d889d407bc..8404685b24182 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -387,6 +387,22 @@ struct xe_device { struct { /** @ref: ref count of memory accesses */ atomic_t ref; + + /** @vram_userfault: Encapsulate vram_userfault related stuff */ + struct { + /** + * @lock: Protects access to @vram_usefault.list + * Using mutex instead of spinlock as lock is applied to entire + * list operation which may sleep + */ + struct mutex lock; + + /** + * @list: Keep list of userfaulted vram bo, which require to release their + * mmap mappings at runtime suspend path + */ + struct list_head list; + } vram_userfault; } mem_access; /** diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index dcc5ded1558e7..7ba2000f535bd 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -774,6 +774,8 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) str_yes_no(xe_device_has_sriov(xe)), xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); + xe_pm_init_early(xe); + err = xe_device_probe(xe); if (err) return err; diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index b429c2876a764..d5f219796d7ef 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -163,6 +163,12 @@ static void xe_pm_runtime_init(struct xe_device *xe) pm_runtime_put(dev); } +void xe_pm_init_early(struct xe_device *xe) +{ + INIT_LIST_HEAD(&xe->mem_access.vram_userfault.list); + drmm_mutex_init(&xe->drm, &xe->mem_access.vram_userfault.lock); +} + void xe_pm_init(struct xe_device *xe) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); @@ -214,6 +220,7 @@ struct task_struct *xe_pm_read_callback_task(struct xe_device *xe) int xe_pm_runtime_suspend(struct xe_device *xe) { + struct xe_bo *bo, *on; struct xe_gt *gt; u8 id; int err = 0; @@ -247,6 +254,16 @@ int xe_pm_runtime_suspend(struct xe_device *xe) */ lock_map_acquire(&xe_device_mem_access_lockdep_map); + /* + * Applying lock for entire list op as xe_ttm_bo_destroy and xe_bo_move_notify + * also checks and delets bo entry from user fault list. + */ + mutex_lock(&xe->mem_access.vram_userfault.lock); + list_for_each_entry_safe(bo, on, + &xe->mem_access.vram_userfault.list, vram_userfault_link) + xe_bo_runtime_pm_release_mmap_offset(bo); + mutex_unlock(&xe->mem_access.vram_userfault.lock); + if (xe->d3cold.allowed) { err = xe_bo_evict_all(xe); if (err) diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h index 6b9031f7af243..64a97c6726a72 100644 --- a/drivers/gpu/drm/xe/xe_pm.h +++ b/drivers/gpu/drm/xe/xe_pm.h @@ -20,6 +20,7 @@ struct xe_device; int xe_pm_suspend(struct xe_device *xe); int xe_pm_resume(struct xe_device *xe); +void xe_pm_init_early(struct xe_device *xe); void xe_pm_init(struct xe_device *xe); void xe_pm_runtime_fini(struct xe_device *xe); int xe_pm_runtime_suspend(struct xe_device *xe); -- GitLab From cd7b0b2dd3d9fecc6057c07b40e8087db2f9f71a Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 13 Dec 2023 14:46:29 +0530 Subject: [PATCH 0215/1420] drm/i915/dp: Fix the max DSC bpc supported by source Use correct helper for getting max DSC bpc supported by the source. Fixes: 1c56e9a39833 ("drm/i915/dp: Get optimal link config to have best compressed bpp") Cc: Ankit Nautiyal Cc: Stanislav Lisovskiy Cc: Jani Nikula Signed-off-by: Ankit Nautiyal Reviewed-by: Swati Sharma Link: https://patchwork.freedesktop.org/patch/msgid/20231213091632.431557-3-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 93f9985ef75c3..a0d4ef1a04938 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2102,7 +2102,7 @@ static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, } } - dsc_max_bpc = intel_dp_dsc_min_src_input_bpc(i915); + dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915); if (!dsc_max_bpc) return -EINVAL; -- GitLab From 9676bee4afb188230d591b9cd015c3ab442f578f Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 8 Jan 2024 21:15:50 +0100 Subject: [PATCH 0216/1420] dt-bindings: nt35510: add compatible for FRIDA FRD400B25025-A-CTK The patch adds the FRIDA FRD400B25025-A-CTK panel, which belongs to the Novatek NT35510-based panel family. Signed-off-by: Dario Binacchi Acked-by: Krzysztof Kozlowski Reviewed-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20240108201618.2798649-6-dario.binacchi@amarulasolutions.com --- .../devicetree/bindings/display/panel/novatek,nt35510.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml index bc92928c805b9..a4afaff483b73 100644 --- a/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml @@ -15,7 +15,9 @@ allOf: properties: compatible: items: - - const: hydis,hva40wv1 + - enum: + - frida,frd400b25025 + - hydis,hva40wv1 - const: novatek,nt35510 description: This indicates the panel manufacturer of the panel that is in turn using the NT35510 panel driver. The compatible -- GitLab From 9b26d5c044d6a29ebfb1845408e0f2a7c5f89818 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 8 Jan 2024 21:15:52 +0100 Subject: [PATCH 0217/1420] drm/panel: nt35510: move hardwired parameters to configuration This patch, preparatory for future developments, move the hardwired parameters to configuration data to allow the addition of new NT35510-based panels. Signed-off-by: Dario Binacchi Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20240108201618.2798649-8-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/panel/panel-novatek-nt35510.c | 140 ++++++++++++++---- 1 file changed, 115 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 83a9cf53d2690..3ecaf87939e61 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -171,6 +171,10 @@ struct nt35510_config { * timing in the display controller. */ const struct drm_display_mode mode; + /** + * @mode_flags: DSI operation mode related flags + */ + unsigned long mode_flags; /** * @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V * in 0.1V steps the default is 0x05 which means 6.0V @@ -273,6 +277,100 @@ struct nt35510_config { * same layout of bytes as @vgp. */ u8 vgn[NT35510_P1_VGN_LEN]; + /** + * @dopctr: setting optional control for display + * ERR bits 0..1 in the first byte is the ERR pin output signal setting. + * 0 = Disable, ERR pin output low + * 1 = ERR pin output CRC error only + * 2 = ERR pin output ECC error only + * 3 = ERR pin output CRC and ECC error + * The default is 0. + * N565 bit 2 in the first byte is the 16-bit/pixel format selection. + * 0 = R[4:0] + G[5:3] & G[2:0] + B[4:0] + * 1 = G[2:0] + R[4:0] & B[4:0] + G[5:3] + * The default is 0. + * DIS_EoTP_HS bit 3 in the first byte is "DSI protocol violation" error + * reporting. + * 0 = reporting when error + * 1 = not reporting when error + * DSIM bit 4 in the first byte is the video mode data type enable + * 0 = Video mode data type disable + * 1 = Video mode data type enable + * The default is 0. + * DSIG bit 5 int the first byte is the generic r/w data type enable + * 0 = Generic r/w disable + * 1 = Generic r/w enable + * The default is 0. + * DSITE bit 6 in the first byte is TE line enable + * 0 = TE line is disabled + * 1 = TE line is enabled + * The default is 0. + * RAMKP bit 7 in the first byte is the frame memory keep/loss in + * sleep-in mode + * 0 = contents loss in sleep-in + * 1 = contents keep in sleep-in + * The default is 0. + * CRL bit 1 in the second byte is the source driver data shift + * direction selection. This bit is XOR operation with bit RSMX + * of 3600h command. + * 0 (RMSX = 0) = S1 -> S1440 + * 0 (RMSX = 1) = S1440 -> S1 + * 1 (RMSX = 0) = S1440 -> S1 + * 1 (RMSX = 1) = S1 -> S1440 + * The default is 0. + * CTB bit 2 in the second byte is the vertical scanning direction + * selection for gate control signals. This bit is XOR operation + * with bit ML of 3600h command. + * 0 (ML = 0) = Forward (top -> bottom) + * 0 (ML = 1) = Reverse (bottom -> top) + * 1 (ML = 0) = Reverse (bottom -> top) + * 1 (ML = 1) = Forward (top -> bottom) + * The default is 0. + * CRGB bit 3 in the second byte is RGB-BGR order selection. This + * bit is XOR operation with bit RGB of 3600h command. + * 0 (RGB = 0) = RGB/Normal + * 0 (RGB = 1) = BGR/RB swap + * 1 (RGB = 0) = BGR/RB swap + * 1 (RGB = 1) = RGB/Normal + * The default is 0. + * TE_PWR_SEL bit 4 in the second byte is the TE output voltage + * level selection (only valid when DSTB_SEL = 0 or DSTB_SEL = 1, + * VSEL = High and VDDI = 1.665~3.3V). + * 0 = TE output voltage level is VDDI + * 1 = TE output voltage level is VDDA + * The default is 0. + */ + u8 dopctr[NT35510_P0_DOPCTR_LEN]; + /** + * @madctl: Memory data access control + * RSMY bit 0 is flip vertical. Flips the display image top to down. + * RSMX bit 1 is flip horizontal. Flips the display image left to right. + * MH bit 2 is the horizontal refresh order. + * RGB bit 3 is the RGB-BGR order. + * 0 = RGB color sequence + * 1 = BGR color sequence + * ML bit 4 is the vertical refresh order. + * MV bit 5 is the row/column exchange. + * MX bit 6 is the column address order. + * MY bit 7 is the row address order. + */ + u8 madctl; + /** + * @sdhdtctr: source output data hold time + * 0x00..0x3F = 0..31.5us in steps of 0.5us + * The default is 0x05 = 2.5us. + */ + u8 sdhdtctr; + /** + * @gseqctr: EQ control for gate signals + * GFEQ_XX[3:0]: time setting of EQ step for falling edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + * GREQ_XX[7:4]: time setting of EQ step for rising edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + */ + u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; /** * @sdeqctr: Source driver control settings, first byte is * 0 for mode 1 and 1 for mode 2. Mode 1 uses two steps and @@ -536,46 +634,28 @@ static int nt35510_setup_display(struct nt35510 *nt) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); const struct nt35510_config *conf = nt->conf; - u8 dopctr[NT35510_P0_DOPCTR_LEN]; - u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; u8 dpfrctr[NT35510_P0_DPFRCTR1_LEN]; - /* FIXME: set up any rotation (assume none for now) */ - u8 addr_mode = NT35510_ROTATE_0_SETTING; - u8 val; int ret; - /* Enable TE, EoTP and RGB pixel format */ - dopctr[0] = NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | - NT35510_DOPCTR_0_N565; - dopctr[1] = NT35510_DOPCTR_1_CTB; ret = nt35510_send_long(nt, dsi, NT35510_P0_DOPCTR, NT35510_P0_DOPCTR_LEN, - dopctr); + conf->dopctr); if (ret) return ret; - ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &addr_mode, - sizeof(addr_mode)); + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &conf->madctl, + sizeof(conf->madctl)); if (ret < 0) return ret; - /* - * Source data hold time, default 0x05 = 2.5us - * 0x00..0x3F = 0 .. 31.5us in steps of 0.5us - * 0x0A = 5us - */ - val = 0x0A; - ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &val, - sizeof(val)); + ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &conf->sdhdtctr, + sizeof(conf->sdhdtctr)); if (ret < 0) return ret; - /* EQ control for gate signals, 0x00 = 0 us */ - gseqctr[0] = 0x00; - gseqctr[1] = 0x00; ret = nt35510_send_long(nt, dsi, NT35510_P0_GSEQCTR, NT35510_P0_GSEQCTR_LEN, - gseqctr); + conf->gseqctr); if (ret) return ret; @@ -896,7 +976,6 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) */ dsi->hs_rate = 349440000; dsi->lp_rate = 9600000; - dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; /* * Every new incarnation of this display must have a unique @@ -908,6 +987,8 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return -ENODEV; } + dsi->mode_flags = nt->conf->mode_flags; + nt->supplies[0].supply = "vdd"; /* 2.3-4.8 V */ nt->supplies[1].supply = "vddi"; /* 1.65-3.3V */ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->supplies), @@ -1030,6 +1111,7 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vtotal = 800 + 2 + 0 + 5, /* VBP = 5 */ .flags = 0, }, + .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS, /* 0x09: AVDD = 5.6V */ .avdd = { 0x09, 0x09, 0x09 }, /* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */ @@ -1050,6 +1132,14 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vgp = { 0x00, 0xA3, 0x00 }, /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ .vgn = { 0x00, 0xA3, 0x00 }, + /* Enable TE, EoTP and RGB pixel format */ + .dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | + NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB }, + .madctl = NT35510_ROTATE_0_SETTING, + /* 0x0A: SDT = 5 us */ + .sdhdtctr = 0x0A, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, /* SDEQCTR: source driver EQ mode 2, 2.5 us rise time on each step */ .sdeqctr = { 0x01, 0x05, 0x05, 0x05 }, /* SDVPCTR: Normal operation off color during v porch */ -- GitLab From 219a1f49094f50bf9c382830d06149e677f76bed Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 8 Jan 2024 21:15:53 +0100 Subject: [PATCH 0218/1420] drm/panel: nt35510: support FRIDA FRD400B25025-A-CTK The initialization commands are taken from the STMicroelectronics driver found at [1]. To ensure backward compatibility, flags have been added to enable gamma correction setting and display control. In other cases, registers have been set to their default values according to the specifications found in the datasheet. [1] https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Drivers/BSP/Components/nt35510/ Signed-off-by: Dario Binacchi Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20240108201618.2798649-9-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/panel/panel-novatek-nt35510.c | 284 ++++++++++++++++-- 1 file changed, 252 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 3ecaf87939e61..d3bfdfc9cff64 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -36,6 +36,9 @@ #include #include +#define NT35510_CMD_CORRECT_GAMMA BIT(0) +#define NT35510_CMD_CONTROL_DISPLAY BIT(1) + #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ #define MCS_CMD_READ_ID1 0xDA #define MCS_CMD_READ_ID2 0xDB @@ -112,18 +115,33 @@ /* AVDD and AVEE setting 3 bytes */ #define NT35510_P1_AVDD_LEN 3 #define NT35510_P1_AVEE_LEN 3 +#define NT35510_P1_VCL_LEN 3 #define NT35510_P1_VGH_LEN 3 #define NT35510_P1_VGL_LEN 3 #define NT35510_P1_VGP_LEN 3 #define NT35510_P1_VGN_LEN 3 +#define NT35510_P1_VCMOFF_LEN 2 /* BT1CTR thru BT5CTR setting 3 bytes */ #define NT35510_P1_BT1CTR_LEN 3 #define NT35510_P1_BT2CTR_LEN 3 +#define NT35510_P1_BT3CTR_LEN 3 #define NT35510_P1_BT4CTR_LEN 3 #define NT35510_P1_BT5CTR_LEN 3 /* 52 gamma parameters times two per color: positive and negative */ #define NT35510_P1_GAMMA_LEN 52 +#define NT35510_WRCTRLD_BCTRL BIT(5) +#define NT35510_WRCTRLD_A BIT(4) +#define NT35510_WRCTRLD_DD BIT(3) +#define NT35510_WRCTRLD_BL BIT(2) +#define NT35510_WRCTRLD_DB BIT(1) +#define NT35510_WRCTRLD_G BIT(0) + +#define NT35510_WRCABC_OFF 0 +#define NT35510_WRCABC_UI_MODE 1 +#define NT35510_WRCABC_STILL_MODE 2 +#define NT35510_WRCABC_MOVING_MODE 3 + /** * struct nt35510_config - the display-specific NT35510 configuration * @@ -175,6 +193,10 @@ struct nt35510_config { * @mode_flags: DSI operation mode related flags */ unsigned long mode_flags; + /** + * @cmds: enable DSI commands + */ + u32 cmds; /** * @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V * in 0.1V steps the default is 0x05 which means 6.0V @@ -224,6 +246,25 @@ struct nt35510_config { * The defaults are 4 and 3 yielding 0x34 */ u8 bt2ctr[NT35510_P1_BT2CTR_LEN]; + /** + * @vcl: setting for VCL ranging from 0x00 = -2.5V to 0x11 = -4.0V + * in 1V steps, the default is 0x00 which means -2.5V + */ + u8 vcl[NT35510_P1_VCL_LEN]; + /** + * @bt3ctr: setting for boost power control for the VCL step-up + * circuit (3) + * bits 0..2 in the lower nibble controls CLCK, the booster clock + * frequency, the values are the same as for PCK in @bt1ctr. + * bits 4..5 in the upper nibble controls BTCL, the boosting + * amplification for the step-up circuit. + * 0 = Disable + * 1 = -0.5 x VDDB + * 2 = -1 x VDDB + * 3 = -2 x VDDB + * The defaults are 4 and 2 yielding 0x24 + */ + u8 bt3ctr[NT35510_P1_BT3CTR_LEN]; /** * @vgh: setting for VGH ranging from 0x00 = 7.0V to 0x0B = 18.0V * in 1V steps, the default is 0x08 which means 15V @@ -277,6 +318,19 @@ struct nt35510_config { * same layout of bytes as @vgp. */ u8 vgn[NT35510_P1_VGN_LEN]; + /** + * @vcmoff: setting the DC VCOM offset voltage + * The first byte contains bit 8 of VCM in bit 0 and VCMOFFSEL in bit 4. + * The second byte contains bits 0..7 of VCM. + * VCMOFFSEL the common voltage offset mode. + * VCMOFFSEL 0x00 = VCOM .. 0x01 Gamma. + * The default is 0x00. + * VCM the VCOM output voltage (VCMOFFSEL = 0) or the internal register + * offset for gamma voltage (VCMOFFSEL = 1). + * VCM 0x00 = 0V/0 .. 0x118 = 3.5V/280 in steps of 12.5mV/1step + * The default is 0x00 = 0V/0. + */ + u8 vcmoff[NT35510_P1_VCMOFF_LEN]; /** * @dopctr: setting optional control for display * ERR bits 0..1 in the first byte is the ERR pin output signal setting. @@ -441,6 +495,43 @@ struct nt35510_config { * @gamma_corr_neg_b: Blue gamma correction parameters, negative */ u8 gamma_corr_neg_b[NT35510_P1_GAMMA_LEN]; + /** + * @wrdisbv: write display brightness + * 0x00 value means the lowest brightness and 0xff value means + * the highest brightness. + * The default is 0x00. + */ + u8 wrdisbv; + /** + * @wrctrld: write control display + * G bit 0 selects gamma curve: 0 = Manual, 1 = Automatic + * DB bit 1 selects display brightness: 0 = Manual, 1 = Automatic + * BL bit 2 controls backlight control: 0 = Off, 1 = On + * DD bit 3 controls display dimming: 0 = Off, 1 = On + * A bit 4 controls LABC block: 0 = Off, 1 = On + * BCTRL bit 5 controls brightness block: 0 = Off, 1 = On + */ + u8 wrctrld; + /** + * @wrcabc: write content adaptive brightness control + * There is possible to use 4 different modes for content adaptive + * image functionality: + * 0: Off + * 1: User Interface Image (UI-Mode) + * 2: Still Picture Image (Still-Mode) + * 3: Moving Picture Image (Moving-Mode) + * The default is 0 + */ + u8 wrcabc; + /** + * @wrcabcmb: write CABC minimum brightness + * Set the minimum brightness value of the display for CABC + * function. + * 0x00 value means the lowest brightness for CABC and 0xff + * value means the highest brightness for CABC. + * The default is 0x00. + */ + u8 wrcabcmb; }; /** @@ -584,6 +675,16 @@ static int nt35510_setup_power(struct nt35510 *nt) nt->conf->bt2ctr); if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCL, + NT35510_P1_VCL_LEN, + nt->conf->vcl); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_BT3CTR, + NT35510_P1_BT3CTR_LEN, + nt->conf->bt3ctr); + if (ret) + return ret; ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGH, NT35510_P1_VGH_LEN, nt->conf->vgh); @@ -620,6 +721,12 @@ static int nt35510_setup_power(struct nt35510 *nt) if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCMOFF, + NT35510_P1_VCMOFF_LEN, + nt->conf->vcmoff); + if (ret) + return ret; + /* Typically 10 ms */ usleep_range(10000, 20000); @@ -799,36 +906,38 @@ static int nt35510_power_on(struct nt35510 *nt) if (ret) return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_b); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_b); - if (ret) - return ret; + if (nt->conf->cmds & NT35510_CMD_CORRECT_GAMMA) { + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_b); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_b); + if (ret) + return ret; + } /* Set up stuff in manufacturer control, page 0 */ ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR, @@ -907,6 +1016,26 @@ static int nt35510_prepare(struct drm_panel *panel) /* Up to 120 ms */ usleep_range(120000, 150000); + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) { + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &nt->conf->wrctrld, + sizeof(nt->conf->wrctrld)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE, + &nt->conf->wrcabc, + sizeof(nt->conf->wrcabc)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, + &nt->conf->wrcabcmb, + sizeof(nt->conf->wrcabcmb)); + if (ret < 0) + return ret; + } + ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { dev_err(nt->dev, "failed to turn display on (%d)\n", ret); @@ -1004,7 +1133,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(nt->reset_gpio)) { dev_err(dev, "error getting RESET GPIO\n"); return PTR_ERR(nt->reset_gpio); @@ -1033,7 +1162,10 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return PTR_ERR(bl); } bl->props.max_brightness = 255; - bl->props.brightness = 255; + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) + bl->props.brightness = nt->conf->wrdisbv; + else + bl->props.brightness = 255; bl->props.power = FB_BLANK_POWERDOWN; nt->panel.backlight = bl; } @@ -1112,6 +1244,7 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .flags = 0, }, .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS, + .cmds = NT35510_CMD_CORRECT_GAMMA, /* 0x09: AVDD = 5.6V */ .avdd = { 0x09, 0x09, 0x09 }, /* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */ @@ -1120,6 +1253,10 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .avee = { 0x09, 0x09, 0x09 }, /* 0x24: NCK = Hsync/2, BTN = -2 x VDDB */ .bt2ctr = { 0x24, 0x24, 0x24 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -2.5V */ + .vcl = { 0x00, 0x00, 0x00 }, + /* 0x24: CLCK = Hsync/2, BTN = -1 x VDDB */ + .bt3ctr = { 0x24, 0x24, 0x24 }, /* 0x05 = 12V */ .vgh = { 0x05, 0x05, 0x05 }, /* 0x24: NCKA = Hsync/2, VGH = 2 x AVDD - AVEE */ @@ -1132,6 +1269,8 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vgp = { 0x00, 0xA3, 0x00 }, /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ .vgn = { 0x00, 0xA3, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = 0V */ + .vcmoff = { 0x00, 0x00 }, /* Enable TE, EoTP and RGB pixel format */ .dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB }, @@ -1163,7 +1302,88 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .gamma_corr_neg_b = { NT35510_GAMMA_NEG_DEFAULT }, }; +static const struct nt35510_config nt35510_frida_frd400b25025 = { + .width_mm = 52, + .height_mm = 86, + .mode = { + .clock = 23000, + .hdisplay = 480, + .hsync_start = 480 + 34, /* HFP = 34 */ + .hsync_end = 480 + 34 + 2, /* HSync = 2 */ + .htotal = 480 + 34 + 2 + 34, /* HBP = 34 */ + .vdisplay = 800, + .vsync_start = 800 + 15, /* VFP = 15 */ + .vsync_end = 800 + 15 + 12, /* VSync = 12 */ + .vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */ + .flags = 0, + }, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM, + .cmds = NT35510_CMD_CONTROL_DISPLAY, + /* 0x03: AVDD = 6.2V */ + .avdd = { 0x03, 0x03, 0x03 }, + /* 0x46: PCK = 2 x Hsync, BTP = 2.5 x VDDB */ + .bt1ctr = { 0x46, 0x46, 0x46 }, + /* 0x03: AVEE = -6.2V */ + .avee = { 0x03, 0x03, 0x03 }, + /* 0x36: PCK = 2 x Hsync, BTP = 2 x VDDB */ + .bt2ctr = { 0x36, 0x36, 0x36 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -3.5V */ + .vcl = { 0x00, 0x00, 0x02 }, + /* 0x26: CLCK = 2 x Hsync, BTN = -1 x VDDB */ + .bt3ctr = { 0x26, 0x26, 0x26 }, + /* 0x09 = 16V */ + .vgh = { 0x09, 0x09, 0x09 }, + /* 0x36: HCK = 2 x Hsync, VGH = 2 x AVDD - AVEE */ + .bt4ctr = { 0x36, 0x36, 0x36 }, + /* 0x08 = -10V */ + .vgl = { 0x08, 0x08, 0x08 }, + /* 0x26: LCK = 2 x Hsync, VGL = AVDD + VCL - AVDD */ + .bt5ctr = { 0x26, 0x26, 0x26 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgp = { 0x00, 0x80, 0x00 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgn = { 0x00, 0x80, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = -1V */ + .vcmoff = { 0x00, 0x50 }, + .dopctr = { NT35510_DOPCTR_0_RAMKP | NT35510_DOPCTR_0_DSITE | + NT35510_DOPCTR_0_DSIG | NT35510_DOPCTR_0_DSIM | + NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, 0 }, + .madctl = NT35510_ROTATE_180_SETTING, + /* 0x03: SDT = 1.5 us */ + .sdhdtctr = 0x03, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, + /* SDEQCTR: source driver EQ mode 2, 1 us rise time on each step */ + .sdeqctr = { 0x01, 0x02, 0x02, 0x02 }, + /* SDVPCTR: Normal operation off color during v porch */ + .sdvpctr = 0x01, + /* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */ + .t1 = 0x0184, + /* VBP: vertical back porch toward the panel */ + .vbp = 0x1C, + /* VFP: vertical front porch toward the panel */ + .vfp = 0x1C, + /* PSEL: divide pixel clock 23MHz with 1 (no clock downscaling) */ + .psel = 0, + /* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */ + .dpmctr12 = { 0x03, 0x00, 0x00, }, + /* write display brightness */ + .wrdisbv = 0x7f, + /* write control display */ + .wrctrld = NT35510_WRCTRLD_BCTRL | NT35510_WRCTRLD_DD | + NT35510_WRCTRLD_BL, + /* write content adaptive brightness control */ + .wrcabc = NT35510_WRCABC_STILL_MODE, + /* write CABC minimum brightness */ + .wrcabcmb = 0xff, +}; + static const struct of_device_id nt35510_of_match[] = { + { + .compatible = "frida,frd400b25025", + .data = &nt35510_frida_frd400b25025, + }, { .compatible = "hydis,hva40wv1", .data = &nt35510_hydis_hva40wv1, -- GitLab From 9962c25ac41bf6e45bf3afeb56e10a03f0c663f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:49:58 +0200 Subject: [PATCH 0219/1420] drm: Add eDP 1.5 early transport definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DP_PSR_ENABLE_SU_REGION_ET to enable panel early transport. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-2-jouni.hogander@intel.com --- include/drm/display/drm_dp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 83d2039c018b4..9f3bbbb67adda 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -715,6 +715,7 @@ # define DP_PSR_SU_REGION_SCANLINE_CAPTURE BIT(4) /* eDP 1.4a */ # define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS BIT(5) /* eDP 1.4a */ # define DP_PSR_ENABLE_PSR2 BIT(6) /* eDP 1.4a */ +# define DP_PSR_ENABLE_SU_REGION_ET BIT(7) /* eDP 1.5 */ #define DP_ADAPTER_CTRL 0x1a0 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) -- GitLab From 1bff93b8bc27a18aa87752819bfda6f00bceb10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:49:59 +0200 Subject: [PATCH 0220/1420] drm/i915/psr: Extend SU area to cover cursor fully if needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case early transport is enabled SU area needs to be extended to cover cursor area fully when cursor is in SU area. Bspec: 68927 Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 38 +++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 54120b45958b0..d0495d09e3d7e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2002,6 +2002,29 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment; } +/* + * When early transport is in use we need to extend SU area to cover + * cursor fully when cursor is in SU area. + */ +static void +intel_psr2_sel_fetch_et_alignment(struct intel_crtc_state *crtc_state, + struct intel_plane_state *cursor_state, + struct drm_rect *pipe_clip) +{ + struct drm_rect inter; + + if (!crtc_state->enable_psr2_su_region_et || + !cursor_state->uapi.visible) + return; + + inter = *pipe_clip; + if (!drm_rect_intersect(&inter, &cursor_state->uapi.dst)) + return; + + clip_area_update(pipe_clip, &cursor_state->uapi.dst, + &crtc_state->pipe_src); +} + /* * TODO: Not clear how to handle planes with negative position, * also planes are not updated if they have a negative X @@ -2043,7 +2066,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct drm_rect pipe_clip = { .x1 = 0, .y1 = -1, .x2 = INT_MAX, .y2 = -1 }; - struct intel_plane_state *new_plane_state, *old_plane_state; + struct intel_plane_state *new_plane_state, *old_plane_state, + *cursor_plane_state = NULL; struct intel_plane *plane; bool full_update = false; int i, ret; @@ -2123,6 +2147,13 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1; clip_area_update(&pipe_clip, &damaged_area, &crtc_state->pipe_src); + + /* + * Cursor plane new state is stored to adjust su area to cover + * cursor are fully. + */ + if (plane->id == PLANE_CURSOR) + cursor_plane_state = new_plane_state; } /* @@ -2151,6 +2182,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (ret) return ret; + /* Adjust su area to cover cursor fully as necessary */ + if (cursor_plane_state) + intel_psr2_sel_fetch_et_alignment(crtc_state, cursor_plane_state, + &pipe_clip); + intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip); /* -- GitLab From 86b26b6aeac78c396fa022f49c58a4daffffc983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:50:00 +0200 Subject: [PATCH 0221/1420] drm/i915/psr: Carry su area in crtc_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Su_area is needed when configuring CUR_POS_ERLY_TPT and PIPE_SRC_SZ_ERLY_TPT. Store it into intel_crtc_state->psr2_su_area. Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-4-jouni.hogander@intel.com --- .../drm/i915/display/intel_display_types.h | 2 + drivers/gpu/drm/i915/display/intel_psr.c | 62 ++++++++++--------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 3556ccedbe4c1..13a893f4130ac 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1401,6 +1401,8 @@ struct intel_crtc_state { u32 psr2_man_track_ctl; + struct drm_rect psr2_su_area; + /* Variable Refresh Rate state */ struct { bool enable, in_range; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index d0495d09e3d7e..fa0af5a6816b1 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1932,7 +1932,7 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st } static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, - struct drm_rect *clip, bool full_update) + bool full_update) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -1947,17 +1947,21 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, goto exit; } - if (clip->y1 == -1) + if (crtc_state->psr2_su_area.y1 == -1) goto exit; if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) { - val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1); - val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1); + val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(crtc_state->psr2_su_area.y1); + val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(crtc_state->psr2_su_area.y2 - 1); } else { - drm_WARN_ON(crtc_state->uapi.crtc->dev, clip->y1 % 4 || clip->y2 % 4); + drm_WARN_ON(crtc_state->uapi.crtc->dev, + crtc_state->psr2_su_area.y1 % 4 || + crtc_state->psr2_su_area.y2 % 4); - val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1 / 4 + 1); - val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 / 4 + 1); + val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR( + crtc_state->psr2_su_area.y1 / 4 + 1); + val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR( + crtc_state->psr2_su_area.y2 / 4 + 1); } exit: crtc_state->psr2_man_track_ctl = val; @@ -1983,8 +1987,7 @@ static void clip_area_update(struct drm_rect *overlap_damage_area, overlap_damage_area->y2 = damage_area->y2; } -static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *crtc_state, - struct drm_rect *pipe_clip) +static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; @@ -1997,9 +2000,10 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c else y_alignment = crtc_state->su_y_granularity; - pipe_clip->y1 -= pipe_clip->y1 % y_alignment; - if (pipe_clip->y2 % y_alignment) - pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment; + crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment; + if (crtc_state->psr2_su_area.y2 % y_alignment) + crtc_state->psr2_su_area.y2 = ((crtc_state->psr2_su_area.y2 / + y_alignment) + 1) * y_alignment; } /* @@ -2008,8 +2012,7 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c */ static void intel_psr2_sel_fetch_et_alignment(struct intel_crtc_state *crtc_state, - struct intel_plane_state *cursor_state, - struct drm_rect *pipe_clip) + struct intel_plane_state *cursor_state) { struct drm_rect inter; @@ -2017,11 +2020,11 @@ intel_psr2_sel_fetch_et_alignment(struct intel_crtc_state *crtc_state, !cursor_state->uapi.visible) return; - inter = *pipe_clip; + inter = crtc_state->psr2_su_area; if (!drm_rect_intersect(&inter, &cursor_state->uapi.dst)) return; - clip_area_update(pipe_clip, &cursor_state->uapi.dst, + clip_area_update(&crtc_state->psr2_su_area, &cursor_state->uapi.dst, &crtc_state->pipe_src); } @@ -2065,7 +2068,6 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_rect pipe_clip = { .x1 = 0, .y1 = -1, .x2 = INT_MAX, .y2 = -1 }; struct intel_plane_state *new_plane_state, *old_plane_state, *cursor_plane_state = NULL; struct intel_plane *plane; @@ -2080,6 +2082,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, goto skip_sel_fetch_set_loop; } + crtc_state->psr2_su_area.x1 = 0; + crtc_state->psr2_su_area.y1 = -1; + crtc_state->psr2_su_area.x2 = INT_MAX; + crtc_state->psr2_su_area.y2 = -1; + /* * Calculate minimal selective fetch area of each plane and calculate * the pipe damaged area. @@ -2114,14 +2121,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (old_plane_state->uapi.visible) { damaged_area.y1 = old_plane_state->uapi.dst.y1; damaged_area.y2 = old_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); } if (new_plane_state->uapi.visible) { damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); } continue; @@ -2129,7 +2136,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, /* If alpha changed mark the whole plane area as damaged */ damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); continue; } @@ -2146,7 +2153,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1; damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1; - clip_area_update(&pipe_clip, &damaged_area, &crtc_state->pipe_src); + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); /* * Cursor plane new state is stored to adjust su area to cover @@ -2162,7 +2169,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, * should identify cases where this happens and fix the area * calculation for those. */ - if (pipe_clip.y1 == -1) { + if (crtc_state->psr2_su_area.y1 == -1) { drm_info_once(&dev_priv->drm, "Selective fetch area calculation failed in pipe %c\n", pipe_name(crtc->pipe)); @@ -2176,7 +2183,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if ((IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) && crtc_state->splitter.enable) - pipe_clip.y1 = 0; + crtc_state->psr2_su_area.y1 = 0; ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); if (ret) @@ -2184,10 +2191,9 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, /* Adjust su area to cover cursor fully as necessary */ if (cursor_plane_state) - intel_psr2_sel_fetch_et_alignment(crtc_state, cursor_plane_state, - &pipe_clip); + intel_psr2_sel_fetch_et_alignment(crtc_state, cursor_plane_state); - intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip); + intel_psr2_sel_fetch_pipe_alignment(crtc_state); /* * Now that we have the pipe damaged area check if it intersect with @@ -2202,7 +2208,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, !new_plane_state->uapi.visible) continue; - inter = pipe_clip; + inter = crtc_state->psr2_su_area; sel_fetch_area = &new_plane_state->psr2_sel_fetch_area; if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) { sel_fetch_area->y1 = -1; @@ -2247,7 +2253,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, } skip_sel_fetch_set_loop: - psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update); + psr2_man_trk_ctl_calc(crtc_state, full_update); return 0; } -- GitLab From 7f85883e4a7b95559fb61cd202196ac8c8f857d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:50:01 +0200 Subject: [PATCH 0222/1420] drm/i915/psr: Calculate and configure CUR_POS_ERLY_TPT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New register CUR_POS_ERLY_TPT related to early transport is supposed to be configured when early transport is in use. This register is used to configure cursor vertical postion from beginning of selective update area. Bspec: 68927 Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-5-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 32 ++++++++++++++++----- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 926e2de00eb58..ecff90e233f0e 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -47,12 +47,23 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) return base + plane_state->view.color_plane[0].offset; } -static u32 intel_cursor_position(const struct intel_plane_state *plane_state) +static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + bool early_tpt) { int x = plane_state->uapi.dst.x1; int y = plane_state->uapi.dst.y1; u32 pos = 0; + /* + * Formula from Bspec: + * MAX(-1 * + 1, CUR_POS Y Position - Update region Y position + */ + if (early_tpt) + y = max(-1 * drm_rect_height(&plane_state->uapi.dst) + 1, + y - crtc_state->psr2_su_area.y1); + if (x < 0) { pos |= CURSOR_POS_X_SIGN; x = -x; @@ -274,7 +285,7 @@ static void i845_cursor_update_arm(struct intel_plane *plane, size = CURSOR_HEIGHT(height) | CURSOR_WIDTH(width); base = intel_cursor_base(plane_state); - pos = intel_cursor_position(plane_state); + pos = intel_cursor_position(crtc_state, plane_state, false); } /* On these chipsets we can only modify the base/size/stride @@ -503,17 +514,24 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; if (!crtc_state->enable_psr2_sel_fetch) return; - if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) { + if (crtc_state->enable_psr2_su_region_et) { + u32 val = intel_cursor_position(crtc_state, plane_state, + true); + intel_de_write_fw(dev_priv, CURPOS_ERLY_TPT(pipe), val); + } + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), plane_state->ctl); - else + } else { i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); + } } /* TODO: split into noarm+arm pair */ @@ -536,7 +554,7 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1); base = intel_cursor_base(plane_state); - pos = intel_cursor_position(plane_state); + pos = intel_cursor_position(crtc_state, plane_state, false); } /* diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 220fcd9f8f1db..75bc08081fce9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3059,6 +3059,7 @@ #define MCURSOR_MODE_64_ARGB_AX (0x20 | MCURSOR_MODE_64_32B_AX) #define _CURABASE 0x70084 #define _CURAPOS 0x70088 +#define _CURAPOS_ERLY_TPT 0x7008c #define CURSOR_POS_Y_SIGN REG_BIT(31) #define CURSOR_POS_Y_MASK REG_GENMASK(30, 16) #define CURSOR_POS_Y(y) REG_FIELD_PREP(CURSOR_POS_Y_MASK, (y)) @@ -3087,6 +3088,7 @@ #define CURCNTR(pipe) _MMIO_CURSOR2(pipe, _CURACNTR) #define CURBASE(pipe) _MMIO_CURSOR2(pipe, _CURABASE) #define CURPOS(pipe) _MMIO_CURSOR2(pipe, _CURAPOS) +#define CURPOS_ERLY_TPT(pipe) _MMIO_CURSOR2(pipe, _CURAPOS_ERLY_TPT) #define CURSIZE(pipe) _MMIO_CURSOR2(pipe, _CURASIZE) #define CUR_FBC_CTL(pipe) _MMIO_CURSOR2(pipe, _CUR_FBC_CTL_A) #define CUR_CHICKEN(pipe) _MMIO_CURSOR2(pipe, _CUR_CHICKEN_A) -- GitLab From 3291bbb93e160e8b9b74ed0116738570f8744fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:50:02 +0200 Subject: [PATCH 0223/1420] drm/i915/psr: Configure PIPE_SRCSZ_ERLY_TPT for psr2 early transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a new register used to configure selective update area size for early transport. Configure PIPE_SRCSZ_ERLY_TPT using calculated selective update area carried in crtc_state->su_area. Bspec: 68927 Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-6-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 10 ++++++++++ drivers/gpu/drm/i915/display/intel_psr_regs.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4a1d0613dfe7b..e161d9544f2af 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -104,6 +104,7 @@ #include "intel_pmdemand.h" #include "intel_pps.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "intel_sdvo.h" #include "intel_snps_phy.h" #include "intel_tc.h" @@ -2706,6 +2707,15 @@ static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) */ intel_de_write(dev_priv, PIPESRC(pipe), PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1)); + + if (!crtc_state->enable_psr2_su_region_et) + return; + + width = drm_rect_width(&crtc_state->psr2_su_area); + height = drm_rect_height(&crtc_state->psr2_su_area); + + intel_de_write(dev_priv, PIPE_SRCSZ_ERLY_TPT(pipe), + PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1)); } static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index efe4306b37e0c..ceefcc70e8f98 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -245,6 +245,11 @@ #define ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME REG_BIT(14) #define ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME REG_BIT(13) +/* PSR2 Early transport */ +#define _PIPE_SRCSZ_ERLY_TPT_A 0x70074 + +#define PIPE_SRCSZ_ERLY_TPT(trans) _MMIO_TRANS2(trans, _PIPE_SRCSZ_ERLY_TPT_A) + #define _SEL_FETCH_PLANE_BASE_1_A 0x70890 #define _SEL_FETCH_PLANE_BASE_2_A 0x708B0 #define _SEL_FETCH_PLANE_BASE_3_A 0x708D0 -- GitLab From 467e4e061c44ff79cdd2c6b5cbc42842caf189f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:50:03 +0200 Subject: [PATCH 0224/1420] drm/i915/psr: Enable psr2 early transport as possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check source and sink support for psr2 early transport and enable it if not disabled by debug flag. Bspec: 68934 Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-7-jouni.hogander@intel.com --- .../drm/i915/display/intel_display_types.h | 16 ++++++++------ drivers/gpu/drm/i915/display/intel_psr.c | 22 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_psr_regs.h | 1 + 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 13a893f4130ac..ae2e8cff9d691 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1213,6 +1213,7 @@ struct intel_crtc_state { bool has_psr; bool has_psr2; bool enable_psr2_sel_fetch; + bool enable_psr2_su_region_et; bool req_psr2_sdp_prior_scanline; bool has_panel_replay; bool wm_level_disabled; @@ -1683,13 +1684,14 @@ struct intel_psr { /* Mutex for PSR state of the transcoder */ struct mutex lock; -#define I915_PSR_DEBUG_MODE_MASK 0x0f -#define I915_PSR_DEBUG_DEFAULT 0x00 -#define I915_PSR_DEBUG_DISABLE 0x01 -#define I915_PSR_DEBUG_ENABLE 0x02 -#define I915_PSR_DEBUG_FORCE_PSR1 0x03 -#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4 -#define I915_PSR_DEBUG_IRQ 0x10 +#define I915_PSR_DEBUG_MODE_MASK 0x0f +#define I915_PSR_DEBUG_DEFAULT 0x00 +#define I915_PSR_DEBUG_DISABLE 0x01 +#define I915_PSR_DEBUG_ENABLE 0x02 +#define I915_PSR_DEBUG_FORCE_PSR1 0x03 +#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4 +#define I915_PSR_DEBUG_IRQ 0x10 +#define I915_PSR_DEBUG_SU_REGION_ET_DISABLE 0x20 u32 debug; bool sink_support; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index fa0af5a6816b1..682ceae00710e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -528,7 +528,7 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp) intel_dp_get_sink_sync_latency(intel_dp); if (DISPLAY_VER(i915) >= 9 && - intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { + intel_dp->psr_dpcd[0] >= DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { bool y_req = intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; bool alpm = intel_dp_get_alpm_status(intel_dp); @@ -601,6 +601,18 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) aux_ctl); } +static bool psr2_su_region_et_valid(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + if (DISPLAY_VER(i915) >= 20 && + intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED && + !(intel_dp->psr.debug & I915_PSR_DEBUG_SU_REGION_ET_DISABLE)) + return true; + + return false; +} + static void intel_psr_enable_sink(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -616,6 +628,8 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE); dpcd_val |= DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS; + if (psr2_su_region_et_valid(intel_dp)) + dpcd_val |= DP_PSR_ENABLE_SU_REGION_ET; } else { if (intel_dp->psr.link_standby) dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; @@ -866,6 +880,9 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(cpu_transcoder), 0); } + if (psr2_su_region_et_valid(intel_dp)) + val |= LNL_EDP_PSR2_SU_REGION_ET_ENABLE; + /* * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. @@ -1028,6 +1045,9 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, return false; } + if (psr2_su_region_et_valid(intel_dp)) + crtc_state->enable_psr2_su_region_et = true; + return crtc_state->enable_psr2_sel_fetch = true; } diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index ceefcc70e8f98..bc252f38239e0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -159,6 +159,7 @@ #define TGL_EDP_PSR2_BLOCK_COUNT_MASK REG_BIT(28) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_2 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 0) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_3 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 1) +#define LNL_EDP_PSR2_SU_REGION_ET_ENABLE REG_BIT(27) #define EDP_Y_COORDINATE_ENABLE REG_BIT(25) /* display 10, 11 and 12 */ #define EDP_PSR2_SU_SDP_SCANLINE REG_BIT(25) /* display 13+ */ #define EDP_MAX_SU_DISABLE_TIME_MASK REG_GENMASK(24, 20) -- GitLab From f3c2031db7dfdf470a2d9bf3bd1efa6edfa72d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 18 Dec 2023 19:50:04 +0200 Subject: [PATCH 0225/1420] drm/i915/psr: Disable early transport by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Early transport validation is currently incomplete. Due to this disable the feature by default. Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231218175004.52875-8-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 682ceae00710e..dff21a5edeb7f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2842,6 +2842,9 @@ void intel_psr_init(struct intel_dp *intel_dp) else intel_dp->psr.source_support = true; + /* Disable early transport for now */ + intel_dp->psr.debug |= I915_PSR_DEBUG_SU_REGION_ET_DISABLE; + /* Set link_standby x link_off defaults */ if (DISPLAY_VER(dev_priv) < 12) /* For new platforms up to TGL let's respect VBT back again */ -- GitLab From 29f424eb8702b686cb6f07ddd659c6312e0c796d Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 13 Dec 2023 17:47:04 +0000 Subject: [PATCH 0226/1420] drm/xe/exec: move fence reservation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently assume that we can upfront know exactly how many fence slots we will need at the start of the exec, however the TTM bo_validate can itself consume numerous fence slots, and due to how the dma_resv_reserve_fences() works it only ensures that at least that many fence slots are available. With this it is quite possible that TTM steals some of the fence slots and then when it comes time to do the vma binding and final exec stage we are lacking enough fence slots, leading to some nasty BUG_ON(). A simple fix is to reserve our own fences later, after the validate stage. References: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/698 Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Tested-by: José Roberto de Souza Reviewed-by: José Roberto de Souza --- drivers/gpu/drm/xe/xe_exec.c | 40 ++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index ba92e5619da39..63e82e5285bc6 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -96,7 +96,44 @@ static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec) { - return drm_gpuvm_validate(vm_exec->vm, &vm_exec->exec); + struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm); + struct drm_gem_object *obj; + unsigned long index; + int num_fences; + int ret; + + ret = drm_gpuvm_validate(vm_exec->vm, &vm_exec->exec); + if (ret) + return ret; + + /* + * 1 fence slot for the final submit, and one more for every per-tile + * bind. Note that there are potentially many vma per object/dma-resv, + * however the fence slot will just be re-used, since they are largely + * the same timeline and the seqno should be in order. + */ + num_fences = 1 + vm->xe->info.tile_count; + + /* + * We don't know upfront exactly how many fence slots we will need at + * the start of the exec, since the TTM bo_validate above can consume + * numerous fence slots. Also due to how the dma_resv_reserve_fences() + * works it only ensures that at least that many fence slots are + * available i.e if there are already 10 slots available and we reserve + * two more, it can just noop without reserving anything. With this it + * is quite possible that TTM steals some of the fence slots and then + * when it comes time to do the vma binding and final exec stage we are + * lacking enough fence slots, leading to some nasty BUG_ON() when + * adding the fences. Hence just add our own fences here, after the + * validate stage. + */ + drm_exec_for_each_locked_object(&vm_exec->exec, index, obj) { + ret = dma_resv_reserve_fences(obj->resv, num_fences); + if (ret) + return ret; + } + + return 0; } int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -189,7 +226,6 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) } vm_exec.vm = &vm->gpuvm; - vm_exec.num_fences = 1 + vm->xe->info.tile_count; vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT; if (xe_vm_in_lr_mode(vm)) { drm_exec_init(exec, vm_exec.flags); -- GitLab From f4e8ab468fc6cfaf718bb8610940d57a5e2309ba Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 13 Dec 2023 17:47:05 +0000 Subject: [PATCH 0227/1420] drm/xe/exec: reserve fence slot for CPU bind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks possible to switch from CPU binding to GPU binding mid exec, and if that happens for the same dma-resv we might use two fence slots, once for the dummy fence, and another for the actual GPU bind. References: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/698 Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Reviewed-by: José Roberto de Souza --- drivers/gpu/drm/xe/xe_exec.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index 63e82e5285bc6..0c78a377f4532 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -107,12 +107,14 @@ static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec) return ret; /* - * 1 fence slot for the final submit, and one more for every per-tile - * bind. Note that there are potentially many vma per object/dma-resv, - * however the fence slot will just be re-used, since they are largely - * the same timeline and the seqno should be in order. + * 1 fence slot for the final submit, and 1 more for every per-tile for + * GPU bind and 1 extra for CPU bind. Note that there are potentially + * many vma per object/dma-resv, however the fence slot will just be + * re-used, since they are largely the same timeline and the seqno + * should be in order. In the case of CPU bind there is dummy fence used + * for all CPU binds, so no need to have a per-tile slot for that. */ - num_fences = 1 + vm->xe->info.tile_count; + num_fences = 1 + 1 + vm->xe->info.tile_count; /* * We don't know upfront exactly how many fence slots we will need at -- GitLab From 97d0047cbb17318431eaf37dfe1a6855539340f9 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 4 Jan 2024 00:00:39 -0800 Subject: [PATCH 0228/1420] drm/xe: Fix exec IOCTL long running exec queue ring full condition The intent is to return -EWOULDBLOCK to the user if a long running exec queue is full during the exec IOCTL. -EWOULDBLOCK aliases to -EAGAIN which results in the exec IOCTL doing a retry loop. Fix this by ensuring the retry loop is broken when returning -EWOULDBLOCK. Fixes: 8ae8a2e8dd21 ("drm/xe: Long running job update") Reported-by: Sai Gowtham Ch Signed-off-by: Matthew Brost Reviewed-by: Brian Welty --- drivers/gpu/drm/xe/xe_exec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index 0c78a377f4532..9db1867878a42 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -154,7 +154,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct xe_sched_job *job; struct dma_fence *rebind_fence; struct xe_vm *vm; - bool write_locked; + bool write_locked, skip_retry = false; ktime_t end = 0; int err = 0; @@ -265,7 +265,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) } if (xe_exec_queue_is_lr(q) && xe_exec_queue_ring_full(q)) { - err = -EWOULDBLOCK; + err = -EWOULDBLOCK; /* Aliased to -EAGAIN */ + skip_retry = true; goto err_exec; } @@ -375,7 +376,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) up_write(&vm->lock); else up_read(&vm->lock); - if (err == -EAGAIN) + if (err == -EAGAIN && !skip_retry) goto retry; err_syncs: for (i = 0; i < num_syncs; i++) -- GitLab From 5030e16140b655ba00217d47680e697480ac3587 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 2 Jan 2024 12:35:38 -0800 Subject: [PATCH 0229/1420] drm/xe/guc: Only take actions in CT irq handler if CTs are enabled Protect entire IRQ handler by CT being enabled rather than just G2H handler. v2: Return on not enabled in CT irq handler (Michal) Suggested-by: Michal Wajdeczko Signed-off-by: Matthew Brost Reviewed-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_ct.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h index f15f8a4857e07..9ecb67db8ec40 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.h +++ b/drivers/gpu/drm/xe/xe_guc_ct.h @@ -24,9 +24,11 @@ void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool atomic); static inline void xe_guc_ct_irq_handler(struct xe_guc_ct *ct) { + if (!ct->enabled) + return; + wake_up_all(&ct->wq); - if (ct->enabled) - queue_work(system_unbound_wq, &ct->g2h_worker); + queue_work(system_unbound_wq, &ct->g2h_worker); xe_guc_ct_fast_path(ct); } -- GitLab From 9d0c1c5618be02c5acda7e6bbb728007b0632984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 22 Dec 2023 18:59:04 +0100 Subject: [PATCH 0230/1420] drm/xe/vm: Fix an error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If using the VM_BIND_OP_UNMAP_ALL without any bound vmas for the vm, we will end up dereferencing an uninitialized variable and leak a bo lock. Fix this. v2: - Updated commit message (Lucas De Marchi) Reported-by: Dafna Hirschfeld Closes: https://lore.kernel.org/intel-xe/jrwua7ckbiozfcaodx4gg2h4taiuxs53j5zlpf3qzvyhyiyl2d@pbs3plurokrj/ Suggested-by: Dafna Hirschfeld Fixes: b06d47be7c83 ("drm/xe: Port Xe to GPUVA") Signed-off-by: Thomas Hellström Acked-by: Lucas De Marchi Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20231222175904.16732-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_vm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 1ca917b8315c2..127842656a239 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -2063,9 +2063,11 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_bo *bo, if (err) return ERR_PTR(err); - vm_bo = drm_gpuvm_bo_find(&vm->gpuvm, obj); - if (!vm_bo) - break; + vm_bo = drm_gpuvm_bo_obtain(&vm->gpuvm, obj); + if (IS_ERR(vm_bo)) { + xe_bo_unlock(bo); + return ERR_CAST(vm_bo); + } ops = drm_gpuvm_bo_unmap_ops_create(vm_bo); drm_gpuvm_bo_put(vm_bo); -- GitLab From 9d03bf30e78673d827484bbc17a6fd8f5e43a039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Tue, 9 Jan 2024 12:24:02 +0100 Subject: [PATCH 0231/1420] drm/xe: Use __iomem for the regs pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regs pointer points to IO memory. Annotate it properly and fix the corresponding sparse warning. Fixes: a4e2f3a299ea ("drm/xe: refactor xe_mmio_probe_tiles to support MMIO extension") Cc: Koby Elbaz Cc: Ofir Bitton Cc: Moti Haimovski Cc: Rodrigo Vivi Signed-off-by: Thomas Hellström Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20240109112405.108136-2-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index f660cfb79f504..c8c5d74b6e904 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -303,7 +303,7 @@ void xe_mmio_probe_tiles(struct xe_device *xe) u8 id, tile_count = xe->info.tile_count; struct xe_gt *gt = xe_root_mmio_gt(xe); struct xe_tile *tile; - void *regs; + void __iomem *regs; u32 mtcfg; if (tile_count == 1) -- GitLab From 20855b62a30538361e587cfc7c5245f07d4f826a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Tue, 9 Jan 2024 12:24:03 +0100 Subject: [PATCH 0232/1420] drm/xe: Annotate xe_mem_region::mapping with __iomem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer points to IO memory, but the __iomem annotation was incorrectly placed. Annotate it correctly, update its usage accordingly and fix the corresponding sparse error. Fixes: 0887a2e7ab62 ("drm/xe: Make xe_mem_region struct") Cc: Oak Zeng Cc: Michael J. Ruhl Cc: Matthew Brost Cc: Rodrigo Vivi Signed-off-by: Thomas Hellström Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20240109112405.108136-3-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_bo.c | 4 ++-- drivers/gpu/drm/xe/xe_device_types.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 2e4d2157179c8..338f9688a2c93 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -442,7 +442,7 @@ static int xe_ttm_io_mem_reserve(struct ttm_device *bdev, if (vram->mapping && mem->placement & TTM_PL_FLAG_CONTIGUOUS) - mem->bus.addr = (u8 *)vram->mapping + + mem->bus.addr = (u8 __force *)vram->mapping + mem->bus.offset; mem->bus.offset += vram->io_start; @@ -748,7 +748,7 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, /* Create a new VMAP once kernel BO back in VRAM */ if (!ret && resource_is_vram(new_mem)) { struct xe_mem_region *vram = res_to_mem_region(new_mem); - void *new_addr = vram->mapping + + void __iomem *new_addr = vram->mapping + (new_mem->start << PAGE_SHIFT); if (XE_WARN_ON(new_mem->start == XE_BO_INVALID_OFFSET)) { diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 8404685b24182..3c2bcd597d2a5 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -98,7 +98,7 @@ struct xe_mem_region { */ resource_size_t actual_physical_size; /** @mapping: pointer to VRAM mappable space */ - void *__iomem mapping; + void __iomem *mapping; }; /** -- GitLab From 9d612ee52c6096bc70d43f54921ba2831ffbf1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Tue, 9 Jan 2024 12:24:04 +0100 Subject: [PATCH 0233/1420] drm/xe: Annotate multiple mmio pointers with __iomem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a couple of pointers pointing to MMIO space. Annotate them with __iomem and fix the corresponding sparse warnings. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Fixes: 3b0d4a557996 ("drm/xe: Move register MMIO into xe_tile") Fixes: 399a13323f0d ("drm/xe: add 28-bit address support in struct xe_reg") Cc: Rodrigo Vivi Cc: Matthew Brost Cc: Lucas De Marchi Cc: Matt Roper Cc: Koby Elbaz Cc: Ofir Bitton Cc: Moti Haimovski Signed-off-by: Thomas Hellström Reviewed-by: Lucas De Marchi Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20240109112405.108136-4-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_device_types.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 3c2bcd597d2a5..7eda86bd4c2a4 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -147,7 +147,7 @@ struct xe_tile { size_t size; /** @regs: pointer to tile's MMIO space (starting with registers) */ - void *regs; + void __iomem *regs; } mmio; /** @@ -160,7 +160,7 @@ struct xe_tile { size_t size; /** @regs: pointer to tile's additional MMIO-extension space */ - void *regs; + void __iomem *regs; } mmio_ext; /** @mem: memory management info for tile */ @@ -306,7 +306,7 @@ struct xe_device { /** @size: size of MMIO space for device */ size_t size; /** @regs: pointer to MMIO space for device */ - void *regs; + void __iomem *regs; } mmio; /** @mem: memory info for device */ -- GitLab From dcddb6f0b06d454c9a3b2b240a43f0e7310c7f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Tue, 9 Jan 2024 12:24:05 +0100 Subject: [PATCH 0234/1420] drm/xe: Annotate xe_ttm_stolen_mgr::mapping with __iomem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer points to IO memory, but the __iomem annotation was incorrectly placed. Annotate it correctly, update its usage accordingly and fix the corresponding sparse error. Fixes: d8b52a02cb40 ("drm/xe: Implement stolen memory.") Cc: Maarten Lankhorst Cc: Matthew Brost Cc: Rodrigo Vivi Signed-off-by: Thomas Hellström Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20240109112405.108136-5-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index d2b00d0bf1e20..e5d7d5e2bec12 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c @@ -31,7 +31,7 @@ struct xe_ttm_stolen_mgr { /* GPU base offset */ resource_size_t stolen_base; - void *__iomem mapping; + void __iomem *mapping; }; static inline struct xe_ttm_stolen_mgr * @@ -275,7 +275,7 @@ static int __xe_ttm_stolen_io_mem_reserve_bar2(struct xe_device *xe, drm_WARN_ON(&xe->drm, !(mem->placement & TTM_PL_FLAG_CONTIGUOUS)); if (mem->placement & TTM_PL_FLAG_CONTIGUOUS && mgr->mapping) - mem->bus.addr = (u8 *)mgr->mapping + mem->bus.offset; + mem->bus.addr = (u8 __force *)mgr->mapping + mem->bus.offset; mem->bus.offset += mgr->io_base; mem->bus.is_iomem = true; -- GitLab From ca077ff8cac5af8a5a3c476983a6dd54aa3511b7 Mon Sep 17 00:00:00 2001 From: xiazhengqiao Date: Thu, 21 Dec 2023 17:30:57 +0800 Subject: [PATCH 0235/1420] drm/bridge: Fixed a DP link training bug To have better compatibility for DP sink, there is a retry mechanism for the link training process to switch between different training process. The original driver code doesn't reset the retry counter when training state is pass. If the system triggers link training over 3 times, there will be a chance to causes the driver to use the wrong training method and return a training fail result. To Fix this, we reset the retry counter when training state is pass each time. Signed-off-by: Allen Chen Signed-off-by: xiazhengqiao Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231221093057.7073-1-xiazhengqiao@huaqin.corp-partner.google.com --- drivers/gpu/drm/bridge/ite-it6505.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 2f300f5ca051c..b589136ca6da9 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2240,11 +2240,13 @@ static void it6505_link_training_work(struct work_struct *work) ret = it6505_link_start_auto_train(it6505); DRM_DEV_DEBUG_DRIVER(dev, "auto train %s, auto_train_retry: %d", ret ? "pass" : "failed", it6505->auto_train_retry); - it6505->auto_train_retry--; if (ret) { + it6505->auto_train_retry = AUTO_TRAIN_RETRY; it6505_link_train_ok(it6505); return; + } else { + it6505->auto_train_retry--; } it6505_dump(it6505); -- GitLab From 5e83c060e95bea2cf76d01fa554cd31a1727e19a Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 27 Dec 2023 20:55:57 -0800 Subject: [PATCH 0236/1420] drm/i915/guc: Flush context destruction worker at suspend When suspending, flush the context-guc-id deregistration worker at the final stages of intel_gt_suspend_late when we finally call gt_sanitize that eventually leads down to __uc_sanitize so that the deregistration worker doesn't fire off later as we reset the GuC microcontroller. Signed-off-by: Alan Previn Reviewed-by: Rodrigo Vivi Tested-by: Mousumi Jana Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231228045558.536585-2-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 5 +++++ drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h | 2 ++ drivers/gpu/drm/i915/gt/uc/intel_uc.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index a259f1118c5ab..9c64ae0766cc0 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1613,6 +1613,11 @@ static void guc_flush_submissions(struct intel_guc *guc) spin_unlock_irqrestore(&sched_engine->lock, flags); } +void intel_guc_submission_flush_work(struct intel_guc *guc) +{ + flush_work(&guc->submission_state.destroyed_worker); +} + static void guc_flush_destroyed_contexts(struct intel_guc *guc); void intel_guc_submission_reset_prepare(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h index c57b29cdb1a64..b6df75622d3b9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h @@ -38,6 +38,8 @@ int intel_guc_wait_for_pending_msg(struct intel_guc *guc, bool interruptible, long timeout); +void intel_guc_submission_flush_work(struct intel_guc *guc); + static inline bool intel_guc_submission_is_supported(struct intel_guc *guc) { return guc->submission_supported; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index 3872d309ed31f..b8b09b1bee3ea 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -690,6 +690,8 @@ void intel_uc_suspend(struct intel_uc *uc) return; } + intel_guc_submission_flush_work(guc); + with_intel_runtime_pm(&uc_to_gt(uc)->i915->runtime_pm, wakeref) { err = intel_guc_suspend(guc); if (err) -- GitLab From 2f2cc53b5fe7022f3ae602eb24573d52f8740959 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Fri, 29 Dec 2023 13:51:43 -0800 Subject: [PATCH 0237/1420] drm/i915/guc: Close deregister-context race against CT-loss If we are at the end of suspend or very early in resume its possible an async fence signal (via rcu_call) is triggered to free_engines which could lead us to the execution of the context destruction worker (after a prior worker flush). Thus, when suspending, insert rcu_barriers at the start of i915_gem_suspend (part of driver's suspend prepare) and again in i915_gem_suspend_late so that all such cases have completed and context destruction list isn't missing anything. In destroyed_worker_func, close the race against CT-loss by checking that CT is enabled before calling into deregister_destroyed_contexts. Based on testing, guc_lrc_desc_unpin may still race and fail as we traverse the GuC's context-destroy list because the CT could be disabled right before calling GuC's CT send function. We've witnessed this race condition once every ~6000-8000 suspend-resume cycles while ensuring workloads that render something onscreen is continuously started just before we suspend (and the workload is small enough to complete and trigger the queued engine/context free-up either very late in suspend or very early in resume). In such a case, we need to unroll the entire process because guc-lrc-unpin takes a gt wakeref which only gets released in the G2H IRQ reply that never comes through in this corner case. Without the unroll, the taken wakeref is leaked and will cascade into a kernel hang later at the tail end of suspend in this function: intel_wakeref_wait_for_idle(>->wakeref) (called by) - intel_gt_pm_wait_for_idle (called by) - wait_for_suspend Thus, do an unroll in guc_lrc_desc_unpin and deregister_destroyed_- contexts if guc_lrc_desc_unpin fails due to CT send falure. When unrolling, keep the context in the GuC's destroy-list so it can get picked up on the next destroy worker invocation (if suspend aborted) or get fully purged as part of a GuC sanitization (end of suspend) or a reset flow. Signed-off-by: Alan Previn Signed-off-by: Anshuman Gupta Tested-by: Mousumi Jana Acked-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231229215143.581619-1-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_pm.c | 10 +++ .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 73 +++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 0d812f4d787d7..3b27218aabe20 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -28,6 +28,13 @@ void i915_gem_suspend(struct drm_i915_private *i915) GEM_TRACE("%s\n", dev_name(i915->drm.dev)); intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, 0); + /* + * On rare occasions, we've observed the fence completion triggers + * free_engines asynchronously via rcu_call. Ensure those are done. + * This path is only called on suspend, so it's an acceptable cost. + */ + rcu_barrier(); + flush_workqueue(i915->wq); /* @@ -160,6 +167,9 @@ void i915_gem_suspend_late(struct drm_i915_private *i915) * machine in an unusable condition. */ + /* Like i915_gem_suspend, flush tasks staged from fence triggers */ + rcu_barrier(); + for_each_gt(gt, i915, i) intel_gt_suspend_late(gt); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 9c64ae0766cc0..cae637fc3eadf 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -236,6 +236,13 @@ set_context_destroyed(struct intel_context *ce) ce->guc_state.sched_state |= SCHED_STATE_DESTROYED; } +static inline void +clr_context_destroyed(struct intel_context *ce) +{ + lockdep_assert_held(&ce->guc_state.lock); + ce->guc_state.sched_state &= ~SCHED_STATE_DESTROYED; +} + static inline bool context_pending_disable(struct intel_context *ce) { return ce->guc_state.sched_state & SCHED_STATE_PENDING_DISABLE; @@ -613,6 +620,8 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc, u32 g2h_len_dw, bool loop) { + int ret; + /* * We always loop when a send requires a reply (i.e. g2h_len_dw > 0), * so we don't handle the case where we don't get a reply because we @@ -623,7 +632,11 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc, if (g2h_len_dw) atomic_inc(&guc->outstanding_submission_g2h); - return intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); + ret = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); + if (ret) + atomic_dec(&guc->outstanding_submission_g2h); + + return ret; } int intel_guc_wait_for_pending_msg(struct intel_guc *guc, @@ -3288,12 +3301,13 @@ static void guc_context_close(struct intel_context *ce) spin_unlock_irqrestore(&ce->guc_state.lock, flags); } -static inline void guc_lrc_desc_unpin(struct intel_context *ce) +static inline int guc_lrc_desc_unpin(struct intel_context *ce) { struct intel_guc *guc = ce_to_guc(ce); struct intel_gt *gt = guc_to_gt(guc); unsigned long flags; bool disabled; + int ret; GEM_BUG_ON(!intel_gt_pm_is_awake(gt)); GEM_BUG_ON(!ctx_id_mapped(guc, ce->guc_id.id)); @@ -3304,18 +3318,41 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce) spin_lock_irqsave(&ce->guc_state.lock, flags); disabled = submission_disabled(guc); if (likely(!disabled)) { + /* + * Take a gt-pm ref and change context state to be destroyed. + * NOTE: a G2H IRQ that comes after will put this gt-pm ref back + */ __intel_gt_pm_get(gt); set_context_destroyed(ce); clr_context_registered(ce); } spin_unlock_irqrestore(&ce->guc_state.lock, flags); + if (unlikely(disabled)) { release_guc_id(guc, ce); __guc_context_destroy(ce); - return; + return 0; } - deregister_context(ce, ce->guc_id.id); + /* + * GuC is active, lets destroy this context, but at this point we can still be racing + * with suspend, so we undo everything if the H2G fails in deregister_context so + * that GuC reset will find this context during clean up. + */ + ret = deregister_context(ce, ce->guc_id.id); + if (ret) { + spin_lock(&ce->guc_state.lock); + set_context_registered(ce); + clr_context_destroyed(ce); + spin_unlock(&ce->guc_state.lock); + /* + * As gt-pm is awake at function entry, intel_wakeref_put_async merely decrements + * the wakeref immediately but per function spec usage call this after unlock. + */ + intel_wakeref_put_async(>->wakeref); + } + + return ret; } static void __guc_context_destroy(struct intel_context *ce) @@ -3383,7 +3420,22 @@ static void deregister_destroyed_contexts(struct intel_guc *guc) if (!ce) break; - guc_lrc_desc_unpin(ce); + if (guc_lrc_desc_unpin(ce)) { + /* + * This means GuC's CT link severed mid-way which could happen + * in suspend-resume corner cases. In this case, put the + * context back into the destroyed_contexts list which will + * get picked up on the next context deregistration event or + * purged in a GuC sanitization event (reset/unload/wedged/...). + */ + spin_lock_irqsave(&guc->submission_state.lock, flags); + list_add_tail(&ce->destroyed_link, + &guc->submission_state.destroyed_contexts); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); + /* Bail now since the list might never be emptied if h2gs fail */ + break; + } + } } @@ -3394,6 +3446,17 @@ static void destroyed_worker_func(struct work_struct *w) struct intel_gt *gt = guc_to_gt(guc); intel_wakeref_t wakeref; + /* + * In rare cases we can get here via async context-free fence-signals that + * come very late in suspend flow or very early in resume flows. In these + * cases, GuC won't be ready but just skipping it here is fine as these + * pending-destroy-contexts get destroyed totally at GuC reset time at the + * end of suspend.. OR.. this worker can be picked up later on the next + * context destruction trigger after resume-completes + */ + if (!intel_guc_is_ready(guc)) + return; + with_intel_gt_pm(gt, wakeref) deregister_destroyed_contexts(guc); } -- GitLab From 632ca3c92f3840d91ba7ddda0271f84813036a11 Mon Sep 17 00:00:00 2001 From: Chen Haonan Date: Tue, 9 Jan 2024 14:24:11 +0800 Subject: [PATCH 0238/1420] drm/nouveau/disp: switch to use kmemdup() helper Use kmemdup() helper instead of open-coding to simplify the code. Signed-off-by: Chen Haonan Reviewed-by: Yang Guang Reviewed-by: Kees Cook Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/202401091424115185126@zte.com.cn --- drivers/gpu/drm/nouveau/nvif/outp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 5d3190c05250a..6daeb7f0b09b6 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -452,13 +452,12 @@ nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid) if (ret) goto done; - *pedid = kmalloc(args->size, GFP_KERNEL); + *pedid = kmemdup(args->data, args->size, GFP_KERNEL); if (!*pedid) { ret = -ENOMEM; goto done; } - memcpy(*pedid, args->data, args->size); ret = args->size; done: kfree(args); -- GitLab From 0e00a8814eec16057e783170456442adde80c0b4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 19 Dec 2023 11:59:57 -0800 Subject: [PATCH 0239/1420] drm/i915/guc: Avoid circular locking issue on busyness flush Avoid the following lockdep complaint: <4> [298.856498] ====================================================== <4> [298.856500] WARNING: possible circular locking dependency detected <4> [298.856503] 6.7.0-rc5-CI_DRM_14017-g58ac4ffc75b6+ #1 Tainted: G N <4> [298.856505] ------------------------------------------------------ <4> [298.856507] kworker/4:1H/190 is trying to acquire lock: <4> [298.856509] ffff8881103e9978 (>->reset.backoff_srcu){++++}-{0:0}, at: _intel_gt_reset_lock+0x35/0x380 [i915] <4> [298.856661] but task is already holding lock: <4> [298.856663] ffffc900013f7e58 ((work_completion)(&(&guc->timestamp.work)->work)){+.+.}-{0:0}, at: process_scheduled_works+0x264/0x530 <4> [298.856671] which lock already depends on the new lock. The complaint is not actually valid. The busyness worker thread does indeed hold the worker lock and then attempt to acquire the reset lock (which may have happened in reverse order elsewhere). However, it does so with a trylock that exits if the reset lock is not available (specifically to prevent this and other similar deadlocks). Unfortunately, lockdep does not understand the trylock semantics (the lock is an i915 specific custom implementation for resets). Not doing a synchronous flush of the worker thread when a reset is in progress resolves the lockdep splat by never even attempting to grab the lock in this particular scenario. There are situatons where a synchronous cancel is required, however. So, always do the synchronous cancel if not in reset. And add an extra synchronous cancel to the end of the reset flow to account for when a reset is occurring at driver shutdown and the cancel is no longer synchronous but could lead to unallocated memory accesses if the worker is not stopped. Signed-off-by: Zhanjun Dong Signed-off-by: John Harrison Cc: Andi Shyti Cc: Daniel Vetter Reviewed-by: Andi Shyti Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231219195957.212600-1-John.C.Harrison@Intel.com --- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 48 ++++++++++++++++++- drivers/gpu/drm/i915/gt/uc/intel_uc.c | 2 +- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index cae637fc3eadf..f3dcae4b9d455 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1375,7 +1375,45 @@ static void guc_enable_busyness_worker(struct intel_guc *guc) static void guc_cancel_busyness_worker(struct intel_guc *guc) { - cancel_delayed_work_sync(&guc->timestamp.work); + /* + * There are many different call stacks that can get here. Some of them + * hold the reset mutex. The busyness worker also attempts to acquire the + * reset mutex. Synchronously flushing a worker thread requires acquiring + * the worker mutex. Lockdep sees this as a conflict. It thinks that the + * flush can deadlock because it holds the worker mutex while waiting for + * the reset mutex, but another thread is holding the reset mutex and might + * attempt to use other worker functions. + * + * In practice, this scenario does not exist because the busyness worker + * does not block waiting for the reset mutex. It does a try-lock on it and + * immediately exits if the lock is already held. Unfortunately, the mutex + * in question (I915_RESET_BACKOFF) is an i915 implementation which has lockdep + * annotation but not to the extent of explaining the 'might lock' is also a + * 'does not need to lock'. So one option would be to add more complex lockdep + * annotations to ignore the issue (if at all possible). A simpler option is to + * just not flush synchronously when a rest in progress. Given that the worker + * will just early exit and re-schedule itself anyway, there is no advantage + * to running it immediately. + * + * If a reset is not in progress, then the synchronous flush may be required. + * As noted many call stacks lead here, some during suspend and driver unload + * which do require a synchronous flush to make sure the worker is stopped + * before memory is freed. + * + * Trying to pass a 'need_sync' or 'in_reset' flag all the way down through + * every possible call stack is unfeasible. It would be too intrusive to many + * areas that really don't care about the GuC backend. However, there is the + * 'reset_in_progress' flag available, so just use that. + * + * And note that in the case of a reset occurring during driver unload + * (wedge_on_fini), skipping the cancel in _prepare (when the reset flag is set + * is fine because there is another cancel in _finish (when the reset flag is + * not). + */ + if (guc_to_gt(guc)->uc.reset_in_progress) + cancel_delayed_work(&guc->timestamp.work); + else + cancel_delayed_work_sync(&guc->timestamp.work); } static void __reset_guc_busyness_stats(struct intel_guc *guc) @@ -1966,8 +2004,16 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc) void intel_guc_submission_reset_finish(struct intel_guc *guc) { + /* + * Ensure the busyness worker gets cancelled even on a fatal wedge. + * Note that reset_prepare is not allowed to because it confuses lockdep. + */ + if (guc_submission_initialized(guc)) + guc_cancel_busyness_worker(guc); + /* Reset called during driver load or during wedge? */ if (unlikely(!guc_submission_initialized(guc) || + !intel_guc_is_fw_running(guc) || intel_gt_is_wedged(guc_to_gt(guc)))) { return; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index b8b09b1bee3ea..6dfe5d9456c69 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -640,7 +640,7 @@ void intel_uc_reset_finish(struct intel_uc *uc) uc->reset_in_progress = false; /* Firmware expected to be running when this function is called */ - if (intel_guc_is_fw_running(guc) && intel_uc_uses_guc_submission(uc)) + if (intel_uc_uses_guc_submission(uc)) intel_guc_submission_reset_finish(guc); } -- GitLab From 9fbedddfc90062e09426108335585487647067e3 Mon Sep 17 00:00:00 2001 From: Shekhar Chauhan Date: Tue, 9 Jan 2024 11:25:50 +0530 Subject: [PATCH 0240/1420] drm/xe/xe2_lpg: Add Wa_16018610683 Force max 128KB SLM during WMTP PASS1 Restore. BSpec: 70202 Signed-off-by: Shekhar Chauhan Reviewed-by: Matt Roper Link: https://lore.kernel.org/r/20240109055550.679289-1-shekhar.chauhan@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 3 +++ drivers/gpu/drm/xe/xe_wa.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 6dfad86aaea64..4017319c63000 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -345,6 +345,9 @@ #define ROW_CHICKEN3 XE_REG_MCR(0xe49c, XE_REG_OPTION_MASKED) #define DIS_FIX_EOT1_FLUSH REG_BIT(9) +#define TDL_TSL_CHICKEN XE_REG_MCR(0xe4c4, XE_REG_OPTION_MASKED) +#define SLM_WMTP_RESTORE REG_BIT(11) + #define ROW_CHICKEN XE_REG_MCR(0xe4f0, XE_REG_OPTION_MASKED) #define UGM_BACKUP_MODE REG_BIT(13) #define MDQ_ARBITRATION_MODE REG_BIT(12) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index b77d406e083e2..3299130ba10ae 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -455,7 +455,10 @@ static const struct xe_rtp_entry_sr engine_was[] = { PPHWSP_CSB_AND_TIMESTAMP_REPORT_DIS, XE_RTP_ACTION_FLAG(ENGINE_BASE))) }, - + { XE_RTP_NAME("16018610683"), + XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(TDL_TSL_CHICKEN, SLM_WMTP_RESTORE)) + }, {} }; -- GitLab From b16483f9f8120b530327879fa3ea576e897946da Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Fri, 5 Jan 2024 11:04:39 -0800 Subject: [PATCH 0241/1420] drm/xe: Fix guc_exec_queue_set_priority We need to set q->priority prior to calling guc_exec_queue_add_msg() as that will call init_policies() and sets the scheduling properties to those stored in the exec_queue. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_guc_submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 21ac68e3246f8..5de3ac47c4623 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1308,8 +1308,8 @@ static int guc_exec_queue_set_priority(struct xe_exec_queue *q, if (!msg) return -ENOMEM; - guc_exec_queue_add_msg(q, msg, SET_SCHED_PROPS); q->priority = priority; + guc_exec_queue_add_msg(q, msg, SET_SCHED_PROPS); return 0; } -- GitLab From a8004af338f6b3319476ecbed63ea49bf393fc1f Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Fri, 5 Jan 2024 11:04:40 -0800 Subject: [PATCH 0242/1420] drm/xe: Fix modifying exec_queue priority in xe_migrate_init After exec_queue has been created, we cannot simply modify q->priority. This needs to be done by the backend via q->ops. However in this case, it would be more efficient to simply pass a flag when creating the exec_queue and set the desired priority upfront during queue creation. To that end: new flag EXEC_QUEUE_FLAG_HIGH_PRIORITY is introduced. The priority field is moved to be with other scheduling properties and is now exec_queue.sched_props.priority. This is no longer set to initial value by the backend, but is now set within __xe_exec_queue_create(). Fixes: b4eecedc75c1 ("drm/xe: Fix potential deadlock handling page faults") Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_exec_queue.c | 5 +++++ drivers/gpu/drm/xe/xe_exec_queue_types.h | 6 ++++-- drivers/gpu/drm/xe/xe_guc_submit.c | 7 +++---- drivers/gpu/drm/xe/xe_migrate.c | 5 ++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 44fe8097b7cda..bcfc4127c7c59 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -67,6 +67,11 @@ static struct xe_exec_queue *__xe_exec_queue_create(struct xe_device *xe, q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; q->sched_props.preempt_timeout_us = hwe->eclass->sched_props.preempt_timeout_us; + if (q->flags & EXEC_QUEUE_FLAG_KERNEL && + q->flags & EXEC_QUEUE_FLAG_HIGH_PRIORITY) + q->sched_props.priority = XE_EXEC_QUEUE_PRIORITY_KERNEL; + else + q->sched_props.priority = XE_EXEC_QUEUE_PRIORITY_NORMAL; if (xe_exec_queue_is_parallel(q)) { q->parallel.composite_fence_ctx = dma_fence_context_alloc(1); diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 3d7e704ec3d9f..8d4b7feb8c306 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -52,8 +52,6 @@ struct xe_exec_queue { struct xe_vm *vm; /** @class: class of this exec queue */ enum xe_engine_class class; - /** @priority: priority of this exec queue */ - enum xe_exec_queue_priority priority; /** * @logical_mask: logical mask of where job submitted to exec queue can run */ @@ -84,6 +82,8 @@ struct xe_exec_queue { #define EXEC_QUEUE_FLAG_VM BIT(4) /* child of VM queue for multi-tile VM jobs */ #define EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD BIT(5) +/* kernel exec_queue only, set priority to highest level */ +#define EXEC_QUEUE_FLAG_HIGH_PRIORITY BIT(6) /** * @flags: flags for this exec queue, should statically setup aside from ban @@ -142,6 +142,8 @@ struct xe_exec_queue { u32 timeslice_us; /** @preempt_timeout_us: preemption timeout in micro-seconds */ u32 preempt_timeout_us; + /** @priority: priority of this exec queue */ + enum xe_exec_queue_priority priority; } sched_props; /** @compute: compute exec queue state */ diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 5de3ac47c4623..54ffcfcdd41f9 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -421,7 +421,7 @@ static void init_policies(struct xe_guc *guc, struct xe_exec_queue *q) { struct exec_queue_policy policy; struct xe_device *xe = guc_to_xe(guc); - enum xe_exec_queue_priority prio = q->priority; + enum xe_exec_queue_priority prio = q->sched_props.priority; u32 timeslice_us = q->sched_props.timeslice_us; u32 preempt_timeout_us = q->sched_props.preempt_timeout_us; @@ -1231,7 +1231,6 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) err = xe_sched_entity_init(&ge->entity, sched); if (err) goto err_sched; - q->priority = XE_EXEC_QUEUE_PRIORITY_NORMAL; if (xe_exec_queue_is_lr(q)) INIT_WORK(&q->guc->lr_tdr, xe_guc_exec_queue_lr_cleanup); @@ -1301,14 +1300,14 @@ static int guc_exec_queue_set_priority(struct xe_exec_queue *q, { struct xe_sched_msg *msg; - if (q->priority == priority || exec_queue_killed_or_banned(q)) + if (q->sched_props.priority == priority || exec_queue_killed_or_banned(q)) return 0; msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (!msg) return -ENOMEM; - q->priority = priority; + q->sched_props.priority = priority; guc_exec_queue_add_msg(q, msg, SET_SCHED_PROPS); return 0; diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index adf1dab5eba25..02fca8f9adc28 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -344,7 +344,8 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) m->q = xe_exec_queue_create(xe, vm, logical_mask, 1, hwe, EXEC_QUEUE_FLAG_KERNEL | - EXEC_QUEUE_FLAG_PERMANENT); + EXEC_QUEUE_FLAG_PERMANENT | + EXEC_QUEUE_FLAG_HIGH_PRIORITY); } else { m->q = xe_exec_queue_create_class(xe, primary_gt, vm, XE_ENGINE_CLASS_COPY, @@ -355,8 +356,6 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) xe_vm_close_and_put(vm); return ERR_CAST(m->q); } - if (xe->info.has_usm) - m->q->priority = XE_EXEC_QUEUE_PRIORITY_KERNEL; mutex_init(&m->job_mutex); -- GitLab From 4ae3aeab32d7f37cde4724524f5525703e5a9b54 Mon Sep 17 00:00:00 2001 From: Sujaritha Sundaresan Date: Tue, 9 Jan 2024 16:34:18 +0530 Subject: [PATCH 0243/1420] drm/xe: Add vram frequency sysfs attributes Add vram frequency sysfs attributes under the below hierarchy; /device/tile#/memory/freq0 |-max_freq |-min_freq v2: Drop "vram" from attribute names (Rodrigo) v3: Add documentation for new sysfs (Riana) Drop prefix from XEHP_PCODE_FREQUENCY_CONFIG (Riana) v4: Create sysfs under tile#/freq0 after removal of physical_memsize attrbute v5: Revert back to creating sysfs under tile#/memory/freq0 Remove definition of GT_FREQUENCY_MULTIPLIER (Rodrigo) v6: Rename attributes to max/min_freq (Anshuman) Fix review comments (Rodrigo) v7: Make documentation more verbose Move sysfs to separate file (Anshuman) v8: Fix platform specific conditions and add kernel doc (Anshuman) Fix typos and remove redundant headers (Riana) v9: Fix typo (Riana) Change function name to include "sysfs" (Lucas) Signed-off-by: Sujaritha Sundaresan Reviewed-by: Anshuman Gupta Link: https://lore.kernel.org/r/20240109110418.2065101-1-sujaritha.sundaresan@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_pcode_api.h | 7 ++ drivers/gpu/drm/xe/xe_tile_sysfs.c | 3 + drivers/gpu/drm/xe/xe_vram_freq.c | 129 +++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_vram_freq.h | 13 +++ 5 files changed, 153 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_vram_freq.c create mode 100644 drivers/gpu/drm/xe/xe_vram_freq.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 6952da8979ea7..f3495d0e701cc 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -139,6 +139,7 @@ xe-y += xe_bb.o \ xe_uc_debugfs.o \ xe_uc_fw.o \ xe_vm.o \ + xe_vram_freq.o \ xe_wait_user_fence.o \ xe_wa.o \ xe_wopcm.o diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index 5935cfe302044..f153ce96f69a7 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -42,6 +42,13 @@ #define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */ #define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0) +#define PCODE_FREQUENCY_CONFIG 0x6e +/* Frequency Config Sub Commands (param1) */ +#define PCODE_MBOX_FC_SC_READ_FUSED_P0 0x0 +#define PCODE_MBOX_FC_SC_READ_FUSED_PN 0x1 +/* Domain IDs (param2) */ +#define PCODE_MBOX_DOMAIN_HBM 0x2 + struct pcode_err_decode { int errno; const char *str; diff --git a/drivers/gpu/drm/xe/xe_tile_sysfs.c b/drivers/gpu/drm/xe/xe_tile_sysfs.c index 0f8d3e7fce46a..0662968d7bcbe 100644 --- a/drivers/gpu/drm/xe/xe_tile_sysfs.c +++ b/drivers/gpu/drm/xe/xe_tile_sysfs.c @@ -9,6 +9,7 @@ #include "xe_tile.h" #include "xe_tile_sysfs.h" +#include "xe_vram_freq.h" static void xe_tile_sysfs_kobj_release(struct kobject *kobj) { @@ -50,6 +51,8 @@ void xe_tile_sysfs_init(struct xe_tile *tile) tile->sysfs = &kt->base; + xe_vram_freq_sysfs_init(tile); + err = drmm_add_action_or_reset(&xe->drm, tile_sysfs_fini, tile); if (err) drm_warn(&xe->drm, "%s: drmm_add_action_or_reset failed, err: %d\n", diff --git a/drivers/gpu/drm/xe/xe_vram_freq.c b/drivers/gpu/drm/xe/xe_vram_freq.c new file mode 100644 index 0000000000000..7331462933070 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_vram_freq.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2024 Intel Corporation + */ +#include +#include + +#include "xe_gt_types.h" +#include "xe_pcode.h" +#include "xe_pcode_api.h" +#include "xe_tile.h" +#include "xe_tile_sysfs.h" +#include "xe_vram_freq.h" + +/** + * DOC: Xe VRAM freq + * + * Provides sysfs entries for vram frequency in tile + * + * device/tile#/memory/freq0/max_freq - This is maximum frequency. This value is read-only as it + * is the fixed fuse point P0. It is not the system + * configuration. + * device/tile#/memory/freq0/min_freq - This is minimum frequency. This value is read-only as it + * is the fixed fuse point PN. It is not the system + * configuration. + */ + +static struct xe_tile *dev_to_tile(struct device *dev) +{ + return kobj_to_tile(dev->kobj.parent); +} + +static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct xe_tile *tile = dev_to_tile(dev); + struct xe_gt *gt = tile->primary_gt; + u32 val, mbox; + int err; + + mbox = REG_FIELD_PREP(PCODE_MB_COMMAND, PCODE_FREQUENCY_CONFIG) + | REG_FIELD_PREP(PCODE_MB_PARAM1, PCODE_MBOX_FC_SC_READ_FUSED_P0) + | REG_FIELD_PREP(PCODE_MB_PARAM2, PCODE_MBOX_DOMAIN_HBM); + + err = xe_pcode_read(gt, mbox, &val, NULL); + if (err) + return err; + + /* data_out - Fused P0 for domain ID in units of 50 MHz */ + val *= 50; + + return sysfs_emit(buf, "%u\n", val); +} +static DEVICE_ATTR_RO(max_freq); + +static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct xe_tile *tile = dev_to_tile(dev); + struct xe_gt *gt = tile->primary_gt; + u32 val, mbox; + int err; + + mbox = REG_FIELD_PREP(PCODE_MB_COMMAND, PCODE_FREQUENCY_CONFIG) + | REG_FIELD_PREP(PCODE_MB_PARAM1, PCODE_MBOX_FC_SC_READ_FUSED_PN) + | REG_FIELD_PREP(PCODE_MB_PARAM2, PCODE_MBOX_DOMAIN_HBM); + + err = xe_pcode_read(gt, mbox, &val, NULL); + if (err) + return err; + + /* data_out - Fused Pn for domain ID in units of 50 MHz */ + val *= 50; + + return sysfs_emit(buf, "%u\n", val); +} +static DEVICE_ATTR_RO(min_freq); + +static struct attribute *freq_attrs[] = { + &dev_attr_max_freq.attr, + &dev_attr_min_freq.attr, + NULL +}; + +static const struct attribute_group freq_group_attrs = { + .name = "freq0", + .attrs = freq_attrs, +}; + +static void vram_freq_sysfs_fini(struct drm_device *drm, void *arg) +{ + struct kobject *kobj = arg; + + sysfs_remove_group(kobj, &freq_group_attrs); + kobject_put(kobj); +} + +/* + * xe_vram_freq_init - Initialize vram frequency component + * @tile: Xe Tile object + * + * It needs to be initialized after the main tile component is ready + */ + +void xe_vram_freq_sysfs_init(struct xe_tile *tile) +{ + struct xe_device *xe = tile_to_xe(tile); + struct kobject *kobj; + int err; + + if (xe->info.platform != XE_PVC) + return; + + kobj = kobject_create_and_add("memory", tile->sysfs); + if (!kobj) + drm_warn(&xe->drm, "failed to add memory directory, err: %d\n", -ENOMEM); + + err = sysfs_create_group(kobj, &freq_group_attrs); + if (err) { + kobject_put(kobj); + drm_warn(&xe->drm, "failed to register vram freq sysfs, err: %d\n", err); + return; + } + + err = drmm_add_action_or_reset(&xe->drm, vram_freq_sysfs_fini, kobj); + if (err) + drm_warn(&xe->drm, "%s: drmm_add_action_or_reset failed, err: %d\n", + __func__, err); +} diff --git a/drivers/gpu/drm/xe/xe_vram_freq.h b/drivers/gpu/drm/xe/xe_vram_freq.h new file mode 100644 index 0000000000000..cbe8c12fbd645 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_vram_freq.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_VRAM_FREQ_H_ +#define _XE_VRAM_FREQ_H_ + +struct xe_tile; + +void xe_vram_freq_sysfs_init(struct xe_tile *tile); + +#endif /* _XE_VRAM_FREQ_H_ */ -- GitLab From 69cac0a8f3ef8db4d62441c4a2686ec676c9facd Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Mon, 8 Jan 2024 14:58:42 -0800 Subject: [PATCH 0244/1420] drm/xe: Check skip_guc_pc before setting SLPC flag Don't set SLPC GuC feature ctl flag if skip_guc_pc is true. v2: Skip the freq related sysfs creation as well (Badal) v3: Remove unnecessary parenthesis (Lucas) Fixes: 975e4a3795d4 ("drm/xe: Manually setup C6 when skip_guc_pc is set") Fixes: bef52b5c7a19 ("drm/xe: Create a xe_gt_freq component for raw management and sysfs") Reviewed-by: Lucas De Marchi Signed-off-by: Vinay Belgaumkar Link: https://lore.kernel.org/r/20240108225842.966066-1-vinay.belgaumkar@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_gt_freq.c | 3 +++ drivers/gpu/drm/xe/xe_guc.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c index 3adfa6686e7cf..e5b0f4ecdbe82 100644 --- a/drivers/gpu/drm/xe/xe_gt_freq.c +++ b/drivers/gpu/drm/xe/xe_gt_freq.c @@ -196,6 +196,9 @@ void xe_gt_freq_init(struct xe_gt *gt) struct xe_device *xe = gt_to_xe(gt); int err; + if (xe->info.skip_guc_pc) + return; + gt->freq = kobject_create_and_add("freq0", gt->sysfs); if (!gt->freq) { drm_warn(&xe->drm, "failed to add freq0 directory to %s\n", diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 311a0364bff15..6e73ebf672514 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -63,7 +63,12 @@ static u32 guc_ctl_debug_flags(struct xe_guc *guc) static u32 guc_ctl_feature_flags(struct xe_guc *guc) { - return GUC_CTL_ENABLE_SLPC; + u32 flags = 0; + + if (!guc_to_xe(guc)->info.skip_guc_pc) + flags |= GUC_CTL_ENABLE_SLPC; + + return flags; } static u32 guc_ctl_log_params_flags(struct xe_guc *guc) -- GitLab From c3c33a139a8831972b9073c442dd6b39382b6c2a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 22:16:30 +0200 Subject: [PATCH 0245/1420] drm/nouveau: include drm/drm_edid.h only where needed Including drm_edid.h from nouveau_connector.h causes the rebuild of 15 files when drm_edid.h is modified, while there are only a few files that actually need to include drm_edid.h. Cc: Karol Herbst Cc: Lyude Paul Cc: Danilo Krummrich Cc: nouveau@lists.freedesktop.org Signed-off-by: Jani Nikula Acked-by: Alex Deucher Reviewed-by: Andi Shyti Reviewed-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20240104201632.1100753-1-jani.nikula@intel.com --- drivers/gpu/drm/nouveau/dispnv50/head.c | 1 + drivers/gpu/drm/nouveau/nouveau_connector.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 5f490fbf18772..83355dbc15eeb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -32,6 +32,7 @@ #include #include +#include #include #include "nouveau_connector.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a2df4918340cb..0608cabed058e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -44,6 +43,7 @@ struct nvkm_i2c_port; struct dcb_output; +struct edid; #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT struct nouveau_backlight { -- GitLab From 5465b0a591edc2d4ffa6491ed012c7af36a1b6e0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 22:16:31 +0200 Subject: [PATCH 0246/1420] drm/hisilicon: include drm/drm_edid.h only where needed Reduce the need for rebuilds when drm_edid.h is modified by including it only where needed. Cc: Xinliang Liu Cc: Tian Tao Cc: Xinwei Kong Cc: Sumit Semwal Cc: Yongqin Liu Cc: John Stultz Signed-off-by: Jani Nikula Reviewed-by: Andi Shyti Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20240104201632.1100753-2-jani.nikula@intel.com --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 1 - drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index f957552c6c507..207aa3f660b03 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -18,7 +18,6 @@ #include #include -#include #include struct hibmc_connector { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 8c6d2ea2a4729..94e2c573a7aff 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include -- GitLab From a109d19992294736abd4f4232ea639e03eb1f9e7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 10 Jan 2024 06:48:29 -0800 Subject: [PATCH 0247/1420] drm/xe: Fix build bug for GCC 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building drivers/gpu/drm/xe/xe_gt_pagefault.c with GCC 11 results in the following build errors: ./include/linux/fortify-string.h:57:33: error: writing 16 bytes into a region of size 0 [-Werror=stringop-overflow=] 57 | #define __underlying_memcpy __builtin_memcpy | ^ ./include/linux/fortify-string.h:644:9: note: in expansion of macro ‘__underlying_memcpy’ 644 | __underlying_##op(p, q, __fortify_size); \ | ^~~~~~~~~~~~~ ./include/linux/fortify-string.h:689:26: note: in expansion of macro ‘__fortify_memcpy_chk’ 689 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \ | ^~~~~~~~~~~~~~~~~~~~ drivers/gpu/drm/xe/xe_gt_pagefault.c:340:17: note: in expansion of macro ‘memcpy’ 340 | memcpy(pf_queue->data + pf_queue->tail, msg, len * sizeof(u32)); | ^~~~~~ In file included from drivers/gpu/drm/xe/xe_device_types.h:17, from drivers/gpu/drm/xe/xe_vm_types.h:16, from drivers/gpu/drm/xe/xe_bo.h:13, from drivers/gpu/drm/xe/xe_gt_pagefault.c:16: drivers/gpu/drm/xe/xe_gt_types.h:102:25: note: at offset [1144, 265324] into destination object ‘tile’ of size 8 102 | struct xe_tile *tile; | ^~~~ Fix these by removing -Wstringop-overflow from drm/xe builds. Closes: https://lore.kernel.org/all/45ad1d0f-a10f-483e-848a-76a30252edbe@paulmck-laptop/ Fixes: 7a8bc11782d3 ("drm/xe: Enable W=1 warnings by default") Suggested-by: Stephen Rothwell Signed-off-by: Paul E. McKenney [ This particular warning is broken on GCC11. In future changes it will be moved to the normal C flags in the top level Makefile (out of Makefile.extrawarn), but accounting for the compiler support. Just remove it out of xe's forced extra warnings for now ] Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index f3495d0e701cc..e16b84f79ddf3 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) subdir-ccflags-y += $(call cc-option, -Wformat-overflow) subdir-ccflags-y += $(call cc-option, -Wformat-truncation) -subdir-ccflags-y += $(call cc-option, -Wstringop-overflow) subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) # The following turn off the warnings enabled by -Wextra ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) -- GitLab From 284781470de227e6177e491ad091d72492290a65 Mon Sep 17 00:00:00 2001 From: Juan Escamilla Date: Tue, 9 Jan 2024 17:03:00 -0800 Subject: [PATCH 0248/1420] drm/i915/gt: Use rc6.supported flag from intel_gt for rc6_enable sysfs Currently if rc6 is supported, it gets enabled and the sysfs files for rc6_enable_show and rc6_enable_dev_show uses masks to check information from drm_i915_private. However rc6_support functions take more variables and conditions into consideration and thus these masks are not enough for most of the modern hardware and it is simpley lyting to the user. Let's fix it by at least use the rc6.supported flag from intel_gt information. Signed-off-by: Juan Escamilla Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20240110010302.553597-1-jcescami@wasd.net --- drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c index f0dea54880af2..2d3c4dab6d215 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c @@ -176,27 +176,13 @@ static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id) return DIV_ROUND_CLOSEST_ULL(res, 1000); } -static u8 get_rc6_mask(struct intel_gt *gt) -{ - u8 mask = 0; - - if (HAS_RC6(gt->i915)) - mask |= BIT(0); - if (HAS_RC6p(gt->i915)) - mask |= BIT(1); - if (HAS_RC6pp(gt->i915)) - mask |= BIT(2); - - return mask; -} - static ssize_t rc6_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); - return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); + return sysfs_emit(buff, "%x\n", gt->rc6.supported); } static ssize_t rc6_enable_dev_show(struct device *dev, @@ -205,7 +191,7 @@ static ssize_t rc6_enable_dev_show(struct device *dev, { struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name); - return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); + return sysfs_emit(buff, "%x\n", gt->rc6.supported); } static u32 __rc6_residency_ms_show(struct intel_gt *gt) -- GitLab From d11dc7aa98e5ef20642d08a00b02e3d2220ebfd9 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 10 Jan 2024 14:04:27 -0500 Subject: [PATCH 0249/1420] drm/doc/rfc: Remove Xe's pre-merge plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last TODO item here that was not marked as done was the display portion, which came along with the pull-request. So, now that Xe is part of drm-next and it includes the display portion, let's entirely kill this RFC here. Cc: Lucas De Marchi Cc: Thomas Hellström Cc: Oded Gabbay Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20240110190427.63095-1-rodrigo.vivi@intel.com Acked-by: Lucas De Marchi --- Documentation/gpu/rfc/xe.rst | 234 ----------------------------------- 1 file changed, 234 deletions(-) delete mode 100644 Documentation/gpu/rfc/xe.rst diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst deleted file mode 100644 index 97cf87578f973..0000000000000 --- a/Documentation/gpu/rfc/xe.rst +++ /dev/null @@ -1,234 +0,0 @@ -========================== -Xe – Merge Acceptance Plan -========================== -Xe is a new driver for Intel GPUs that supports both integrated and -discrete platforms starting with Tiger Lake (first Intel Xe Architecture). - -This document aims to establish a merge plan for the Xe, by writing down clear -pre-merge goals, in order to avoid unnecessary delays. - -Xe – Overview -============= -The main motivation of Xe is to have a fresh base to work from that is -unencumbered by older platforms, whilst also taking the opportunity to -rearchitect our driver to increase sharing across the drm subsystem, both -leveraging and allowing us to contribute more towards other shared components -like TTM and drm/scheduler. - -This is also an opportunity to start from the beginning with a clean uAPI that is -extensible by design and already aligned with the modern userspace needs. For -this reason, the memory model is solely based on GPU Virtual Address space -bind/unbind (‘VM_BIND’) of GEM buffer objects (BOs) and execution only supporting -explicit synchronization. With persistent mapping across the execution, the -userspace does not need to provide a list of all required mappings during each -submission. - -The new driver leverages a lot from i915. As for display, the intent is to share -the display code with the i915 driver so that there is maximum reuse there. - -As for the power management area, the goal is to have a much-simplified support -for the system suspend states (S-states), PCI device suspend states (D-states), -GPU/Render suspend states (R-states) and frequency management. It should leverage -as much as possible all the existent PCI-subsystem infrastructure (pm and -runtime_pm) and underlying firmware components such PCODE and GuC for the power -states and frequency decisions. - -Repository: - -https://gitlab.freedesktop.org/drm/xe/kernel (branch drm-xe-next) - -Xe – Platforms -============== -Currently, Xe is already functional and has experimental support for multiple -platforms starting from Tiger Lake, with initial support in userspace implemented -in Mesa (for Iris and Anv, our OpenGL and Vulkan drivers), as well as in NEO -(for OpenCL and Level0). - -During a transition period, platforms will be supported by both Xe and i915. -However, the force_probe mechanism existent in both drivers will allow only one -official and by-default probe at a given time. - -For instance, in order to probe a DG2 which PCI ID is 0x5690 by Xe instead of -i915, the following set of parameters need to be used: - -``` -i915.force_probe=!5690 xe.force_probe=5690 -``` - -In both drivers, the ‘.require_force_probe’ protection forces the user to use the -force_probe parameter while the driver is under development. This protection is -only removed when the support for the platform and the uAPI are stable. Stability -which needs to be demonstrated by CI results. - -In order to avoid user space regressions, i915 will continue to support all the -current platforms that are already out of this protection. Xe support will be -forever experimental and dependent on the usage of force_probe for these -platforms. - -When the time comes for Xe, the protection will be lifted on Xe and kept in i915. - -Xe – Pre-Merge Goals - Work-in-Progress -======================================= - -Display integration with i915 ------------------------------ -In order to share the display code with the i915 driver so that there is maximum -reuse, the i915/display/ code is built twice, once for i915.ko and then for -xe.ko. Currently, the i915/display code in Xe tree is polluted with many 'ifdefs' -depending on the build target. The goal is to refactor both Xe and i915/display -code simultaneously in order to get a clean result before they land upstream, so -that display can already be part of the initial pull request towards drm-next. - -However, display code should not gate the acceptance of Xe in upstream. Xe -patches will be refactored in a way that display code can be removed, if needed, -from the first pull request of Xe towards drm-next. The expectation is that when -both drivers are part of the drm-tip, the introduction of cleaner patches will be -easier and speed up. - -Xe – uAPI high level overview -============================= - -...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. - -Xe – Pre-Merge Goals - Completed -================================ - -Drm_exec --------- -Helper to make dma_resv locking for a big number of buffers is getting removed in -the drm_exec series proposed in https://patchwork.freedesktop.org/patch/524376/ -If that happens, Xe needs to change and incorporate the changes in the driver. -The goal is to engage with the Community to understand if the best approach is to -move that to the drivers that are using it or if we should keep the helpers in -place waiting for Xe to get merged. - -This item ties into the GPUVA, VM_BIND, and even long-running compute support. - -As a key measurable result, we need to have a community consensus documented in -this document and the Xe driver prepared for the changes, if necessary. - -Userptr integration and vm_bind -------------------------------- -Different drivers implement different ways of dealing with execution of userptr. -With multiple drivers currently introducing support to VM_BIND, the goal is to -aim for a DRM consensus on what’s the best way to have that support. To some -extent this is already getting addressed itself with the GPUVA where likely the -userptr will be a GPUVA with a NULL GEM call VM bind directly on the userptr. -However, there are more aspects around the rules for that and the usage of -mmu_notifiers, locking and other aspects. - -This task here has the goal of introducing a documentation of the basic rules. - -The documentation *needs* to first live in this document (API session below) and -then moved to another more specific document or at Xe level or at DRM level. - -Documentation should include: - - * The userptr part of the VM_BIND api. - - * Locking, including the page-faulting case. - - * O(1) complexity under VM_BIND. - -The document is now included in the drm documentation :doc:`here `. - -Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when -the second driver supporting VM_BIND+userptr appears. Details to be defined when -the time comes. - -The DRM GPUVM helpers do not yet include the userptr parts, but discussions -about implementing them are ongoing. - -ASYNC VM_BIND -------------- -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to have a consensus with other drivers and Mesa. -It needs to be clear how to handle async VM_BIND and interactions with userspace -memory fences. Ideally with helper support so people don't get it wrong in all -possible ways. - -As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of -various flavors, error handling and sample API suggestions are documented in -:doc:`The ASYNC VM_BIND document `. - -Drm_scheduler -------------- -Xe primarily uses Firmware based scheduling (GuC FW). However, it will use -drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to -resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is -not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and -drm_sched_entity. - -Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but -some consensus needs to be reached between Xe and other community drivers that -could also benefit from this work, for coupling FW based/assisted submission such -as the ARM’s new Mali GPU driver, and others. - -As a key measurable result, the patch series introducing Xe itself shall not -depend on any other patch touching drm_scheduler itself that was not yet merged -through drm-misc. This, by itself, already includes the reach of an agreement for -uniform 1 to 1 relationship implementation / usage across drivers. - -Long running compute: minimal data structure/scaffolding --------------------------------------------------------- -The generic scheduler code needs to include the handling of endless compute -contexts, with the minimal scaffolding for preempt-ctx fences (probably on the -drm_sched_entity) and making sure drm_scheduler can cope with the lack of job -completion fence. - -The goal is to achieve a consensus ahead of Xe initial pull-request, ideally with -this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any -drm driver, including Xe, could re-use and add their own individual needs on top -in a next stage. However, this should not block the initial merge. - -Dev_coredump ------------- - -Xe needs to align with other drivers on the way that the error states are -dumped, avoiding a Xe only error_state solution. The goal is to use devcoredump -infrastructure to report error states, since it produces a standardized way -by exposing a virtual and temporary /sys/class/devcoredump device. - -As the key measurable result, Xe driver needs to provide GPU snapshots captured -at hang time through devcoredump, but without depending on any core modification -of devcoredump infrastructure itself. - -Later, when we are in-tree, the goal is to collaborate with devcoredump -infrastructure with overall possible improvements, like multiple file support -for better organization of the dumps, snapshot support, dmesg extra print, -and whatever may make sense and help the overall infrastructure. - -DRM_VM_BIND ------------ -Nouveau, and Xe are all implementing ‘VM_BIND’ and new ‘Exec’ uAPIs in order to -fulfill the needs of the modern uAPI. Xe merge should *not* be blocked on the -development of a common new drm_infrastructure. However, the Xe team needs to -engage with the community to explore the options of a common API. - -As a key measurable result, the DRM_VM_BIND needs to be documented in this file -below, or this entire block deleted if the consensus is for independent drivers -vm_bind ioctls. - -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to enforce the overall locking scheme for all major -structs and list (so vm and vma). So, a consensus is needed, and possibly some -common helpers. If helpers are needed, they should be also documented in this -document. - -GPU VA ------- -Two main goals of Xe are meeting together here: - -1) Have an uAPI that aligns with modern UMD needs. - -2) Early upstream engagement. - -RedHat engineers working on Nouveau proposed a new DRM feature to handle keeping -track of GPU virtual address mappings. This is still not merged upstream, but -this aligns very well with our goals and with our VM_BIND. The engagement with -upstream and the port of Xe towards GPUVA is already ongoing. - -As a key measurable result, Xe needs to be aligned with the GPU VA and working in -our tree. Missing Nouveau patches should *not* block Xe and any needed GPUVA -related patch should be independent and present on dri-devel or acked by -maintainers to go along with the first Xe pull request towards drm-next. -- GitLab From 6e144a7d6f8a22f22f49f2ecf4268da1c75bcc4a Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:49 -0800 Subject: [PATCH 0250/1420] drm/xe: Refactor __xe_exec_queue_create() Split __xe_exec_queue_create() into two functions, alloc and init. We have an issue in that exec_queue_user_extensions are applied too late. In the case of USM properties, these need to be set prior to xe_lrc_init(). Refactor the logic here, so we can resolve this in follow-on. We only need the xe_vm_lock held during the exec_queue_init function. Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_exec_queue.c | 58 ++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index bcfc4127c7c59..cd2b9a8e51f56 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -30,16 +30,14 @@ enum xe_exec_queue_sched_prop { XE_EXEC_QUEUE_SCHED_PROP_MAX = 3, }; -static struct xe_exec_queue *__xe_exec_queue_create(struct xe_device *xe, - struct xe_vm *vm, - u32 logical_mask, - u16 width, struct xe_hw_engine *hwe, - u32 flags) +static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, + struct xe_vm *vm, + u32 logical_mask, + u16 width, struct xe_hw_engine *hwe, + u32 flags) { struct xe_exec_queue *q; struct xe_gt *gt = hwe->gt; - int err; - int i; /* only kernel queues can be permanent */ XE_WARN_ON((flags & EXEC_QUEUE_FLAG_PERMANENT) && !(flags & EXEC_QUEUE_FLAG_KERNEL)); @@ -82,8 +80,23 @@ static struct xe_exec_queue *__xe_exec_queue_create(struct xe_device *xe, q->bind.fence_seqno = XE_FENCE_INITIAL_SEQNO; } - for (i = 0; i < width; ++i) { - err = xe_lrc_init(q->lrc + i, hwe, q, vm, SZ_16K); + return q; +} + +static void __xe_exec_queue_free(struct xe_exec_queue *q) +{ + if (q->vm) + xe_vm_put(q->vm); + kfree(q); +} + +static int __xe_exec_queue_init(struct xe_exec_queue *q) +{ + struct xe_device *xe = gt_to_xe(q->gt); + int i, err; + + for (i = 0; i < q->width; ++i) { + err = xe_lrc_init(q->lrc + i, q->hwe, q, q->vm, SZ_16K); if (err) goto err_lrc; } @@ -100,16 +113,15 @@ static struct xe_exec_queue *__xe_exec_queue_create(struct xe_device *xe, * can perform GuC CT actions when needed. Caller is expected to have * already grabbed the rpm ref outside any sensitive locks. */ - if (!(q->flags & EXEC_QUEUE_FLAG_PERMANENT) && (q->flags & EXEC_QUEUE_FLAG_VM || !vm)) + if (!(q->flags & EXEC_QUEUE_FLAG_PERMANENT) && (q->flags & EXEC_QUEUE_FLAG_VM || !q->vm)) drm_WARN_ON(&xe->drm, !xe_device_mem_access_get_if_ongoing(xe)); - return q; + return 0; err_lrc: for (i = i - 1; i >= 0; --i) xe_lrc_finish(q->lrc + i); - kfree(q); - return ERR_PTR(err); + return err; } struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm, @@ -119,16 +131,27 @@ struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *v struct xe_exec_queue *q; int err; + q = __xe_exec_queue_alloc(xe, vm, logical_mask, width, hwe, flags); + if (IS_ERR(q)) + return q; + if (vm) { err = xe_vm_lock(vm, true); if (err) - return ERR_PTR(err); + goto err_post_alloc; } - q = __xe_exec_queue_create(xe, vm, logical_mask, width, hwe, flags); + + err = __xe_exec_queue_init(q); if (vm) xe_vm_unlock(vm); + if (err) + goto err_post_alloc; return q; + +err_post_alloc: + __xe_exec_queue_free(q); + return ERR_PTR(err); } struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe_gt *gt, @@ -179,10 +202,7 @@ void xe_exec_queue_fini(struct xe_exec_queue *q) xe_lrc_finish(q->lrc + i); if (!(q->flags & EXEC_QUEUE_FLAG_PERMANENT) && (q->flags & EXEC_QUEUE_FLAG_VM || !q->vm)) xe_device_mem_access_put(gt_to_xe(q->gt)); - if (q->vm) - xe_vm_put(q->vm); - - kfree(q); + __xe_exec_queue_free(q); } void xe_exec_queue_assign_name(struct xe_exec_queue *q, u32 instance) -- GitLab From 6ae24344e2e3e12e06f7b382af4bba2fd417b2ff Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:50 -0800 Subject: [PATCH 0251/1420] drm/xe: Add exec_queue.sched_props.job_timeout_ms The purpose here is to allow to optimize exec_queue_set_job_timeout() in follow-on patch. Currently it does q->ops->set_job_timeout(...). But we'd like to apply exec_queue_user_extensions much earlier and q->ops cannot be called before __xe_exec_queue_init(). It will be much more efficient to instead only have to set q->sched_props.job_timeout_ms when applying user extensions. That value will then be used during q->ops->init(). Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_exec_queue.c | 2 ++ drivers/gpu/drm/xe/xe_exec_queue_types.h | 2 ++ drivers/gpu/drm/xe/xe_guc_submit.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index cd2b9a8e51f56..4ff7e50112ca9 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -65,6 +65,8 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; q->sched_props.preempt_timeout_us = hwe->eclass->sched_props.preempt_timeout_us; + q->sched_props.job_timeout_ms = + hwe->eclass->sched_props.job_timeout_ms; if (q->flags & EXEC_QUEUE_FLAG_KERNEL && q->flags & EXEC_QUEUE_FLAG_HIGH_PRIORITY) q->sched_props.priority = XE_EXEC_QUEUE_PRIORITY_KERNEL; diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 8d4b7feb8c306..6041892d894e2 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -142,6 +142,8 @@ struct xe_exec_queue { u32 timeslice_us; /** @preempt_timeout_us: preemption timeout in micro-seconds */ u32 preempt_timeout_us; + /** @job_timeout_ms: job timeout in milliseconds */ + u32 job_timeout_ms; /** @priority: priority of this exec queue */ enum xe_exec_queue_priority priority; } sched_props; diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 54ffcfcdd41f9..392cbde629573 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1218,7 +1218,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) init_waitqueue_head(&ge->suspend_wait); timeout = (q->vm && xe_vm_in_lr_mode(q->vm)) ? MAX_SCHEDULE_TIMEOUT : - q->hwe->eclass->sched_props.job_timeout_ms; + q->sched_props.job_timeout_ms; err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops, get_submit_wq(guc), q->lrc[0].ring.size / MAX_JOB_SIZE_BYTES, 64, -- GitLab From 25ce7c5063b335808e1753ced5f0069981073f17 Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:51 -0800 Subject: [PATCH 0252/1420] drm/xe: Finish refactoring of exec_queue_create Setting of exec_queue user extensions is moved from the end of the ioctl function earlier, into __xe_exec_queue_alloc(). This fixes bug in that the USM attributes for access counters were being applied too late, and effectively were ignored. However, in order to apply user extensions this early, we can no longer call q->ops functions. Instead, make it more efficient. The user extension functions can simply update the q->sched_props values and they will be applied by the backend during q->ops->init(). v2: minor changes for readability (Matt) Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_exec_queue.c | 74 ++++++++++++++++++++---------- drivers/gpu/drm/xe/xe_exec_queue.h | 3 +- drivers/gpu/drm/xe/xe_gsc.c | 2 +- drivers/gpu/drm/xe/xe_gt.c | 4 +- drivers/gpu/drm/xe/xe_migrate.c | 2 +- 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 4ff7e50112ca9..c0b7434e78f11 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -30,14 +30,18 @@ enum xe_exec_queue_sched_prop { XE_EXEC_QUEUE_SCHED_PROP_MAX = 3, }; +static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, + u64 extensions, int ext_number, bool create); + static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, struct xe_vm *vm, u32 logical_mask, u16 width, struct xe_hw_engine *hwe, - u32 flags) + u32 flags, u64 extensions) { struct xe_exec_queue *q; struct xe_gt *gt = hwe->gt; + int err; /* only kernel queues can be permanent */ XE_WARN_ON((flags & EXEC_QUEUE_FLAG_PERMANENT) && !(flags & EXEC_QUEUE_FLAG_KERNEL)); @@ -50,8 +54,6 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, q->flags = flags; q->hwe = hwe; q->gt = gt; - if (vm) - q->vm = xe_vm_get(vm); q->class = hwe->class; q->width = width; q->logical_mask = logical_mask; @@ -73,6 +75,21 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, else q->sched_props.priority = XE_EXEC_QUEUE_PRIORITY_NORMAL; + if (extensions) { + /* + * may set q->usm, must come before xe_lrc_init(), + * may overwrite q->sched_props, must come before q->ops->init() + */ + err = exec_queue_user_extensions(xe, q, extensions, 0, true); + if (err) { + kfree(q); + return ERR_PTR(err); + } + } + + if (vm) + q->vm = xe_vm_get(vm); + if (xe_exec_queue_is_parallel(q)) { q->parallel.composite_fence_ctx = dma_fence_context_alloc(1); q->parallel.composite_fence_seqno = XE_FENCE_INITIAL_SEQNO; @@ -128,12 +145,14 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q) struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm, u32 logical_mask, u16 width, - struct xe_hw_engine *hwe, u32 flags) + struct xe_hw_engine *hwe, u32 flags, + u64 extensions) { struct xe_exec_queue *q; int err; - q = __xe_exec_queue_alloc(xe, vm, logical_mask, width, hwe, flags); + q = __xe_exec_queue_alloc(xe, vm, logical_mask, width, hwe, flags, + extensions); if (IS_ERR(q)) return q; @@ -178,7 +197,7 @@ struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe if (!logical_mask) return ERR_PTR(-ENODEV); - return xe_exec_queue_create(xe, vm, logical_mask, 1, hwe0, flags); + return xe_exec_queue_create(xe, vm, logical_mask, 1, hwe0, flags, 0); } void xe_exec_queue_destroy(struct kref *ref) @@ -262,7 +281,11 @@ static int exec_queue_set_priority(struct xe_device *xe, struct xe_exec_queue *q if (XE_IOCTL_DBG(xe, value > xe_exec_queue_device_get_max_priority(xe))) return -EPERM; - return q->ops->set_priority(q, value); + if (!create) + return q->ops->set_priority(q, value); + + q->sched_props.priority = value; + return 0; } static bool xe_exec_queue_enforce_schedule_limit(void) @@ -329,7 +352,11 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue * !xe_hw_engine_timeout_in_range(value, min, max)) return -EINVAL; - return q->ops->set_timeslice(q, value); + if (!create) + return q->ops->set_timeslice(q, value); + + q->sched_props.timeslice_us = value; + return 0; } static int exec_queue_set_preemption_timeout(struct xe_device *xe, @@ -345,7 +372,11 @@ static int exec_queue_set_preemption_timeout(struct xe_device *xe, !xe_hw_engine_timeout_in_range(value, min, max)) return -EINVAL; - return q->ops->set_preempt_timeout(q, value); + if (!create) + return q->ops->set_preempt_timeout(q, value); + + q->sched_props.preempt_timeout_us = value; + return 0; } static int exec_queue_set_persistence(struct xe_device *xe, struct xe_exec_queue *q, @@ -380,7 +411,9 @@ static int exec_queue_set_job_timeout(struct xe_device *xe, struct xe_exec_queue !xe_hw_engine_timeout_in_range(value, min, max)) return -EINVAL; - return q->ops->set_job_timeout(q, value); + q->sched_props.job_timeout_ms = value; + + return 0; } static int exec_queue_set_acc_trigger(struct xe_device *xe, struct xe_exec_queue *q, @@ -655,6 +688,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, if (eci[0].engine_class == DRM_XE_ENGINE_CLASS_VM_BIND) { for_each_gt(gt, xe, id) { struct xe_exec_queue *new; + u32 flags; if (xe_gt_is_media_type(gt)) continue; @@ -673,14 +707,13 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, /* The migration vm doesn't hold rpm ref */ xe_device_mem_access_get(xe); + flags = EXEC_QUEUE_FLAG_PERSISTENT | EXEC_QUEUE_FLAG_VM | + (id ? EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD : 0); + migrate_vm = xe_migrate_get_vm(gt_to_tile(gt)->migrate); new = xe_exec_queue_create(xe, migrate_vm, logical_mask, - args->width, hwe, - EXEC_QUEUE_FLAG_PERSISTENT | - EXEC_QUEUE_FLAG_VM | - (id ? - EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD : - 0)); + args->width, hwe, flags, + args->extensions); xe_device_mem_access_put(xe); /* now held by engine */ @@ -728,7 +761,8 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, q = xe_exec_queue_create(xe, vm, logical_mask, args->width, hwe, xe_vm_in_lr_mode(vm) ? 0 : - EXEC_QUEUE_FLAG_PERSISTENT); + EXEC_QUEUE_FLAG_PERSISTENT, + args->extensions); up_read(&vm->lock); xe_vm_put(vm); if (IS_ERR(q)) @@ -744,12 +778,6 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, } } - if (args->extensions) { - err = exec_queue_user_extensions(xe, q, args->extensions, 0, true); - if (XE_IOCTL_DBG(xe, err)) - goto kill_exec_queue; - } - q->persistent.xef = xef; mutex_lock(&xef->exec_queue.lock); diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h index d959cc4a1a82a..02ce8d204622f 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.h +++ b/drivers/gpu/drm/xe/xe_exec_queue.h @@ -16,7 +16,8 @@ struct xe_file; struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm, u32 logical_mask, u16 width, - struct xe_hw_engine *hw_engine, u32 flags); + struct xe_hw_engine *hw_engine, u32 flags, + u64 extensions); struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe_gt *gt, struct xe_vm *vm, enum xe_engine_class class, u32 flags); diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c index a8a895cf4b448..5b84fc9ab8adc 100644 --- a/drivers/gpu/drm/xe/xe_gsc.c +++ b/drivers/gpu/drm/xe/xe_gsc.c @@ -356,7 +356,7 @@ int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc) q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), 1, hwe, EXEC_QUEUE_FLAG_KERNEL | - EXEC_QUEUE_FLAG_PERMANENT); + EXEC_QUEUE_FLAG_PERMANENT, 0); if (IS_ERR(q)) { xe_gt_err(gt, "Failed to create queue for GSC submission\n"); err = PTR_ERR(q); diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 3af2adec12956..0f2258dc4a005 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -235,7 +235,7 @@ int xe_gt_record_default_lrcs(struct xe_gt *gt) return -ENOMEM; q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), 1, - hwe, EXEC_QUEUE_FLAG_KERNEL); + hwe, EXEC_QUEUE_FLAG_KERNEL, 0); if (IS_ERR(q)) { err = PTR_ERR(q); xe_gt_err(gt, "hwe %s: xe_exec_queue_create failed (%pe)\n", @@ -252,7 +252,7 @@ int xe_gt_record_default_lrcs(struct xe_gt *gt) } nop_q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), - 1, hwe, EXEC_QUEUE_FLAG_KERNEL); + 1, hwe, EXEC_QUEUE_FLAG_KERNEL, 0); if (IS_ERR(nop_q)) { err = PTR_ERR(nop_q); xe_gt_err(gt, "hwe %s: nop xe_exec_queue_create failed (%pe)\n", diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 02fca8f9adc28..83fa92d2a35a1 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -345,7 +345,7 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) m->q = xe_exec_queue_create(xe, vm, logical_mask, 1, hwe, EXEC_QUEUE_FLAG_KERNEL | EXEC_QUEUE_FLAG_PERMANENT | - EXEC_QUEUE_FLAG_HIGH_PRIORITY); + EXEC_QUEUE_FLAG_HIGH_PRIORITY, 0); } else { m->q = xe_exec_queue_create_class(xe, primary_gt, vm, XE_ENGINE_CLASS_COPY, -- GitLab From 801e8c7ed6705bd34508f52376cdbb3fc374c921 Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:52 -0800 Subject: [PATCH 0253/1420] drm/xe: Remove set_job_timeout_ms() from exec_queue_ops This function is no longer used as the job_timeout is now updated prior to calling queue_ops.init(). Signed-off-by: Brian Welty Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_exec_queue_types.h | 2 -- drivers/gpu/drm/xe/xe_execlist.c | 8 -------- drivers/gpu/drm/xe/xe_guc_submit.c | 16 ---------------- 3 files changed, 26 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 6041892d894e2..e7f84dee5275f 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -200,8 +200,6 @@ struct xe_exec_queue_ops { int (*set_timeslice)(struct xe_exec_queue *q, u32 timeslice_us); /** @set_preempt_timeout: Set preemption timeout for exec queue */ int (*set_preempt_timeout)(struct xe_exec_queue *q, u32 preempt_timeout_us); - /** @set_job_timeout: Set job timeout for exec queue */ - int (*set_job_timeout)(struct xe_exec_queue *q, u32 job_timeout_ms); /** * @suspend: Suspend exec queue from executing, allowed to be called * multiple times in a row before resume with the caveat that diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c index 96b5224eb4787..58dfe6a78ffeb 100644 --- a/drivers/gpu/drm/xe/xe_execlist.c +++ b/drivers/gpu/drm/xe/xe_execlist.c @@ -418,13 +418,6 @@ static int execlist_exec_queue_set_preempt_timeout(struct xe_exec_queue *q, return 0; } -static int execlist_exec_queue_set_job_timeout(struct xe_exec_queue *q, - u32 job_timeout_ms) -{ - /* NIY */ - return 0; -} - static int execlist_exec_queue_suspend(struct xe_exec_queue *q) { /* NIY */ @@ -455,7 +448,6 @@ static const struct xe_exec_queue_ops execlist_exec_queue_ops = { .set_priority = execlist_exec_queue_set_priority, .set_timeslice = execlist_exec_queue_set_timeslice, .set_preempt_timeout = execlist_exec_queue_set_preempt_timeout, - .set_job_timeout = execlist_exec_queue_set_job_timeout, .suspend = execlist_exec_queue_suspend, .suspend_wait = execlist_exec_queue_suspend_wait, .resume = execlist_exec_queue_resume, diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 392cbde629573..7c29b8333c719 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1350,21 +1350,6 @@ static int guc_exec_queue_set_preempt_timeout(struct xe_exec_queue *q, return 0; } -static int guc_exec_queue_set_job_timeout(struct xe_exec_queue *q, u32 job_timeout_ms) -{ - struct xe_gpu_scheduler *sched = &q->guc->sched; - struct xe_guc *guc = exec_queue_to_guc(q); - struct xe_device *xe = guc_to_xe(guc); - - xe_assert(xe, !exec_queue_registered(q)); - xe_assert(xe, !exec_queue_banned(q)); - xe_assert(xe, !exec_queue_killed(q)); - - sched->base.timeout = job_timeout_ms; - - return 0; -} - static int guc_exec_queue_suspend(struct xe_exec_queue *q) { struct xe_sched_msg *msg = q->guc->static_msgs + STATIC_MSG_SUSPEND; @@ -1415,7 +1400,6 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = { .set_priority = guc_exec_queue_set_priority, .set_timeslice = guc_exec_queue_set_timeslice, .set_preempt_timeout = guc_exec_queue_set_preempt_timeout, - .set_job_timeout = guc_exec_queue_set_job_timeout, .suspend = guc_exec_queue_suspend, .suspend_wait = guc_exec_queue_suspend_wait, .resume = guc_exec_queue_resume, -- GitLab From 86f41f4333e31b62d143c5e38c0c58c85193c4c8 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:36 -0800 Subject: [PATCH 0254/1420] drm/xe: Add build on bug to assert page fault queue works If PF_QUEUE_NUM_DW % PF_MSG_LEN_DW != 0 then the page fault queue logic does not work when wrapping occurs. Add a build bug on to assert PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0 to enforce this restriction and document the code. v2: - s/NUM_PF_QUEUE/PF_QUEUE_NUM_DW (Brian) Cc: Lucas De Marchi Signed-off-by: Matthew Brost Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 4489aadc7a525..0a61e4413679e 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -328,6 +328,11 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len) u32 asid; bool full; + /* + * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0 + */ + BUILD_BUG_ON(PF_QUEUE_NUM_DW % PF_MSG_LEN_DW); + if (unlikely(len != PF_MSG_LEN_DW)) return -EPROTO; -- GitLab From 1fd77ceaf0d843af2b7fde83e447b0738d0404cb Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:37 -0800 Subject: [PATCH 0255/1420] drm/xe: Invert page fault queue head / tail Convention for queues in Linux is the producer moves the head and consumer moves the tail. Fix the page fault queue to conform to this convention. Cc: Lucas De Marchi Signed-off-by: Matthew Brost Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 14 +++++++------- drivers/gpu/drm/xe/xe_gt_types.h | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 0a61e4413679e..3ca715e2ec19e 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -282,9 +282,9 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf) bool ret = false; spin_lock_irq(&pf_queue->lock); - if (pf_queue->head != pf_queue->tail) { + if (pf_queue->tail != pf_queue->head) { desc = (const struct xe_guc_pagefault_desc *) - (pf_queue->data + pf_queue->head); + (pf_queue->data + pf_queue->tail); pf->fault_level = FIELD_GET(PFD_FAULT_LEVEL, desc->dw0); pf->trva_fault = FIELD_GET(XE2_PFD_TRVA_FAULT, desc->dw0); @@ -302,7 +302,7 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf) pf->page_addr |= FIELD_GET(PFD_VIRTUAL_ADDR_LO, desc->dw2) << PFD_VIRTUAL_ADDR_LO_SHIFT; - pf_queue->head = (pf_queue->head + PF_MSG_LEN_DW) % + pf_queue->tail = (pf_queue->tail + PF_MSG_LEN_DW) % PF_QUEUE_NUM_DW; ret = true; } @@ -315,7 +315,7 @@ static bool pf_queue_full(struct pf_queue *pf_queue) { lockdep_assert_held(&pf_queue->lock); - return CIRC_SPACE(pf_queue->tail, pf_queue->head, PF_QUEUE_NUM_DW) <= + return CIRC_SPACE(pf_queue->head, pf_queue->tail, PF_QUEUE_NUM_DW) <= PF_MSG_LEN_DW; } @@ -342,8 +342,8 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len) spin_lock_irqsave(&pf_queue->lock, flags); full = pf_queue_full(pf_queue); if (!full) { - memcpy(pf_queue->data + pf_queue->tail, msg, len * sizeof(u32)); - pf_queue->tail = (pf_queue->tail + len) % PF_QUEUE_NUM_DW; + memcpy(pf_queue->data + pf_queue->head, msg, len * sizeof(u32)); + pf_queue->head = (pf_queue->head + len) % PF_QUEUE_NUM_DW; queue_work(gt->usm.pf_wq, &pf_queue->worker); } else { drm_warn(&xe->drm, "PF Queue full, shouldn't be possible"); @@ -389,7 +389,7 @@ static void pf_queue_work_func(struct work_struct *w) send_pagefault_reply(>->uc.guc, &reply); if (time_after(jiffies, threshold) && - pf_queue->head != pf_queue->tail) { + pf_queue->tail != pf_queue->head) { queue_work(gt->usm.pf_wq, w); break; } diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h index f746846604759..b15503dabba4b 100644 --- a/drivers/gpu/drm/xe/xe_gt_types.h +++ b/drivers/gpu/drm/xe/xe_gt_types.h @@ -225,16 +225,16 @@ struct xe_gt { #define PF_QUEUE_NUM_DW 128 /** @data: data in the page fault queue */ u32 data[PF_QUEUE_NUM_DW]; - /** - * @head: head pointer in DWs for page fault queue, - * moved by worker which processes faults. - */ - u16 head; /** * @tail: tail pointer in DWs for page fault queue, - * moved by G2H handler. + * moved by worker which processes faults (consumer). */ u16 tail; + /** + * @head: head pointer in DWs for page fault queue, + * moved by G2H handler (producer). + */ + u16 head; /** @lock: protects page fault queue */ spinlock_t lock; /** @worker: to process page faults */ -- GitLab From d0ca70c0339838198a704b15b7e6c3318f887536 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:38 -0800 Subject: [PATCH 0256/1420] drm/xe: Add build on bug to assert access counter queue works If ACC_QUEUE_NUM_DW % ACC_MSG_LEN_DW != 0 then the access counter queue logic does not work when wrapping occurs. Add a build bug on to assert ACC_QUEUE_NUM_DW % ACC_MSG_LEN_DW == 0 to enforce this restriction and document the code. v2: - s/NUM_ACC_QUEUE/ACC_QUEUE_NUM_DW (Brian) Cc: Lucas De Marchi Signed-off-by: Matthew Brost Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 3ca715e2ec19e..13183088401f6 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -629,6 +629,11 @@ int xe_guc_access_counter_notify_handler(struct xe_guc *guc, u32 *msg, u32 len) u32 asid; bool full; + /* + * The below logic doesn't work unless ACC_QUEUE_NUM_DW % ACC_MSG_LEN_DW == 0 + */ + BUILD_BUG_ON(ACC_QUEUE_NUM_DW % ACC_MSG_LEN_DW); + if (unlikely(len != ACC_MSG_LEN_DW)) return -EPROTO; -- GitLab From 7c0f97cb62dcc57463e3c66301330648cbf9b24a Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:39 -0800 Subject: [PATCH 0257/1420] drm/xe: Invert access counter queue head / tail Convention for queues in Linux is the producer moves the head and consumer moves the tail. Fix the access counter queue to conform to this convention. Cc: Lucas De Marchi Signed-off-by: Matthew Brost Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 14 +++++++------- drivers/gpu/drm/xe/xe_gt_types.h | 13 +++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 13183088401f6..5c2603075af96 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -564,9 +564,9 @@ static bool get_acc(struct acc_queue *acc_queue, struct acc *acc) bool ret = false; spin_lock(&acc_queue->lock); - if (acc_queue->head != acc_queue->tail) { + if (acc_queue->tail != acc_queue->head) { desc = (const struct xe_guc_acc_desc *) - (acc_queue->data + acc_queue->head); + (acc_queue->data + acc_queue->tail); acc->granularity = FIELD_GET(ACC_GRANULARITY, desc->dw2); acc->sub_granularity = FIELD_GET(ACC_SUBG_HI, desc->dw1) << 31 | @@ -579,7 +579,7 @@ static bool get_acc(struct acc_queue *acc_queue, struct acc *acc) acc->va_range_base = make_u64(desc->dw3 & ACC_VIRTUAL_ADDR_RANGE_HI, desc->dw2 & ACC_VIRTUAL_ADDR_RANGE_LO); - acc_queue->head = (acc_queue->head + ACC_MSG_LEN_DW) % + acc_queue->tail = (acc_queue->tail + ACC_MSG_LEN_DW) % ACC_QUEUE_NUM_DW; ret = true; } @@ -607,7 +607,7 @@ static void acc_queue_work_func(struct work_struct *w) } if (time_after(jiffies, threshold) && - acc_queue->head != acc_queue->tail) { + acc_queue->tail != acc_queue->head) { queue_work(gt->usm.acc_wq, w); break; } @@ -618,7 +618,7 @@ static bool acc_queue_full(struct acc_queue *acc_queue) { lockdep_assert_held(&acc_queue->lock); - return CIRC_SPACE(acc_queue->tail, acc_queue->head, ACC_QUEUE_NUM_DW) <= + return CIRC_SPACE(acc_queue->head, acc_queue->tail, ACC_QUEUE_NUM_DW) <= ACC_MSG_LEN_DW; } @@ -643,9 +643,9 @@ int xe_guc_access_counter_notify_handler(struct xe_guc *guc, u32 *msg, u32 len) spin_lock(&acc_queue->lock); full = acc_queue_full(acc_queue); if (!full) { - memcpy(acc_queue->data + acc_queue->tail, msg, + memcpy(acc_queue->data + acc_queue->head, msg, len * sizeof(u32)); - acc_queue->tail = (acc_queue->tail + len) % ACC_QUEUE_NUM_DW; + acc_queue->head = (acc_queue->head + len) % ACC_QUEUE_NUM_DW; queue_work(gt->usm.acc_wq, &acc_queue->worker); } else { drm_warn(>_to_xe(gt)->drm, "ACC Queue full, dropping ACC"); diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h index b15503dabba4b..047cde6cda107 100644 --- a/drivers/gpu/drm/xe/xe_gt_types.h +++ b/drivers/gpu/drm/xe/xe_gt_types.h @@ -252,15 +252,16 @@ struct xe_gt { /** @data: data in the page fault queue */ u32 data[ACC_QUEUE_NUM_DW]; /** - * @head: head pointer in DWs for page fault queue, - * moved by worker which processes faults. + * @tail: tail pointer in DWs for access counter queue, + * moved by worker which processes counters + * (consumer). */ - u16 head; + u16 tail; /** - * @tail: tail pointer in DWs for page fault queue, - * moved by G2H handler. + * @head: head pointer in DWs for access counter queue, + * moved by G2H handler (producer). */ - u16 tail; + u16 head; /** @lock: protects page fault queue */ spinlock_t lock; /** @worker: to process access counters */ -- GitLab From c10da95afa68060e13c5f920d96671943a7e54d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:22:23 +0300 Subject: [PATCH 0258/1420] drm/xe/device: clean up on error in probe() This error path should clean up before returning. Smatch detected this bug: drivers/gpu/drm/xe/xe_device.c:487 xe_device_probe() warn: missing unwind goto? Fixes: 4cb12b71923b ("drm/xe/xe2: Determine bios enablement for flat ccs on igfx") Signed-off-by: Dan Carpenter Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 004e65544e8d8..a94c0b27f04e8 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -495,7 +495,7 @@ int xe_device_probe(struct xe_device *xe) err = xe_device_set_has_flat_ccs(xe); if (err) - return err; + goto err_irq_shutdown; err = xe_mmio_probe_vram(xe); if (err) -- GitLab From 88ec23528b32ddb9ce2e8492f2629b0056353697 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:20:35 +0300 Subject: [PATCH 0259/1420] drm/xe/selftests: Fix an error pointer dereference bug Check if "bo" is an error pointer before calling xe_bo_lock() on it. Fixes: d6abc18d6693 ("drm/xe/xe2: Modify xe_bo_test for system memory") Signed-off-by: Dan Carpenter Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/tests/xe_bo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_bo.c b/drivers/gpu/drm/xe/tests/xe_bo.c index 412b2e7ce40cb..3436fd9cf2b27 100644 --- a/drivers/gpu/drm/xe/tests/xe_bo.c +++ b/drivers/gpu/drm/xe/tests/xe_bo.c @@ -125,14 +125,13 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile, bo = xe_bo_create_user(xe, NULL, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC, ttm_bo_type_device, bo_flags); - - xe_bo_lock(bo, false); - if (IS_ERR(bo)) { KUNIT_FAIL(test, "Failed to create bo.\n"); return; } + xe_bo_lock(bo, false); + kunit_info(test, "Verifying that CCS data is cleared on creation.\n"); ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL, test); -- GitLab From cf46019e8550a810cc023af7aa020ba43103b44d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:20:22 +0300 Subject: [PATCH 0260/1420] drm/xe: unlock on error path in xe_vm_add_compute_exec_queue() Drop the "&vm->lock" before returning. Fixes: 24f947d58fe5 ("drm/xe: Use DRM GPUVM helpers for external- and evicted objects") Signed-off-by: Dan Carpenter Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost --- drivers/gpu/drm/xe/xe_vm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 127842656a239..a7e7a0b240991 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -335,13 +335,13 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) down_write(&vm->lock); err = drm_gpuvm_exec_lock(&vm_exec); if (err) - return err; + goto out_up_write; pfence = xe_preempt_fence_create(q, q->compute.context, ++q->compute.seqno); if (!pfence) { err = -ENOMEM; - goto out_unlock; + goto out_fini; } list_add(&q->compute.link, &vm->preempt.exec_queues); @@ -364,8 +364,9 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) up_read(&vm->userptr.notifier_lock); -out_unlock: +out_fini: drm_exec_fini(exec); +out_up_write: up_write(&vm->lock); return err; -- GitLab From ef51d7542d143f3fd9a48d4e2c307563661668aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 10 Jan 2024 17:34:15 +0100 Subject: [PATCH 0261/1420] drm/xe/migrate: Fix CCS copy for small VRAM copy chunks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the migrate code is using the identity map for addressing VRAM, copy chunks may become as small as 64K if the VRAM resource is fragmented. However, a chunk size smaller that 1MiB may lead to the *next* chunk's offset into the CCS metadata backup memory may not be page-aligned, and the XY_CTRL_SURF_COPY_BLT command can't handle that, and even if it could, the current code doesn't handle the offset calculaton correctly. To fix this, make sure we align the size of VRAM copy chunks to 1MiB. If the remaining data to copy is smaller than that, that's not a problem, so use the remaining size. If the VRAM copy cunk becomes fragmented due to the size alignment restriction, don't use the identity map, but instead emit PTEs into the page-table like we do for system memory. v2: - Rebase v3: - Future proof somewhat by taking into account the real data size to flat CCS metadata size ratio. (Matt Roper) - Invert a couple of if-statements for better readability. - Fix support for 4K-granularity VRAM sizes. (Tested on DG1). v4: - Fix up code comments - Fix debug printout format typo. v5: - Add a Fixes: tag. Cc: Matt Roper Cc: Matthew Auld Cc: Matthew Brost Fixes: e89b384cde62 ("drm/xe/migrate: Update emit_pte to cope with a size level than 4k") Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20240110163415.524165-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/tests/xe_migrate.c | 2 +- drivers/gpu/drm/xe/xe_migrate.c | 128 ++++++++++++++++---------- 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c index 7a32faa2f6888..a6523df0f1d39 100644 --- a/drivers/gpu/drm/xe/tests/xe_migrate.c +++ b/drivers/gpu/drm/xe/tests/xe_migrate.c @@ -331,7 +331,7 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test) xe_res_first_sg(xe_bo_sg(pt), 0, pt->size, &src_it); emit_pte(m, bb, NUM_KERNEL_PDE - 1, xe_bo_is_vram(pt), false, - &src_it, XE_PAGE_SIZE, pt); + &src_it, XE_PAGE_SIZE, pt->ttm.resource); run_sanity_job(m, xe, bb, bb->len, "Writing PTE for our fake PT", test); diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 83fa92d2a35a1..88a32b272dda6 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -62,6 +62,8 @@ struct xe_migrate { * out of the pt_bo. */ struct drm_suballoc_manager vm_update_sa; + /** @min_chunk_size: For dgfx, Minimum chunk size */ + u64 min_chunk_size; }; #define MAX_PREEMPTDISABLE_TRANSFER SZ_8M /* Around 1ms. */ @@ -363,6 +365,19 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) if (err) return ERR_PTR(err); + if (IS_DGFX(xe)) { + if (xe_device_has_flat_ccs(xe)) + /* min chunk size corresponds to 4K of CCS Metadata */ + m->min_chunk_size = SZ_4K * SZ_64K / + xe_device_ccs_bytes(xe, SZ_64K); + else + /* Somewhat arbitrary to avoid a huge amount of blits */ + m->min_chunk_size = SZ_64K; + m->min_chunk_size = roundup_pow_of_two(m->min_chunk_size); + drm_dbg(&xe->drm, "Migrate min chunk size is 0x%08llx\n", + (unsigned long long)m->min_chunk_size); + } + return m; } @@ -374,16 +389,35 @@ static u64 max_mem_transfer_per_pass(struct xe_device *xe) return MAX_PREEMPTDISABLE_TRANSFER; } -static u64 xe_migrate_res_sizes(struct xe_device *xe, struct xe_res_cursor *cur) +static u64 xe_migrate_res_sizes(struct xe_migrate *m, struct xe_res_cursor *cur) { - /* - * For VRAM we use identity mapped pages so we are limited to current - * cursor size. For system we program the pages ourselves so we have no - * such limitation. - */ - return min_t(u64, max_mem_transfer_per_pass(xe), - mem_type_is_vram(cur->mem_type) ? cur->size : - cur->remaining); + struct xe_device *xe = tile_to_xe(m->tile); + u64 size = min_t(u64, max_mem_transfer_per_pass(xe), cur->remaining); + + if (mem_type_is_vram(cur->mem_type)) { + /* + * VRAM we want to blit in chunks with sizes aligned to + * min_chunk_size in order for the offset to CCS metadata to be + * page-aligned. If it's the last chunk it may be smaller. + * + * Another constraint is that we need to limit the blit to + * the VRAM block size, unless size is smaller than + * min_chunk_size. + */ + u64 chunk = max_t(u64, cur->size, m->min_chunk_size); + + size = min_t(u64, size, chunk); + if (size > m->min_chunk_size) + size = round_down(size, m->min_chunk_size); + } + + return size; +} + +static bool xe_migrate_allow_identity(u64 size, const struct xe_res_cursor *cur) +{ + /* If the chunk is not fragmented, allow identity map. */ + return cur->size >= size; } static u32 pte_update_size(struct xe_migrate *m, @@ -396,7 +430,12 @@ static u32 pte_update_size(struct xe_migrate *m, u32 cmds = 0; *L0_pt = pt_ofs; - if (!is_vram) { + if (is_vram && xe_migrate_allow_identity(*L0, cur)) { + /* Offset into identity map. */ + *L0_ofs = xe_migrate_vram_ofs(tile_to_xe(m->tile), + cur->start + vram_region_gpu_offset(res)); + cmds += cmd_size; + } else { /* Clip L0 to available size */ u64 size = min(*L0, (u64)avail_pts * SZ_2M); u64 num_4k_pages = DIV_ROUND_UP(size, XE_PAGE_SIZE); @@ -412,11 +451,6 @@ static u32 pte_update_size(struct xe_migrate *m, /* Each chunk has a single blit command */ cmds += cmd_size; - } else { - /* Offset into identity map. */ - *L0_ofs = xe_migrate_vram_ofs(tile_to_xe(m->tile), - cur->start + vram_region_gpu_offset(res)); - cmds += cmd_size; } return cmds; @@ -426,10 +460,10 @@ static void emit_pte(struct xe_migrate *m, struct xe_bb *bb, u32 at_pt, bool is_vram, bool is_comp_pte, struct xe_res_cursor *cur, - u32 size, struct xe_bo *bo) + u32 size, struct ttm_resource *res) { struct xe_device *xe = tile_to_xe(m->tile); - + struct xe_vm *vm = m->q->vm; u16 pat_index; u32 ptes; u64 ofs = at_pt * XE_PAGE_SIZE; @@ -442,13 +476,6 @@ static void emit_pte(struct xe_migrate *m, else pat_index = xe->pat.idx[XE_CACHE_WB]; - /* - * FIXME: Emitting VRAM PTEs to L0 PTs is forbidden. Currently - * we're only emitting VRAM PTEs during sanity tests, so when - * that's moved to a Kunit test, we should condition VRAM PTEs - * on running tests. - */ - ptes = DIV_ROUND_UP(size, XE_PAGE_SIZE); while (ptes) { @@ -468,20 +495,22 @@ static void emit_pte(struct xe_migrate *m, addr = xe_res_dma(cur) & PAGE_MASK; if (is_vram) { - /* Is this a 64K PTE entry? */ - if ((m->q->vm->flags & XE_VM_FLAG_64K) && - !(cur_ofs & (16 * 8 - 1))) { - xe_tile_assert(m->tile, IS_ALIGNED(addr, SZ_64K)); + if (vm->flags & XE_VM_FLAG_64K) { + u64 va = cur_ofs * XE_PAGE_SIZE / 8; + + xe_assert(xe, (va & (SZ_64K - 1)) == + (addr & (SZ_64K - 1))); + flags |= XE_PTE_PS64; } - addr += vram_region_gpu_offset(bo->ttm.resource); + addr += vram_region_gpu_offset(res); devmem = true; } - addr = m->q->vm->pt_ops->pte_encode_addr(m->tile->xe, - addr, pat_index, - 0, devmem, flags); + addr = vm->pt_ops->pte_encode_addr(m->tile->xe, + addr, pat_index, + 0, devmem, flags); bb->cs[bb->len++] = lower_32_bits(addr); bb->cs[bb->len++] = upper_32_bits(addr); @@ -693,8 +722,8 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, bool usm = xe->info.has_usm; u32 avail_pts = max_mem_transfer_per_pass(xe) / LEVEL0_PAGE_TABLE_ENCODE_SIZE; - src_L0 = xe_migrate_res_sizes(xe, &src_it); - dst_L0 = xe_migrate_res_sizes(xe, &dst_it); + src_L0 = xe_migrate_res_sizes(m, &src_it); + dst_L0 = xe_migrate_res_sizes(m, &dst_it); drm_dbg(&xe->drm, "Pass %u, sizes: %llu & %llu\n", pass++, src_L0, dst_L0); @@ -715,6 +744,7 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, &ccs_ofs, &ccs_pt, 0, 2 * avail_pts, avail_pts); + xe_assert(xe, IS_ALIGNED(ccs_it.start, PAGE_SIZE)); } /* Add copy commands size here */ @@ -727,20 +757,20 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, goto err_sync; } - if (!src_is_vram) - emit_pte(m, bb, src_L0_pt, src_is_vram, true, &src_it, src_L0, - src_bo); - else + if (src_is_vram && xe_migrate_allow_identity(src_L0, &src_it)) xe_res_next(&src_it, src_L0); - - if (!dst_is_vram) - emit_pte(m, bb, dst_L0_pt, dst_is_vram, true, &dst_it, src_L0, - dst_bo); else + emit_pte(m, bb, src_L0_pt, src_is_vram, true, &src_it, src_L0, + src); + + if (dst_is_vram && xe_migrate_allow_identity(src_L0, &dst_it)) xe_res_next(&dst_it, src_L0); + else + emit_pte(m, bb, dst_L0_pt, dst_is_vram, true, &dst_it, src_L0, + dst); if (copy_system_ccs) - emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src_bo); + emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src); bb->cs[bb->len++] = MI_BATCH_BUFFER_END; update_idx = bb->len; @@ -949,7 +979,7 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, bool usm = xe->info.has_usm; u32 avail_pts = max_mem_transfer_per_pass(xe) / LEVEL0_PAGE_TABLE_ENCODE_SIZE; - clear_L0 = xe_migrate_res_sizes(xe, &src_it); + clear_L0 = xe_migrate_res_sizes(m, &src_it); drm_dbg(&xe->drm, "Pass %u, size: %llu\n", pass++, clear_L0); @@ -976,12 +1006,12 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, size -= clear_L0; /* Preemption is enabled again by the ring ops. */ - if (!clear_vram) { - emit_pte(m, bb, clear_L0_pt, clear_vram, true, &src_it, clear_L0, - bo); - } else { + if (clear_vram && xe_migrate_allow_identity(clear_L0, &src_it)) xe_res_next(&src_it, clear_L0); - } + else + emit_pte(m, bb, clear_L0_pt, clear_vram, true, &src_it, clear_L0, + dst); + bb->cs[bb->len++] = MI_BATCH_BUFFER_END; update_idx = bb->len; -- GitLab From cbe7cea7eece110b75a3e26edf750ca0e2f3ebef Mon Sep 17 00:00:00 2001 From: chenxuebing Date: Thu, 11 Jan 2024 06:39:21 +0000 Subject: [PATCH 0262/1420] drm/edid: Clean up errors in drm_edid.c Fix the following errors reported by checkpatch: ERROR: do not use assignment in if condition Signed-off-by: chenxuebing Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20240111063921.8701-1-chenxb_99091@126.com --- drivers/gpu/drm/drm_edid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index e677dc8eb7a97..d45f86413402b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3610,7 +3610,8 @@ static bool mode_in_range(const struct drm_display_mode *mode, if (!mode_in_vsync_range(mode, edid, t)) return false; - if ((max_clock = range_pixel_clock(edid, t))) + max_clock = range_pixel_clock(edid, t); + if (max_clock) if (mode->clock > max_clock) return false; -- GitLab From 5ee0d47dcf33efd8950b347dcf4d20bab12a3fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Fri, 5 Jan 2024 14:58:36 -0300 Subject: [PATCH 0263/1420] drm/vc4: don't check if plane->state->fb == state->fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when using non-blocking commits, we can see the following kernel warning: [ 110.908514] ------------[ cut here ]------------ [ 110.908529] refcount_t: underflow; use-after-free. [ 110.908620] WARNING: CPU: 0 PID: 1866 at lib/refcount.c:87 refcount_dec_not_one+0xb8/0xc0 [ 110.908664] Modules linked in: rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device cmac algif_hash aes_arm64 aes_generic algif_skcipher af_alg bnep hid_logitech_hidpp vc4 brcmfmac hci_uart btbcm brcmutil bluetooth snd_soc_hdmi_codec cfg80211 cec drm_display_helper drm_dma_helper drm_kms_helper snd_soc_core snd_compress snd_pcm_dmaengine fb_sys_fops sysimgblt syscopyarea sysfillrect raspberrypi_hwmon ecdh_generic ecc rfkill libaes i2c_bcm2835 binfmt_misc joydev snd_bcm2835(C) bcm2835_codec(C) bcm2835_isp(C) v4l2_mem2mem videobuf2_dma_contig snd_pcm bcm2835_v4l2(C) raspberrypi_gpiomem bcm2835_mmal_vchiq(C) videobuf2_v4l2 snd_timer videobuf2_vmalloc videobuf2_memops videobuf2_common snd videodev vc_sm_cma(C) mc hid_logitech_dj uio_pdrv_genirq uio i2c_dev drm fuse dm_mod drm_panel_orientation_quirks backlight ip_tables x_tables ipv6 [ 110.909086] CPU: 0 PID: 1866 Comm: kodi.bin Tainted: G C 6.1.66-v8+ #32 [ 110.909104] Hardware name: Raspberry Pi 3 Model B Rev 1.2 (DT) [ 110.909114] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 110.909132] pc : refcount_dec_not_one+0xb8/0xc0 [ 110.909152] lr : refcount_dec_not_one+0xb4/0xc0 [ 110.909170] sp : ffffffc00913b9c0 [ 110.909177] x29: ffffffc00913b9c0 x28: 000000556969bbb0 x27: 000000556990df60 [ 110.909205] x26: 0000000000000002 x25: 0000000000000004 x24: ffffff8004448480 [ 110.909230] x23: ffffff800570b500 x22: ffffff802e03a7bc x21: ffffffecfca68c78 [ 110.909257] x20: ffffff8002b42000 x19: ffffff802e03a600 x18: 0000000000000000 [ 110.909283] x17: 0000000000000011 x16: ffffffffffffffff x15: 0000000000000004 [ 110.909308] x14: 0000000000000fff x13: ffffffed577e47e0 x12: 0000000000000003 [ 110.909333] x11: 0000000000000000 x10: 0000000000000027 x9 : c912d0d083728c00 [ 110.909359] x8 : c912d0d083728c00 x7 : 65646e75203a745f x6 : 746e756f63666572 [ 110.909384] x5 : ffffffed579f62ee x4 : ffffffed579eb01e x3 : 0000000000000000 [ 110.909409] x2 : 0000000000000000 x1 : ffffffc00913b750 x0 : 0000000000000001 [ 110.909434] Call trace: [ 110.909441] refcount_dec_not_one+0xb8/0xc0 [ 110.909461] vc4_bo_dec_usecnt+0x4c/0x1b0 [vc4] [ 110.909903] vc4_cleanup_fb+0x44/0x50 [vc4] [ 110.910315] drm_atomic_helper_cleanup_planes+0x88/0xa4 [drm_kms_helper] [ 110.910669] vc4_atomic_commit_tail+0x390/0x9dc [vc4] [ 110.911079] commit_tail+0xb0/0x164 [drm_kms_helper] [ 110.911397] drm_atomic_helper_commit+0x1d0/0x1f0 [drm_kms_helper] [ 110.911716] drm_atomic_commit+0xb0/0xdc [drm] [ 110.912569] drm_mode_atomic_ioctl+0x348/0x4b8 [drm] [ 110.913330] drm_ioctl_kernel+0xec/0x15c [drm] [ 110.914091] drm_ioctl+0x24c/0x3b0 [drm] [ 110.914850] __arm64_sys_ioctl+0x9c/0xd4 [ 110.914873] invoke_syscall+0x4c/0x114 [ 110.914897] el0_svc_common+0xd0/0x118 [ 110.914917] do_el0_svc+0x38/0xd0 [ 110.914936] el0_svc+0x30/0x8c [ 110.914958] el0t_64_sync_handler+0x84/0xf0 [ 110.914979] el0t_64_sync+0x18c/0x190 [ 110.914996] ---[ end trace 0000000000000000 ]--- This happens because, although `prepare_fb` and `cleanup_fb` are perfectly balanced, we cannot guarantee consistency in the check plane->state->fb == state->fb. This means that sometimes we can increase the refcount in `prepare_fb` and don't decrease it in `cleanup_fb`. The opposite can also be true. In fact, the struct drm_plane .state shouldn't be accessed directly but instead, the `drm_atomic_get_new_plane_state()` helper function should be used. So, we could stick to this check, but using `drm_atomic_get_new_plane_state()`. But actually, this check is not really needed. We can increase and decrease the refcount symmetrically without problems. This is going to make the code more simple and consistent. Signed-off-by: Maíra Canal Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240105175908.242000-1-mcanal@igalia.com --- drivers/gpu/drm/vc4/vc4_plane.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index b8184374332ce..07caf2a47c6ce 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1508,9 +1508,6 @@ static int vc4_prepare_fb(struct drm_plane *plane, if (ret) return ret; - if (plane->state->fb == state->fb) - return 0; - return vc4_bo_inc_usecnt(bo); } @@ -1519,7 +1516,7 @@ static void vc4_cleanup_fb(struct drm_plane *plane, { struct vc4_bo *bo; - if (plane->state->fb == state->fb || !state->fb) + if (!state->fb) return; bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); -- GitLab From b9bc05495174759902f226deccc2f68cdc231891 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Thu, 11 Jan 2024 11:28:49 +0100 Subject: [PATCH 0264/1420] drm/ttm/tests: Fix argument in ttm_tt_kunit_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a leftover definition of page order and pass an empty flag value in ttm_pool_pre_populated(). Signed-off-by: Karolina Stolarek Tested-by: Amaranath Somalapuram Reviewed-by: Dominik Karol Piątkowski Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/db34f34a039cf951c5933e8ae046b4ed72d20dcb.1704959786.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/ttm_pool_test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ttm/tests/ttm_pool_test.c b/drivers/gpu/drm/ttm/tests/ttm_pool_test.c index 2d9cae8cd9844..b97f7b6daf5bd 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_pool_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_pool_test.c @@ -78,10 +78,9 @@ static struct ttm_pool *ttm_pool_pre_populated(struct kunit *test, struct ttm_test_devices *devs = priv->devs; struct ttm_pool *pool; struct ttm_tt *tt; - unsigned long order = __fls(size / PAGE_SIZE); int err; - tt = ttm_tt_kunit_init(test, order, caching, size); + tt = ttm_tt_kunit_init(test, 0, caching, size); KUNIT_ASSERT_NOT_NULL(test, tt); pool = kunit_kzalloc(test, sizeof(*pool), GFP_KERNEL); -- GitLab From 502756e23360d1192c496bc6791e97621e8578d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Fri, 5 Jan 2024 11:57:42 -0300 Subject: [PATCH 0265/1420] drm/v3d: Show the memory-management stats on debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dump the contents of the DRM MM allocator of the V3D driver. This will help us to debug the VA ranges allocated. Signed-off-by: Maíra Canal Reviewed-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20240105145851.193492-1-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_debugfs.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c index f843a50d5dce6..cdfe1d3bf5eef 100644 --- a/drivers/gpu/drm/v3d/v3d_debugfs.c +++ b/drivers/gpu/drm/v3d/v3d_debugfs.c @@ -260,11 +260,26 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) return 0; } +static int v3d_debugfs_mm(struct seq_file *m, void *unused) +{ + struct drm_printer p = drm_seq_file_printer(m); + struct drm_debugfs_entry *entry = m->private; + struct drm_device *dev = entry->dev; + struct v3d_dev *v3d = to_v3d_dev(dev); + + spin_lock(&v3d->mm_lock); + drm_mm_print(&v3d->mm, &p); + spin_unlock(&v3d->mm_lock); + + return 0; +} + static const struct drm_debugfs_info v3d_debugfs_list[] = { {"v3d_ident", v3d_v3d_debugfs_ident, 0}, {"v3d_regs", v3d_v3d_debugfs_regs, 0}, {"measure_clock", v3d_measure_clock, 0}, {"bo_stats", v3d_debugfs_bo_stats, 0}, + {"v3d_mm", v3d_debugfs_mm, 0}, }; void -- GitLab From 88cbf8502023dcb97bf9e40655d4848ba14350e0 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 17:20:51 +0100 Subject: [PATCH 0266/1420] drm/xe: Split GuC communication initialization Soon we will be trying to communicate with the GuC firmware very early during VF driver probe, before we finish normal init steps. Split GuC communication initialization code so the GuC MMIO based communication xe_guc_mmio_send() functions will work where needed. Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20240111162051.585-1-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc.c | 21 +++++++++++++++++---- drivers/gpu/drm/xe/xe_guc.h | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 6e73ebf672514..0fd9b5efe4c2d 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -243,6 +243,22 @@ static void guc_fini(struct drm_device *drm, void *arg) xe_force_wake_put(gt_to_fw(guc_to_gt(guc)), XE_FORCEWAKE_ALL); } +/** + * xe_guc_comm_init_early - early initialization of GuC communication + * @guc: the &xe_guc to initialize + * + * Must be called prior to first MMIO communication with GuC firmware. + */ +void xe_guc_comm_init_early(struct xe_guc *guc) +{ + struct xe_gt *gt = guc_to_gt(guc); + + if (xe_gt_is_media_type(gt)) + guc->notify_reg = MED_GUC_HOST_INTERRUPT; + else + guc->notify_reg = GUC_HOST_INTERRUPT; +} + int xe_guc_init(struct xe_guc *guc) { struct xe_device *xe = guc_to_xe(guc); @@ -283,10 +299,7 @@ int xe_guc_init(struct xe_guc *guc) guc_init_params(guc); - if (xe_gt_is_media_type(gt)) - guc->notify_reg = MED_GUC_HOST_INTERRUPT; - else - guc->notify_reg = GUC_HOST_INTERRUPT; + xe_guc_comm_init_early(guc); xe_uc_fw_change_status(&guc->fw, XE_UC_FIRMWARE_LOADABLE); diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h index d3e49e7fd7c34..94f2dc5f6f90b 100644 --- a/drivers/gpu/drm/xe/xe_guc.h +++ b/drivers/gpu/drm/xe/xe_guc.h @@ -13,6 +13,7 @@ struct drm_printer; +void xe_guc_comm_init_early(struct xe_guc *guc); int xe_guc_init(struct xe_guc *guc); int xe_guc_init_post_hwconfig(struct xe_guc *guc); int xe_guc_post_load_init(struct xe_guc *guc); -- GitLab From 3c01e01214026114609c577ce31f81d4e037dd50 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 16:48:38 +0100 Subject: [PATCH 0267/1420] drm/xe/guc: Treat non-response message after BUSY as unexpected Once GuC replied with GUC_HXG_TYPE_NO_RESPONSE_BUSY message then we may expect that only RESPONSE_SUCCESS or FAILURE message will be sent, anything else is a violation of the HXG protocol. Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20240111154838.541-1-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 0fd9b5efe4c2d..235d27b17ff99 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -731,8 +731,12 @@ int xe_guc_mmio_send_recv(struct xe_guc *guc, const u32 *request, if (unlikely(FIELD_GET(GUC_HXG_MSG_0_ORIGIN, header) != GUC_HXG_ORIGIN_GUC)) goto proto; - if (unlikely(ret)) + if (unlikely(ret)) { + if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) != + GUC_HXG_TYPE_NO_RESPONSE_BUSY) + goto proto; goto timeout; + } } if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) == -- GitLab From d898c2e55593fea5da068de48a878c66520a4af8 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 16:27:24 +0100 Subject: [PATCH 0268/1420] drm/xe/guc: Return CTB response length Not all CTB responses from the GuC are fixed size and we need to pass response length to the caller, if there was a response_buffer. Easiest solution is to return it as positive value from all xe_guc_ct_send_recv() functions. The CTB response length is always between 1 and 254 (ie. GUC_HXG_MSG_MIN_LEN and GUC_CTB_MAX_DWORDS - GUC_HXG_MSG_MIN_LEN). Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20240111152724.497-1-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_ct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index c29f095aa1b98..d490a4d42c01b 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -780,7 +780,7 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, ret = -EIO; } - return ret > 0 ? 0 : ret; + return ret > 0 ? response_buffer ? g2h_fence.response_len : 0 : ret; } int xe_guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, -- GitLab From d4978a67ae97a2b875c8e8b6684866ee1d35fa80 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 22:06:32 +0100 Subject: [PATCH 0269/1420] drm/xe/guc: Use HXG definitions on HXG messages While parsing and processing CTB G2H messages we should extract underlying HXG message and use HXG definitions on such message. Using outer CTB layer message in HXG definitions require use of shifted dword index, which might be confusing: FIELD_GET(GUC_HXG_MSG_0_xxx, msg[1]) instead of: FIELD_GET(GUC_HXG_MSG_0_xxx, hxg[0]) Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20240111210632.717-1-michal.wajdeczko@intel.com Signed-off-by: Michal Wajdeczko --- drivers/gpu/drm/xe/xe_guc_ct.c | 72 +++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index d490a4d42c01b..b2cc3f993eb6c 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -796,9 +796,20 @@ int xe_guc_ct_send_recv_no_fail(struct xe_guc_ct *ct, const u32 *action, return guc_ct_send_recv(ct, action, len, response_buffer, true); } +static u32 *msg_to_hxg(u32 *msg) +{ + return msg + GUC_CTB_MSG_MIN_LEN; +} + +static u32 msg_len_to_hxg_len(u32 len) +{ + return len - GUC_CTB_MSG_MIN_LEN; +} + static int parse_g2h_event(struct xe_guc_ct *ct, u32 *msg, u32 len) { - u32 action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[1]); + u32 *hxg = msg_to_hxg(msg); + u32 action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, hxg[0]); lockdep_assert_held(&ct->lock); @@ -817,9 +828,10 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) { struct xe_gt *gt = ct_to_gt(ct); struct xe_device *xe = gt_to_xe(gt); - u32 response_len = len - GUC_CTB_MSG_MIN_LEN; + u32 *hxg = msg_to_hxg(msg); + u32 hxg_len = msg_len_to_hxg_len(len); u32 fence = FIELD_GET(GUC_CTB_MSG_0_FENCE, msg[0]); - u32 type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[1]); + u32 type = FIELD_GET(GUC_HXG_MSG_0_TYPE, hxg[0]); struct g2h_fence *g2h_fence; lockdep_assert_held(&ct->lock); @@ -836,8 +848,8 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) if (type == GUC_HXG_TYPE_RESPONSE_FAILURE) xe_gt_err(gt, "FAST_REQ H2G fence 0x%x failed! e=0x%x, h=%u\n", fence, - FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, msg[1]), - FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, msg[1])); + FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, hxg[0]), + FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, hxg[0])); else xe_gt_err(gt, "unexpected response %u for FAST_REQ H2G fence 0x%x!\n", type, fence); @@ -857,18 +869,14 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) if (type == GUC_HXG_TYPE_RESPONSE_FAILURE) { g2h_fence->fail = true; - g2h_fence->error = - FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, msg[1]); - g2h_fence->hint = - FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, msg[1]); + g2h_fence->error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, hxg[0]); + g2h_fence->hint = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, hxg[0]); } else if (type == GUC_HXG_TYPE_NO_RESPONSE_RETRY) { g2h_fence->retry = true; - g2h_fence->reason = - FIELD_GET(GUC_HXG_RETRY_MSG_0_REASON, msg[1]); + g2h_fence->reason = FIELD_GET(GUC_HXG_RETRY_MSG_0_REASON, hxg[0]); } else if (g2h_fence->response_buffer) { - g2h_fence->response_len = response_len; - memcpy(g2h_fence->response_buffer, msg + GUC_CTB_MSG_MIN_LEN, - response_len * sizeof(u32)); + g2h_fence->response_len = hxg_len; + memcpy(g2h_fence->response_buffer, hxg, hxg_len * sizeof(u32)); } g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); @@ -884,14 +892,13 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) { struct xe_device *xe = ct_to_xe(ct); - u32 hxg, origin, type; + u32 *hxg = msg_to_hxg(msg); + u32 origin, type; int ret; lockdep_assert_held(&ct->lock); - hxg = msg[1]; - - origin = FIELD_GET(GUC_HXG_MSG_0_ORIGIN, hxg); + origin = FIELD_GET(GUC_HXG_MSG_0_ORIGIN, hxg[0]); if (unlikely(origin != GUC_HXG_ORIGIN_GUC)) { drm_err(&xe->drm, "G2H channel broken on read, origin=%d, reset required\n", @@ -901,7 +908,7 @@ static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) return -EPROTO; } - type = FIELD_GET(GUC_HXG_MSG_0_TYPE, hxg); + type = FIELD_GET(GUC_HXG_MSG_0_TYPE, hxg[0]); switch (type) { case GUC_HXG_TYPE_EVENT: ret = parse_g2h_event(ct, msg, len); @@ -927,14 +934,19 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) { struct xe_device *xe = ct_to_xe(ct); struct xe_guc *guc = ct_to_guc(ct); - u32 action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[1]); - u32 *payload = msg + GUC_CTB_HXG_MSG_MIN_LEN; - u32 adj_len = len - GUC_CTB_HXG_MSG_MIN_LEN; + u32 hxg_len = msg_len_to_hxg_len(len); + u32 *hxg = msg_to_hxg(msg); + u32 action, adj_len; + u32 *payload; int ret = 0; - if (FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[1]) != GUC_HXG_TYPE_EVENT) + if (FIELD_GET(GUC_HXG_MSG_0_TYPE, hxg[0]) != GUC_HXG_TYPE_EVENT) return 0; + action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, hxg[0]); + payload = hxg + GUC_HXG_EVENT_MSG_MIN_LEN; + adj_len = hxg_len - GUC_HXG_EVENT_MSG_MIN_LEN; + switch (action) { case XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE: ret = xe_guc_sched_done_handler(guc, payload, adj_len); @@ -995,6 +1007,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) u32 tail, head, len; s32 avail; u32 action; + u32 *hxg; lockdep_assert_held(&ct->fast_lock); @@ -1045,10 +1058,11 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) avail * sizeof(u32)); } - action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[1]); + hxg = msg_to_hxg(msg); + action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, hxg[0]); if (fast_path) { - if (FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[1]) != GUC_HXG_TYPE_EVENT) + if (FIELD_GET(GUC_HXG_MSG_0_TYPE, hxg[0]) != GUC_HXG_TYPE_EVENT) return 0; switch (action) { @@ -1074,9 +1088,11 @@ static void g2h_fast_path(struct xe_guc_ct *ct, u32 *msg, u32 len) { struct xe_device *xe = ct_to_xe(ct); struct xe_guc *guc = ct_to_guc(ct); - u32 action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[1]); - u32 *payload = msg + GUC_CTB_HXG_MSG_MIN_LEN; - u32 adj_len = len - GUC_CTB_HXG_MSG_MIN_LEN; + u32 hxg_len = msg_len_to_hxg_len(len); + u32 *hxg = msg_to_hxg(msg); + u32 action = FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, hxg[0]); + u32 *payload = hxg + GUC_HXG_MSG_MIN_LEN; + u32 adj_len = hxg_len - GUC_HXG_MSG_MIN_LEN; int ret = 0; switch (action) { -- GitLab From c3ba13a0ed3d81d28aaf475687a5f39766566768 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 10 Jan 2024 09:22:45 +0100 Subject: [PATCH 0270/1420] drm: panel: simple: convert LG LB070WV8 fixed mode into display timings At least the pixelclock has a range which can vary. Convert fixed mode into display timings so they can be overwritten in DT if necessary. Signed-off-by: Alexander Stein Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240110082245.417736-1-alexander.stein@ew.tq-group.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20240110082245.417736-1-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/panel/panel-simple.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 2214cb09678cd..7054b4fb3fc00 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2754,21 +2754,21 @@ static const struct panel_desc lemaker_bl035_rgb_002 = { .bus_flags = DRM_BUS_FLAG_DE_LOW, }; -static const struct drm_display_mode lg_lb070wv8_mode = { - .clock = 33246, - .hdisplay = 800, - .hsync_start = 800 + 88, - .hsync_end = 800 + 88 + 80, - .htotal = 800 + 88 + 80 + 88, - .vdisplay = 480, - .vsync_start = 480 + 10, - .vsync_end = 480 + 10 + 25, - .vtotal = 480 + 10 + 25 + 10, +static const struct display_timing lg_lb070wv8_timing = { + .pixelclock = { 31950000, 33260000, 34600000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 88, 88, 88 }, + .hback_porch = { 88, 88, 88 }, + .hsync_len = { 80, 80, 80 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 10, 10, 10 }, + .vback_porch = { 10, 10, 10 }, + .vsync_len = { 25, 25, 25 }, }; static const struct panel_desc lg_lb070wv8 = { - .modes = &lg_lb070wv8_mode, - .num_modes = 1, + .timings = &lg_lb070wv8_timing, + .num_timings = 1, .bpc = 8, .size = { .width = 151, -- GitLab From baae3a0b10c499d4228514a701602f6fd2a8d6b4 Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Tue, 2 Jan 2024 17:15:44 +0100 Subject: [PATCH 0271/1420] dt-bindings: display: panel: Add BOE TH101MB31IG002-28A panel Add bindings for the BOE TH101MB31IG002-28A LCD panel. It is used e.g. in the Pine64 PineTab2 and PineTab-V. Signed-off-by: Manuel Traut Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240102-pinetab2-v3-1-cb1aa69f8c30@mecka.net Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20240102-pinetab2-v3-1-cb1aa69f8c30@mecka.net --- .../display/panel/boe,th101mb31ig002-28a.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml diff --git a/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml b/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml new file mode 100644 index 0000000000000..32df26cbfeed7 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/boe,th101mb31ig002-28a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BOE TH101MB31IG002-28A WXGA DSI Display Panel + +maintainers: + - Manuel Traut + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + enum: + # BOE TH101MB31IG002-28A 10.1" WXGA TFT LCD panel + - boe,th101mb31ig002-28a + + reg: true + backlight: true + enable-gpios: true + power-supply: true + port: true + rotation: true + +required: + - compatible + - reg + - enable-gpios + - power-supply + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "boe,th101mb31ig002-28a"; + reg = <0>; + backlight = <&backlight_lcd0>; + enable-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>; + rotation = <90>; + power-supply = <&vcc_3v3>; + port { + panel_in_dsi: endpoint { + remote-endpoint = <&dsi_out_con>; + }; + }; + }; + }; + +... -- GitLab From 420186db1483da4e16cd5d5a472f511a35dbc1b7 Mon Sep 17 00:00:00 2001 From: Alexander Warnecke Date: Tue, 2 Jan 2024 17:15:45 +0100 Subject: [PATCH 0272/1420] drm/panel: Add driver for BOE TH101MB31IG002-28A panel The BOE TH101MB31IG002-28A panel is a WXGA panel. It is used in Pine64 PineTab2 and PineTab-V. Signed-off-by: Alexander Warnecke Signed-off-by: Manuel Traut Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20240102-pinetab2-v3-2-cb1aa69f8c30@mecka.net Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20240102-pinetab2-v3-2-cb1aa69f8c30@mecka.net --- drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + .../drm/panel/panel-boe-th101mb31ig002-28a.c | 322 ++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index dad938cf6decf..cd2b6ebf8d823 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -67,6 +67,17 @@ config DRM_PANEL_BOE_HIMAX8279D 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. +config DRM_PANEL_BOE_TH101MB31UIG002_28A + tristate "Boe TH101MB31UIG002-28A panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Boe + TH101MB31UIG002-28A TFT-LCD modules. The panel has a 800x1280 + resolution and uses 24 bit RGB per pixel. It provides a MIPI DSI + interface to the host and has a built-in LED backlight. + config DRM_PANEL_BOE_TV101WUM_NL6 tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d94a644d0a6ce..015bb8d70fbdb 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596. obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o +obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o diff --git a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c new file mode 100644 index 0000000000000..763e9f8342d3c --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Alexander Warnecke + * Copyright (c) 2023 Manuel Traut + * Copyright (c) 2023 Dang Huynh + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct boe_th101mb31ig002 { + struct drm_panel panel; + + struct mipi_dsi_device *dsi; + + struct regulator *power; + struct gpio_desc *enable; + struct gpio_desc *reset; + + enum drm_panel_orientation orientation; +}; + +static void boe_th101mb31ig002_reset(struct boe_th101mb31ig002 *ctx) +{ + gpiod_direction_output(ctx->reset, 0); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 1); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 0); + usleep_range(5000, 6000); +} + +static int boe_th101mb31ig002_enable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + mipi_dsi_dcs_write_seq(dsi, 0xE0, 0xAB, 0xBA); + mipi_dsi_dcs_write_seq(dsi, 0xE1, 0xBA, 0xAB); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x10, 0x01, 0x47, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C, 0x14, 0x04, 0x50, 0x50, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x56, 0x53, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33, 0x30, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0xB0, 0x00, 0x00, 0x10, 0x00, 0x10, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, + 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, + 0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7C, + 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, + 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, + 0x46, 0x39, 0x26, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0xFF, 0x87, 0x12, 0x34, 0x44, 0x44, + 0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0F, + 0x00, 0x00, 0xC1); + mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x54, 0x94, 0x02, 0x85, 0x9F, 0x00, + 0x7F, 0x00, 0x54, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, + 0x22, 0x20, 0x44, 0xFF, 0x18, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC3, 0x86, 0x46, 0x05, 0x05, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0F, 0x0F, 0x0D, 0x0D, 0x13, 0x13, 0x11, + 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC4, 0x07, 0x07, 0x04, 0x04, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0E, 0x0E, 0x0C, 0x0C, 0x12, 0x12, 0x10, + 0x10, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC6, 0x2A, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0xC8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0xCA, 0xCB, 0x43); + mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x0E, 0x4B, 0x4B, 0x20, 0x19, 0x6B, + 0x06, 0xB3); + mipi_dsi_dcs_write_seq(dsi, 0xD2, 0xE3, 0x2B, 0x38, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x00, 0x01, 0x00, 0x0E, 0x04, 0x44, + 0x08, 0x10, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xE6, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF0, 0x12, 0x03, 0x20, 0x00, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF3, 0x00); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + + msleep(120); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set panel on: %d\n", ret); + return ret; + } + + return 0; +} + +static int boe_th101mb31ig002_disable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + dev_err(dev, "Failed to set panel off: %d\n", ret); + + msleep(120); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + + return 0; +} + +static int boe_th101mb31ig002_unprepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + gpiod_set_value_cansleep(ctx->reset, 1); + gpiod_set_value_cansleep(ctx->enable, 0); + regulator_disable(ctx->power); + + return 0; +} + +static int boe_th101mb31ig002_prepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_enable(ctx->power); + if (ret) { + dev_err(dev, "Failed to enable power supply: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable, 1); + msleep(50); + boe_th101mb31ig002_reset(ctx); + boe_th101mb31ig002_enable(panel); + + return 0; +} + +static const struct drm_display_mode boe_th101mb31ig002_default_mode = { + .clock = 73500, + .hdisplay = 800, + .hsync_start = 800 + 64, + .hsync_end = 800 + 64 + 16, + .htotal = 800 + 64 + 16 + 64, + .vdisplay = 1280, + .vsync_start = 1280 + 2, + .vsync_end = 1280 + 2 + 4, + .vtotal = 1280 + 2 + 4 + 12, + .width_mm = 135, + .height_mm = 216, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static int boe_th101mb31ig002_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, + &boe_th101mb31ig002_default_mode); + if (!mode) { + dev_err(panel->dev, "Failed to add mode %ux%u@%u\n", + boe_th101mb31ig002_default_mode.hdisplay, + boe_th101mb31ig002_default_mode.vdisplay, + drm_mode_vrefresh(&boe_th101mb31ig002_default_mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + connector->display_info.bpc = 8; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + /* + * TODO: Remove once all drm drivers call + * drm_connector_set_orientation_from_panel() + */ + drm_connector_set_panel_orientation(connector, ctx->orientation); + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static enum drm_panel_orientation +boe_th101mb31ig002_get_orientation(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + return ctx->orientation; +} + +static const struct drm_panel_funcs boe_th101mb31ig002_funcs = { + .prepare = boe_th101mb31ig002_prepare, + .unprepare = boe_th101mb31ig002_unprepare, + .disable = boe_th101mb31ig002_disable, + .get_modes = boe_th101mb31ig002_get_modes, + .get_orientation = boe_th101mb31ig002_get_orientation, +}; + +static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx; + int ret; + + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + ctx->dsi = dsi; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_MODE_LPM; + + ctx->power = devm_regulator_get(&dsi->dev, "power"); + if (IS_ERR(ctx->power)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), + "Failed to get power regulator\n"); + + ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable), + "Failed to get enable GPIO\n"); + + ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), + "Failed to get reset GPIO\n"); + + ret = of_drm_get_panel_orientation(dsi->dev.of_node, + &ctx->orientation); + if (ret) + return dev_err_probe(&dsi->dev, ret, + "Failed to get orientation\n"); + + drm_panel_init(&ctx->panel, &dsi->dev, &boe_th101mb31ig002_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err_probe(&dsi->dev, ret, + "Failed to attach panel to DSI host\n"); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id boe_th101mb31ig002_of_match[] = { + { .compatible = "boe,th101mb31ig002-28a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, boe_th101mb31ig002_of_match); + +static struct mipi_dsi_driver boe_th101mb31ig002_driver = { + .driver = { + .name = "boe-th101mb31ig002-28a", + .of_match_table = boe_th101mb31ig002_of_match, + }, + .probe = boe_th101mb31ig002_dsi_probe, + .remove = boe_th101mb31ig002_dsi_remove, +}; +module_mipi_dsi_driver(boe_th101mb31ig002_driver); + +MODULE_AUTHOR("Alexander Warnecke "); +MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel"); +MODULE_LICENSE("GPL"); -- GitLab From 30cc664f0962ed1e62d9009a34bf04b48e1a5a4a Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Mon, 8 Jan 2024 15:29:01 +0530 Subject: [PATCH 0273/1420] dt-bindings: display: panel: Add Novatek NT36672E LCD DSI Document Novatek NT36672E FHD+ LCD DSI panel. Signed-off-by: Ritesh Kumar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240108095902.22725-2-quic_riteshk@quicinc.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20240108095902.22725-2-quic_riteshk@quicinc.com --- .../display/panel/novatek,nt36672e.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml new file mode 100644 index 0000000000000..dc4672f3d01d7 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/novatek,nt36672e.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT36672E LCD DSI Panel + +maintainers: + - Ritesh Kumar + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: novatek,nt36672e + + reg: + maxItems: 1 + description: DSI virtual channel + + vddi-supply: true + avdd-supply: true + avee-supply: true + port: true + reset-gpios: true + backlight: true + +required: + - compatible + - reg + - vddi-supply + - avdd-supply + - avee-supply + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "novatek,nt36672e"; + reg = <0>; + + reset-gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>; + + vddi-supply = <&vreg_l8c_1p8>; + avdd-supply = <&disp_avdd>; + avee-supply = <&disp_avee>; + + backlight = <&pwm_backlight>; + + port { + panel0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; +... -- GitLab From ea4f9975625af861c2795c557b8fab2b492ff749 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Mon, 8 Jan 2024 15:29:02 +0530 Subject: [PATCH 0274/1420] drm/panel: Add support for Novatek NT36672E panel driver Add support for the 1080x2408 Novatek NT36672E video mode DSI panel driver. Signed-off-by: Ritesh Kumar Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20240108095902.22725-3-quic_riteshk@quicinc.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20240108095902.22725-3-quic_riteshk@quicinc.com --- drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-novatek-nt36672e.c | 643 ++++++++++++++++++ 3 files changed, 654 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36672e.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index cd2b6ebf8d823..23b089a2103de 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -449,6 +449,16 @@ config DRM_PANEL_NOVATEK_NT36672A around the Novatek NT36672A display controller, such as some Tianma panels used in a few Xiaomi Poco F1 mobile phones. +config DRM_PANEL_NOVATEK_NT36672E + tristate "Novatek NT36672E DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Novatek NT36672E DSI Video Mode + LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit + RGB per pixel. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 015bb8d70fbdb..1c4f4e7f25bb8 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c new file mode 100644 index 0000000000000..d4e85c2fc8999 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include