From 939fcf7b8691b9e9ac80e92eedeb14476069021b Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Sep 2023 13:34:08 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c index bafdfe49c1d8..dc9dea664a28 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) -- cgit v1.2.3 From 4c6e6c01d82fc0edd8b47cb1ffbd05289029b005 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:03 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index b5f73502e3dd..be2f459c66b5 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; -- cgit v1.2.3 From 4cb91cc2cd0d31ffc690b23c88901f4f315b9d78 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:04 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a8d3fa81e4ec..a3a17316a328 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) -- cgit v1.2.3 From a10a43eee8589221d79b9050556aed2c5842d8b8 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 2 Oct 2023 19:12:05 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a3a17316a328..8fe39e31d22d 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); } -- cgit v1.2.3 From 9afc1e0aa4851ef48482b03f6304047cf9b550ca Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:27 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index ec87c4fc1ad5..c92fe2052ef6 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 81661d8827aa..779fbc038f17 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 e261e3660d0b..2f51c833a536 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 000000000000..029e1f094bb0 --- /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 46ff9c75bb12..02b96d23fdb9 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) { -- cgit v1.2.3 From e6f7c641fae339cd5df28186677de1741e0c40c7 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:28 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index c92fe2052ef6..f570530bbb60 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 779fbc038f17..ba4e5c689164 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 000000000000..fd4502c18de6 --- /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 e0a77671edd6..d978dc539a9b 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, -- cgit v1.2.3 From 995279d280d1ef5cc349b6eafee4dccd720c99bf Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:29 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index f570530bbb60..468535f7eed2 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 000000000000..1f8a4f8adc92 --- /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 ba4e5c689164..7b7c1fa805fc 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; -- cgit v1.2.3 From 8acf543cc68cefb0b41011fd66d5e11fd8fcee56 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Dec 2023 15:25:57 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 129e2b91dbfe..e6b5b06de148 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) -- cgit v1.2.3 From afe6fcb9775882230cd29b529203eabd5d2a638d Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 24 Oct 2023 08:07:38 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index fbfe92a816d4..e419b76e57d3 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); -- cgit v1.2.3 From 11aa6d78ab8b135bdeba0bdaa10e63527c837b89 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 13 Dec 2023 12:19:51 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index ccb5d74fa227..682011166a8f 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 dc2dcb5ca1c8..88af956ad0e7 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 83341576630d..bad3b8fcc726 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 -- cgit v1.2.3 From 0800880f4eb789b7d299db40f2e86e056bd33a4e Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Wed, 4 Oct 2023 22:10:55 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index ef02d530f78d..ae12d001a04b 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) -- cgit v1.2.3 From 830c1ded356369cd1303e8bb87ce3fea6e744de8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:08 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index e419b76e57d3..0c8ad8ee5009 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 @@ unregister: mipi_dsi_host_unregister(&dsi->host); mipi_free: tegra_mipi_free(dsi->mipi); +remove: + tegra_output_remove(&dsi->output); return err; } -- cgit v1.2.3 From 5286a9fc280c45b6b307ee1b07f7a997e042252c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:09 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 0c8ad8ee5009..db606e151afc 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); -- cgit v1.2.3 From 643ae131b8598fb2940c92c7d23fe62823a119c8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:10 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index a1fcee665023..417fb884240a 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) -- cgit v1.2.3 From bc456b5d93dbfdbd89f2a036f4f3d8026595f9e4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:11 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index fc66bbd913b2..53c492b13d12 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) -- cgit v1.2.3 From 45c8034db47842b25a3ab6139d71e13b4e67b9b3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:12 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 53c492b13d12..1e8ec50b759e 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; -- cgit v1.2.3 From 2db4578ef6ffb2b52115ca0ebf897b60ec559556 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:13 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 88af956ad0e7..4da3c3d1abbc 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) -- cgit v1.2.3 From c3b78577462782e20c18cd30f8fe9b735746467b Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:51 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 615cc8f950d7..b8b29b291b72 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, }; -- cgit v1.2.3 From 31094d3d2a5c67a9d47ea64eea38ba27335ff67f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:52 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index b8b29b291b72..637d38ec7628 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 -- cgit v1.2.3 From f8a4ac9e9e3c56047c3f92748c30fb90476015e4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:53 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 637d38ec7628..e07b71d1ea8e 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), }; -- cgit v1.2.3 From b36bc498d1837398e5b355c019dc400201040811 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:54 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index e07b71d1ea8e..45f8876210fe 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 = { -- cgit v1.2.3 From ef34c0eb0b58dfdd846093b1a26e63a08acaaf22 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:55 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 45f8876210fe..d1cde022cb5e 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), -- cgit v1.2.3 From 230dae78d6d4531cd440daa782533d16ea3cfc33 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:56 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index d1cde022cb5e..10465398d4e6 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, -- cgit v1.2.3 From 9203f67272531ee17d58966e51f086e9a5deb840 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:57 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 10465398d4e6..eb0d82a91cb9 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 -- cgit v1.2.3 From 045159f5018eee5fd2b502dbbfdc31985ac8f516 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 7 Dec 2023 17:10:43 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index be5914caa17d..98cd589e4427 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; -- cgit v1.2.3 From 3a63826c720675f35144a444b9a8e506493f5166 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 15 Dec 2023 13:11:29 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 31cfe2c2a2af..4b8b8f8a0e72 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 -- cgit v1.2.3 From 4464af92f276537716db87aa21828190b5e12463 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:50 +0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index a0b6f69b916f..44acf9cacaf7 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; -- cgit v1.2.3 From f4ccd9fea227070497df29d68dcbcb55bdb3a9e3 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:51 +0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 44acf9cacaf7..b059f5895d3a 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"), -- cgit v1.2.3 From 7c8690d8fc80e6149d9a8c85d22ba03f4d8dcc69 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:52 +0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index b059f5895d3a..e23737284f31 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"), -- cgit v1.2.3 From 0547692ac14650d0574e065094891bed31e37007 Mon Sep 17 00:00:00 2001 From: Xuxin Xiong Date: Mon, 18 Dec 2023 17:59:33 +0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index e23737284f31..cd05c76868e3 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"), -- cgit v1.2.3 From 4773293bc564b967e8f863e05dbcc729a58b0409 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 19 Dec 2023 12:47:45 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 39b3f7c0c77c..f9010094ff29 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; } -- cgit v1.2.3 From 547a720e8e8f1b2c93f29a5dbe7315e285eb73a6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 19 Dec 2023 12:47:46 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index f9010094ff29..ee29fcb860e4 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; } } -- cgit v1.2.3 From 86ceaaaec59707b06216a15b3852867fa2f1574e Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 28 Nov 2023 08:25:05 -0800 Subject: 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 --- drivers/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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 12cb2ef8dbd6..8968a09f3e44 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 1d3ebdf4069b..0e21ce9d3e5a 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 8dadb2f8436d..000000000000 --- 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 6a2a78c61f21..a72cecd2dbc7 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 c166ad5e187a..02e10451867a 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); -- cgit v1.2.3 From 47cdb66a55f559e89da55a1e305530633e7f6f7c Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 6 Dec 2023 22:09:48 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 9227f8146a58..6b69ef0cdbb4 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; -- cgit v1.2.3 From 8e1cd40ddfbaaac475e521db7b699a906dad895b Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:40 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0b24c0cba94e..7194d844a2b4 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 -- cgit v1.2.3 From 6c7ffa7a1c92c161d4876e5b267bdac50b8a5435 Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:41 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7194d844a2b4..8cbf026a27ab 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 27dc903f0553..220fcd9f8f1d 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) -- cgit v1.2.3 From 3ee302ec22d6e1d7d1e6d381b0d507ee80f2135c Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Wed, 13 Dec 2023 13:15:42 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8cbf026a27ab..dcfcc626d503 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) -- cgit v1.2.3 From 89d6708d947ac76cd5444ca93dd5cedf084212f9 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 24 Nov 2023 17:55:23 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c985ebb6831a..0da9bcce25b1 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 }, {} }; -- cgit v1.2.3 From 20277d8c1ff57b575dc2c1a1b2898cf211c51800 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 15 Dec 2023 15:02:03 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 322c1eccecca..1ca917b8315c 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; -- cgit v1.2.3 From 717cf0a78340f5bf0e47ed5000e6b8685890d9d7 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Mon, 18 Dec 2023 08:33:01 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c index b0a7896f7fcb..a75eeba7bfe5 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; -- cgit v1.2.3 From 4e124151fcfc3b13786b81627b5d4f0373d3c8f1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 15 Dec 2023 13:45:31 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 482cb0df9f15..76b31d542e1a 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 ef79552e4f2f..d205d684d809 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 5f61dd87c586..7d6b86d602c8 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 727bdc429212..e73b84e01ea1 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) -- cgit v1.2.3 From 6901f732691f12154f35ee405c25b00ef51266ab Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:35 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/instructions/xe_mi_commands.h b/drivers/gpu/drm/xe/instructions/xe_mi_commands.h index 1cfa96167fde..c74ceb550dce 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 b7fa3831b684..44586e612eaf 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; -- cgit v1.2.3 From 54020e2b406d8d4be6d79409957f2130e93b4fa3 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:36 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h index 5592774fc690..bd9c956f48a7 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) -- cgit v1.2.3 From e3408839dd27b2645636f91c85a7fd847e36cb91 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:37 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h index 4be81abc86ad..1825d8f79db6 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 -- cgit v1.2.3 From 7158a688935ca90c5036e67b2b95c3119b3a0ac7 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:38 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 1dd361046b5d..6aaaf1f63c72 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) -- cgit v1.2.3 From 35c933f68048da55ca043b1a2f1fef386e133a9d Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:39 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 1fa5cf5eea97..832989c83a25 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 39908dec042a..dfeaaac08b7f 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; /** -- cgit v1.2.3 From f15de1936f8d1bb5b4f7ee55da7fdba8c7540792 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:40 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index 9b1279aca127..97b32528c600 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 3efd2d066bf7..c639dbf3bdd2 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; -- cgit v1.2.3 From a6581ebe76856bf23d1a7f3ee95828173b560a05 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:41 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 53bd2a8ba1ae..9214915d9566 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 d9ae77fe7382..86867d42d532 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 3da83b233206..af8ac2e9e270 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 c45ef17b3473..71f23ac365e6 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 000000000000..76e95535d7f6 --- /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 000000000000..2d40d03c3095 --- /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 000000000000..625b6b8736cc --- /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 -- cgit v1.2.3 From 9a30b04f15f043cdb5add993413a4fc5b692b25f Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:42 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index 44586e612eaf..f17e9785355e 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; -- cgit v1.2.3 From aef4eb7c7dec62f8b289651540fcc851257b1a16 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:43 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 76b31d542e1a..811e8b201270 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); -- cgit v1.2.3 From b130289b23244dc5bc5fcbd42ac57ad689cccae9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 17:53:44 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index d1f5ba4bb745..907c8ff0fa21 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 -- cgit v1.2.3 From b2e1f97fb41843ddee5afbf4ba7812642f3cfab9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:20 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_printk.h b/drivers/gpu/drm/xe/xe_gt_printk.h index 5991bcadd47e..c2b004d3f48e 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 -- cgit v1.2.3 From e8b9b3097ca82f29d4e4e32d0ad79732ed041b7c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:21 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c index 7eef23a00d77..e3a4131ebb58 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; } -- cgit v1.2.3 From 587c73343ac79000223b05e1e58a0657a0b59f01 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:22 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 9214915d9566..a1aa0028e153 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 000000000000..15816f90e960 --- /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 000000000000..c250fa0ca9d6 --- /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 cd80802e8918..16de203c62a7 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 25e1ddfd2f86..4408ea1751e7 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: -- cgit v1.2.3 From 4ceb8645bd85aeefab0929ada82a95603c6e1f2b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:23 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 602793644f61..f62809ca8b51 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 811ffe5bd9fd..f40dcec83992 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; -- cgit v1.2.3 From 5095d13d758b4e602eb78771abf65ee5dc867645 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:24 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index a1aa0028e153..df8601d6a59f 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 000000000000..6d72dbf06139 --- /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 000000000000..067a1babf049 --- /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 -- cgit v1.2.3 From 0b75475723b182400a4bfa5aaff9a969afdfdb76 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:25 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c index 6d72dbf06139..fefe79b3b75a 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; } -- cgit v1.2.3 From d8ba1ede4cbd8df3a2a9a8a089df04398b8a7db6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:26 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c index 4a6972897675..21e77026518b 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 */ -- cgit v1.2.3 From 29d52c9c1b9d1abdbddc9b6cbd8eb2d70b025e6c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:27 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index a53c22a19582..3d7f3ef62ae9 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; -- cgit v1.2.3 From 90ad6f3017894860429bc1f8820024e0b177e676 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:28 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/.kunitconfig b/drivers/gpu/drm/xe/.kunitconfig index 9590eac91af3..ad4b9b4a9f55 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 -- cgit v1.2.3 From 6e2546131750a7c5e5dc668f9050d6a99c095d51 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 18 Dec 2023 20:06:29 +0100 Subject: 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 (limited to 'drivers/gpu/drm') 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 000000000000..a87a7b4b040a --- /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 15816f90e960..c1c04575d82d 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 -- cgit v1.2.3 From c5be725eb09de1f1083ba9b4762460ebc66b669c Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Tue, 19 Dec 2023 12:26:13 +0530 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 7d6b86d602c8..3456ca6f7b32 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 */ -- cgit v1.2.3 From 0eb16fd26795639d5420b58bb12d11c7705e6dfa Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 6 Dec 2023 13:14:41 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/abi/guc_messages_abi.h b/drivers/gpu/drm/xe/abi/guc_messages_abi.h index 3d199016cf88..ff888d16bd4f 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 24a33fa36496..4cde93c18a2d 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 @@ retry: 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; } -- cgit v1.2.3 From da2d668480c37d43a423ff7822caba2e0c58c4ac Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Fri, 15 Dec 2023 10:39:16 +0530 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index ee29fcb860e4..c3e692e7f790 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); -- cgit v1.2.3 From e11300a1d8e38a2311beaebdd2169a15265de103 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:03 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 3fdd8a517983..bbdc2041a990 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 b6e2e70e1290..9d5dc3fb6f20 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); -- cgit v1.2.3 From 00076671a648e1d10ebbccf2fa71bf7edbedddb8 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:04 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index bbdc2041a990..b9b9d9f2bc0b 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 dcfcc626d503..d1cb325c64d1 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 9d5dc3fb6f20..d9fffc802335 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) -- cgit v1.2.3 From 31a5b6ed88c79b2b80262a3060c2f13a12397ea4 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:05 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d1cb325c64d1..6607dba8049e 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 05db46b111f2..b911706d2e95 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 d9fffc802335..494d08817d71 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); -- cgit v1.2.3 From fde53fa18d8e859adaadec0ecdad3d267e3b010b Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:06 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6607dba8049e..173562f4ec45 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] -- cgit v1.2.3 From 6b6276138450617575f1a3176de3a9e289dfa3db Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:07 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 66b4c3f3ceb1..9b9a30c11e1c 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 173562f4ec45..f4a22d40eec2 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; -- cgit v1.2.3 From 16448cf437ea935b0b05ad4c5891b5bc430fa6ff Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:08 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 12a29363e5df..2746655bcb26 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); } -- cgit v1.2.3 From bac2d7d8e64bb06522a438a79d9f12f942069b5d Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 20 Dec 2023 12:36:09 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 39e4f5f7c817..eedef8121ff7 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); } -- cgit v1.2.3 From 0c68132df6e66244acec1bb5b9e19b0751414389 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Mon, 18 Dec 2023 16:05:43 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index f92c2a464ebe..dbbc95d18550 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); } -- cgit v1.2.3 From 0e209fa7bf66e8a5b8a9efdc4d4926dcb441af18 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 21 Dec 2023 14:28:04 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig index 5b3da06e7ba3..a53b0fdc15a7 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 -- cgit v1.2.3 From 570a8fc233b2adb659015bfb09f90a46a6b594d4 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 7 Dec 2023 09:51:17 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h index bd9c956f48a7..0b1266c88a6a 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 e66ae1bdaf9c..3fa2ece7d228 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 3456ca6f7b32..b77d406e083e 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)) + }, {} }; -- cgit v1.2.3 From a196a5166e0812db267281c32fa0724fc5be6582 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Fri, 22 Dec 2023 12:52:17 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 23bf16f596f6..cd5eefa06060 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; } -- cgit v1.2.3 From e7b2d82d420a389da078be315b80cc5bc18ee734 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 21 Dec 2023 12:54:14 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 49e24b7cf675..96673dc707e7 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); -- cgit v1.2.3 From 7353c3d7c15017140a8b984e41f94be0bf535e73 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:29 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 c573c067779f..03bc7f9d191b 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; }; -- cgit v1.2.3 From cd1d91115ff1929ec346d85f512ef260ddf8131e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 28 Dec 2023 15:49:46 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.h b/drivers/gpu/drm/i915/gt/intel_gsc.h index 7ab3ca0f9f26..013c64251448 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 { -- cgit v1.2.3 From e4cf1a70fad3e2107503e99cfe9cc0c9cba19dad Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:31 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index e22c12ce245a..813cc888e6fa 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; -- cgit v1.2.3 From aa253baca534357e033bd29b074ce1eade2a9362 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Dec 2023 11:54:32 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index 13b1ae9b96c7..46445248d193 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; -- cgit v1.2.3 From 407eaa4aa64a8429094fa75fac00fff5e471138d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:53 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index c51ca82320cb..b9ee02061d5b 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 406e981c75bd..fbf1bcc68625 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 -- cgit v1.2.3 From 47a145c03484d33e65d773169d5ca1b9fe2a492e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:54 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f6d819803c0e..50c984ac107d 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; -- cgit v1.2.3 From 099be7b6718685ebafb417e74bb637abf992474a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:55 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 50c984ac107d..a50d1d7e9e06 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, }; -- cgit v1.2.3 From 8f0df2012b8a94aed0cc450016f7592c24e92cfb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:56 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index a50d1d7e9e06..0b16e449c17b 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) -- cgit v1.2.3 From ff4d4fa76fcc19f7d5d261f717121f0a88ec4e30 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:57 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 0b16e449c17b..4616ff8c22e7 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 -- cgit v1.2.3 From d3e040f450ec8e46ff42fa495a433b976ab47686 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:58 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 4616ff8c22e7..38990a13ee19 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 -- cgit v1.2.3 From d7ba3d711cf537ef0ece14cd85d2113ca338a00b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:59 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 38990a13ee19..437c5dcbab0d 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; -- cgit v1.2.3 From f8723484e045ff2d176124484907ec0199c55a0c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:00 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 437c5dcbab0d..6120ab8dd8fd 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); -- cgit v1.2.3 From c1ceee3248742149d1a602fd913bd88857da1d52 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:01 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 6120ab8dd8fd..3cb84943646f 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 || -- cgit v1.2.3 From 139771b8239c43ad1bd6c2976aa12788096a5483 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:02 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 3cb84943646f..b5ba5fecbec9 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 -- cgit v1.2.3 From 5f92474844a4fcb7997da20dd1de2031aed1d794 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:03 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index b5ba5fecbec9..682087275aeb 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) -- cgit v1.2.3 From aa4f96e2de82f5e0dfc0102d08f66918c5e3637f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:04 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 682087275aeb..08b5e4da4718 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 -- cgit v1.2.3 From cc9ec38cb2cd32518fe02615d004e96ce2fd0348 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:05 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 08b5e4da4718..90a163029773 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) -- cgit v1.2.3 From 4278ff62b73936a9138b60cc0610381003132b77 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:06 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 90a163029773..bec91a14965b 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) -- cgit v1.2.3 From 153fe8dbd866869846af3a359ecf82d5ad9fe247 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:07 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index bec91a14965b..f17f0c4859d3 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)) -- cgit v1.2.3 From 073aa696f8cbc170a2c3502c2165aeb835be0156 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:08 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f17f0c4859d3..610e7241e4f3 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; -- cgit v1.2.3 From f68a68fe9d9197ea6aa9cb461270685f370b165e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:09 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 610e7241e4f3..9fb1e49bc909 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 -- cgit v1.2.3 From ceeb0f0104a62c867656c2730a51df47e7350b8f Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:10 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 9fb1e49bc909..c6a4b228ea93 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 = { -- cgit v1.2.3 From 164abbd2b7ef62aae6fc80450a2d085acdc3da3e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:11 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index c6a4b228ea93..fbf73f6b99ca 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 * -- cgit v1.2.3 From 71892cee6ceb3e1b88e0bb44b05c8397d8261a85 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:12 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index fbf73f6b99ca..763d61704ee6 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, -- cgit v1.2.3 From f01e33cb586b5fd354cba73052f82c3b4246109d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:13 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 763d61704ee6..da77171b2b42 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 93245b55f967..a7edf3559e60 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 -- cgit v1.2.3 From b4299c936d8fd62b75621cad8dbf8aa9178e7c0e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:21 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 84e035a7ab3f..84bfde31d172 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 bef293922b98..447d0c7c88c6 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 @@ power_off: 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 075c5c3ee75a..a4554018bb2a 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 }; -- cgit v1.2.3 From b8a5d1f4a08751031a18621ce1b59fc49d042494 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 16 Dec 2023 14:15:27 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 00e713faecd5..b8184374332c 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; -- cgit v1.2.3 From ffcc67cd79ff2e93fd0bdb837c99cbab6c59d38c Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:22 -0500 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4b8b8f8a0e72..628f90ed8a9b 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 000000000000..b9ecdebecb0b --- /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. -- cgit v1.2.3 From 2fee84030d12d9fddfa874e4562d71761a129277 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:24 -0500 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 3c99fb8b54e2..e7441b227b3c 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); -- cgit v1.2.3 From 0c75d52190b8bfa22cdb66e07148aea599c4535d Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sat, 23 Dec 2023 19:32:48 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f4715a67e340..08fcefd804bc 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 */ -- cgit v1.2.3 From 835e4d9bb3a13879031942ca6692d5a82ec00158 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 2 Jan 2024 01:02:31 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 63724e17829a..f7372f736a77 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; -- cgit v1.2.3 From 93cbc1accbcec2740231755774420934658e2b18 Mon Sep 17 00:00:00 2001 From: Haridhar Kalvala Date: Wed, 20 Dec 2023 00:22:33 +0530 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 612d4cd9dacb..696ae59874a9 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 aa169b0055e9..0e61e424802e 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 0da9bcce25b1..c5fecde7afa8 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 a7d8f3fc98de..6964f4b95865 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 40d7b6f3f489..854566ba5414 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 04f62f27ad74..76076509f771 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 a8fa3a20990e..2d65a538f83e 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 240beafb38ed..3cad6dac06b0 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 1b03ea60a7a8..89e89ede265d 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) -- cgit v1.2.3 From 09d015deddd6234430c04a1eddaa8a28fd621dec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Dec 2023 17:19:55 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c index 5c514946bbad..1c7c7f61a222 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); -- cgit v1.2.3 From ecc8271f56d317627b5875918f2ac7e94242ea6d Mon Sep 17 00:00:00 2001 From: Ghanshyam Agrawal Date: Fri, 15 Dec 2023 11:00:16 +0530 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 36987ef3fc30..272141b6164c 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 -- cgit v1.2.3 From 834b1d72051145e553222926b1a375f5441b24eb Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:41:02 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ba0c0e12cfe9..6bc23bdf32c2 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) { -- cgit v1.2.3 From 89709105a6091948ffb6ec2427954cbfe45358ce Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 4 Dec 2023 17:14:16 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index ceb4d3d3b965..a0b47c9b33f5 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); -- cgit v1.2.3 From 85110d04688d7a12ff594f1152c0ae85f3b90bbe Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:56:38 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 680441bb1786..10498725034c 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. */ -- cgit v1.2.3 From 27571c64f1855881753e6f33c3186573afbab7ba Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sun, 24 Dec 2023 00:25:40 -0500 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5fd0ccaa0b41..8589a1c3cc36 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; } -- cgit v1.2.3 From bb056046c2139c72e20a5b6fc39c9caaf9eac2b8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 3 Jan 2024 19:13:01 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index bd08d57486fe..7069a3d4d581 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); -- cgit v1.2.3 From 5f2e93e6719701a91307090f8f7696fd6b3bffdf Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:14 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index da77171b2b42..676c1cd73862 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, }, {}, }; -- cgit v1.2.3 From aa54f334c291effe321aa4b9ac0e67a895fd7b58 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:15 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 676c1cd73862..5045836993b5 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 @@ err_cleanup_hdmi: 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); -- cgit v1.2.3 From 701029621d4141d0c9f8b81a88a37b95ec84ce65 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:16 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 5045836993b5..22697e714b23 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 -- cgit v1.2.3 From 50a3c772bd927dd409c484832ddd9f6bf00b7389 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:17 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 22697e714b23..925320fef0a8 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, -- cgit v1.2.3 From f4304beadd88d074333b23fdc7f35d00ee763e14 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:39 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 884a1da36089..6b25e195232f 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++) { -- cgit v1.2.3 From 172516e153c9269e02cfd64f11df7142c482ffe2 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:40 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6b25e195232f..fc7211675b2f 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, -- cgit v1.2.3 From 2e13b5bb5e28a098eecd2b5f00d745b27f87e2e8 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Jan 2024 13:57:41 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index fc7211675b2f..d0b6b4e439e1 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]); } } -- cgit v1.2.3 From 79b09453c4e369ca81cfb670d0136d089e3b92f0 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:48 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 59341654ec32..6ecb6b8a1dcd 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) -- cgit v1.2.3 From 52d11c863ac92e36a0365249f7f6d27ac48c78bc Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:49 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 6ecb6b8a1dcd..77b76cff1adb 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) -- cgit v1.2.3 From a1d91c6e989d0e66b89aa911f2cd459d7bdebbe5 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 19 Dec 2023 14:32:46 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index d0b6b4e439e1..ce1bddf74a82 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]; -- cgit v1.2.3 From 65afd91e8d70e10c7f99126d61bf0045ef52d271 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:57 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 6e3670508e3a..69e4b4c97558 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)) { -- cgit v1.2.3 From 056a9965e58e47928e8afd4dc017221f9221b3d3 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:58 +0100 Subject: 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 --- drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 69e4b4c97558..32ebedadbcdc 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); -- cgit v1.2.3 From 9b0b61c5bc08e1aa55a0c1e7cda28f952b2d02cc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 3 Jan 2024 17:26:09 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 494d08817d71..54120b45958b 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); -- cgit v1.2.3 From de06b42edc5bf05aefbb7e2f59475d6022ed57e1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 18:46:00 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index f78bfcf2ce00..42da2af80976 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]); -- cgit v1.2.3 From a133e35bc65007379b8fd58c02d8035396fe4be4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:46 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 6964f4b95865..99843883cef7 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 | -- cgit v1.2.3 From 102971422e578c55381e0f5e38577293bbf8d919 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:47 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b70502586ab9..835781624482 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", -- cgit v1.2.3 From fbfb125c849282b00c130f5497bd51e1a76037c8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:48 +0200 Subject: 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 --- drivers/gpu/drm/i915/display/intel_hdcp_regs.h | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h index 8023c85c7fa0..a568a457e532 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)) -- cgit v1.2.3 From ee3c386e4bee2cae6fc88defd15052e3f4c3e18b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:49 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 0b522c6a8d6f..c02d79b50006 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); -- cgit v1.2.3 From 39c9f38e1ad36d4f87e5506806001543cf4274ec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 19:43:50 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index d4386cb3569e..9a217805d2f6 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 { -- cgit v1.2.3 From c27f010aa1884276ee5dae72034d84987060c769 Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Thu, 4 Jan 2024 08:24:09 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 482c28b5c2de..a6c7122fd671 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; -- cgit v1.2.3 From fe761f3465c00f372cb4acb004579c7c377ae08b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 18:46:00 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index f23080a4368d..6fd4fa52253a 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]); -- cgit v1.2.3 From fdbadf504375886a0320ac6f84c850322a6b32e1 Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Thu, 4 Jan 2024 08:18:32 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 1c5e30cf10ca..ecb1c0707706 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; -- cgit v1.2.3 From 9bab383d47c934ff550f31b3e05b4509fa6136bd Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Thu, 4 Jan 2024 08:18:41 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 5d2a77b52db4..420eba0e4be0 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); -- cgit v1.2.3 From 0cfb7caefabd740a13ae0c26d092641a5ac7e785 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:22 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 86867d42d532..004e65544e8d 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 71f23ac365e6..163d889d407b 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 42a0e0c917a0..f295d91886b1 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 5af73a3172b0..1545552162c9 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) { -- cgit v1.2.3 From b97d87039fe5a2fc91feb9f42c5b443ad0927864 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:23 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_sriov_types.h b/drivers/gpu/drm/xe/xe_sriov_types.h index 999a4311b98b..1a138108d139 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) -- cgit v1.2.3 From 13f976ea62208d64d2f324bce27f79c574394caf Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:24 +0100 Subject: 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 (limited to 'drivers/gpu/drm') 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 000000000000..17624b16300a --- /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 -- cgit v1.2.3 From e6cbc458b4f875ce35610af635911d6926804c4c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:25 +0100 Subject: 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 (limited to 'drivers/gpu/drm') 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 000000000000..aeeb573c6842 --- /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 -- cgit v1.2.3 From e83679985ac73cca54259abaf7d55835c150bbe4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:26 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 3b83f907ece4..4aaed1cb4e12 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 -- cgit v1.2.3 From fa6c12e036c9450c43782d52648bf0fb915a7bbb Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:27 +0100 Subject: 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 --- drivers/gpu/drm/xe/abi/guc_actions_sriov_abi.h | 174 +++++++++++++++++++++ drivers/gpu/drm/xe/abi/guc_relay_actions_abi.h | 79 ++++++++++ .../gpu/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 (limited to 'drivers/gpu/drm') 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 000000000000..5496a5890847 --- /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 000000000000..747e428de421 --- /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 000000000000..f92625f04796 --- /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 -- cgit v1.2.3 From 811fe9f556fcb281ea2db1b0fff3bab20f0a4d42 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:28 +0100 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index df8601d6a59f..6952da8979ea 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 811e8b201270..311a0364bff1 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 000000000000..0e7383256408 --- /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 000000000000..385429aa188a --- /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 000000000000..5999fcb77e96 --- /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 16de203c62a7..dc6059de669c 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 */ -- cgit v1.2.3 From 4469eae6bc52b3746b39941f90b9213bcef0255a Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:29 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 4cde93c18a2d..8f208267ffc6 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 @@ retry_same_fence: 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); } -- cgit v1.2.3 From 927b042a8daf2c773fd1802b388e22ca6087235c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:30 +0100 Subject: 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 (limited to 'drivers/gpu/drm') 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 000000000000..13701451b923 --- /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 0e7383256408..b772088979bd 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 @@ wait: 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 -- cgit v1.2.3 From 26d4481ac23fe16bb7d64d2b43db250bcb65003e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 4 Jan 2024 23:20:31 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 8f208267ffc6..c29f095aa1b9 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); } -- cgit v1.2.3 From 0d68d06553ee9ad6d4ffc000599765211cad4930 Mon Sep 17 00:00:00 2001 From: Ruthuvikas Ravikumar Date: Sat, 23 Dec 2023 00:53:52 +0530 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_mocs.c b/drivers/gpu/drm/xe/tests/xe_mocs.c index 7dd34f94e809..df5c36b70ab4 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 ef56bd517b28..4f62e7a4270b 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 7faa3575e6c3..e7699d495411 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 -- cgit v1.2.3 From c5b32a41946139b9f4f7a087fda2355a90f671cb Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Wed, 3 Jan 2024 11:01:11 +0530 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 3eacbc50caf8..270b56fc85e2 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, -- cgit v1.2.3 From 5343f29b3dc534be01b45cd3a3e43572996f96f8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 2 Jan 2024 13:21:58 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cb4031d5dcbb..e677dc8eb7a9 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 ac9a406250c5..45238ec5df1b 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 86c1812a8034..7923bc00dc7a 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 c613f0abe9dc..b9bb92e4b029 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, -- cgit v1.2.3 From 2b35ae108c7f5486adbc9e70377110ab8c91f61b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 5 Jan 2024 18:19:47 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index b772088979bd..c0a2d8d5d3b3 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" -- cgit v1.2.3 From a797099562267ebb281acd59750f1a8dbba36eef Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 2 Jan 2024 14:22:02 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 0f79cb658518..52332bb14339 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 ba9e07fc2b57..0945b177d5f9 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); -- cgit v1.2.3 From 3bb45618061c0e1838e99ad246d7342727396451 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:30:25 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 550492a7a031..b99d4e9ff109 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__); -- cgit v1.2.3 From 26a4591b31916e1c53a7c64fa3ba3fc7cc5d549f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:37:37 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index b99d4e9ff109..1abbcdf38430 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 @@ 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__); - return ret; + return -ENOMEM; } EXPORT_SYMBOL(drm_sched_init); -- cgit v1.2.3 From 0fa647659c492c0a4342f7da70f5f946a40df250 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 5 Jan 2024 13:22:43 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index ce1bddf74a82..e67c25975947 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, -- cgit v1.2.3 From f5b6fd4ea320176468597afd8343e4b94544f986 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 5 Jan 2024 09:25:17 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 2fb18b782b05..54fce00e2136 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; } -- cgit v1.2.3 From 2e367ad4da3339e2763a32592cba4f6e1ab53f59 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Jan 2024 18:57:48 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af3ce5a6a636..1596937bb5ad 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; } /* -- cgit v1.2.3 From babebd1dc1279027206583a9921e05657f97da87 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Jan 2024 18:57:49 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3f479483d7d8..d1e1ade66f81 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 fad3c4003b2b..62741a88796b 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); -- cgit v1.2.3 From 264ed178781c05f87735e2712a34c4ab35b0c91c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Jan 2024 09:20:14 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c index a75eeba7bfe5..f69721339201 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; } -- cgit v1.2.3 From 289d4180bda98bfd47e0dac402a1caf2a8f50cf7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:57 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index abaacea5c2cc..b330337b842a 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 f4a22d40eec2..8803a9323353 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 9111e9d46486..83898ba493d1 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 eedef8121ff7..55048c56bc52 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 0362d02d70b6..c660dd88dec7 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 9a217805d2f6..1b19443739c3 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); -- cgit v1.2.3 From f7d16a538ad226d8b60990f8628e1c81787ee62c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:58 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 0c0700c6ec66..74513c3d3690 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); -- cgit v1.2.3 From a1a0e8630711e404952e8d6485715183676b99f9 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:29:59 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 9df9097a0255..da549962fecc 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(); -- cgit v1.2.3 From 24b412b1bfebb29ffca93bec215d26fd3a85a405 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:00 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index da549962fecc..1974f2394a51 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 8dead878e51a..55badc20a10f 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); -- cgit v1.2.3 From f4ed123ae295e3ce6f52d054540fdce258ea47e1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:01 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 55badc20a10f..0d78df3e7eff 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); -- cgit v1.2.3 From 1ef28d86bea92503341215fcc7d934d6156b9ba0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:02 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 0d78df3e7eff..8005a29e78ca 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); -- cgit v1.2.3 From bd738d859e71acb9315634cf38676fd0585d4668 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 15:23:35 +0200 Subject: 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 + drivers/gpu/drm/i915/display/intel_display_core.h | 7 ++ .../gpu/drm/i915/display/intel_display_driver.c | 138 +++++++++++++++++++++ .../gpu/drm/i915/display/intel_display_driver.h | 6 + drivers/gpu/drm/i915/i915_driver.c | 19 ++- 5 files changed, 171 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9b9a30c11e1c..4a1d0613dfe7 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 7349a2b928c0..cd3b34459b87 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 1974f2394a51..dcdd26eefaaf 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 @@ cleanup_bios: 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 c276a58ee329..42cc4af6d3fd 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 8005a29e78ca..7603771ae107 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); -- cgit v1.2.3 From cd572b3bb27e86f4a4c814acabbf1f197259c011 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:04 +0200 Subject: 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 --- drivers/gpu/drm/i915/display/intel_display_core.h | 6 + .../gpu/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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index cd3b34459b87..54278db823df 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 dcdd26eefaaf..ecf9cb74734b 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 8803a9323353..6ce003b97dcc 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 74513c3d3690..d9ec349f3c8c 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 424ae5dbf5a0..a17253ddec83 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__ */ -- cgit v1.2.3 From bab87ef4db9aafeb8f95b7bfa5c12b187c01d13e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:05 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index b330337b842a..b9733a73e21d 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 6ce003b97dcc..b2591148670b 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 8a9432335030..5fa25a5a36b5 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 83898ba493d1..8ca9ae4798a8 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 55048c56bc52..7020e5806109 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 0d8e5320a4f8..073ea3166c36 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 c660dd88dec7..cea909046ccd 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 1b19443739c3..a96bcfcf90a3 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; -- cgit v1.2.3 From 9210e94a5a3bf7fc84b3d94dd5d2099ca434931b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:06 +0200 Subject: 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 ++ drivers/gpu/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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2746655bcb26..922194b957be 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 b9b9d9f2bc0b..3556ccedbe4c 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 b2591148670b..a320bb0292d9 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 b911706d2e95..530cc97bc42f 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 2e2af71bcd5a..b36ef321e835 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 @@ out: 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 dcf05e00e505..80aed9e87927 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 80a61e52850e..936fa2daaa74 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); -- cgit v1.2.3 From 2e4b90fbe75536c978218bb3eb1d04f8988e13cd Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:07 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a320bb0292d9..93f9985ef75c 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 80aed9e87927..f34743e6eeed 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 936fa2daaa74..26c4265368c1 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); -- cgit v1.2.3 From d544d000a3cbf845825508dafe0aebe7f93f0e04 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jan 2024 10:30:08 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index b36ef321e835..4f4a0e3b3114 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; -- cgit v1.2.3 From 5f807f00b5f5de849e7a790864ec1d398cd1222e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 16 Dec 2023 12:11:52 -0800 Subject: 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 --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c | 136 ++++++++++++------------ 1 file changed, 68 insertions(+), 68 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 142079403864..b54f044c4483 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 * */ -- cgit v1.2.3 From 648c3814dcf6fde9e654da01d2963e73077d07fd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:30 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index a34917b048f9..4310ad71870b 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. -- cgit v1.2.3 From 607a9b29ef813f95c8879a45bfb7401ba7df48b5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:31 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c index adf01ca9e035..2af3615c5205 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. * -- cgit v1.2.3 From ce6106ffa9f4ddc3757dd9ad1be321e8b8b3278e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:32 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index c494a1ff2d57..986e8d547c94 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. -- cgit v1.2.3 From eeb8e8d9f124f279e80ae679f4ba6e822ce4f95f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Dec 2023 15:36:33 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 8c2faa964511..ccac88da8864 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) -- cgit v1.2.3 From be8755a0a81866bbf89bf3fb03ae180978b5a91f Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 21 Dec 2023 08:32:13 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index 3d7f3ef62ae9..5cfd5844c17b 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), -- cgit v1.2.3 From bdb7a38a8f409cdc3acdfc1935d09e31735e3ab4 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:35 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c5fecde7afa8..0012e3171f3f 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)) -- cgit v1.2.3 From 7af2f3e55c1ec09bfa04963f4a8d0ef052be22bb Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:36 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0012e3171f3f..b9354ad46fee 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)); -- cgit v1.2.3 From ebb9c4240deaaa54b70926bdc4d4ceb22518c0cb Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:37 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index b9354ad46fee..fbe9aba41c35 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 -- cgit v1.2.3 From 935e486b718fc1c98191137cbf09b05ca5d8b9d6 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 5 Jan 2024 11:05:38 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index fbe9aba41c35..26200ee3e23f 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 */ -- cgit v1.2.3 From ddb5bade29de7a3e1e1ce42df33f4a98f8a9f323 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Thu, 4 Jan 2024 19:26:15 +0100 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 6aaaf1f63c72..6dfad86aaea6 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 832989c83a25..e279ef6c527c 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) + }, {} }; -- cgit v1.2.3 From 49ddab089611ae5ddd0201ddbbf633da75bfcc25 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Wed, 20 Dec 2023 14:13:11 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index cd05c76868e3..7d556b1bfa82 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; -- cgit v1.2.3 From fa78e188d8d1df850eb232a2631012093aeeb0e0 Mon Sep 17 00:00:00 2001 From: Badal Nilawar Date: Thu, 4 Jan 2024 18:37:02 +0530 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8e4a3b1f6b93..2e4d2157179c 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 97b32528c600..350cc73cadf8 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 64c2249a4e40..14ef13b7b421 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 163d889d407b..8404685b2418 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 dcc5ded1558e..7ba2000f535b 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 b429c2876a76..d5f219796d7e 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 6b9031f7af24..64a97c6726a7 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); -- cgit v1.2.3 From cd7b0b2dd3d9fecc6057c07b40e8087db2f9f71a Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 13 Dec 2023 14:46:29 +0530 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 93f9985ef75c..a0d4ef1a0493 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; -- cgit v1.2.3 From 9b26d5c044d6a29ebfb1845408e0f2a7c5f89818 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 8 Jan 2024 21:15:52 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 83a9cf53d269..3ecaf87939e6 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 */ -- cgit v1.2.3 From 219a1f49094f50bf9c382830d06149e677f76bed Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 8 Jan 2024 21:15:53 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 3ecaf87939e6..d3bfdfc9cff6 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, -- cgit v1.2.3 From 1bff93b8bc27a18aa87752819bfda6f00bceb10e Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:49:59 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 54120b45958b..d0495d09e3d7 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); /* -- cgit v1.2.3 From 86b26b6aeac78c396fa022f49c58a4daffffc983 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:50:00 +0200 Subject: 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 --- drivers/gpu/drm/i915/display/intel_display_types.h | 2 + drivers/gpu/drm/i915/display/intel_psr.c | 62 ++++++++++++---------- 2 files changed, 36 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 3556ccedbe4c..13a893f4130a 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 d0495d09e3d7..fa0af5a6816b 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; } -- cgit v1.2.3 From 7f85883e4a7b95559fb61cd202196ac8c8f857d7 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:50:01 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 926e2de00eb5..ecff90e233f0 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 220fcd9f8f1d..75bc08081fce 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) -- cgit v1.2.3 From 3291bbb93e160e8b9b74ed0116738570f8744fe5 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:50:02 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4a1d0613dfe7..e161d9544f2a 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 efe4306b37e0..ceefcc70e8f9 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 -- cgit v1.2.3 From 467e4e061c44ff79cdd2c6b5cbc42842caf189f1 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:50:03 +0200 Subject: 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 --- drivers/gpu/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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 13a893f4130a..ae2e8cff9d69 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 fa0af5a6816b..682ceae00710 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 ceefcc70e8f9..bc252f38239e 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) -- cgit v1.2.3 From f3c2031db7dfdf470a2d9bf3bd1efa6edfa72d8d Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 18 Dec 2023 19:50:04 +0200 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 682ceae00710..dff21a5edeb7 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 */ -- cgit v1.2.3 From 29f424eb8702b686cb6f07ddd659c6312e0c796d Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 13 Dec 2023 17:47:04 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index ba92e5619da3..63e82e5285bc 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 @@ retry: } 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); -- cgit v1.2.3 From f4e8ab468fc6cfaf718bb8610940d57a5e2309ba Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 13 Dec 2023 17:47:05 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index 63e82e5285bc..0c78a377f453 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 -- cgit v1.2.3 From 97d0047cbb17318431eaf37dfe1a6855539340f9 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 4 Jan 2024 00:00:39 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index 0c78a377f453..9db1867878a4 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 @@ retry: } 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 @@ err_unlock_list: 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++) -- cgit v1.2.3 From 5030e16140b655ba00217d47680e697480ac3587 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 2 Jan 2024 12:35:38 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h index f15f8a4857e0..9ecb67db8ec4 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); } -- cgit v1.2.3 From 9d0c1c5618be02c5acda7e6bbb728007b0632984 Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Fri, 22 Dec 2023 18:59:04 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 1ca917b8315c..127842656a23 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); -- cgit v1.2.3 From 9d03bf30e78673d827484bbc17a6fd8f5e43a039 Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Tue, 9 Jan 2024 12:24:02 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index f660cfb79f50..c8c5d74b6e90 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) -- cgit v1.2.3 From 20855b62a30538361e587cfc7c5245f07d4f826a Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Tue, 9 Jan 2024 12:24:03 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 2e4d2157179c..338f9688a2c9 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 8404685b2418..3c2bcd597d2a 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; }; /** -- cgit v1.2.3 From 9d612ee52c6096bc70d43f54921ba2831ffbf1ad Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Tue, 9 Jan 2024 12:24:04 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 3c2bcd597d2a..7eda86bd4c2a 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 */ -- cgit v1.2.3 From dcddb6f0b06d454c9a3b2b240a43f0e7310c7f7c Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Tue, 9 Jan 2024 12:24:05 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index d2b00d0bf1e2..e5d7d5e2bec1 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; -- cgit v1.2.3 From ca077ff8cac5af8a5a3c476983a6dd54aa3511b7 Mon Sep 17 00:00:00 2001 From: xiazhengqiao Date: Thu, 21 Dec 2023 17:30:57 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 2f300f5ca051..b589136ca6da 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); -- cgit v1.2.3 From 5e83c060e95bea2cf76d01fa554cd31a1727e19a Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 27 Dec 2023 20:55:57 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') 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 a259f1118c5a..9c64ae0766cc 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 c57b29cdb1a6..b6df75622d3b 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 3872d309ed31..b8b09b1bee3e 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) -- cgit v1.2.3 From 2f2cc53b5fe7022f3ae602eb24573d52f8740959 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Fri, 29 Dec 2023 13:51:43 -0800 Subject: 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 ++++ drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 73 +++++++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 0d812f4d787d..3b27218aabe2 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 9c64ae0766cc..cae637fc3ead 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); } -- cgit v1.2.3 From 632ca3c92f3840d91ba7ddda0271f84813036a11 Mon Sep 17 00:00:00 2001 From: Chen Haonan Date: Tue, 9 Jan 2024 14:24:11 +0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 5d3190c05250..6daeb7f0b09b 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); -- cgit v1.2.3 From 0e00a8814eec16057e783170456442adde80c0b4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 19 Dec 2023 11:59:57 -0800 Subject: 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 --- drivers/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(-) (limited to 'drivers/gpu/drm') 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 cae637fc3ead..f3dcae4b9d45 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 b8b09b1bee3e..6dfe5d9456c6 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); } -- cgit v1.2.3 From 9fbedddfc90062e09426108335585487647067e3 Mon Sep 17 00:00:00 2001 From: Shekhar Chauhan Date: Tue, 9 Jan 2024 11:25:50 +0530 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 6dfad86aaea6..4017319c6300 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 b77d406e083e..3299130ba10a 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)) + }, {} }; -- cgit v1.2.3 From b16483f9f8120b530327879fa3ea576e897946da Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Fri, 5 Jan 2024 11:04:39 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 21ac68e3246f..5de3ac47c462 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; } -- cgit v1.2.3 From a8004af338f6b3319476ecbed63ea49bf393fc1f Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Fri, 5 Jan 2024 11:04:40 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 44fe8097b7cd..bcfc4127c7c5 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 3d7e704ec3d9..8d4b7feb8c30 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 5de3ac47c462..54ffcfcdd41f 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 adf1dab5eba2..02fca8f9adc2 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); -- cgit v1.2.3 From 4ae3aeab32d7f37cde4724524f5525703e5a9b54 Mon Sep 17 00:00:00 2001 From: Sujaritha Sundaresan Date: Tue, 9 Jan 2024 16:34:18 +0530 Subject: 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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 6952da8979ea..f3495d0e701c 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 5935cfe30204..f153ce96f69a 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 0f8d3e7fce46..0662968d7bcb 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 000000000000..733146293307 --- /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 000000000000..cbe8c12fbd64 --- /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_ */ -- cgit v1.2.3 From 69cac0a8f3ef8db4d62441c4a2686ec676c9facd Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Mon, 8 Jan 2024 14:58:42 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c index 3adfa6686e7c..e5b0f4ecdbe8 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 311a0364bff1..6e73ebf67251 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) -- cgit v1.2.3 From c3c33a139a8831972b9073c442dd6b39382b6c2a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 22:16:30 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 5f490fbf1877..83355dbc15ee 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 a2df4918340c..0608cabed058 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 { -- cgit v1.2.3 From 5465b0a591edc2d4ffa6491ed012c7af36a1b6e0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 22:16:31 +0200 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index f957552c6c50..207aa3f660b0 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 8c6d2ea2a472..94e2c573a7af 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 -- cgit v1.2.3 From a109d19992294736abd4f4232ea639e03eb1f9e7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 10 Jan 2024 06:48:29 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index f3495d0e701c..e16b84f79ddf 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)),) -- cgit v1.2.3 From 284781470de227e6177e491ad091d72492290a65 Mon Sep 17 00:00:00 2001 From: Juan Escamilla Date: Tue, 9 Jan 2024 17:03:00 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') 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 f0dea54880af..2d3c4dab6d21 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) -- cgit v1.2.3 From 6e144a7d6f8a22f22f49f2ecf4268da1c75bcc4a Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:49 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index bcfc4127c7c5..cd2b9a8e51f5 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) -- cgit v1.2.3 From 6ae24344e2e3e12e06f7b382af4bba2fd417b2ff Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:50 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index cd2b9a8e51f5..4ff7e50112ca 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 8d4b7feb8c30..6041892d894e 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 54ffcfcdd41f..392cbde62957 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, -- cgit v1.2.3 From 25ce7c5063b335808e1753ced5f0069981073f17 Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:51 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 4ff7e50112ca..c0b7434e78f1 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 @@ err_lrc: 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 d959cc4a1a82..02ce8d204622 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 a8a895cf4b44..5b84fc9ab8ad 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 3af2adec1295..0f2258dc4a00 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 02fca8f9adc2..83fa92d2a35a 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, -- cgit v1.2.3 From 801e8c7ed6705bd34508f52376cdbb3fc374c921 Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 10 Jan 2024 09:32:52 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 6041892d894e..e7f84dee5275 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 96b5224eb478..58dfe6a78ffe 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 392cbde62957..7c29b8333c71 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, -- cgit v1.2.3 From 86f41f4333e31b62d143c5e38c0c58c85193c4c8 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:36 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 4489aadc7a52..0a61e4413679 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; -- cgit v1.2.3 From 1fd77ceaf0d843af2b7fde83e447b0738d0404cb Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:37 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 0a61e4413679..3ca715e2ec19 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 f74684660475..b15503dabba4 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 */ -- cgit v1.2.3 From d0ca70c0339838198a704b15b7e6c3318f887536 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:38 -0800 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 3ca715e2ec19..13183088401f 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; -- cgit v1.2.3 From 7c0f97cb62dcc57463e3c66301330648cbf9b24a Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 9 Jan 2024 17:24:39 -0800 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 13183088401f..5c2603075af9 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 b15503dabba4..047cde6cda10 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 */ -- cgit v1.2.3 From c10da95afa68060e13c5f920d96671943a7e54d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:22:23 +0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 004e65544e8d..a94c0b27f04e 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) -- cgit v1.2.3 From 88ec23528b32ddb9ce2e8492f2629b0056353697 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:20:35 +0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_bo.c b/drivers/gpu/drm/xe/tests/xe_bo.c index 412b2e7ce40c..3436fd9cf2b2 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); -- cgit v1.2.3 From cf46019e8550a810cc023af7aa020ba43103b44d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Jan 2024 15:20:22 +0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 127842656a23..a7e7a0b24099 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; -- cgit v1.2.3 From ef51d7542d143f3fd9a48d4e2c307563661668aa Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Wed, 10 Jan 2024 17:34:15 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c index 7a32faa2f688..a6523df0f1d3 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 83fa92d2a35a..88a32b272dda 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; -- cgit v1.2.3 From cbe7cea7eece110b75a3e26edf750ca0e2f3ebef Mon Sep 17 00:00:00 2001 From: chenxuebing Date: Thu, 11 Jan 2024 06:39:21 +0000 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index e677dc8eb7a9..d45f86413402 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; -- cgit v1.2.3 From 5ee0d47dcf33efd8950b347dcf4d20bab12a3fa9 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Fri, 5 Jan 2024 14:58:36 -0300 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index b8184374332c..07caf2a47c6c 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); -- cgit v1.2.3 From b9bc05495174759902f226deccc2f68cdc231891 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Thu, 11 Jan 2024 11:28:49 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/ttm/tests/ttm_pool_test.c b/drivers/gpu/drm/ttm/tests/ttm_pool_test.c index 2d9cae8cd984..b97f7b6daf5b 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); -- cgit v1.2.3 From 502756e23360d1192c496bc6791e97621e8578d8 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Fri, 5 Jan 2024 11:57:42 -0300 Subject: 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(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c index f843a50d5dce..cdfe1d3bf5ee 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 -- cgit v1.2.3 From 88cbf8502023dcb97bf9e40655d4848ba14350e0 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 17:20:51 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 6e73ebf67251..0fd9b5efe4c2 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 d3e49e7fd7c3..94f2dc5f6f90 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); -- cgit v1.2.3 From 3c01e01214026114609c577ce31f81d4e037dd50 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 16:48:38 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 0fd9b5efe4c2..235d27b17ff9 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -731,8 +731,12 @@ timeout: 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) == -- cgit v1.2.3 From d898c2e55593fea5da068de48a878c66520a4af8 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 16:27:24 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index c29f095aa1b9..d490a4d42c01 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -780,7 +780,7 @@ retry_same_fence: 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, -- cgit v1.2.3 From d4978a67ae97a2b875c8e8b6684866ee1d35fa80 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2024 22:06:32 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index d490a4d42c01..b2cc3f993eb6 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) { -- cgit v1.2.3 From c3ba13a0ed3d81d28aaf475687a5f39766566768 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 10 Jan 2024 09:22:45 +0100 Subject: 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(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 2214cb09678c..7054b4fb3fc0 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, -- cgit v1.2.3 From 420186db1483da4e16cd5d5a472f511a35dbc1b7 Mon Sep 17 00:00:00 2001 From: Alexander Warnecke Date: Tue, 2 Jan 2024 17:15:45 +0100 Subject: 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 + .../gpu/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 (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index dad938cf6dec..cd2b6ebf8d82 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 d94a644d0a6c..015bb8d70fbd 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 000000000000..763e9f8342d3 --- /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"); -- cgit v1.2.3 From ea4f9975625af861c2795c557b8fab2b492ff749 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Mon, 8 Jan 2024 15:29:02 +0530 Subject: 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 + drivers/gpu/drm/panel/panel-novatek-nt36672e.c | 643 +++++++++++++++++++++++++ 3 files changed, 654 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36672e.c (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index cd2b6ebf8d82..23b089a2103d 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 015bb8d70fbd..1c4f4e7f25bb 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 000000000000..d4e85c2fc899 --- /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