From patchwork Wed Jan 18 06:12:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45020 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176188wrn; Tue, 17 Jan 2023 22:38:08 -0800 (PST) X-Google-Smtp-Source: AMrXdXtdLS4fltF4KzN/5v/Ngg6iOf8+pSVpF1NFsFu/hg9YFlwL2Yv0v45w1w21eQX3LfkBBDR+ X-Received: by 2002:a05:6a20:c213:b0:b8:5c35:b75 with SMTP id bt19-20020a056a20c21300b000b85c350b75mr5691778pzb.26.1674023888162; Tue, 17 Jan 2023 22:38:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023888; cv=none; d=google.com; s=arc-20160816; b=Ab3370wSaWvPZj/qzynTu2l+xtje82CLR2DM3vz2uyrBvqK3bS2EChRIlHAoWy3jwc DYFRW5JBZML+wUOOO5GC0bCjfTDO0QlspzaX1EwgM1pJ57PDRkujT9Cr9zuEeehjLWvw r4DpAFkbEN5T1eKzD71qOJvWOyj87sgc5wczaxcm1wC8IqDRWg5H+qN/EqrBlogZW1VI csTLcFSQy0UCp2al2+Oit/v9Nr4h3HyHdVmc6EoFVeSU04+SmAE2KRBF09DWbFJbtzUt +/NfKyegUIoFtmm7ez7RJNmQ6eF5UJ3nL3/F1bzz1VejJE7wCNwumK3oGYdPeNXbzh7r zk+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=leSDSUqYxgVrElrnUnSnvkj6D04l7A7PmoOZI2j6TnU=; b=ppmgBzxkuVeeC1iIJqqm01mibps+TEXgDCJD/0PAwa2OqMWHmMLRqdV0WXL1f8wDkV NN9hXYfiP2AhKQkI4FW1faLCs3TCCpN4oqfG2lgyOrVXhWOWOLX0kouML/HtoUMDB2Aj DgYEMYzToG5AhlH9EwUpB57usCRO9fmjwqLHvoezlarIXBonEBlhcjHc8C+fGsj/tvjP 0VoKr+OdU7fDdwjm3kuZzAZTQPMuTp8y/fzhQpxdSxZe+szI91xfDoX4PQ+FSuqvmdUr UajBrBDgiDbpeWJItkmTyXHTZSOeJtaDqcjpn/Rz15a5v4HGyZFzhScnLe7OggfnPXPY Km5g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=HIMwOE19; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id y6-20020a17090abd0600b00226e74464f7si1189002pjr.108.2023.01.17.22.37.56; Tue, 17 Jan 2023 22:38:08 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=HIMwOE19; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229991AbjARGgO (ORCPT + 99 others); Wed, 18 Jan 2023 01:36:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54964 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229694AbjARGYj (ORCPT ); Wed, 18 Jan 2023 01:24:39 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0A3853F8E for ; Tue, 17 Jan 2023 22:13:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022410; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=leSDSUqYxgVrElrnUnSnvkj6D04l7A7PmoOZI2j6TnU=; b=HIMwOE19pLxBr3BvQfea21aNzgUgsOc1CL7/OBAFoDFez7zyK4zxjkHUXaxNeTu7LBOym+ N6dJQjw8R4q3/LTpT/AtRJfB9vLB4Xp9WwCKLcT96FHv/xxC69JW4IPMSArTbsJngkdpYn Jt+jGyy4EFHmoa6tlXJ5emouu2y2B8g= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-125-t5D0IGpoNSmyHo9VTKXwWQ-1; Wed, 18 Jan 2023 01:13:28 -0500 X-MC-Unique: t5D0IGpoNSmyHo9VTKXwWQ-1 Received: by mail-ej1-f70.google.com with SMTP id gn31-20020a1709070d1f00b0087024adbba2so5788530ejc.20 for ; Tue, 17 Jan 2023 22:13:28 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=leSDSUqYxgVrElrnUnSnvkj6D04l7A7PmoOZI2j6TnU=; b=1Klm73Qq+4qAqiCgVDsNVk+awBI0TwTufVzJ/YfISy4C1vUp5rIqKLBI25agENw8r0 07fDmL/b9II6qbSTdh7gUOS0T0ZMHvdr01csdWXz5hESCEzcmnEwtNXHQjfLuNjHXMOP 9SCcJnJ8qon0DFcafqVXkDi3I2t835UxzgeHPy0PFfkpuIP3jfmQy4dx3AuF89iboD1q gMNKbbQNDRaAhmphRzIcAUYNj34UjNNtZt2TibPOPPkt9Y1uYIJgBd9Z3hijIlBttsWU uE1I1AP6iJuWMlvGWTv3VqBh5eQU2ayxPBlUoMnjvT4RkHVlaGvxQ5BSqW/GtSv7h3tB PLgQ== X-Gm-Message-State: AFqh2kqE7Bv9wiA3G4BydKradVnaM4XTPGRM2pMLZTYUYFmHXXscTbCD NyaRgfPIC1BroyRF9a3I3Wqg3WlhFzESkaEbgOBZLlpyxZLMrdtt1CZ0nlGpsRMgfjWTamp6J7q 7QTDyWh0KQk7OT639dIpBvoix X-Received: by 2002:a05:6402:400a:b0:496:bdb5:572f with SMTP id d10-20020a056402400a00b00496bdb5572fmr7142135eda.31.1674022407649; Tue, 17 Jan 2023 22:13:27 -0800 (PST) X-Received: by 2002:a05:6402:400a:b0:496:bdb5:572f with SMTP id d10-20020a056402400a00b00496bdb5572fmr7142114eda.31.1674022407317; Tue, 17 Jan 2023 22:13:27 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id r24-20020aa7da18000000b004704658abebsm13776387eds.54.2023.01.17.22.13.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:26 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH drm-next 01/14] drm: execution context for GEM buffers Date: Wed, 18 Jan 2023 07:12:43 +0100 Message-Id: <20230118061256.2689-2-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341272312159147?= X-GMAIL-MSGID: =?utf-8?q?1755341272312159147?= From: Christian König This adds the infrastructure for an execution context for GEM buffers which is similar to the existinc TTMs execbuf util and intended to replace it in the long term. The basic functionality is that we abstracts the necessary loop to lock many different GEM buffers with automated deadlock and duplicate handling. v2: drop xarray and use dynamic resized array instead, the locking overhead is unecessary and measureable. Signed-off-by: Christian König --- Documentation/gpu/drm-mm.rst | 12 ++ drivers/gpu/drm/Kconfig | 6 + drivers/gpu/drm/Makefile | 2 + drivers/gpu/drm/amd/amdgpu/Kconfig | 1 + drivers/gpu/drm/drm_exec.c | 295 +++++++++++++++++++++++++++++ include/drm/drm_exec.h | 144 ++++++++++++++ 6 files changed, 460 insertions(+) create mode 100644 drivers/gpu/drm/drm_exec.c create mode 100644 include/drm/drm_exec.h diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index a79fd3549ff8..a52e6f4117d6 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -493,6 +493,18 @@ DRM Sync Objects .. kernel-doc:: drivers/gpu/drm/drm_syncobj.c :export: +DRM Execution context +===================== + +.. kernel-doc:: drivers/gpu/drm/drm_exec.c + :doc: Overview + +.. kernel-doc:: include/drm/drm_exec.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_exec.c + :export: + GPU Scheduler ============= diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 748b93d00184..05134256da59 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -200,6 +200,12 @@ config DRM_TTM GPU memory types. Will be enabled automatically if a device driver uses it. +config DRM_EXEC + tristate + depends on DRM + help + Execution context for command submissions + config DRM_BUDDY tristate depends on DRM diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 496fa5a6147a..4fe190aee584 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -78,6 +78,8 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o # # Memory-management helpers # +# +obj-$(CONFIG_DRM_EXEC) += drm_exec.o obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 5341b6b242c3..279fb3bba810 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -11,6 +11,7 @@ config DRM_AMDGPU select DRM_SCHED select DRM_TTM select DRM_TTM_HELPER + select DRM_EXEC select POWER_SUPPLY select HWMON select I2C diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c new file mode 100644 index 000000000000..ed2106c22786 --- /dev/null +++ b/drivers/gpu/drm/drm_exec.c @@ -0,0 +1,295 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ + +#include +#include +#include + +/** + * DOC: Overview + * + * This component mainly abstracts the retry loop necessary for locking + * multiple GEM objects while preparing hardware operations (e.g. command + * submissions, page table updates etc..). + * + * If a contention is detected while locking a GEM object the cleanup procedure + * unlocks all previously locked GEM objects and locks the contended one first + * before locking any further objects. + * + * After an object is locked fences slots can optionally be reserved on the + * dma_resv object inside the GEM object. + * + * A typical usage pattern should look like this:: + * + * struct drm_gem_object *obj; + * struct drm_exec exec; + * unsigned long index; + * int ret; + * + * drm_exec_init(&exec, true); + * drm_exec_while_not_all_locked(&exec) { + * ret = drm_exec_prepare_obj(&exec, boA, 1); + * drm_exec_continue_on_contention(&exec); + * if (ret) + * goto error; + * + * ret = drm_exec_lock(&exec, boB, 1); + * drm_exec_continue_on_contention(&exec); + * if (ret) + * goto error; + * } + * + * drm_exec_for_each_locked_object(&exec, index, obj) { + * dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ); + * ... + * } + * drm_exec_fini(&exec); + * + * See struct dma_exec for more details. + */ + +/* Dummy value used to initially enter the retry loop */ +#define DRM_EXEC_DUMMY (void*)~0 + +/* Initialize the drm_exec_objects container */ +static void drm_exec_objects_init(struct drm_exec_objects *container) +{ + container->objects = kmalloc(PAGE_SIZE, GFP_KERNEL); + + /* If allocation here fails, just delay that till the first use */ + container->max_objects = container->objects ? + PAGE_SIZE / sizeof(void *) : 0; + container->num_objects = 0; +} + +/* Cleanup the drm_exec_objects container */ +static void drm_exec_objects_fini(struct drm_exec_objects *container) +{ + kvfree(container->objects); +} + +/* Make sure we have enough room and add an object the container */ +static int drm_exec_objects_add(struct drm_exec_objects *container, + struct drm_gem_object *obj) +{ + if (unlikely(container->num_objects == container->max_objects)) { + size_t size = container->max_objects * sizeof(void *); + void *tmp; + + tmp = kvrealloc(container->objects, size, size + PAGE_SIZE, + GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + container->objects = tmp; + container->max_objects += PAGE_SIZE / sizeof(void *); + } + drm_gem_object_get(obj); + container->objects[container->num_objects++] = obj; + return 0; +} + +/* Unlock all objects and drop references */ +static void drm_exec_unlock_all(struct drm_exec *exec) +{ + struct drm_gem_object *obj; + unsigned long index; + + drm_exec_for_each_duplicate_object(exec, index, obj) + drm_gem_object_put(obj); + + drm_exec_for_each_locked_object(exec, index, obj) { + dma_resv_unlock(obj->resv); + drm_gem_object_put(obj); + } +} + +/** + * drm_exec_init - initialize a drm_exec object + * @exec: the drm_exec object to initialize + * @interruptible: if locks should be acquired interruptible + * + * Initialize the object and make sure that we can track locked and duplicate + * objects. + */ +void drm_exec_init(struct drm_exec *exec, bool interruptible) +{ + exec->interruptible = interruptible; + drm_exec_objects_init(&exec->locked); + drm_exec_objects_init(&exec->duplicates); + exec->contended = DRM_EXEC_DUMMY; +} +EXPORT_SYMBOL(drm_exec_init); + +/** + * drm_exec_fini - finalize a drm_exec object + * @exec: the drm_exec object to finilize + * + * Unlock all locked objects, drop the references to objects and free all memory + * used for tracking the state. + */ +void drm_exec_fini(struct drm_exec *exec) +{ + drm_exec_unlock_all(exec); + drm_exec_objects_fini(&exec->locked); + drm_exec_objects_fini(&exec->duplicates); + if (exec->contended != DRM_EXEC_DUMMY) { + drm_gem_object_put(exec->contended); + ww_acquire_fini(&exec->ticket); + } +} +EXPORT_SYMBOL(drm_exec_fini); + +/** + * drm_exec_cleanup - cleanup when contention is detected + * @exec: the drm_exec object to cleanup + * + * Cleanup the current state and return true if we should stay inside the retry + * loop, false if there wasn't any contention detected and we can keep the + * objects locked. + */ +bool drm_exec_cleanup(struct drm_exec *exec) +{ + if (likely(!exec->contended)) { + ww_acquire_done(&exec->ticket); + return false; + } + + if (likely(exec->contended == DRM_EXEC_DUMMY)) { + exec->contended = NULL; + ww_acquire_init(&exec->ticket, &reservation_ww_class); + return true; + } + + drm_exec_unlock_all(exec); + exec->locked.num_objects = 0; + exec->duplicates.num_objects = 0; + return true; +} +EXPORT_SYMBOL(drm_exec_cleanup); + +/* Track the locked object in the xa and reserve fences */ +static int drm_exec_obj_locked(struct drm_exec_objects *container, + struct drm_gem_object *obj, + unsigned int num_fences) +{ + int ret; + + if (container) { + ret = drm_exec_objects_add(container, obj); + if (ret) + return ret; + } + + if (num_fences) { + ret = dma_resv_reserve_fences(obj->resv, num_fences); + if (ret) + goto error_erase; + } + + return 0; + +error_erase: + if (container) { + --container->num_objects; + drm_gem_object_put(obj); + } + return ret; +} + +/* Make sure the contended object is locked first */ +static int drm_exec_lock_contended(struct drm_exec *exec) +{ + struct drm_gem_object *obj = exec->contended; + int ret; + + if (likely(!obj)) + return 0; + + if (exec->interruptible) { + ret = dma_resv_lock_slow_interruptible(obj->resv, + &exec->ticket); + if (unlikely(ret)) + goto error_dropref; + } else { + dma_resv_lock_slow(obj->resv, &exec->ticket); + } + + ret = drm_exec_obj_locked(&exec->locked, obj, 0); + if (unlikely(ret)) + dma_resv_unlock(obj->resv); + +error_dropref: + /* Always cleanup the contention so that error handling can kick in */ + drm_gem_object_put(obj); + exec->contended = NULL; + return ret; +} + +/** + * drm_exec_prepare_obj - prepare a GEM object for use + * @exec: the drm_exec object with the state + * @obj: the GEM object to prepare + * @num_fences: how many fences to reserve + * + * Prepare a GEM object for use by locking it and reserving fence slots. All + * succesfully locked objects are put into the locked container. Duplicates + * detected as well and automatically moved into the duplicates container. + * + * Returns: -EDEADLK if a contention is detected, -ENOMEM when memory + * allocation failed and zero for success. + */ +int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, + unsigned int num_fences) +{ + int ret; + + ret = drm_exec_lock_contended(exec); + if (unlikely(ret)) + return ret; + + if (exec->interruptible) + ret = dma_resv_lock_interruptible(obj->resv, &exec->ticket); + else + ret = dma_resv_lock(obj->resv, &exec->ticket); + + if (unlikely(ret == -EDEADLK)) { + drm_gem_object_get(obj); + exec->contended = obj; + return -EDEADLK; + } + + if (unlikely(ret == -EALREADY)) { + struct drm_exec_objects *container = &exec->duplicates; + + /* + * If this is the first locked GEM object it was most likely + * just contended. So don't add it to the duplicates, just + * reserve the fence slots. + */ + if (exec->locked.num_objects && exec->locked.objects[0] == obj) + container = NULL; + + ret = drm_exec_obj_locked(container, obj, num_fences); + if (ret) + return ret; + + } else if (unlikely(ret)) { + return ret; + + } else { + ret = drm_exec_obj_locked(&exec->locked, obj, num_fences); + if (ret) + goto error_unlock; + } + + drm_gem_object_get(obj); + return 0; + +error_unlock: + dma_resv_unlock(obj->resv); + return ret; +} +EXPORT_SYMBOL(drm_exec_prepare_obj); + +MODULE_DESCRIPTION("DRM execution context"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/include/drm/drm_exec.h b/include/drm/drm_exec.h new file mode 100644 index 000000000000..f73981c6292e --- /dev/null +++ b/include/drm/drm_exec.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ + +#ifndef __DRM_EXEC_H__ +#define __DRM_EXEC_H__ + +#include + +struct drm_gem_object; + +/** + * struct drm_exec_objects - Container for GEM objects in a drm_exec + */ +struct drm_exec_objects { + unsigned int num_objects; + unsigned int max_objects; + struct drm_gem_object **objects; +}; + +/** + * drm_exec_objects_for_each - iterate over all the objects inside the container + */ +#define drm_exec_objects_for_each(array, index, obj) \ + for (index = 0, obj = (array)->objects[0]; \ + index < (array)->num_objects; \ + ++index, obj = (array)->objects[index]) + +/** + * struct drm_exec - Execution context + */ +struct drm_exec { + /** + * @interruptible: If locks should be taken interruptible + */ + bool interruptible; + + /** + * @ticket: WW ticket used for acquiring locks + */ + struct ww_acquire_ctx ticket; + + /** + * @locked: container for the locked GEM objects + */ + struct drm_exec_objects locked; + + /** + * @duplicates: container for the duplicated GEM objects + */ + struct drm_exec_objects duplicates; + + /** + * @contended: contended GEM object we backet of for. + */ + struct drm_gem_object *contended; +}; + +/** + * drm_exec_for_each_locked_object - iterate over all the locked objects + * @exec: drm_exec object + * @index: unsigned long index for the iteration + * @obj: the current GEM object + * + * Iterate over all the locked GEM objects inside the drm_exec object. + */ +#define drm_exec_for_each_locked_object(exec, index, obj) \ + drm_exec_objects_for_each(&(exec)->locked, index, obj) + +/** + * drm_exec_for_each_duplicate_object - iterate over all the duplicate objects + * @exec: drm_exec object + * @index: unsigned long index for the iteration + * @obj: the current GEM object + * + * Iterate over all the duplicate GEM objects inside the drm_exec object. + */ +#define drm_exec_for_each_duplicate_object(exec, index, obj) \ + drm_exec_objects_for_each(&(exec)->duplicates, index, obj) + +/** + * drm_exec_while_not_all_locked - loop until all GEM objects are prepared + * @exec: drm_exec object + * + * Core functionality of the drm_exec object. Loops until all GEM objects are + * prepared and no more contention exists. + * + * At the beginning of the loop it is guaranteed that no GEM object is locked. + */ +#define drm_exec_while_not_all_locked(exec) \ + while (drm_exec_cleanup(exec)) + +/** + * drm_exec_continue_on_contention - continue the loop when we need to cleanup + * @exec: drm_exec object + * + * Control flow helper to continue when a contention was detected and we need to + * clean up and re-start the loop to prepare all GEM objects. + */ +#define drm_exec_continue_on_contention(exec) \ + if (unlikely(drm_exec_is_contended(exec))) \ + continue + +/** + * drm_exec_break_on_contention - break a subordinal loop on contention + * @exec: drm_exec object + * + * Control flow helper to break a subordinal loop when a contention was detected + * and we need to clean up and re-start the loop to prepare all GEM objects. + */ +#define drm_exec_break_on_contention(exec) \ + if (unlikely(drm_exec_is_contended(exec))) \ + break + +/** + * drm_exec_is_contended - check for contention + * @exec: drm_exec object + * + * Returns true if the drm_exec object has run into some contention while + * locking a GEM object and needs to clean up. + */ +static inline bool drm_exec_is_contended(struct drm_exec *exec) +{ + return !!exec->contended; +} + +/** + * drm_exec_has_duplicates - check for duplicated GEM object + * @exec: drm_exec object + * + * Return true if the drm_exec object has encountered some already locked GEM + * objects while trying to lock them. This can happen if multiple GEM objects + * share the same underlying resv object. + */ +static inline bool drm_exec_has_duplicates(struct drm_exec *exec) +{ + return exec->duplicates.num_objects > 0; +} + +void drm_exec_init(struct drm_exec *exec, bool interruptible); +void drm_exec_fini(struct drm_exec *exec); +bool drm_exec_cleanup(struct drm_exec *exec); +int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, + unsigned int num_fences); + +#endif From patchwork Wed Jan 18 06:12:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45044 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2190594wrn; Tue, 17 Jan 2023 23:22:17 -0800 (PST) X-Google-Smtp-Source: AMrXdXv+8GNGzK05DRmzxYaBjgl4DbtJxXXxpzQw1aAvNZrdaQsjuQ2P9WT/9gEGN+37Svu5LxdC X-Received: by 2002:a05:6402:1c10:b0:49c:fde2:a6f4 with SMTP id ck16-20020a0564021c1000b0049cfde2a6f4mr5831529edb.15.1674026537371; Tue, 17 Jan 2023 23:22:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674026537; cv=none; d=google.com; s=arc-20160816; b=lvPjF7G3mN/viecMqNKfE3AoDb6GtaCi2t+dVejjBoPV8xAo5iujH83ghz71nu53Ur KWSyQ0Iy0rUd+pawMdMm+r3VPInyTcwIN/Wdgtsp/3lXZXcZUfW+fk23KdGwYKqfSgHe M9FBDAmEe6iBk6niUhKG0Ew7b7cCmuXcAWKG93RBLxQLSvbNQNIEYgdfifRpp3Jr0Ny7 idI6R7wOoUgnMbc69iqGp3W3H4Xe1yCucozOkiWQuiT7ifuUu810x+zI4LrFd7iDh5kY UiXhAehS7GxEWsP6X0LM14Pu1ZjZt/D+9Ra+Y5hMVkPhTTH76DWYap7eBF4jBFNsuA61 aJJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=9bPNRTAzSirKPyPC/a7kemJ9gbWhkHOBWemjVPOdr94=; b=RU8lTlSIYlnefir9UdI68wXZ2otDOgCDoiTEmcyjnfBaTFO84FvxljURr5sMVSN/k/ rZB7otAf0g/kUX9GdVjOjhQYGcObYILFta5Af5AI9cVBusM/qsyyysD/wEFs4XKMdP/O x9xf0V9DFYmMSWSKWFzGem1PSjIgjgGpui/aPzJdufHRuuY2gDofnUJ2jmAmLXAqWI3h FM5PotnoxjHhIxu25vq13tCX310mznBA+y9sqtrue4UyLtzLamQv7NW8eVDi8/FGGQnU //3Q77Kt7qeYQad1/YE3kTQDdNyyZClboFOY9yVTd8pyIv3u1Kl98Z6Y2Tb3eWHSyudh F+IQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=D5XLcIm3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id d14-20020aa7d5ce000000b0049b63678b52si12032312eds.516.2023.01.17.23.21.53; Tue, 17 Jan 2023 23:22:17 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=D5XLcIm3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230224AbjARGua (ORCPT + 99 others); Wed, 18 Jan 2023 01:50:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54122 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229752AbjARGYO (ORCPT ); Wed, 18 Jan 2023 01:24:14 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B459951C4A for ; Tue, 17 Jan 2023 22:13:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022413; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9bPNRTAzSirKPyPC/a7kemJ9gbWhkHOBWemjVPOdr94=; b=D5XLcIm3F40BezvWsfnmWbzGJQPArQIhha6JyaGO1z9qb69iD63RiJ1x83bU/7OX7+Ny7b /hr/jFrx1LEhcDFvS9d8jrX2TiOXWnKXq5DcK8unDmQvCzUUQNCa/Gp2lXABMbQsTAmRKn 8XJDvQZ4cldQV3Nb0c2F9rUaYYrd8ZQ= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-621-75qeEFwnO1WKGnZ3uQfY3A-1; Wed, 18 Jan 2023 01:13:32 -0500 X-MC-Unique: 75qeEFwnO1WKGnZ3uQfY3A-1 Received: by mail-ed1-f70.google.com with SMTP id b15-20020a056402350f00b0049e42713e2bso1687686edd.0 for ; Tue, 17 Jan 2023 22:13:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9bPNRTAzSirKPyPC/a7kemJ9gbWhkHOBWemjVPOdr94=; b=yBDUFji8lJj1oF6eM8Y+zukkmTA5lX+Pg9fL1fBH3NVjD+seC7MIC0mldmUkSomZZS zx+IWi9BXUeA3i9ynma0TZYecvPLNCImtspsP2hdFaT0FJ8QuQ71W7lLuvbflXgecPPa fcvtN9mmnn2yF0c62Y1boxEV21ObKVv90WVXVKF/IjYoASwnPOEaX0kintnYF8E1sKs1 V2Pkd5UOsJTQGFX19KswYxWVIR14McSDjVFuO/vgLnawTt1xZ+K1BJzOfslSZ72/qcBt wZrkR0PDgnxLTm6rKX4gsyU4l0B6QX4ns5a68eCO69+EnXlKF6H5gmb+aH3YBUEPgGFh 5OPA== X-Gm-Message-State: AFqh2kqY4+oH7mOZoXUi00qaBxjOkN9FptK2tebHxXb/FaMNituXbn5R dbSimm4KPUsWv2oA9PxxBLimmOW6YC7vIWo7Hbz36hvpX0iqWQktamYCe77X3rw3HwQWXb0aBE1 bJM8QCVKtm7vS+huxlNC047WF X-Received: by 2002:aa7:c0d4:0:b0:49d:9bd8:6253 with SMTP id j20-20020aa7c0d4000000b0049d9bd86253mr6311446edp.17.1674022411762; Tue, 17 Jan 2023 22:13:31 -0800 (PST) X-Received: by 2002:aa7:c0d4:0:b0:49d:9bd8:6253 with SMTP id j20-20020aa7c0d4000000b0049d9bd86253mr6311429edp.17.1674022411580; Tue, 17 Jan 2023 22:13:31 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id y11-20020aa7c24b000000b004954c90c94bsm13745667edo.6.2023.01.17.22.13.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:31 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 02/14] drm/exec: fix memory leak in drm_exec_prepare_obj() Date: Wed, 18 Jan 2023 07:12:44 +0100 Message-Id: <20230118061256.2689-3-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755344050229882756?= X-GMAIL-MSGID: =?utf-8?q?1755344050229882756?= Don't call drm_gem_object_get() unconditionally. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/drm_exec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index ed2106c22786..5713a589a6a3 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -282,7 +282,6 @@ int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, goto error_unlock; } - drm_gem_object_get(obj); return 0; error_unlock: From patchwork Wed Jan 18 06:12:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45022 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176531wrn; Tue, 17 Jan 2023 22:39:16 -0800 (PST) X-Google-Smtp-Source: AMrXdXsHzSGhEXaghl3C8GAnJfGMTF6EbopqcDGz5Ci/WtoFQHJW+y71bZXBhTme1GNLhBZwKc3n X-Received: by 2002:a05:6a20:3d0f:b0:af:9539:a2c0 with SMTP id y15-20020a056a203d0f00b000af9539a2c0mr8309163pzi.26.1674023956570; Tue, 17 Jan 2023 22:39:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023956; cv=none; d=google.com; s=arc-20160816; b=UmS71v7nXHPsUvZZLTeZZF3/C8eEq+vRx1lpIZ5O6FB12rGpysLyVqqjdN7r405+/l 2TbKp+u1/NtJu/S0BaOaVMKBjCBUSfsubdNE88m8y3YQC/F0PT6RhIeH5B6iOyvsfs3H 1wy7X+FI8SmdGbYln+b35j5ZDZCqB/0RoJZSJAUzN3c6Qzha8VvOuTgDDvU12Ab5Uhu0 TeD5t2TUgTl6Pi7QPoEI7eKDAJppl5ICrpoyvlSeA10jXYaHO4TTY3AQ/gOzZNxSILOX g/VWO/STKbqNzc3W3vmqc75WvgWmBNrhs+ezAmAw1pFRTmMf6zZioFLiRvkW2eBRHYyX unlw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=w2RMk8xDmnIjb575xiF+d/wjpDV2miuxgU5XcZOuakg=; b=CbA558vi/ecO+4/Bw4WFO65Rt/sApJyaQAs7DfP+jdJZUeXxzDnwHhOLJDdzz7284R 3Z8WG3TTf+rmDRL+Vss1ftX9Sm6GHlKbFf7SffJ3se9tOz6srTWH8zKnBvnp3+L7vlIn yoGlnxOjWGYqrkslevl4N42ITEpothFIWc7gf/lAWUvh8BA5JjFLMsjlpUQlMDY21atq VTyi8g5IwgHxY0s+10OypEsMFYKQUPhpa4RMzutK9HBXyNT/sy5ICQ10l1sdWiDFzSyh 86s5sI4s+hj7q7sgP7pcRw8SXphVIXIHYlrFqUe2kQ3+OPstxXG2qUABp1xn9+aGWeEl 7qmQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ZN+gRmUe; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 17-20020a631251000000b00497a800555csi25477219pgs.284.2023.01.17.22.38.59; Tue, 17 Jan 2023 22:39:16 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ZN+gRmUe; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229862AbjARGh0 (ORCPT + 99 others); Wed, 18 Jan 2023 01:37:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229769AbjARGYz (ORCPT ); Wed, 18 Jan 2023 01:24:55 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA770568BF for ; Tue, 17 Jan 2023 22:13:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022421; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w2RMk8xDmnIjb575xiF+d/wjpDV2miuxgU5XcZOuakg=; b=ZN+gRmUeBKQ8YIe3WE3ZRrwrC43BZTDlE9DsPwPI0WdBDvEkL1WUcl575K8DGkfRIYDUrc 1Ph0B3lPT5JJyLpqu7PfuP+ebDGc1SjUio+YrPU1/VfhaEJmaQRPVYfNwUZL6ZSry9cFDL faDyMOjp7PfHOrFY+41Mr70RBONnNKg= Received: from mail-ed1-f71.google.com (mail-ed1-f71.google.com [209.85.208.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-207-3rZSFB3kPc2hVV0ZmFJHVQ-1; Wed, 18 Jan 2023 01:13:40 -0500 X-MC-Unique: 3rZSFB3kPc2hVV0ZmFJHVQ-1 Received: by mail-ed1-f71.google.com with SMTP id dz20-20020a0564021d5400b0049e15ded5fcso5870241edb.23 for ; Tue, 17 Jan 2023 22:13:39 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w2RMk8xDmnIjb575xiF+d/wjpDV2miuxgU5XcZOuakg=; b=qIoLoY67Ct9pbvyScau4rP4Irf76FroY2PwiqP1Z1/6Y3RZAr3OMw34U14eCfVb3CY 47K9+ukvcYVqeta3qO49RI1Y54XMjGhUHozuI80NegzBYcntTAd+j93LVbDxpeJBP001 aOn+X1V55VMXJ9Iy58b2o0hVi/fnQHwZLDD3Bf4ukvBmGff38Ys4sdCIhj8290MXxmVH 7+ttg7Kk8Ic7OxfN1GWEUKAc6lo041Tn/+/+FDstYARTtVkbFY9EKqLrksz9Pbod52CK 9hYWih7ZmXsFnf1XJ03TtRuJm3smrdA3UIFShQnwyiR2DTp3uIVpTLMeFMghA6VszTsh lpxw== X-Gm-Message-State: AFqh2kquOtRBpEg59kt4xqZTkec0clf5gwiHrXI4itcNKbMAy8xm464Q GRkuuF4w1TjrBzq1DzQKoFZvFO7ySDMYOYwbrORGwxO7gKqLYnBNirnX1deMM1UB/LlB7W6h5oN fcvFDMnxfn4a8vws/Q7xipKVc X-Received: by 2002:a17:906:2b57:b0:86d:3c59:73f8 with SMTP id b23-20020a1709062b5700b0086d3c5973f8mr5837037ejg.34.1674022416786; Tue, 17 Jan 2023 22:13:36 -0800 (PST) X-Received: by 2002:a17:906:2b57:b0:86d:3c59:73f8 with SMTP id b23-20020a1709062b5700b0086d3c5973f8mr5836999ejg.34.1674022415972; Tue, 17 Jan 2023 22:13:35 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id o12-20020a170906768c00b0085ff3202ce7sm8419084ejm.219.2023.01.17.22.13.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:35 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 03/14] drm: manager to keep track of GPUs VA mappings Date: Wed, 18 Jan 2023 07:12:45 +0100 Message-Id: <20230118061256.2689-4-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,T_FILL_THIS_FORM_SHORT autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341344640994909?= X-GMAIL-MSGID: =?utf-8?q?1755341344640994909?= This adds the infrastructure for a manager implementation to keep track of GPU virtual address (VA) mappings. New UAPIs, motivated by Vulkan sparse memory bindings graphics drivers start implementing, allow userspace applications to request multiple and arbitrary GPU VA mappings of buffer objects. The DRM GPU VA manager is intended to serve the following purposes in this context. 1) Provide a dedicated range allocator to track GPU VA allocations and mappings, making use of the drm_mm range allocator. 2) Generically connect GPU VA mappings to their backing buffers, in particular DRM GEM objects. 3) Provide a common implementation to perform more complex mapping operations on the GPU VA space. In particular splitting and merging of GPU VA mappings, e.g. for intersecting mapping requests or partial unmap requests. Idea-suggested-by: Dave Airlie Signed-off-by: Danilo Krummrich --- Documentation/gpu/drm-mm.rst | 31 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_gem.c | 3 + drivers/gpu/drm/drm_gpuva_mgr.c | 1323 +++++++++++++++++++++++++++++++ include/drm/drm_drv.h | 6 + include/drm/drm_gem.h | 75 ++ include/drm/drm_gpuva_mgr.h | 527 ++++++++++++ 7 files changed, 1966 insertions(+) create mode 100644 drivers/gpu/drm/drm_gpuva_mgr.c create mode 100644 include/drm/drm_gpuva_mgr.h diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index a52e6f4117d6..c9f120cfe730 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -466,6 +466,37 @@ DRM MM Range Allocator Function References .. kernel-doc:: drivers/gpu/drm/drm_mm.c :export: +DRM GPU VA Manager +================== + +Overview +-------- + +.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c + :doc: Overview + +Split and Merge +--------------- + +.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c + :doc: Split and Merge + +Locking +------- + +.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c + :doc: Locking + + +DRM GPU VA Manager Function References +-------------------------------------- + +.. kernel-doc:: include/drm/drm_gpuva_mgr.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c + :export: + DRM Buddy Allocator =================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4fe190aee584..de2ffca3b6e4 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -45,6 +45,7 @@ drm-y := \ drm_vblank.o \ drm_vblank_work.o \ drm_vma_manager.o \ + drm_gpuva_mgr.o \ drm_writeback.o drm-$(CONFIG_DRM_LEGACY) += \ drm_agpsupport.o \ diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 59a0bb5ebd85..65115fe88627 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -164,6 +164,9 @@ void drm_gem_private_object_init(struct drm_device *dev, if (!obj->resv) obj->resv = &obj->_resv; + if (drm_core_check_feature(dev, DRIVER_GEM_GPUVA)) + drm_gem_gpuva_init(obj); + drm_vma_node_reset(&obj->vma_node); INIT_LIST_HEAD(&obj->lru_node); } diff --git a/drivers/gpu/drm/drm_gpuva_mgr.c b/drivers/gpu/drm/drm_gpuva_mgr.c new file mode 100644 index 000000000000..e665f642689d --- /dev/null +++ b/drivers/gpu/drm/drm_gpuva_mgr.c @@ -0,0 +1,1323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Danilo Krummrich + * + */ + +#include +#include + +/** + * DOC: Overview + * + * The DRM GPU VA Manager, represented by struct drm_gpuva_manager keeps track + * of a GPU's virtual address (VA) space and manages the corresponding virtual + * mappings represented by &drm_gpuva objects. It also keeps track of the + * mapping's backing &drm_gem_object buffers. + * + * &drm_gem_object buffers maintain a list (and a corresponding list lock) of + * &drm_gpuva objects representing all existent GPU VA mappings using this + * &drm_gem_object as backing buffer. + * + * A GPU VA mapping can only be created within a previously allocated + * &drm_gpuva_region, which represents a reserved portion of the GPU VA space. + * GPU VA mappings are not allowed to span over a &drm_gpuva_region's boundary. + * + * GPU VA regions can also be flagged as sparse, which allows drivers to create + * sparse mappings for a whole GPU VA region in order to support Vulkan + * 'Sparse Resources'. + * + * The GPU VA manager internally uses the &drm_mm range allocator to manage the + * &drm_gpuva mappings and the &drm_gpuva_regions within a GPU's virtual address + * space. + * + * Besides the GPU VA space regions (&drm_gpuva_region) allocated by a driver + * the &drm_gpuva_manager contains a special region representing the portion of + * VA space reserved by the kernel. This node is initialized together with the + * GPU VA manager instance and removed when the GPU VA manager is destroyed. + * + * In a typical application drivers would embed struct drm_gpuva_manager, + * struct drm_gpuva_region and struct drm_gpuva within their own driver + * specific structures, there won't be any memory allocations of it's own nor + * memory allocations of &drm_gpuva or &drm_gpuva_region entries. + */ + +/** + * DOC: Split and Merge + * + * The DRM GPU VA manager also provides an algorithm implementing splitting and + * merging of existent GPU VA mappings with the ones that are requested to be + * mapped or unmapped. This feature is required by the Vulkan API to implement + * Vulkan 'Sparse Memory Bindings' - drivers UAPIs often refer to this as + * VM BIND. + * + * Drivers can call drm_gpuva_sm_map_ops_create() to obtain a list of map, unmap + * and remap operations for a given newly requested mapping. This list + * represents the set of operations to execute in order to integrate the new + * mapping cleanly into the current state of the GPU VA space. + * + * Depending on how the new GPU VA mapping intersects with the existent mappings + * of the GPU VA space the &drm_gpuva_ops contain an arbitrary amount of unmap + * operations, a maximum of two remap operations and a single map operation. + * The set of operations can also be empty if no operation is required, e.g. if + * the requested mapping already exists in the exact same way. + * + * The single map operation, if existent, represents the original map operation + * requested by the caller. Please note that this operation might be altered + * comparing it with the original map operation, e.g. because it was merged with + * an already existent mapping. Hence, drivers must execute this map operation + * instead of the original one they passed to drm_gpuva_sm_map_ops_create(). + * + * &drm_gpuva_op_unmap contains a 'keep' field, which indicates whether the + * &drm_gpuva to unmap is physically contiguous with the original mapping + * request. Optionally, if 'keep' is set, drivers may keep the actual page table + * entries for this &drm_gpuva, adding the missing page table entries only and + * update the &drm_gpuva_manager's view of things accordingly. + * + * Drivers may do the same optimization, namely delta page table updates, also + * for remap operations. This is possible since &drm_gpuva_op_remap consists of + * one unmap operation and one or two map operations, such that drivers can + * derive the page table update delta accordingly. + * + * Note that there can't be more than two existent mappings to split up, one at + * the beginning and one at the end of the new mapping, hence there is a + * maximum of two remap operations. + * + * Generally, the DRM GPU VA manager never merges mappings across the + * boundaries of &drm_gpuva_regions. This is the case since merging between + * GPU VA regions would result into unmap and map operations to be issued for + * both regions involved although the original mapping request was referred to + * one specific GPU VA region only. Since the other GPU VA region, the one not + * explicitly requested to be altered, might be in use by the GPU, we are not + * allowed to issue any map/unmap operations for this region. + * + * Note that before calling drm_gpuva_sm_map_ops_create() again with another + * mapping request it is necessary to update the &drm_gpuva_manager's view of + * the GPU VA space. The previously obtained operations must be either fully + * processed or completely abandoned. + * + * To update the &drm_gpuva_manager's view of the GPU VA space + * drm_gpuva_insert(), drm_gpuva_destroy_locked() and/or + * drm_gpuva_destroy_unlocked() should be used. + * + * Analogue to drm_gpuva_sm_map_ops_create() drm_gpuva_sm_unmap_ops_create() + * provides drivers a the list of operations to be executed in order to unmap + * a range of GPU VA space. The logic behind this functions is way simpler + * though: For all existent mappings enclosed by the given range unmap + * operations are created. For mappings which are only partically located within + * the given range, remap operations are created such that those mappings are + * split up and re-mapped partically. + * + * The following paragraph depicts the basic constellations of existent GPU VA + * mappings, a newly requested mapping and the resulting mappings as implemented + * by drm_gpuva_sm_map_ops_create() - it doesn't cover arbitrary combinations + * of those constellations. + * + * :: + * + * 1) Existent mapping is kept. + * ---------------------------- + * + * 0 a 1 + * old: |-----------| (bo_offset=n) + * + * 0 a 1 + * req: |-----------| (bo_offset=n) + * + * 0 a 1 + * new: |-----------| (bo_offset=n) + * + * + * 2) Existent mapping is replaced. + * -------------------------------- + * + * 0 a 1 + * old: |-----------| (bo_offset=n) + * + * 0 a 1 + * req: |-----------| (bo_offset=m) + * + * 0 a 1 + * new: |-----------| (bo_offset=m) + * + * + * 3) Existent mapping is replaced. + * -------------------------------- + * + * 0 a 1 + * old: |-----------| (bo_offset=n) + * + * 0 b 1 + * req: |-----------| (bo_offset=n) + * + * 0 b 1 + * new: |-----------| (bo_offset=n) + * + * + * 4) Existent mapping is replaced. + * -------------------------------- + * + * 0 a 1 + * old: |-----| (bo_offset=n) + * + * 0 a 2 + * req: |-----------| (bo_offset=n) + * + * 0 a 2 + * new: |-----------| (bo_offset=n) + * + * Note: We expect to see the same result for a request with a different bo + * and/or bo_offset. + * + * + * 5) Existent mapping is split. + * ----------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 0 b 1 + * req: |-----| (bo_offset=n) + * + * 0 b 1 a' 2 + * new: |-----|-----| (b.bo_offset=n, a.bo_offset=n+1) + * + * Note: We expect to see the same result for a request with a different bo + * and/or non-contiguous bo_offset. + * + * + * 6) Existent mapping is kept. + * ---------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 0 a 1 + * req: |-----| (bo_offset=n) + * + * 0 a 2 + * new: |-----------| (bo_offset=n) + * + * + * 7) Existent mapping is split. + * ----------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 1 b 2 + * req: |-----| (bo_offset=m) + * + * 0 a 1 b 2 + * new: |-----|-----| (a.bo_offset=n,b.bo_offset=m) + * + * + * 8) Existent mapping is kept. + * ---------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 1 a 2 + * req: |-----| (bo_offset=n+1) + * + * 0 a 2 + * new: |-----------| (bo_offset=n) + * + * + * 9) Existent mapping is split. + * ----------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 1 b 3 + * req: |-----------| (bo_offset=m) + * + * 0 a 1 b 3 + * new: |-----|-----------| (a.bo_offset=n,b.bo_offset=m) + * + * + * 10) Existent mapping is merged. + * ------------------------------- + * + * 0 a 2 + * old: |-----------| (bo_offset=n) + * + * 1 a 3 + * req: |-----------| (bo_offset=n+1) + * + * 0 a 3 + * new: |-----------------| (bo_offset=n) + * + * + * 11) Existent mapping is split. + * ------------------------------ + * + * 0 a 3 + * old: |-----------------| (bo_offset=n) + * + * 1 b 2 + * req: |-----| (bo_offset=m) + * + * 0 a 1 b 2 a' 3 + * new: |-----|-----|-----| (a.bo_offset=n,b.bo_offset=m,a'.bo_offset=n+2) + * + * + * 12) Existent mapping is kept. + * ----------------------------- + * + * 0 a 3 + * old: |-----------------| (bo_offset=n) + * + * 1 a 2 + * req: |-----| (bo_offset=n+1) + * + * 0 a 3 + * old: |-----------------| (bo_offset=n) + * + * + * 13) Existent mapping is replaced. + * --------------------------------- + * + * 1 a 2 + * old: |-----| (bo_offset=n) + * + * 0 a 2 + * req: |-----------| (bo_offset=n) + * + * 0 a 2 + * new: |-----------| (bo_offset=n) + * + * Note: We expect to see the same result for a request with a different bo + * and/or non-contiguous bo_offset. + * + * + * 14) Existent mapping is replaced. + * --------------------------------- + * + * 1 a 2 + * old: |-----| (bo_offset=n) + * + * 0 a 3 + * req: |----------------| (bo_offset=n) + * + * 0 a 3 + * new: |----------------| (bo_offset=n) + * + * Note: We expect to see the same result for a request with a different bo + * and/or non-contiguous bo_offset. + * + * + * 15) Existent mapping is split. + * ------------------------------ + * + * 1 a 3 + * old: |-----------| (bo_offset=n) + * + * 0 b 2 + * req: |-----------| (bo_offset=m) + * + * 0 b 2 a' 3 + * new: |-----------|-----| (b.bo_offset=m,a.bo_offset=n+2) + * + * + * 16) Existent mappings are merged. + * --------------------------------- + * + * 0 a 1 + * old: |-----------| (bo_offset=n) + * + * 2 a 3 + * old': |-----------| (bo_offset=n+2) + * + * 1 a 2 + * req: |-----------| (bo_offset=n+1) + * + * a + * new: |----------------------------------| (bo_offset=n) + */ + +/** + * DOC: Locking + * + * Generally, the GPU VA manager does not take care of locking itself, it is + * the drivers responsibility to take care about locking. Drivers might want to + * protect the following operations: inserting, destroying and iterating + * &drm_gpuva and &drm_gpuva_region objects as well as generating split and merge + * operations. + * + * The GPU VA manager does take care of the locking of the backing + * &drm_gem_object buffers GPU VA lists though, unless the provided functions + * documentation claims otherwise. + */ + +/** + * drm_gpuva_manager_init - initialize a &drm_gpuva_manager + * @mgr: pointer to the &drm_gpuva_manager to initialize + * @name: the name of the GPU VA space + * @start_offset: the start offset of the GPU VA space + * @range: the size of the GPU VA space + * @reserve_offset: the start of the kernel reserved GPU VA area + * @reserve_range: the size of the kernel reserved GPU VA area + * + * The &drm_gpuva_manager must be initialized with this function before use. + * + * Note that @mgr must be cleared to 0 before calling this function. The given + * &name is expected to be managed by the surrounding driver structures. + */ +void +drm_gpuva_manager_init(struct drm_gpuva_manager *mgr, + const char *name, + u64 start_offset, u64 range, + u64 reserve_offset, u64 reserve_range) +{ + drm_mm_init(&mgr->va_mm, start_offset, range); + drm_mm_init(&mgr->region_mm, start_offset, range); + + mgr->mm_start = start_offset; + mgr->mm_range = range; + + mgr->name = name ? name : "unknown"; + + memset(&mgr->kernel_alloc_node, 0, sizeof(struct drm_mm_node)); + mgr->kernel_alloc_node.start = reserve_offset; + mgr->kernel_alloc_node.size = reserve_range; + drm_mm_reserve_node(&mgr->region_mm, &mgr->kernel_alloc_node); +} +EXPORT_SYMBOL(drm_gpuva_manager_init); + +/** + * drm_gpuva_manager_destroy - cleanup a &drm_gpuva_manager + * @mgr: pointer to the &drm_gpuva_manager to clean up + * + * Note that it is a bug to call this function on a manager that still + * holds GPU VA mappings. + */ +void +drm_gpuva_manager_destroy(struct drm_gpuva_manager *mgr) +{ + mgr->name = NULL; + drm_mm_remove_node(&mgr->kernel_alloc_node); + drm_mm_takedown(&mgr->va_mm); + drm_mm_takedown(&mgr->region_mm); +} +EXPORT_SYMBOL(drm_gpuva_manager_destroy); + +static struct drm_gpuva_region * +drm_gpuva_in_region(struct drm_gpuva_manager *mgr, u64 addr, u64 range) +{ + struct drm_gpuva_region *reg; + + /* Find the VA region the requested range is strictly enclosed by. */ + drm_gpuva_for_each_region_in_range(reg, mgr, addr, addr + range) { + if (reg->node.start <= addr && + reg->node.start + reg->node.size >= addr + range && + ®->node != &mgr->kernel_alloc_node) + return reg; + } + + return NULL; +} + +static bool +drm_gpuva_in_any_region(struct drm_gpuva_manager *mgr, u64 addr, u64 range) +{ + return !!drm_gpuva_in_region(mgr, addr, range); +} + +/** + * drm_gpuva_insert - insert a &drm_gpuva + * @mgr: the &drm_gpuva_manager to insert the &drm_gpuva in + * @va: the &drm_gpuva to insert + * @addr: the start address of the GPU VA + * @range: the range of the GPU VA + * + * Insert a &drm_gpuva with a given address and range into a + * &drm_gpuva_manager. + * + * The function assumes the caller does not hold the &drm_gem_object's + * GPU VA list mutex. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuva_insert(struct drm_gpuva_manager *mgr, + struct drm_gpuva *va, + u64 addr, u64 range) +{ + struct drm_gpuva_region *reg; + int ret; + + if (!va->gem.obj) + return -EINVAL; + + reg = drm_gpuva_in_region(mgr, addr, range); + if (!reg) + return -EINVAL; + + ret = drm_mm_insert_node_in_range(&mgr->va_mm, &va->node, + range, 0, + 0, addr, + addr + range, + DRM_MM_INSERT_LOW|DRM_MM_INSERT_ONCE); + if (ret) + return ret; + + va->mgr = mgr; + va->region = reg; + + return 0; +} +EXPORT_SYMBOL(drm_gpuva_insert); + +/** + * drm_gpuva_link_locked - link a &drm_gpuva + * @va: the &drm_gpuva to link + * + * This adds the given &va to the GPU VA list of the &drm_gem_object it is + * associated with. + * + * The function assumes the caller already holds the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_link_locked(struct drm_gpuva *va) +{ + lockdep_assert_held(&va->gem.obj->gpuva.mutex); + list_add_tail(&va->head, &va->gem.obj->gpuva.list); +} +EXPORT_SYMBOL(drm_gpuva_link_locked); + +/** + * drm_gpuva_link_unlocked - unlink a &drm_gpuva + * @va: the &drm_gpuva to unlink + * + * This adds the given &va to the GPU VA list of the &drm_gem_object it is + * associated with. + * + * The function assumes the caller does not hold the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_link_unlocked(struct drm_gpuva *va) +{ + drm_gem_gpuva_lock(va->gem.obj); + drm_gpuva_link_locked(va); + drm_gem_gpuva_unlock(va->gem.obj); +} +EXPORT_SYMBOL(drm_gpuva_link_unlocked); + +/** + * drm_gpuva_unlink_locked - unlink a &drm_gpuva + * @va: the &drm_gpuva to unlink + * + * This removes the given &va from the GPU VA list of the &drm_gem_object it is + * associated with. + * + * The function assumes the caller already holds the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_unlink_locked(struct drm_gpuva *va) +{ + lockdep_assert_held(&va->gem.obj->gpuva.mutex); + list_del_init(&va->head); +} +EXPORT_SYMBOL(drm_gpuva_unlink_locked); + +/** + * drm_gpuva_unlink_unlocked - unlink a &drm_gpuva + * @va: the &drm_gpuva to unlink + * + * This removes the given &va from the GPU VA list of the &drm_gem_object it is + * associated with. + * + * The function assumes the caller does not hold the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_unlink_unlocked(struct drm_gpuva *va) +{ + drm_gem_gpuva_lock(va->gem.obj); + drm_gpuva_unlink_locked(va); + drm_gem_gpuva_unlock(va->gem.obj); +} +EXPORT_SYMBOL(drm_gpuva_unlink_unlocked); + +/** + * drm_gpuva_destroy_locked - destroy a &drm_gpuva + * @va: the &drm_gpuva to destroy + * + * This removes the given &va from GPU VA list of the &drm_gem_object it is + * associated with and removes it from the underlaying range allocator. + * + * The function assumes the caller already holds the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_destroy_locked(struct drm_gpuva *va) +{ + lockdep_assert_held(&va->gem.obj->gpuva.mutex); + + list_del(&va->head); + drm_mm_remove_node(&va->node); +} +EXPORT_SYMBOL(drm_gpuva_destroy_locked); + +/** + * drm_gpuva_destroy_unlocked - destroy a &drm_gpuva + * @va: the &drm_gpuva to destroy + * + * This removes the given &va from GPU VA list of the &drm_gem_object it is + * associated with and removes it from the underlaying range allocator. + * + * The function assumes the caller does not hold the &drm_gem_object's + * GPU VA list mutex. + */ +void +drm_gpuva_destroy_unlocked(struct drm_gpuva *va) +{ + drm_gem_gpuva_lock(va->gem.obj); + list_del(&va->head); + drm_gem_gpuva_unlock(va->gem.obj); + + drm_mm_remove_node(&va->node); +} +EXPORT_SYMBOL(drm_gpuva_destroy_unlocked); + +/** + * drm_gpuva_find - find a &drm_gpuva + * @mgr: the &drm_gpuva_manager to search in + * @addr: the &drm_gpuvas address + * @range: the &drm_gpuvas range + * + * Returns: the &drm_gpuva at a given &addr and with a given &range + */ +struct drm_gpuva * +drm_gpuva_find(struct drm_gpuva_manager *mgr, + u64 addr, u64 range) +{ + struct drm_gpuva *va; + + drm_gpuva_for_each_va_in_range(va, mgr, addr, range) { + if (va->node.start == addr && + va->node.size == range) + return va; + } + + return NULL; +} +EXPORT_SYMBOL(drm_gpuva_find); + +/** + * drm_gpuva_find_prev - find the &drm_gpuva before the given address + * @mgr: the &drm_gpuva_manager to search in + * @start: the given GPU VA's start address + * + * Find the adjacent &drm_gpuva before the GPU VA with given &start address. + * + * Note that if there is any free space between the GPU VA mappings no mapping + * is returned. + * + * Returns: a pointer to the found &drm_gpuva or NULL if none was found + */ +struct drm_gpuva * +drm_gpuva_find_prev(struct drm_gpuva_manager *mgr, u64 start) +{ + struct drm_mm_node *node; + + if (start <= mgr->mm_start || + start > (mgr->mm_start + mgr->mm_range)) + return NULL; + + node = __drm_mm_interval_first(&mgr->va_mm, start - 1, start); + if (node == &mgr->va_mm.head_node) + return NULL; + + return (struct drm_gpuva *)node; +} +EXPORT_SYMBOL(drm_gpuva_find_prev); + +/** + * drm_gpuva_find_next - find the &drm_gpuva after the given address + * @mgr: the &drm_gpuva_manager to search in + * @end: the given GPU VA's end address + * + * Find the adjacent &drm_gpuva after the GPU VA with given &end address. + * + * Note that if there is any free space between the GPU VA mappings no mapping + * is returned. + * + * Returns: a pointer to the found &drm_gpuva or NULL if none was found + */ +struct drm_gpuva * +drm_gpuva_find_next(struct drm_gpuva_manager *mgr, u64 end) +{ + struct drm_mm_node *node; + + if (end < mgr->mm_start || + end >= (mgr->mm_start + mgr->mm_range)) + return NULL; + + node = __drm_mm_interval_first(&mgr->va_mm, end, end + 1); + if (node == &mgr->va_mm.head_node) + return NULL; + + return (struct drm_gpuva *)node; +} +EXPORT_SYMBOL(drm_gpuva_find_next); + +/** + * drm_gpuva_region_insert - insert a &drm_gpuva_region + * @mgr: the &drm_gpuva_manager to insert the &drm_gpuva in + * @reg: the &drm_gpuva_region to insert + * @addr: the start address of the GPU VA + * @range: the range of the GPU VA + * + * Insert a &drm_gpuva_region with a given address and range into a + * &drm_gpuva_manager. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuva_region_insert(struct drm_gpuva_manager *mgr, + struct drm_gpuva_region *reg, + u64 addr, u64 range) +{ + int ret; + + ret = drm_mm_insert_node_in_range(&mgr->region_mm, ®->node, + range, 0, + 0, addr, + addr + range, + DRM_MM_INSERT_LOW| + DRM_MM_INSERT_ONCE); + if (ret) + return ret; + + reg->mgr = mgr; + + return 0; +} +EXPORT_SYMBOL(drm_gpuva_region_insert); + +/** + * drm_gpuva_region_destroy - destroy a &drm_gpuva_region + * @mgr: the &drm_gpuva_manager holding the region + * @reg: the &drm_gpuva to destroy + * + * This removes the given ® from the underlaying range allocator. + */ +void +drm_gpuva_region_destroy(struct drm_gpuva_manager *mgr, + struct drm_gpuva_region *reg) +{ + struct drm_gpuva *va; + + drm_gpuva_for_each_va_in_range(va, mgr, + reg->node.start, + reg->node.size) { + WARN(1, "GPU VA region must be empty on destroy.\n"); + return; + } + + if (®->node == &mgr->kernel_alloc_node) { + WARN(1, "Can't destroy kernel reserved region.\n"); + return; + } + + drm_mm_remove_node(®->node); +} +EXPORT_SYMBOL(drm_gpuva_region_destroy); + +/** + * drm_gpuva_region_find - find a &drm_gpuva_region + * @mgr: the &drm_gpuva_manager to search in + * @addr: the &drm_gpuva_regions address + * @range: the &drm_gpuva_regions range + * + * Returns: the &drm_gpuva_region at a given &addr and with a given &range + */ +struct drm_gpuva_region * +drm_gpuva_region_find(struct drm_gpuva_manager *mgr, + u64 addr, u64 range) +{ + struct drm_gpuva_region *reg; + + drm_gpuva_for_each_region_in_range(reg, mgr, addr, addr + range) + if (reg->node.start == addr && + reg->node.size == range) + return reg; + + return NULL; +} +EXPORT_SYMBOL(drm_gpuva_region_find); + +static int +gpuva_op_map_new(struct drm_gpuva_op **pop, + u64 addr, u64 range, + struct drm_gem_object *obj, u64 offset) +{ + struct drm_gpuva_op *op; + + op = *pop = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->op = DRM_GPUVA_OP_MAP; + op->map.va.addr = addr; + op->map.va.range = range; + op->map.gem.obj = obj; + op->map.gem.offset = offset; + + return 0; +} + +static int +gpuva_op_remap_new(struct drm_gpuva_op **pop, + struct drm_gpuva_op_map *prev, + struct drm_gpuva_op_map *next, + struct drm_gpuva_op_unmap *unmap) +{ + struct drm_gpuva_op *op; + struct drm_gpuva_op_remap *r; + + op = *pop = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->op = DRM_GPUVA_OP_REMAP; + r = &op->remap; + + if (prev) { + r->prev = kmemdup(prev, sizeof(*prev), GFP_KERNEL); + if (!r->prev) + goto err_free_op; + } + + if (next) { + r->next = kmemdup(next, sizeof(*next), GFP_KERNEL); + if (!r->next) + goto err_free_prev; + } + + r->unmap = kmemdup(unmap, sizeof(*unmap), GFP_KERNEL); + if (!r->unmap) + goto err_free_next; + + return 0; + +err_free_next: + if (next) + kfree(r->next); +err_free_prev: + if (prev) + kfree(r->prev); +err_free_op: + kfree(op); + *pop = NULL; + + return -ENOMEM; +} + +static int +gpuva_op_unmap_new(struct drm_gpuva_op **pop, + struct drm_gpuva *va, bool merge) +{ + struct drm_gpuva_op *op; + + op = *pop = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->op = DRM_GPUVA_OP_UNMAP; + op->unmap.va = va; + op->unmap.keep = merge; + + return 0; +} + +#define op_map_new_to_list(_ops, _addr, _range, \ + _obj, _offset) \ +do { \ + struct drm_gpuva_op *op; \ + \ + ret = gpuva_op_map_new(&op, _addr, _range, \ + _obj, _offset); \ + if (ret) \ + goto err_free_ops; \ + \ + list_add_tail(&op->entry, _ops); \ +} while (0) + +#define op_remap_new_to_list(_ops, _prev, _next, \ + _unmap) \ +do { \ + struct drm_gpuva_op *op; \ + \ + ret = gpuva_op_remap_new(&op, _prev, _next, \ + _unmap); \ + if (ret) \ + goto err_free_ops; \ + \ + list_add_tail(&op->entry, _ops); \ +} while (0) + +#define op_unmap_new_to_list(_ops, _gpuva, _merge) \ +do { \ + struct drm_gpuva_op *op; \ + \ + ret = gpuva_op_unmap_new(&op, _gpuva, _merge); \ + if (ret) \ + goto err_free_ops; \ + \ + list_add_tail(&op->entry, _ops); \ +} while (0) + +/** + * drm_gpuva_sm_map_ops_create - creates the &drm_gpuva_ops to split and merge + * @mgr: the &drm_gpuva_manager representing the GPU VA space + * @req_addr: the start address of the new mapping + * @req_range: the range of the new mapping + * @req_obj: the &drm_gem_object to map + * @req_offset: the offset within the &drm_gem_object + * + * This function creates a list of operations to perform splitting and merging + * of existent mapping(s) with the newly requested one. + * + * The list can be iterated with &drm_gpuva_for_each_op and must be processed + * in the given order. It can contain map, unmap and remap operations, but it + * also can be empty if no operation is required, e.g. if the requested mapping + * already exists is the exact same way. + * + * There can be an arbitrary amount of unmap operations, a maximum of two remap + * operations and a single map operation. The latter one, if existent, + * represents the original map operation requested by the caller. Please note + * that the map operation might has been modified, e.g. if it was + * merged with an existent mapping. + * + * Note that before calling this function again with another mapping request it + * is necessary to update the &drm_gpuva_manager's view of the GPU VA space. + * The previously obtained operations must be either processed or abandoned. + * To update the &drm_gpuva_manager's view of the GPU VA space + * drm_gpuva_insert(), drm_gpuva_destroy_locked() and/or + * drm_gpuva_destroy_unlocked() should be used. + * + * After the caller finished processing the returned &drm_gpuva_ops, they must + * be freed with &drm_gpuva_ops_free. + * + * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure + */ +struct drm_gpuva_ops * +drm_gpuva_sm_map_ops_create(struct drm_gpuva_manager *mgr, + u64 req_addr, u64 req_range, + struct drm_gem_object *req_obj, u64 req_offset) +{ + struct drm_gpuva_ops *ops; + struct drm_gpuva *va, *prev = NULL; + u64 req_end = req_addr + req_range; + bool skip_pmerge = false, skip_nmerge = false; + int ret; + + if (!drm_gpuva_in_any_region(mgr, req_addr, req_range)) + return ERR_PTR(-EINVAL); + + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&ops->list); + + drm_gpuva_for_each_va_in_range(va, mgr, req_addr, req_end) { + struct drm_gem_object *obj = va->gem.obj; + u64 offset = va->gem.offset; + u64 addr = va->node.start; + u64 range = va->node.size; + u64 end = addr + range; + + /* Generally, we want to skip merging with potential mappings + * left and right of the requested one when we found a + * collision, since merging happens in this loop already. + * + * However, there is one exception when the requested mapping + * spans into a free VM area. If this is the case we might + * still hit the boundary of another mapping before and/or + * after the free VM area. + */ + skip_pmerge = true; + skip_nmerge = true; + + if (addr == req_addr) { + bool merge = obj == req_obj && + offset == req_offset; + if (end == req_end) { + if (merge) + goto done; + + op_unmap_new_to_list(&ops->list, va, false); + break; + } + + if (end < req_end) { + skip_nmerge = false; + op_unmap_new_to_list(&ops->list, va, merge); + goto next; + } + + if (end > req_end) { + struct drm_gpuva_op_map n = { + .va.addr = req_end, + .va.range = range - req_range, + .gem.obj = obj, + .gem.offset = offset + req_range, + }; + struct drm_gpuva_op_unmap u = { .va = va }; + + if (merge) + goto done; + + op_remap_new_to_list(&ops->list, NULL, &n, &u); + break; + } + } else if (addr < req_addr) { + u64 ls_range = req_addr - addr; + struct drm_gpuva_op_map p = { + .va.addr = addr, + .va.range = ls_range, + .gem.obj = obj, + .gem.offset = offset, + }; + struct drm_gpuva_op_unmap u = { .va = va }; + bool merge = obj == req_obj && + offset + ls_range == req_offset; + + if (end == req_end) { + if (merge) + goto done; + + op_remap_new_to_list(&ops->list, &p, NULL, &u); + break; + } + + if (end < req_end) { + u64 new_addr = addr; + u64 new_range = req_range + ls_range; + u64 new_offset = offset; + + /* We validated that the requested mapping is + * within a single VA region already. + * Since it overlaps the current mapping (which + * can't cross a VA region boundary) we can be + * sure that we're still within the boundaries + * of the same VA region after merging. + */ + if (merge) { + req_offset = new_offset; + req_addr = new_addr; + req_range = new_range; + op_unmap_new_to_list(&ops->list, va, true); + goto next; + } + + op_remap_new_to_list(&ops->list, &p, NULL, &u); + goto next; + } + + if (end > req_end) { + struct drm_gpuva_op_map n = { + .va.addr = req_end, + .va.range = end - req_end, + .gem.obj = obj, + .gem.offset = offset + ls_range + + req_range, + }; + + if (merge) + goto done; + + op_remap_new_to_list(&ops->list, &p, &n, &u); + break; + } + } else if (addr > req_addr) { + bool merge = obj == req_obj && + offset == req_offset + + (addr - req_addr); + if (!prev) + skip_pmerge = false; + + if (end == req_end) { + op_unmap_new_to_list(&ops->list, va, merge); + break; + } + + if (end < req_end) { + skip_nmerge = false; + op_unmap_new_to_list(&ops->list, va, merge); + goto next; + } + + if (end > req_end) { + struct drm_gpuva_op_map n = { + .va.addr = req_end, + .va.range = end - req_end, + .gem.obj = obj, + .gem.offset = offset + req_end - addr, + }; + struct drm_gpuva_op_unmap u = { .va = va }; + u64 new_end = end; + u64 new_range = new_end - req_addr; + + /* We validated that the requested mapping is + * within a single VA region already. + * Since it overlaps the current mapping (which + * can't cross a VA region boundary) we can be + * sure that we're still within the boundaries + * of the same VA region after merging. + */ + if (merge) { + req_end = new_end; + req_range = new_range; + op_unmap_new_to_list(&ops->list, va, true); + break; + } + + op_remap_new_to_list(&ops->list, NULL, &n, &u); + break; + } + } +next: + prev = va; + } + + va = skip_pmerge ? NULL : drm_gpuva_find_prev(mgr, req_addr); + if (va) { + struct drm_gem_object *obj = va->gem.obj; + u64 offset = va->gem.offset; + u64 addr = va->node.start; + u64 range = va->node.size; + u64 new_offset = offset; + u64 new_addr = addr; + u64 new_range = req_range + range; + bool merge = obj == req_obj && + offset + range == req_offset; + + /* Don't merge over VA region boundaries. */ + merge &= drm_gpuva_in_any_region(mgr, new_addr, new_range); + if (merge) { + op_unmap_new_to_list(&ops->list, va, true); + + req_offset = new_offset; + req_addr = new_addr; + req_range = new_range; + } + } + + va = skip_nmerge ? NULL : drm_gpuva_find_next(mgr, req_end); + if (va) { + struct drm_gem_object *obj = va->gem.obj; + u64 offset = va->gem.offset; + u64 addr = va->node.start; + u64 range = va->node.size; + u64 end = addr + range; + u64 new_range = req_range + range; + u64 new_end = end; + bool merge = obj == req_obj && + offset == req_offset + req_range; + + /* Don't merge over VA region boundaries. */ + merge &= drm_gpuva_in_any_region(mgr, req_addr, new_range); + if (merge) { + op_unmap_new_to_list(&ops->list, va, true); + + req_range = new_range; + req_end = new_end; + } + } + + op_map_new_to_list(&ops->list, + req_addr, req_range, + req_obj, req_offset); + +done: + return ops; + +err_free_ops: + drm_gpuva_ops_free(ops); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(drm_gpuva_sm_map_ops_create); + +#undef op_map_new_to_list +#undef op_remap_new_to_list +#undef op_unmap_new_to_list + +/** + * drm_gpuva_sm_unmap_ops_create - creates the &drm_gpuva_ops to split on unmap + * @mgr: the &drm_gpuva_manager representing the GPU VA space + * @req_addr: the start address of the range to unmap + * @req_range: the range of the mappings to unmap + * + * This function creates a list of operations to perform unmapping and, if + * required, splitting of the mappings overlapping the unmap range. + * + * The list can be iterated with &drm_gpuva_for_each_op and must be processed + * in the given order. It can contain unmap and remap operations, depending on + * whether there are actual overlapping mappings to split. + * + * There can be an arbitrary amount of unmap operations and a maximum of two + * remap operations. + * + * Note that before calling this function again with another range to unmap it + * is necessary to update the &drm_gpuva_manager's view of the GPU VA space. + * The previously obtained operations must be processed or abandoned. + * To update the &drm_gpuva_manager's view of the GPU VA space + * drm_gpuva_insert(), drm_gpuva_destroy_locked() and/or + * drm_gpuva_destroy_unlocked() should be used. + * + * After the caller finished processing the returned &drm_gpuva_ops, they must + * be freed with &drm_gpuva_ops_free. + * + * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure + */ +struct drm_gpuva_ops * +drm_gpuva_sm_unmap_ops_create(struct drm_gpuva_manager *mgr, + u64 req_addr, u64 req_range) +{ + struct drm_gpuva_ops *ops; + struct drm_gpuva_op *op; + struct drm_gpuva_op_remap *r; + struct drm_gpuva *va; + u64 req_end = req_addr + req_range; + int ret; + + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&ops->list); + + drm_gpuva_for_each_va_in_range(va, mgr, req_addr, req_end) { + struct drm_gem_object *obj = va->gem.obj; + u64 offset = va->gem.offset; + u64 addr = va->node.start; + u64 range = va->node.size; + u64 end = addr + range; + + op = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) { + ret = -ENOMEM; + goto err_free_ops; + } + + r = &op->remap; + + if (addr < req_addr) { + r->prev = kzalloc(sizeof(*r->prev), GFP_KERNEL); + if (!r->prev) { + ret = -ENOMEM; + goto err_free_op; + } + + r->prev->va.addr = addr; + r->prev->va.range = req_addr - addr; + r->prev->gem.obj = obj; + r->prev->gem.offset = offset; + } + + if (end > req_end) { + r->next = kzalloc(sizeof(*r->next), GFP_KERNEL); + if (!r->next) { + ret = -ENOMEM; + goto err_free_prev; + } + + r->next->va.addr = req_end; + r->next->va.range = end - req_end; + r->next->gem.obj = obj; + r->next->gem.offset = offset + (req_end - addr); + } + + if (op->remap.prev || op->remap.next) { + op->op = DRM_GPUVA_OP_REMAP; + r->unmap = kzalloc(sizeof(*r->unmap), GFP_KERNEL); + if (!r->unmap) { + ret = -ENOMEM; + goto err_free_next; + } + + r->unmap->va = va; + } else { + op->op = DRM_GPUVA_OP_UNMAP; + op->unmap.va = va; + } + + list_add_tail(&op->entry, &ops->list); + } + + return ops; + +err_free_next: + if (r->next) + kfree(r->next); +err_free_prev: + if (r->prev) + kfree(r->prev); +err_free_op: + kfree(op); +err_free_ops: + drm_gpuva_ops_free(ops); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(drm_gpuva_sm_unmap_ops_create); + +/** + * drm_gpuva_ops_free - free the given &drm_gpuva_ops + * @ops: the &drm_gpuva_ops to free + * + * Frees the given &drm_gpuva_ops structure including all the ops associated + * with it. + */ +void +drm_gpuva_ops_free(struct drm_gpuva_ops *ops) +{ + struct drm_gpuva_op *op, *next; + + drm_gpuva_for_each_op_safe(op, next, ops) { + list_del(&op->entry); + if (op->op == DRM_GPUVA_OP_REMAP) { + if (op->remap.prev) + kfree(op->remap.prev); + + if (op->remap.next) + kfree(op->remap.next); + + kfree(op->remap.unmap); + } + kfree(op); + } + + kfree(ops); +} +EXPORT_SYMBOL(drm_gpuva_ops_free); diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index d7c521e8860f..6feacd93aca6 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -104,6 +104,12 @@ enum drm_driver_feature { * acceleration should be handled by two drivers that are connected using auxiliary bus. */ DRIVER_COMPUTE_ACCEL = BIT(7), + /** + * @DRIVER_GEM_GPUVA: + * + * Driver supports user defined GPU VA bindings for GEM objects. + */ + DRIVER_GEM_GPUVA = BIT(8), /* IMPORTANT: Below are all the legacy flags, add new ones above. */ diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 772a4adf5287..4a3679034966 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -36,6 +36,8 @@ #include #include +#include +#include #include @@ -337,6 +339,17 @@ struct drm_gem_object { */ struct dma_resv _resv; + /** + * @gpuva: + * + * Provides the list and list mutex of GPU VAs attached to this + * GEM object. + */ + struct { + struct list_head list; + struct mutex mutex; + } gpuva; + /** * @funcs: * @@ -479,4 +492,66 @@ void drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj); unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned nr_to_scan, bool (*shrink)(struct drm_gem_object *obj)); +/** + * drm_gem_gpuva_init - initialize the gpuva list of a GEM object + * @obj: the &drm_gem_object + * + * This initializes the &drm_gem_object's &drm_gpuva list and the mutex + * protecting it. + * + * Calling this function is only necessary for drivers intending to support the + * &drm_driver_feature DRIVER_GEM_GPUVA. + */ +static inline void drm_gem_gpuva_init(struct drm_gem_object *obj) +{ + INIT_LIST_HEAD(&obj->gpuva.list); + mutex_init(&obj->gpuva.mutex); +} + +/** + * drm_gem_gpuva_lock - lock the GEM's gpuva list mutex + * @obj: the &drm_gem_object + * + * This unlocks the mutex protecting the &drm_gem_object's &drm_gpuva list. + */ +static inline void drm_gem_gpuva_lock(struct drm_gem_object *obj) +{ + mutex_lock(&obj->gpuva.mutex); +} + +/** + * drm_gem_gpuva_unlock - unlock the GEM's gpuva list mutex + * @obj: the &drm_gem_object + * + * This unlocks the mutex protecting the &drm_gem_object's &drm_gpuva list. + */ +static inline void drm_gem_gpuva_unlock(struct drm_gem_object *obj) +{ + mutex_unlock(&obj->gpuva.mutex); +} + +/** + * drm_gem_for_each_gpuva - iternator to walk over a list of gpuvas + * @entry: &drm_gpuva structure to assign to in each iteration step + * @obj: the &drm_gem_object the &drm_gpuvas to walk are associated with + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gpuva_manager. + */ +#define drm_gem_for_each_gpuva(entry, obj) \ + list_for_each_entry(entry, &obj->gpuva.list, head) + +/** + * drm_gem_for_each_gpuva_safe - iternator to safely walk over a list of gpuvas + * @entry: &drm_gpuva structure to assign to in each iteration step + * @next: &next &drm_gpuva to store the next step + * @obj: the &drm_gem_object the &drm_gpuvas to walk are associated with + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gem_object. It is implemented with list_for_each_entry_safe(), hence + * it is save against removal of elements. + */ +#define drm_gem_for_each_gpuva_safe(entry, next, obj) \ + list_for_each_entry_safe(entry, next, &obj->gpuva.list, head) + #endif /* __DRM_GEM_H__ */ diff --git a/include/drm/drm_gpuva_mgr.h b/include/drm/drm_gpuva_mgr.h new file mode 100644 index 000000000000..adeb0c916e91 --- /dev/null +++ b/include/drm/drm_gpuva_mgr.h @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef __DRM_GPUVA_MGR_H__ +#define __DRM_GPUVA_MGR_H__ + +/* + * Copyright (c) 2022 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +struct drm_gpuva_region; +struct drm_gpuva; +struct drm_gpuva_ops; + +/** + * struct drm_gpuva_manager - DRM GPU VA Manager + * + * The DRM GPU VA Manager keeps track of a GPU's virtual address space by using + * the &drm_mm range allocator. Typically, this structure is embedded in bigger + * driver structures. + * + * Drivers can pass addresses and ranges in an arbitrary unit, e.g. bytes or + * pages. + * + * There should be one manager instance per GPU virtual address space. + */ +struct drm_gpuva_manager { + /** + * @name: the name of the DRM GPU VA space + */ + const char *name; + + /** + * @mm_start: start of the VA space + */ + u64 mm_start; + + /** + * @mm_range: length of the VA space + */ + u64 mm_range; + + /** + * @region_mm: the &drm_mm range allocator to track GPU VA regions + */ + struct drm_mm region_mm; + + /** + * @va_mm: the &drm_mm range allocator to track GPU VA mappings + */ + struct drm_mm va_mm; + + /** + * @kernel_alloc_node: + * + * &drm_mm_node representing the address space cutout reserved for + * the kernel + */ + struct drm_mm_node kernel_alloc_node; +}; + +void drm_gpuva_manager_init(struct drm_gpuva_manager *mgr, + const char *name, + u64 start_offset, u64 range, + u64 reserve_offset, u64 reserve_range); +void drm_gpuva_manager_destroy(struct drm_gpuva_manager *mgr); + +/** + * struct drm_gpuva_region - structure to track a portion of GPU VA space + * + * This structure represents a portion of a GPUs VA space and is associated + * with a &drm_gpuva_manager. Internally it is based on a &drm_mm_node. + * + * GPU VA mappings, represented by &drm_gpuva objects, are restricted to be + * placed within a &drm_gpuva_region. + */ +struct drm_gpuva_region { + /** + * @node: the &drm_mm_node to track the GPU VA region + */ + struct drm_mm_node node; + + /** + * @mgr: the &drm_gpuva_manager this object is associated with + */ + struct drm_gpuva_manager *mgr; + + /** + * @sparse: indicates whether this region is sparse + */ + bool sparse; +}; + +struct drm_gpuva_region * +drm_gpuva_region_find(struct drm_gpuva_manager *mgr, + u64 addr, u64 range); +int drm_gpuva_region_insert(struct drm_gpuva_manager *mgr, + struct drm_gpuva_region *reg, + u64 addr, u64 range); +void drm_gpuva_region_destroy(struct drm_gpuva_manager *mgr, + struct drm_gpuva_region *reg); + +int drm_gpuva_insert(struct drm_gpuva_manager *mgr, + struct drm_gpuva *va, + u64 addr, u64 range); +/** + * drm_gpuva_for_each_region_in_range - iternator to walk over a range of nodes + * @node__: &drm_gpuva_region structure to assign to in each iteration step + * @gpuva__: &drm_gpuva_manager structure to walk + * @start__: starting offset, the first node will overlap this + * @end__: ending offset, the last node will start before this (but may overlap) + * + * This iterator walks over all nodes in the range allocator that lie + * between @start and @end. It is implemented similarly to list_for_each(), + * but is using &drm_mm's internal interval tree to accelerate the search for + * the starting node, and hence isn't safe against removal of elements. It + * assumes that @end is within (or is the upper limit of) the &drm_gpuva_manager. + * If [@start, @end] are beyond the range of the &drm_gpuva_manager, the + * iterator may walk over the special _unallocated_ &drm_mm.head_node of the + * backing &drm_mm, and may even continue indefinitely. + */ +#define drm_gpuva_for_each_region_in_range(node__, gpuva__, start__, end__) \ + for (node__ = (struct drm_gpuva_region *)__drm_mm_interval_first(&(gpuva__)->region_mm, \ + (start__), (end__)-1); \ + node__->node.start < (end__); \ + node__ = (struct drm_gpuva_region *)list_next_entry(&node__->node, node_list)) + +/** + * drm_gpuva_for_each_region - iternator to walk over a range of nodes + * @entry: &drm_gpuva_region structure to assign to in each iteration step + * @gpuva: &drm_gpuva_manager structure to walk + * + * This iterator walks over all &drm_gpuva_region structures associated with the + * &drm_gpuva_manager. + */ +#define drm_gpuva_for_each_region(entry, gpuva) \ + list_for_each_entry(entry, drm_mm_nodes(&(gpuva)->region_mm), node.node_list) + +/** + * drm_gpuva_for_each_region_safe - iternator to safely walk over a range of + * nodes + * @entry: &drm_gpuva_region structure to assign to in each iteration step + * @next: &next &drm_gpuva_region to store the next step + * @gpuva: &drm_gpuva_manager structure to walk + * + * This iterator walks over all &drm_gpuva_region structures associated with the + * &drm_gpuva_manager. It is implemented with list_for_each_safe(), so save + * against removal of elements. + */ +#define drm_gpuva_for_each_region_safe(entry, next, gpuva) \ + list_for_each_entry_safe(entry, next, drm_mm_nodes(&(gpuva)->region_mm), node.node_list) + + +/** + * enum drm_gpuva_flags - flags for struct drm_gpuva + */ +enum drm_gpuva_flags { + /** + * @DRM_GPUVA_SWAPPED: flag indicating that the &drm_gpuva is swapped + */ + DRM_GPUVA_SWAPPED = (1 << 0), +}; + +/** + * struct drm_gpuva - structure to track a GPU VA mapping + * + * This structure represents a GPU VA mapping and is associated with a + * &drm_gpuva_manager. Internally it is based on a &drm_mm_node. + * + * Typically, this structure is embedded in bigger driver structures. + */ +struct drm_gpuva { + /** + * @node: the &drm_mm_node to track the GPU VA mapping + */ + struct drm_mm_node node; + + /** + * @mgr: the &drm_gpuva_manager this object is associated with + */ + struct drm_gpuva_manager *mgr; + + /** + * @region: the &drm_gpuva_region the &drm_gpuva is mapped in + */ + struct drm_gpuva_region *region; + + /** + * @head: the &list_head to attach this object to a &drm_gem_object + */ + struct list_head head; + + /** + * @flags: the &drm_gpuva_flags for this mapping + */ + enum drm_gpuva_flags flags; + + /** + * @gem: structure containing the &drm_gem_object and it's offset + */ + struct { + /** + * @offset: the offset within the &drm_gem_object + */ + u64 offset; + + /** + * @obj: the mapped &drm_gem_object + */ + struct drm_gem_object *obj; + } gem; +}; + +void drm_gpuva_link_locked(struct drm_gpuva *va); +void drm_gpuva_link_unlocked(struct drm_gpuva *va); +void drm_gpuva_unlink_locked(struct drm_gpuva *va); +void drm_gpuva_unlink_unlocked(struct drm_gpuva *va); + +void drm_gpuva_destroy_locked(struct drm_gpuva *va); +void drm_gpuva_destroy_unlocked(struct drm_gpuva *va); + +struct drm_gpuva *drm_gpuva_find(struct drm_gpuva_manager *mgr, + u64 addr, u64 range); +struct drm_gpuva *drm_gpuva_find_prev(struct drm_gpuva_manager *mgr, u64 start); +struct drm_gpuva *drm_gpuva_find_next(struct drm_gpuva_manager *mgr, u64 end); + +/** + * drm_gpuva_swap - sets whether the backing BO of this &drm_gpuva is swapped + * @va: the &drm_gpuva to set the swap flag of + * @swap: indicates whether the &drm_gpuva is swapped + */ +static inline void drm_gpuva_swap(struct drm_gpuva *va, bool swap) +{ + if (swap) + va->flags |= DRM_GPUVA_SWAPPED; + else + va->flags &= ~DRM_GPUVA_SWAPPED; +} + +/** + * drm_gpuva_swapped - indicates whether the backing BO of this &drm_gpuva + * is swapped + * @va: the &drm_gpuva to check + */ +static inline bool drm_gpuva_swapped(struct drm_gpuva *va) +{ + return va->flags & DRM_GPUVA_SWAPPED; +} + +/** + * drm_gpuva_for_each_va_in_range - iternator to walk over a range of nodes + * @node__: &drm_gpuva structure to assign to in each iteration step + * @gpuva__: &drm_gpuva_manager structure to walk + * @start__: starting offset, the first node will overlap this + * @end__: ending offset, the last node will start before this (but may overlap) + * + * This iterator walks over all nodes in the range allocator that lie + * between @start and @end. It is implemented similarly to list_for_each(), + * but is using &drm_mm's internal interval tree to accelerate the search for + * the starting node, and hence isn't safe against removal of elements. It + * assumes that @end is within (or is the upper limit of) the &drm_gpuva_manager. + * If [@start, @end] are beyond the range of the &drm_gpuva_manager, the + * iterator may walk over the special _unallocated_ &drm_mm.head_node of the + * backing &drm_mm, and may even continue indefinitely. + */ +#define drm_gpuva_for_each_va_in_range(node__, gpuva__, start__, end__) \ + for (node__ = (struct drm_gpuva *)__drm_mm_interval_first(&(gpuva__)->va_mm, \ + (start__), (end__)-1); \ + node__->node.start < (end__); \ + node__ = (struct drm_gpuva *)list_next_entry(&node__->node, node_list)) + +/** + * drm_gpuva_for_each_va - iternator to walk over a range of nodes + * @entry: &drm_gpuva structure to assign to in each iteration step + * @gpuva: &drm_gpuva_manager structure to walk + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gpuva_manager. + */ +#define drm_gpuva_for_each_va(entry, gpuva) \ + list_for_each_entry(entry, drm_mm_nodes(&(gpuva)->va_mm), node.node_list) + +/** + * drm_gpuva_for_each_va_safe - iternator to safely walk over a range of + * nodes + * @entry: &drm_gpuva structure to assign to in each iteration step + * @next: &next &drm_gpuva to store the next step + * @gpuva: &drm_gpuva_manager structure to walk + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gpuva_manager. It is implemented with list_for_each_safe(), so save + * against removal of elements. + */ +#define drm_gpuva_for_each_va_safe(entry, next, gpuva) \ + list_for_each_entry_safe(entry, next, drm_mm_nodes(&(gpuva)->va_mm), node.node_list) + +/** + * enum drm_gpuva_op_type - GPU VA operation type + * + * Operations to alter the GPU VA mappings tracked by the &drm_gpuva_manager + * can be map, remap or unmap operations. + */ +enum drm_gpuva_op_type { + /** + * @DRM_GPUVA_OP_MAP: the map op type + */ + DRM_GPUVA_OP_MAP, + + /** + * @DRM_GPUVA_OP_REMAP: the remap op type + */ + DRM_GPUVA_OP_REMAP, + + /** + * @DRM_GPUVA_OP_UNMAP: the unmap op type + */ + DRM_GPUVA_OP_UNMAP, +}; + +/** + * struct drm_gpuva_op_map - GPU VA map operation + * + * This structure represents a single map operation generated by the + * DRM GPU VA manager. + */ +struct drm_gpuva_op_map { + /** + * @va: structure containing address and range of a map + * operation + */ + struct { + /** + * @addr: the base address of the new mapping + */ + u64 addr; + + /** + * @range: the range of the new mapping + */ + u64 range; + } va; + + /** + * @gem: structure containing the &drm_gem_object and it's offset + */ + struct { + /** + * @offset: the offset within the &drm_gem_object + */ + u64 offset; + + /** + * @obj: the &drm_gem_object to map + */ + struct drm_gem_object *obj; + } gem; +}; + +/** + * struct drm_gpuva_op_unmap - GPU VA unmap operation + * + * This structure represents a single unmap operation generated by the + * DRM GPU VA manager. + */ +struct drm_gpuva_op_unmap { + /** + * @va: the &drm_gpuva to unmap + */ + struct drm_gpuva *va; + + /** + * @keep: + * + * Indicates whether this &drm_gpuva is physically contiguous with the + * original mapping request. + * + * Optionally, if &keep is set, drivers may keep the actual page table + * mappings for this &drm_gpuva, adding the missing page table entries + * only and update the &drm_gpuva_manager accordingly. + */ + bool keep; +}; + +/** + * struct drm_gpuva_op_remap - GPU VA remap operation + * + * This represents a single remap operation generated by the DRM GPU VA manager. + * + * A remap operation is generated when an existing GPU VA mmapping is split up + * by inserting a new GPU VA mapping or by partially unmapping existent + * mapping(s), hence it consists of a maximum of two map and one unmap + * operation. + * + * The @unmap operation takes care of removing the original existing mapping. + * @prev is used to remap the preceding part, @next the subsequent part. + * + * If either a new mapping's start address is aligned with the start address + * of the old mapping or the new mapping's end address is aligned with the + * end address of the old mapping, either @prev or @next is NULL. + * + * Note, the reason for a dedicated remap operation, rather than arbitrary + * unmap and map operations, is to give drivers the chance of extracting driver + * specific data for creating the new mappings from the unmap operations's + * &drm_gpuva structure which typically is embedded in larger driver specific + * structures. + */ +struct drm_gpuva_op_remap { + /** + * @prev: the preceding part of a split mapping + */ + struct drm_gpuva_op_map *prev; + + /** + * @next: the subsequent part of a split mapping + */ + struct drm_gpuva_op_map *next; + + /** + * @unmap: the unmap operation for the original existing mapping + */ + struct drm_gpuva_op_unmap *unmap; +}; + +/** + * struct drm_gpuva_op - GPU VA operation + * + * This structure represents a single generic operation, which can be either + * map, unmap or remap. + * + * The particular type of the operation is defined by @op. + */ +struct drm_gpuva_op { + /** + * @entry: + * + * The &list_head used to distribute instances of this struct within + * &drm_gpuva_ops. + */ + struct list_head entry; + + /** + * @op: the type of the operation + */ + enum drm_gpuva_op_type op; + + union { + /** + * @map: the map operation + */ + struct drm_gpuva_op_map map; + + /** + * @unmap: the unmap operation + */ + struct drm_gpuva_op_unmap unmap; + + /** + * @remap: the remap operation + */ + struct drm_gpuva_op_remap remap; + }; +}; + +/** + * struct drm_gpuva_ops - wraps a list of &drm_gpuva_op + */ +struct drm_gpuva_ops { + /** + * @list: the &list_head + */ + struct list_head list; +}; + +/** + * drm_gpuva_for_each_op - iterator to walk over all ops + * @op: &drm_gpuva_op to assign in each iteration step + * @ops: &drm_gpuva_ops to walk + * + * This iterator walks over all ops within a given list of operations. + */ +#define drm_gpuva_for_each_op(op, ops) list_for_each_entry(op, &(ops)->list, entry) + +/** + * drm_gpuva_for_each_op_safe - iterator to safely walk over all ops + * @op: &drm_gpuva_op to assign in each iteration step + * @next: &next &drm_gpuva_op to store the next step + * @ops: &drm_gpuva_ops to walk + * + * This iterator walks over all ops within a given list of operations. It is + * implemented with list_for_each_safe(), so save against removal of elements. + */ +#define drm_gpuva_for_each_op_safe(op, next, ops) \ + list_for_each_entry_safe(op, next, &(ops)->list, entry) + +struct drm_gpuva_ops * +drm_gpuva_sm_map_ops_create(struct drm_gpuva_manager *mgr, + u64 addr, u64 range, + struct drm_gem_object *obj, u64 offset); +struct drm_gpuva_ops * +drm_gpuva_sm_unmap_ops_create(struct drm_gpuva_manager *mgr, + u64 addr, u64 range); +void drm_gpuva_ops_free(struct drm_gpuva_ops *ops); + +#endif /* __DRM_GPUVA_MGR_H__ */ From patchwork Wed Jan 18 06:12:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45021 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176360wrn; Tue, 17 Jan 2023 22:38:47 -0800 (PST) X-Google-Smtp-Source: AMrXdXsC1Irdw5XflkTHNloH7Z4axAOFBdJLO5tqVhuWobP/I8GO19o5uJ6RfPtQtrfXylFRgU2k X-Received: by 2002:a05:6a20:4c25:b0:ac:83e:a9dc with SMTP id fm37-20020a056a204c2500b000ac083ea9dcmr5438060pzb.13.1674023926792; Tue, 17 Jan 2023 22:38:46 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023926; cv=none; d=google.com; s=arc-20160816; b=Q6kgROS7mG2bEEbNsrdw7RZIVq9fOHrgx5lK07sm3m8wPFZBpzJJXxAr2/56xv0yol Kc+/4920HZ85OWJQLnUOfJ+ShCsVXIkxLQ4rhA1ybpkguyAHrqztfP1OGVqtDHeabh77 nPnAKLVRgGWbq1AvqPTtlJ0rUglWHL2j0Z/0rC+kFRbM/JcXEnJBQluxZCvQbI4BKxqG rbH7XAuMF49kTzQ7oRlSULNyt2TExcsM+mr5s5YzfzbqckyzQhISmpPH06T8RDbJL9uA mCxm7FrLmJBEuq1lIfDz9hXDI3Q1/JMCXgMik2SPL5osOyEUG1CkmaJp+h9igRM15pjC CV6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=LRj04i8kO8UNSuXsGqfC3ZL11EhFJ7RqZPr5BWcyY7o=; b=cy48fe1qsOlFdj8RDqsNB105aiVd43h/dzyDWRbx6zXkb5h0uGQw6w4FreIyUgQaqx ySb8MaxCILkvS0brHCrhvw11K8dN42vdMUU3oCosAU8Fz1o2lIwLAOhlU2zzaUe2NECl tRmDZp3bEhkvYJ4I2prQweEotM5nyYeKTIt4k9JAtyuegUCQrAuNw1aDCV0dURp+yN12 HUXYrdzknYNMeJabkeEurdZe0bXIffkPGUUPwnpxqRXf27bSNH4wB3d7nvHhHG6sQCD+ igY16s/uFDRwRBySsvYYyeEPOu9npEAvCe7NzUDx/YoY54xvtnsv8JqajsFjuSSR5j38 GCiQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ZtPxhE3r; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id y184-20020a638ac1000000b004b6578f3355si4608092pgd.773.2023.01.17.22.38.34; Tue, 17 Jan 2023 22:38:46 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ZtPxhE3r; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229910AbjARGgy (ORCPT + 99 others); Wed, 18 Jan 2023 01:36:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229685AbjARGYe (ORCPT ); Wed, 18 Jan 2023 01:24:34 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 462C834C36 for ; Tue, 17 Jan 2023 22:13:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022422; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LRj04i8kO8UNSuXsGqfC3ZL11EhFJ7RqZPr5BWcyY7o=; b=ZtPxhE3rJNHu91IHySTtya1e39LQkoyfSxMqe0nJpuBSF52YhDOGEv3c6xBZ3rLRspXaSv dIF9JlUYpk9WKR3tMrBfZMIJ3diQGwKAzyrrHhnMRhvO/ifIaWVwNr1zxtzRz5DIJR3eCV fHsGPPgkfAQs52ymH1yZks+30rJK2Wo= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-675-zdLZzG-uNB66xnfFf1yNzA-1; Wed, 18 Jan 2023 01:13:41 -0500 X-MC-Unique: zdLZzG-uNB66xnfFf1yNzA-1 Received: by mail-ej1-f71.google.com with SMTP id sa32-20020a1709076d2000b0084d4593797eso19757421ejc.16 for ; Tue, 17 Jan 2023 22:13:41 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LRj04i8kO8UNSuXsGqfC3ZL11EhFJ7RqZPr5BWcyY7o=; b=t5cAn7yt9h5Z/8xd15nWTZ7Hx2IesWP5/rTDicDXT5uJ9fPZPle5S6D4ksFbansqUI yhIuwipb+5QvvP1C5gQK8lfT49syccDRKqvfMA4NY1eTL0HhX0SWqVfJXYNQSI4HceXW zVzV1qVTRVvoDBqI2zkVUFLqxnW7FNU2mulFbD1hyn1cY61UW5KQaQxZ11NAll5iLoih 6+JBu+vr4qjixNa8k/0JpbcTWV/4tKQBaTO3MeMzfXcTo0sNluAeWfDOleGVnF49qlh9 a3ZH24iiadlDzTGhEtr09g6HvB1sTD5rEWIIqVrojXKb2G2z7PpuLER9efVP8gKrfDQ+ OyVg== X-Gm-Message-State: AFqh2koIF7UbcWJhBYKTWL9yd6GbaDNvPnqV2McsUKOKvKdKQ31/ZtPz Q5rB5aJ+7JcmnT+jPs7m022gal/hVmPA3/8Yhk1+AXl0GGZkZnymPHDzK1uGZP+ERExgWrVHZRk TLM50CaddmuGOdBdkIybZ2286 X-Received: by 2002:a05:6402:1f8c:b0:49c:77ba:fa4e with SMTP id c12-20020a0564021f8c00b0049c77bafa4emr6733974edc.28.1674022420597; Tue, 17 Jan 2023 22:13:40 -0800 (PST) X-Received: by 2002:a05:6402:1f8c:b0:49c:77ba:fa4e with SMTP id c12-20020a0564021f8c00b0049c77bafa4emr6733954edc.28.1674022420424; Tue, 17 Jan 2023 22:13:40 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id f22-20020a17090631d600b00779cde476e4sm14066042ejf.62.2023.01.17.22.13.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:40 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 04/14] drm: debugfs: provide infrastructure to dump a DRM GPU VA space Date: Wed, 18 Jan 2023 07:12:46 +0100 Message-Id: <20230118061256.2689-5-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341312776578978?= X-GMAIL-MSGID: =?utf-8?q?1755341312776578978?= This commit adds a function to dump a DRM GPU VA space and a macro for drivers to register the struct drm_info_list 'gpuvas' entry. Most likely, most drivers might maintain one DRM GPU VA space per struct drm_file, but there might also be drivers not having a fixed relation between DRM GPU VA spaces and a DRM core infrastructure, hence we need the indirection via the driver iterating it's maintained DRM GPU VA spaces. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/drm_debugfs.c | 56 +++++++++++++++++++++++++++++++++++ include/drm/drm_debugfs.h | 25 ++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 4f643a490dc3..5389dd73c0fb 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -175,6 +176,61 @@ static const struct file_operations drm_debugfs_fops = { .release = single_release, }; +/** + * drm_debugfs_gpuva_info - dump the given DRM GPU VA space + * @m: pointer to the &seq_file to write + * @mgr: the &drm_gpuva_manager representing the GPU VA space + * + * Dumps the GPU VA regions and mappings of a given DRM GPU VA manager. + * + * For each DRM GPU VA space drivers should call this function from their + * &drm_info_list's show callback. + * + * Returns: 0 on success, -ENODEV if the &mgr is not initialized + */ +int drm_debugfs_gpuva_info(struct seq_file *m, + struct drm_gpuva_manager *mgr) +{ + struct drm_gpuva_region *reg; + struct drm_gpuva *va; + + if (!mgr->name) + return -ENODEV; + + seq_printf(m, "DRM GPU VA space (%s)\n", mgr->name); + seq_puts (m, "\n"); + seq_puts (m, " VA regions | start | range | end | sparse\n"); + seq_puts (m, "------------------------------------------------------------------------------------\n"); + seq_printf(m, " VA space | 0x%016llx | 0x%016llx | 0x%016llx | -\n", + mgr->mm_start, mgr->mm_range, mgr->mm_start + mgr->mm_range); + seq_puts (m, "-----------------------------------------------------------------------------------\n"); + drm_gpuva_for_each_region(reg, mgr) { + struct drm_mm_node *node = ®->node; + + if (node == &mgr->kernel_alloc_node) { + seq_printf(m, " kernel node | 0x%016llx | 0x%016llx | 0x%016llx | -\n", + node->start, node->size, node->start + node->size); + continue; + } + + seq_printf(m, " | 0x%016llx | 0x%016llx | 0x%016llx | %s\n", + node->start, node->size, node->start + node->size, + reg->sparse ? "true" : "false"); + } + seq_puts(m, "\n"); + seq_puts(m, " VAs | start | range | end | object | object offset\n"); + seq_puts(m, "-------------------------------------------------------------------------------------------------------------\n"); + drm_gpuva_for_each_va(va, mgr) { + struct drm_mm_node *node = &va->node; + + seq_printf(m, " | 0x%016llx | 0x%016llx | 0x%016llx | 0x%016llx | 0x%016llx\n", + node->start, node->size, node->start + node->size, + (u64)va->gem.obj, va->gem.offset); + } + + return 0; +} +EXPORT_SYMBOL(drm_debugfs_gpuva_info); /** * drm_debugfs_create_files - Initialize a given set of debugfs files for DRM diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h index 7616f457ce70..cb2c1956a214 100644 --- a/include/drm/drm_debugfs.h +++ b/include/drm/drm_debugfs.h @@ -34,6 +34,22 @@ #include #include + +#include + +/** + * DRM_DEBUGFS_GPUVA_INFO - &drm_info_list entry to dump a GPU VA space + * @show: the &drm_info_list's show callback + * @data: driver private data + * + * Drivers should use this macro to define a &drm_info_list entry to provide a + * debugfs file for dumping the GPU VA space regions and mappings. + * + * For each DRM GPU VA space drivers should call drm_debugfs_gpuva_info() from + * their @show callback. + */ +#define DRM_DEBUGFS_GPUVA_INFO(show, data) {"gpuvas", show, DRIVER_GEM_GPUVA, data} + /** * struct drm_info_list - debugfs info list entry * @@ -134,6 +150,9 @@ void drm_debugfs_add_file(struct drm_device *dev, const char *name, void drm_debugfs_add_files(struct drm_device *dev, const struct drm_debugfs_info *files, int count); + +int drm_debugfs_gpuva_info(struct seq_file *m, + struct drm_gpuva_manager *mgr); #else static inline void drm_debugfs_create_files(const struct drm_info_list *files, int count, struct dentry *root, @@ -155,6 +174,12 @@ static inline void drm_debugfs_add_files(struct drm_device *dev, const struct drm_debugfs_info *files, int count) {} + +static inline int drm_debugfs_gpuva_info(struct seq_file *m, + struct drm_gpuva_manager *mgr) +{ + return 0; +} #endif #endif /* _DRM_DEBUGFS_H_ */ From patchwork Wed Jan 18 06:12:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45043 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2190212wrn; Tue, 17 Jan 2023 23:20:51 -0800 (PST) X-Google-Smtp-Source: AMrXdXvgYa67huuoMr13CLRAbgLy0eDbzHUJ0fwNZbkpIpdtjXwBUatWU+CDIifClfMAgz5ooDps X-Received: by 2002:a05:6402:524f:b0:49e:910:5706 with SMTP id t15-20020a056402524f00b0049e09105706mr8696229edd.2.1674026450819; Tue, 17 Jan 2023 23:20:50 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674026450; cv=none; d=google.com; s=arc-20160816; b=d/IB53bUurgZ+CZWNLkXtzgckjNjVQYU8n+h/f2p+RnIrkK60srBliRqYwRr4vHmJE aqxhpZkfpNovQIV2lKJOGc1nqMZ/KnpYfY/rpzEImLo/nmQ8kKoITU+mab4/EOlVzRAO /reMt0br1J2ig4qvm3zeCd7dxwGUW0Pmt32/QSDfy7JXYUUbcFh2EG3lNrLskYnNgBMn IoOexwfQt51zOVezOvW1lPnNLhTS2IhsiaJ6f1klF44A/zfeHq+MG9J9bbs6Smk8iV+P byEr6X1xQZzpPTd986aDHNIbnS2MrFWp4Km0ya2TF6cZlAvtpbwuQ9jjs8O2yuWoVgCa GqbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=v4Ui7nnL8WMOF/Rh/0KZxy27XuCjk5hBiGqbg/f/QL4=; b=iTWNyJ70nt2pPAYbI+K7DdpG3mWEfdi1TSSONjzdOjTN9ohvNtQwgVF42+SD6CrMvC ryMTcCZXX9grhcSDTwyfuGG6kkgzgAPp3jMr627B3c7BLICBh4W85JuqP9ZIBokOIubL f2pTuNwKuEbQHFywG5MAma0GbfS2coBwPWLRdq4NX3vfdXzC3pd4QHm/mzSCDrIFibqi b4UCYNt+CFmESBFFPaPxNb6rEJsJ1UP3EpS8r6c5Tt89gDZv2UuFfhFkhgvqOeBkle2a NBhJLnnzfYQ/HWLokWk5l8T1JfioX9/WWAmf7PQvyxGEGZr1tglrDglmxzOZKxj6zh55 fMkA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=aVFzDr4+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id d14-20020aa7d5ce000000b0049b63678b52si12032312eds.516.2023.01.17.23.20.27; Tue, 17 Jan 2023 23:20:50 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=aVFzDr4+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230189AbjARGuR (ORCPT + 99 others); Wed, 18 Jan 2023 01:50:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229777AbjARGZM (ORCPT ); Wed, 18 Jan 2023 01:25:12 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2BDCB367C9 for ; Tue, 17 Jan 2023 22:13:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022427; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=v4Ui7nnL8WMOF/Rh/0KZxy27XuCjk5hBiGqbg/f/QL4=; b=aVFzDr4+bT339l0PB/ORcYTqd2pEpCLUgNaD1c/fRZlZMPbfAf8H/eyoFGpzQsbbzfhvgD bc/kjk+Zb0iaB+Rx+1CN9ODp+RDKzIRchZeRZNY90Ek4trOacgbid3Egnrl1XH4R4hwfN7 ocWs2c9KicPFEjZEi6vfR83ZmDdEH9w= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-155-roYCMS9INbOhA5eixBs-UQ-1; Wed, 18 Jan 2023 01:13:46 -0500 X-MC-Unique: roYCMS9INbOhA5eixBs-UQ-1 Received: by mail-ej1-f72.google.com with SMTP id qf20-20020a1709077f1400b0086ec9755517so6399276ejc.15 for ; Tue, 17 Jan 2023 22:13:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=v4Ui7nnL8WMOF/Rh/0KZxy27XuCjk5hBiGqbg/f/QL4=; b=xkrM5cfMw+2MiJRQDHZuVV8g0094XpDTujrwPz8CLFwl1tvEzSCF20DyjvGlsj2rXB 9zTpADP6z5r8Yq0Wp9AWAdQOqNQ8Ahas17j4ZxKrqbiz2zW74065rBkznjcUFbMlCTpI BOGedhFbYQDIkaDxd3jP6/Svf6xg5KR+Gz19J8KSkHK3OsDA6CMRnt4ypUR7DtUcZejW g8dOH3p/9CO39/+nGf1y8gyUTP3adI5X9vPvnxwSLcBgdbxSa4MZpqwh/jaj7j3PfLdh I4tLu9L0N9KlFWij8jqE2H3OU0kTfAvXF+MnBr94O3ziyYPAh6XyMK+UcQ1I/eaa7Y/1 NAcA== X-Gm-Message-State: AFqh2koS79JO7V1TKEFmyp9Om57DuyUyDJIE51X7mZYHM/bQKUf8EHfo O9yw23N98pL41p15p29CL5BzeMN6lk4JPvN910ffZ49ChiI+sgEUhvp2tiGVzlDX86lqPbkNTtf kqr3rmruahgpx0S0Bc5MyVNDW X-Received: by 2002:a17:907:d10:b0:86e:df17:df94 with SMTP id gn16-20020a1709070d1000b0086edf17df94mr7855522ejc.14.1674022424853; Tue, 17 Jan 2023 22:13:44 -0800 (PST) X-Received: by 2002:a17:907:d10:b0:86e:df17:df94 with SMTP id gn16-20020a1709070d1000b0086edf17df94mr7855498ejc.14.1674022424598; Tue, 17 Jan 2023 22:13:44 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id wi19-20020a170906fd5300b00871075bfcfesm3128359ejb.133.2023.01.17.22.13.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:44 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 05/14] drm/nouveau: new VM_BIND uapi interfaces Date: Wed, 18 Jan 2023 07:12:47 +0100 Message-Id: <20230118061256.2689-6-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755343959466958415?= X-GMAIL-MSGID: =?utf-8?q?1755343959466958415?= This commit provides the interfaces for the new UAPI motivated by the Vulkan API. It allows user mode drivers (UMDs) to: 1) Initialize a GPU virtual address (VA) space via the new DRM_IOCTL_NOUVEAU_VM_INIT ioctl. UMDs can provide a kernel reserved VA area. 2) Bind and unbind GPU VA space mappings via the new DRM_IOCTL_NOUVEAU_VM_BIND ioctl. 3) Execute push buffers with the new DRM_IOCTL_NOUVEAU_EXEC ioctl. Both, DRM_IOCTL_NOUVEAU_VM_BIND and DRM_IOCTL_NOUVEAU_EXEC support asynchronous processing with DRM syncobjs as synchronization mechanism. The default DRM_IOCTL_NOUVEAU_VM_BIND is synchronous processing, DRM_IOCTL_NOUVEAU_EXEC supports asynchronous processing only. Co-authored-by: Dave Airlie Signed-off-by: Danilo Krummrich --- Documentation/gpu/driver-uapi.rst | 8 ++ include/uapi/drm/nouveau_drm.h | 216 ++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst index 4411e6919a3d..9c7ca6e33a68 100644 --- a/Documentation/gpu/driver-uapi.rst +++ b/Documentation/gpu/driver-uapi.rst @@ -6,3 +6,11 @@ drm/i915 uAPI ============= .. kernel-doc:: include/uapi/drm/i915_drm.h + +drm/nouveau uAPI +================ + +VM_BIND / EXEC uAPI +------------------- + +.. kernel-doc:: include/uapi/drm/nouveau_drm.h diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h index 853a327433d3..f6e7d40201d4 100644 --- a/include/uapi/drm/nouveau_drm.h +++ b/include/uapi/drm/nouveau_drm.h @@ -126,6 +126,216 @@ struct drm_nouveau_gem_cpu_fini { __u32 handle; }; +/** + * struct drm_nouveau_sync - sync object + * + * This structure serves as synchronization mechanism for (potentially) + * asynchronous operations such as EXEC or VM_BIND. + */ +struct drm_nouveau_sync { + /** + * @flags: the flags for a sync object + * + * The first 8 bits are used to determine the type of the sync object. + */ + __u32 flags; +#define DRM_NOUVEAU_SYNC_SYNCOBJ 0x0 +#define DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ 0x1 +#define DRM_NOUVEAU_SYNC_TYPE_MASK 0xf + /** + * @handle: the handle of the sync object + */ + __u32 handle; + /** + * @timeline_value: + * + * The timeline point of the sync object in case the syncobj is of + * type DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ. + */ + __u64 timeline_value; +}; + +/** + * struct drm_nouveau_vm_init - GPU VA space init structure + * + * Used to initialize the GPU's VA space for a user client, telling the kernel + * which portion of the VA space is managed by the UMD and kernel respectively. + */ +struct drm_nouveau_vm_init { + /** + * @unmanaged_addr: start address of the kernel managed VA space region + */ + __u64 unmanaged_addr; + /** + * @unmanaged_size: size of the kernel managed VA space region in bytes + */ + __u64 unmanaged_size; +}; + +/** + * struct drm_nouveau_vm_bind_op - VM_BIND operation + * + * This structure represents a single VM_BIND operation. UMDs should pass + * an array of this structure via struct drm_nouveau_vm_bind's &op_ptr field. + */ +struct drm_nouveau_vm_bind_op { + /** + * @op: the operation type + */ + __u32 op; +/** + * @DRM_NOUVEAU_VM_BIND_OP_ALLOC: + * + * The alloc operation is used to reserve a VA space region within the GPU's VA + * space. Optionally, the &DRM_NOUVEAU_VM_BIND_SPARSE flag can be passed to + * instruct the kernel to create sparse mappings for the given region. + */ +#define DRM_NOUVEAU_VM_BIND_OP_ALLOC 0x0 +/** + * @DRM_NOUVEAU_VM_BIND_OP_FREE: Free a reserved VA space region. + */ +#define DRM_NOUVEAU_VM_BIND_OP_FREE 0x1 +/** + * @DRM_NOUVEAU_VM_BIND_OP_MAP: + * + * Map a GEM object to the GPU's VA space. The mapping must be fully enclosed by + * a previously allocated VA space region. If the region is sparse, existing + * sparse mappings are overwritten. + */ +#define DRM_NOUVEAU_VM_BIND_OP_MAP 0x2 +/** + * @DRM_NOUVEAU_VM_BIND_OP_UNMAP: + * + * Unmap an existing mapping in the GPU's VA space. If the region the mapping + * is located in is a sparse region, new sparse mappings are created where the + * unmapped (memory backed) mapping was mapped previously. + */ +#define DRM_NOUVEAU_VM_BIND_OP_UNMAP 0x3 + /** + * @flags: the flags for a &drm_nouveau_vm_bind_op + */ + __u32 flags; +/** + * @DRM_NOUVEAU_VM_BIND_SPARSE: + * + * Indicates that an allocated VA space region should be sparse. + */ +#define DRM_NOUVEAU_VM_BIND_SPARSE (1 << 8) + /** + * @handle: the handle of the DRM GEM object to map + */ + __u32 handle; + /** + * @addr: + * + * the address the VA space region or (memory backed) mapping should be mapped to + */ + __u64 addr; + /** + * @bo_offset: the offset within the BO backing the mapping + */ + __u64 bo_offset; + /** + * @range: the size of the requested mapping in bytes + */ + __u64 range; +}; + +/** + * struct drm_nouveau_vm_bind - structure for DRM_IOCTL_NOUVEAU_VM_BIND + */ +struct drm_nouveau_vm_bind { + /** + * @op_count: the number of &drm_nouveau_vm_bind_op + */ + __u32 op_count; + /** + * @flags: the flags for a &drm_nouveau_vm_bind ioctl + */ + __u32 flags; +/** + * @DRM_NOUVEAU_VM_BIND_RUN_ASYNC: + * + * Indicates that the given VM_BIND operation should be executed asynchronously + * by the kernel. + * + * If this flag is not supplied the kernel executes the associated operations + * synchronously and doesn't accept any &drm_nouveau_sync objects. + */ +#define DRM_NOUVEAU_VM_BIND_RUN_ASYNC 0x1 + /** + * @wait_count: the number of wait &drm_nouveau_syncs + */ + __u32 wait_count; + /** + * @sig_count: the number of &drm_nouveau_syncs to signal when finished + */ + __u32 sig_count; + /** + * @wait_ptr: pointer to &drm_nouveau_syncs to wait for + */ + __u64 wait_ptr; + /** + * @sig_ptr: pointer to &drm_nouveau_syncs to signal when finished + */ + __u64 sig_ptr; + /** + * @op_ptr: pointer to the &drm_nouveau_vm_bind_ops to execute + */ + __u64 op_ptr; +}; + +/** + * struct drm_nouveau_exec_push - EXEC push operation + * + * This structure represents a single EXEC push operation. UMDs should pass an + * array of this structure via struct drm_nouveau_exec's &push_ptr field. + */ +struct drm_nouveau_exec_push { + /** + * @va: the virtual address of the push buffer mapping + */ + __u64 va; + /** + * @va_len: the length of the push buffer mapping + */ + __u64 va_len; +}; + +/** + * struct drm_nouveau_exec - structure for DRM_IOCTL_NOUVEAU_EXEC + */ +struct drm_nouveau_exec { + /** + * @channel: the channel to execute the push buffer in + */ + __u32 channel; + /** + * @push_count: the number of &drm_nouveau_exec_push ops + */ + __u32 push_count; + /** + * @wait_count: the number of wait &drm_nouveau_syncs + */ + __u32 wait_count; + /** + * @sig_count: the number of &drm_nouveau_syncs to signal when finished + */ + __u32 sig_count; + /** + * @wait_ptr: pointer to &drm_nouveau_syncs to wait for + */ + __u64 wait_ptr; + /** + * @sig_ptr: pointer to &drm_nouveau_syncs to signal when finished + */ + __u64 sig_ptr; + /** + * @push_ptr: pointer to &drm_nouveau_exec_push ops + */ + __u64 push_ptr; +}; + #define DRM_NOUVEAU_GETPARAM 0x00 /* deprecated */ #define DRM_NOUVEAU_SETPARAM 0x01 /* deprecated */ #define DRM_NOUVEAU_CHANNEL_ALLOC 0x02 /* deprecated */ @@ -136,6 +346,9 @@ struct drm_nouveau_gem_cpu_fini { #define DRM_NOUVEAU_NVIF 0x07 #define DRM_NOUVEAU_SVM_INIT 0x08 #define DRM_NOUVEAU_SVM_BIND 0x09 +#define DRM_NOUVEAU_VM_INIT 0x10 +#define DRM_NOUVEAU_VM_BIND 0x11 +#define DRM_NOUVEAU_EXEC 0x12 #define DRM_NOUVEAU_GEM_NEW 0x40 #define DRM_NOUVEAU_GEM_PUSHBUF 0x41 #define DRM_NOUVEAU_GEM_CPU_PREP 0x42 @@ -197,6 +410,9 @@ struct drm_nouveau_svm_bind { #define DRM_IOCTL_NOUVEAU_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_FINI, struct drm_nouveau_gem_cpu_fini) #define DRM_IOCTL_NOUVEAU_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_INFO, struct drm_nouveau_gem_info) +#define DRM_IOCTL_NOUVEAU_VM_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_VM_INIT, struct drm_nouveau_vm_init) +#define DRM_IOCTL_NOUVEAU_VM_BIND DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_VM_BIND, struct drm_nouveau_vm_bind) +#define DRM_IOCTL_NOUVEAU_EXEC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_EXEC, struct drm_nouveau_exec) #if defined(__cplusplus) } #endif From patchwork Wed Jan 18 06:12:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45045 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2191093wrn; Tue, 17 Jan 2023 23:23:59 -0800 (PST) X-Google-Smtp-Source: AMrXdXuL2eEn8ctQ4Xg6FNoYETQmSbI81+pk2FLisyWfyO5XaAgsRE554wZg1lPc6OA0wJWvyosv X-Received: by 2002:a17:906:1485:b0:7d3:c516:6ef4 with SMTP id x5-20020a170906148500b007d3c5166ef4mr6149149ejc.20.1674026639226; Tue, 17 Jan 2023 23:23:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674026639; cv=none; d=google.com; s=arc-20160816; b=IB8t9cNPCDIDJ3dmY58ZEqiKzbiXy4Sz7lJVCAFDLLm0D2x7qz3M101uDzjOwFaG2w GnIXTtHfMyDU0ay7PS+fH3htS/g47FbpwqAMlwUyDl00wv2mj0U9j+bCYltnf6PvzOkN xEPuW5xZRshp+XbXGkQDFjKBxP5ihL+FBbj9wneIqdh8eiIg04+41vbobmXRVLy2BATN 8wOKZFR9DbCkXILleaEgN/PD7nOXpIm4pFuMCFgUcdpaPP8Pv0WiseREwtyBmMgVEQsc KUFy/Cx2y4go+idyvdzquKvx9V8TH8FeOjTOFVqK0J23ob2kVo1PL6XOeoq24M1Vgj0q z/mw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=THkjWbjdTDoalDkhZzXhw8wgGXeOdJbZJd1kVOay+qU=; b=qLMR3VZxU9gCl5P/7e9F/IsC1wOk+VBFYUWdixlv5H8Yk9C6Z5hyjAYCSUbfxZva83 rwJkehGszHu+DGOPOJH5ttO7E2aPFq7oetZftL04ssAr/gIFpzI37bJ6kvGMcoCzi4ja AI34klEOGfBkD+ZRD202sED0L1MeyGwzEDVZ3kM4UosDR5NN5s1j2dhjpFQXON85eCUK LiGDFNNQpRcWSIwklq0RR700U+JtQRpUv92S656j8xQYzOMLYcGzee+0GDlZxfdZLSIr M/BarNy6JfA5Rag6YwsXq+ub7g5MUEtBxYRW3kem/zGx2eGEGlMgy7MfNEPiEj8CYu0l Rk2Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=TcjSoSt8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id r19-20020a05640251d300b00485220caa05si43345253edd.597.2023.01.17.23.23.35; Tue, 17 Jan 2023 23:23:59 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=TcjSoSt8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230140AbjARGtz (ORCPT + 99 others); Wed, 18 Jan 2023 01:49:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54356 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229778AbjARGZN (ORCPT ); Wed, 18 Jan 2023 01:25:13 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C489530CA for ; Tue, 17 Jan 2023 22:13:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022431; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=THkjWbjdTDoalDkhZzXhw8wgGXeOdJbZJd1kVOay+qU=; b=TcjSoSt86NPPC1XSTrAcTussVnVMjYKbqnt9lxwbo0f91PobeuiIRJ3vudZUglzC/iumx8 AVXzwvoImf+6nbsrjHuMdDPQfp9bRV/6sLyidn8XhD6+fgOWgNGgxlxgExp29wDE+RVhNH /O0gQG5rXxRRGqHOMciL5Xjs5Be/kLk= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-203-A40zqezQOHGFeVB4WLOFOw-1; Wed, 18 Jan 2023 01:13:50 -0500 X-MC-Unique: A40zqezQOHGFeVB4WLOFOw-1 Received: by mail-ej1-f70.google.com with SMTP id qb2-20020a1709077e8200b00842b790008fso23513348ejc.21 for ; Tue, 17 Jan 2023 22:13:49 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=THkjWbjdTDoalDkhZzXhw8wgGXeOdJbZJd1kVOay+qU=; b=L7evX7OUaruiZc9S89p7u2+dMBeiLd2K+KiaFWpxBvLPCLWnZRLcw+mDggx9NCUviY nCM0HOcVyLIXVcXqw1smGvKhkhDGGlrt/NCf7LMYJTqiQy1WCpOu61Z1kzA9qOW5X4sj bQO3iYW7eXSp+1yUarV68Ah7Nxz+ln2O4mlxra+L9lzyMYe1W9w+y1JPPbadZubuYDqz dGKs6sEOo/W2wB1MepQZUu+Xet48b/Y0/nd+9e2rb9H7FMpuWK8voPEZDGDQrBCXv+kY kYjpmbW4x6Z6P3vBabvyIxCviRLP5XgQZXzUVcqHweE15M7RSnYolbijALP8iaVQAZlI RlZA== X-Gm-Message-State: AFqh2kpgdYOV8SP+ntr0XAQsSyuzxEYAkKLwvZ3smWK8SSWXyf6kv6gH qiOnUIokxKwtidhP8R99c1XGHoQDmkZpAicjS48OaNzRsMmptlYPCdaAeoVeKkptCdsKN47Y0+N tGuHQGcdbuzOLDBXZIC07tstp X-Received: by 2002:a17:907:62a8:b0:86a:d385:81df with SMTP id nd40-20020a17090762a800b0086ad38581dfmr8955220ejc.3.1674022428969; Tue, 17 Jan 2023 22:13:48 -0800 (PST) X-Received: by 2002:a17:907:62a8:b0:86a:d385:81df with SMTP id nd40-20020a17090762a800b0086ad38581dfmr8955202ejc.3.1674022428774; Tue, 17 Jan 2023 22:13:48 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id k2-20020a170906970200b0073dbaeb50f6sm13961020ejx.169.2023.01.17.22.13.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:48 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 06/14] drm/nouveau: get vmm via nouveau_cli_vmm() Date: Wed, 18 Jan 2023 07:12:48 +0100 Message-Id: <20230118061256.2689-7-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755344157085674534?= X-GMAIL-MSGID: =?utf-8?q?1755344157085674534?= Provide a getter function for the client's current vmm context. Since we'll add a new (u)vmm context for UMD bindings in subsequent commits, this will keep the code clean. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 +++++++++ drivers/gpu/drm/nouveau/nouveau_gem.c | 6 +++--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 335fa91ca4ad..d2b32a47e480 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -204,7 +204,7 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, struct nouveau_drm *drm = cli->drm; struct nouveau_bo *nvbo; struct nvif_mmu *mmu = &cli->mmu; - struct nvif_vmm *vmm = cli->svm.cli ? &cli->svm.vmm : &cli->vmm.vmm; + struct nvif_vmm *vmm = &nouveau_cli_vmm(cli)->vmm; int i, pi = -1; if (!*size) { diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index e648ecd0c1a0..1068abe41024 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -148,7 +148,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, chan->device = device; chan->drm = drm; - chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm; + chan->vmm = nouveau_cli_vmm(cli); atomic_set(&chan->killed, 0); /* allocate memory for dma push buffer */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index b5de312a523f..81350e685b50 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -112,6 +112,15 @@ struct nouveau_cli_work { struct dma_fence_cb cb; }; +static inline struct nouveau_vmm * +nouveau_cli_vmm(struct nouveau_cli *cli) +{ + if (cli->svm.cli) + return &cli->svm; + + return &cli->vmm; +} + void nouveau_cli_work_queue(struct nouveau_cli *, struct dma_fence *, struct nouveau_cli_work *); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index ac5793c96957..48e6ba00ec27 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -103,7 +103,7 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); struct device *dev = drm->dev->dev; - struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm; + struct nouveau_vmm *vmm = nouveau_cli_vmm(cli); struct nouveau_vma *vma; int ret; @@ -180,7 +180,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); struct device *dev = drm->dev->dev; - struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : & cli->vmm; + struct nouveau_vmm *vmm = nouveau_cli_vmm(cli); struct nouveau_vma *vma; int ret; @@ -269,7 +269,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, { struct nouveau_cli *cli = nouveau_cli(file_priv); struct nouveau_bo *nvbo = nouveau_gem_object(gem); - struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm; + struct nouveau_vmm *vmm = nouveau_cli_vmm(cli); struct nouveau_vma *vma; if (is_power_of_2(nvbo->valid_domains)) From patchwork Wed Jan 18 06:12:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45023 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176552wrn; Tue, 17 Jan 2023 22:39:24 -0800 (PST) X-Google-Smtp-Source: AMrXdXuFYc2Ji+zNBbKXRpRbNyGb6Ww+5w/ZwCATvHLtrALV5LTrpFn52uxLHYYmstYcDwbLEBGI X-Received: by 2002:aa7:9a12:0:b0:587:25ea:4fcb with SMTP id w18-20020aa79a12000000b0058725ea4fcbmr4898766pfj.19.1674023964100; Tue, 17 Jan 2023 22:39:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023964; cv=none; d=google.com; s=arc-20160816; b=RNpJddzX/yI0J6errjc6iM1xXDID7GUMePyBB4O0jujGUFZOFT69xLnuA+1QzHzgu2 vfO32HI+FFSx/VsaZdEaJazOGHyc//s9JzZdpXyl1upypnZhskSqkDgGOGZor14egIMw CAbmqXMARx3MthWfXyFyfl6szBXP7yBNg0t9aZ91nTRGztw8txvDLcEErkIbRK9kmQUz YC+pCyJ3vUY3HCgaKwb1/rTTZ4DxwmWTZQhX7aCE+eZHmf+sAmuS9jcOGMkzWlFPiPF4 d/ENC4TfqpRI73cc6mSphKmzoRsUQlS0PQrp7NdIhXw93SeSF9FhIAxAksPN9IXQFfFF 5LQw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=GqctRI7P01D+Q/Vr3L/m1m3KsR2bbveGpuxATunwrRo=; b=t+C3lLk7Squ0MoVWMFZz6jwrhywhXL9zJpePKJb/CanXzGL7zaIkfHhDuWmAfu7AA+ PAeVkYZDyn5tnC/v62LBOXv2IYqVJfF1sVHPJYZLPIFmv3nyZX1aJD9xEbEmSu7pqk/2 5IIazzH8jrFugYa3M25Q/TECxM44IQ9qy3as5QTkyRJtTlvTa/Hr//zYY42y87ioY+9B Xxr6dO0aKApS3pCv3HVen7IFD+0ete7s4lnfiT/WD1RxxGXPML8TzNvA857+dnoYGQiZ zw/XReu0uF71Wi/IthHhSvhxZ71vD+W54cVs2Dc2fahxXhi/McuJWdrdL/3eCIWxpNlE EoOg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=KOhmbhiJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id s15-20020aa78bcf000000b00556c1c66b61si21504842pfd.143.2023.01.17.22.39.12; Tue, 17 Jan 2023 22:39:24 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=KOhmbhiJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229888AbjARGh7 (ORCPT + 99 others); Wed, 18 Jan 2023 01:37:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57184 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229775AbjARGZL (ORCPT ); Wed, 18 Jan 2023 01:25:11 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C0BE2E0C1 for ; Tue, 17 Jan 2023 22:13:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022436; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GqctRI7P01D+Q/Vr3L/m1m3KsR2bbveGpuxATunwrRo=; b=KOhmbhiJpPZeXhYtvPZo1qHNnBziQWpN/gtciB6/ViR+djbNf2Ne8SHkvUzHHJrwOViHik HBqT0hgBInOJkOfUhpAGsLRifye6M+u0jmTP199+UlzYUBev13KqummzeslhOwcdwQARck 0ZJ2T6FbY8CpkDZA4j3MM73k10ZTKLQ= Received: from mail-ej1-f69.google.com (mail-ej1-f69.google.com [209.85.218.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-70-NKNBTIm1MoOU6KleVxyOTw-1; Wed, 18 Jan 2023 01:13:54 -0500 X-MC-Unique: NKNBTIm1MoOU6KleVxyOTw-1 Received: by mail-ej1-f69.google.com with SMTP id du14-20020a17090772ce00b0087108bbcfa6so4963794ejc.7 for ; Tue, 17 Jan 2023 22:13:53 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GqctRI7P01D+Q/Vr3L/m1m3KsR2bbveGpuxATunwrRo=; b=tXLWtfwC7StDGgZ1GbVdQvaa8zwrhmlR5WUrGbQZyKnsjNHWnHhLlBU4VH4aaNTaKN Y0DmUNIrVNmVs3h4Z6BqvDrSm/3ZqcElIGAYcuvAyR0wIdsA2LZi6iagK78v8o+ry/2i lnZKGgfZANgyp0b2kR56wkoAt8JhrGZ1keMGyFOr98aIMuzSgizXKCe8HaA0vNy2dTO+ DbPyvU8+luTAqJO0rBWAASunBexDx4+6S/A7JjNon/z8/8SzH/H+7JLikidvb8/NJNbF lWvXy9dA+qQdQS0NEHmqmsWtWeRAJ3+we0Xs0vVbHuOWAB2CE6yfyVUhWSBMeDy1c7Y4 dwtQ== X-Gm-Message-State: AFqh2kpSy6LCUxTnWbSP9Spvvp4LQo6eOiurlpsutNAKZ5V2zyRiSvvp SoYQerBjIOEBhV+q+FY3CWvUi2vGQ4Q9KDzSdvgGZbLxyf+V9XxTVHdMAkZcZHl1ZjTgrMppMu8 lQ3BAYyqGOrnJW7BtRpIt8Mvs X-Received: by 2002:a05:6402:401d:b0:49b:5a1c:9cb5 with SMTP id d29-20020a056402401d00b0049b5a1c9cb5mr6136305eda.16.1674022433100; Tue, 17 Jan 2023 22:13:53 -0800 (PST) X-Received: by 2002:a05:6402:401d:b0:49b:5a1c:9cb5 with SMTP id d29-20020a056402401d00b0049b5a1c9cb5mr6136300eda.16.1674022432934; Tue, 17 Jan 2023 22:13:52 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id p11-20020a05640243cb00b0049e19136c22sm3039222edc.95.2023.01.17.22.13.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:52 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 07/14] drm/nouveau: bo: initialize GEM GPU VA interface Date: Wed, 18 Jan 2023 07:12:49 +0100 Message-Id: <20230118061256.2689-8-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341351877826283?= X-GMAIL-MSGID: =?utf-8?q?1755341351877826283?= Initialize the GEM's DRM GPU VA manager interface in preparation for the (u)vmm implementation, provided by subsequent commits, to make use of it. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index d2b32a47e480..4cdeda7fe2df 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -215,11 +215,14 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); if (!nvbo) return ERR_PTR(-ENOMEM); + INIT_LIST_HEAD(&nvbo->head); INIT_LIST_HEAD(&nvbo->entry); INIT_LIST_HEAD(&nvbo->vma_list); nvbo->bo.bdev = &drm->ttm.bdev; + drm_gem_gpuva_init(&nvbo->bo.base); + /* This is confusing, and doesn't actually mean we want an uncached * mapping, but is what NOUVEAU_GEM_DOMAIN_COHERENT gets translated * into in nouveau_gem_new(). From patchwork Wed Jan 18 06:12:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45047 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2193642wrn; Tue, 17 Jan 2023 23:32:00 -0800 (PST) X-Google-Smtp-Source: AMrXdXtnpGmSVFGYP0b4q5yQ4CI96WipdHdT7RR/23LrpR7bZvHlyWyMgZ6f/WCczRSXch7GdvFa X-Received: by 2002:aa7:dcc5:0:b0:499:bed5:f69b with SMTP id w5-20020aa7dcc5000000b00499bed5f69bmr6429883edu.26.1674027120587; Tue, 17 Jan 2023 23:32:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674027120; cv=none; d=google.com; s=arc-20160816; b=GI2CfYhgPqnbj/iG6z9S9sHEkuQ3/rTW2CeVa6GnxojqabZxgbdJvVG86CXmzuXzw6 sE2N3c+egD+KwsqB0Ye4eh6s7DGFJzX8GGyZYP+Go9tGKto95/eJR+OM67zpl+4RwmRd OGrY1pWweAbQu2LTjHo2VLhSeZ8mHw2YbE5pcURdV073t+YJhuWxxm17BcsQlJ7oYrcC hzI+cS2SB9LpJjuc2wYlrhYpZ2rK9qO9VqDvybc2JRRMQq1qeMUpEKXmiOiGYfJq4KRs HOqBU6U2rvJLetWHoF7UvYFx6gTcA/yP+Yo3uRkxScZ/XPWCar/S/UgyDgkNARSMfxO9 nYMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=kuIA/967bi8fJ2s/oMp21AWFew5v50JdzBzuNFK8Osw=; b=jX3IR4hfJjAJ28J5pbRKDXs7O84enevCFqHcR5Jm0aUQHrUX8EjUvsFihx5LrOvs/h URENWziUTozT5f0DRjRbdZZYOG4TYKGMZOJak9RgVl0EKAJjN8+zgBy0xFUKOtVgtByJ rhq6C9IuttfXmzC24jcd48+CN3kS9HRhEujvEohtqCjhPb2AcO9d+8UaIhWaPhG/PDRo 5nO81TmdVQw7SaNbJVC/ewQfKX98cEkfk6E/BDLPNf85syMCblsF7MvzT9VRSVjwCmi5 u156tLjVj94jLA48z+i19z9wymi8MsHKFBBvWSV3p4IB9C8fGbvf6rDKSD1rQ1UhK0Jb 2Q3w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=Jh1dLKQ9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id w20-20020a056402269400b0049e338fe4c9si6172454edd.460.2023.01.17.23.31.36; Tue, 17 Jan 2023 23:32:00 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=Jh1dLKQ9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229760AbjARGte (ORCPT + 99 others); Wed, 18 Jan 2023 01:49:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57348 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229712AbjARGZZ (ORCPT ); Wed, 18 Jan 2023 01:25:25 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 15A3753E5F for ; Tue, 17 Jan 2023 22:14:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022441; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kuIA/967bi8fJ2s/oMp21AWFew5v50JdzBzuNFK8Osw=; b=Jh1dLKQ9HMPoV5wpxDiPQJgBRG0NvqRjypxBuRBiJsGEIDPZ/jPxFCv6RuJUFgKuQA2Kvv OIp6yAv/EuQqM5GNNreeYpDXQ7X0mPyb+SLyz18V50p1NP3Q247UM+V4t5RvWKGkB0XyDO H8n6iRJ0NTOKSa4CQGrVV+yaJbeJH0A= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-8-VnT9C7ReN-WoAJBfXxtZJg-1; Wed, 18 Jan 2023 01:13:58 -0500 X-MC-Unique: VnT9C7ReN-WoAJBfXxtZJg-1 Received: by mail-ej1-f71.google.com with SMTP id hq7-20020a1709073f0700b0086fe36ed3d0so5823269ejc.3 for ; Tue, 17 Jan 2023 22:13:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kuIA/967bi8fJ2s/oMp21AWFew5v50JdzBzuNFK8Osw=; b=Ibzeyra/MMkEU7X+KbPnyywo9XhVnhVHbQESp3sCb9L3EpcWCsuz7FgUzJpFWjTz/D 4Euj21uEL7TAzaZlQpJ4rv5g5lBwBIjwqlpVSxJ6PubBX5wsD+6GTZtGRdlbqrfW+91u 1+fqnf+CV8NToI7S6G2j++oCaVWRPzFjo5gxXUwONvUGaZ8AOKWNBmThNpSAM2A8tdgu RLOGZPXRVae5h8Bb71GYPoLqaVk4b+O05itS5jTU/mzhOJESO/9wmEx5mqwjE+8lyQS3 ODI+k5dt2p2vp/kPKeOMvDYUWBzVvLFVK5zAT3WlN+ZR5PPZ3DlJfEtVtHoWmkyX/v9m rGtA== X-Gm-Message-State: AFqh2koQAcyX/I6oGS99ADpNOg0lwWlvCfZ9QOmsIMNyovI5y7p6vseD jQZTcNtRgHp3ou72PEufkWv6TeX7J7wyALxr2BDd95nWdXDNwFlgOuDDcLkXDnBdEciNUTqYz9A l8ZvzA486Apz3HDewYYhVvz4w X-Received: by 2002:a17:906:549:b0:84d:3822:a14e with SMTP id k9-20020a170906054900b0084d3822a14emr5532745eja.64.1674022437317; Tue, 17 Jan 2023 22:13:57 -0800 (PST) X-Received: by 2002:a17:906:549:b0:84d:3822:a14e with SMTP id k9-20020a170906054900b0084d3822a14emr5532728eja.64.1674022437107; Tue, 17 Jan 2023 22:13:57 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 11-20020a170906300b00b008675df83251sm7184811ejz.34.2023.01.17.22.13.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:13:56 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 08/14] drm/nouveau: move usercopy helpers to nouveau_drv.h Date: Wed, 18 Jan 2023 07:12:50 +0100 Message-Id: <20230118061256.2689-9-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755344661699212824?= X-GMAIL-MSGID: =?utf-8?q?1755344661699212824?= Move the usercopy helpers to a common driver header file to make it usable for the new API added in subsequent commits. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_drv.h | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_gem.c | 26 -------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 81350e685b50..20a7f31b9082 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -130,6 +130,32 @@ nouveau_cli(struct drm_file *fpriv) return fpriv ? fpriv->driver_priv : NULL; } +static inline void +u_free(void *addr) +{ + kvfree(addr); +} + +static inline void * +u_memcpya(uint64_t user, unsigned nmemb, unsigned size) +{ + void *mem; + void __user *userptr = (void __force __user *)(uintptr_t)user; + + size *= nmemb; + + mem = kvmalloc(size, GFP_KERNEL); + if (!mem) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(mem, userptr, size)) { + u_free(mem); + return ERR_PTR(-EFAULT); + } + + return mem; +} + #include #include diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 48e6ba00ec27..5dad2d0dd5cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -613,32 +613,6 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, return 0; } -static inline void -u_free(void *addr) -{ - kvfree(addr); -} - -static inline void * -u_memcpya(uint64_t user, unsigned nmemb, unsigned size) -{ - void *mem; - void __user *userptr = (void __force __user *)(uintptr_t)user; - - size *= nmemb; - - mem = kvmalloc(size, GFP_KERNEL); - if (!mem) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(mem, userptr, size)) { - u_free(mem); - return ERR_PTR(-EFAULT); - } - - return mem; -} - static int nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf *req, From patchwork Wed Jan 18 06:12:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45024 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176578wrn; Tue, 17 Jan 2023 22:39:30 -0800 (PST) X-Google-Smtp-Source: AMrXdXsY9am8kj5Pal6PBZHe5cjuq3/Vq0uw+rQ3UJHNLfJpE/nTjHsBcYeLNM/XFLDkqSPQhqY8 X-Received: by 2002:a05:6a21:6d9e:b0:b3:bf50:9168 with SMTP id wl30-20020a056a216d9e00b000b3bf509168mr7771462pzb.38.1674023970255; Tue, 17 Jan 2023 22:39:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023970; cv=none; d=google.com; s=arc-20160816; b=zIx7ci1ac7mDwjRgPxphTo5l9AKsO5lvV923QOZkWJOqZRZxEK/ukxHJhFhV3GmaiI KDYFiSwvCdoUxHAr/Qj6c9Jm+YV2UHGUFS1VJj2jtMrpGYeyiJcfhPQfwpJmG6pKoCba +nGxfC3+g5uudBdcJARHh15zOtQ7uPYqQ9asv46xRUHOT4q8ELly6pix858r3zu438TW Tfzw8JELsnqHWG7dT0Cm3kVsb62f0bMq68kabioGjXlXlV/ceb4nrlP/rcj9nlCnC4II Ln1E4UvUN2KZ55Ao43jCm+fMAfOIMKGPNk1j1Ml5Uvx3D0CzxSJscnvlfEeTFQ6YYqsk E3yg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=n9EJ+tT+/p3duz0VW0fK+iHRhTM0v9eouQOWnSy8nPY=; b=oSOyxOOFSjFNfN/FKZIABTHj5MZ2khk2e6HWVvzbsmF5paIXK7jwBvGmXgO2NR1AoN PPIo4AvbJVzt1GogiiaeQaryr/OwiaAWetXGQd0upQrJUAQmXsxkeQTBEPZkxtRAKCg1 5jOL51PThBVoWsUSFNyWVRHEv304CGvE3jrOUUSVj+3TGMMDffE46mxmlE8hD0QABhlg 8CJ/wJIGxXOFNgBz0zpuy3ptAsF63kPc0RxA1EqVwvtPL+p8Fg3/CNKkZre5gedN3GUY 9vgnmnKMOXHIlHO8af5MXrkfk3/mi5tyGC4sJTzDOE/nk19Qom7VuTyHtq0xnM5naiJg l8OA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=TidimVEH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e132-20020a63698a000000b00477ca5b5617si31762903pgc.147.2023.01.17.22.39.18; Tue, 17 Jan 2023 22:39:30 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=TidimVEH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230075AbjARGil (ORCPT + 99 others); Wed, 18 Jan 2023 01:38:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57350 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229628AbjARGZZ (ORCPT ); Wed, 18 Jan 2023 01:25:25 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 15BA453F88 for ; Tue, 17 Jan 2023 22:14:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022443; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n9EJ+tT+/p3duz0VW0fK+iHRhTM0v9eouQOWnSy8nPY=; b=TidimVEH65AvR5Z83LkFKuYB7pNK9BmnuSMaYYSPMtZXsDgZEKHyMEPPpdpb+M3V9rtlVs kt6TF0zwuBcq0sd5UMusW2SxkplZdIYXrY9l20Q5DOkwVBDxFobTJ5t3cKFXhXOunaFEH4 KgUZCgs+SoBqivtUmOxeWg/ACNNTI/A= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-659-jVj8y5AqMu2RQPNRTyjKdg-1; Wed, 18 Jan 2023 01:14:02 -0500 X-MC-Unique: jVj8y5AqMu2RQPNRTyjKdg-1 Received: by mail-ej1-f71.google.com with SMTP id hp2-20020a1709073e0200b0084d47e3fe82so19195839ejc.8 for ; Tue, 17 Jan 2023 22:14:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=n9EJ+tT+/p3duz0VW0fK+iHRhTM0v9eouQOWnSy8nPY=; b=NhXx31/OcBdDdi1QRi/AH3IOB/re1mu7tu+kJl+Iw8uzKo0hx1qWHfsQgX4UNyzaCb HapHQLfJusc19HDt2NOhcuFE/NAsJzxol7S72eMnZdreC6nBDeX4wdKI3Hq4BMSL48Ub Hbh7nVHiK/h7OO84Y2dMIO+cYTCa2T1eoAG06Tj9hr7A1Mv4wgT5oJktO0syvNgfcavQ +GNZKQxIqOfEEulUrvf9XS2vRb7Lbxlbh+AuhGlcd7nQi7c3U3ST+8w2ChdA0O2NEg2F a4W2IXLhgKUKrToRZuyJMH2EQeCVELX5UyCuusBPocTilQOQKZovU7lc87TNRN8Q17eX fdaw== X-Gm-Message-State: AFqh2krw0gXCLO17xD79cfGGGdYsiymPIF/BivYOuDWjgAZXNEaGnnN+ Vt7Jt32rTXFArQia+WqiH8T5o6xUL7Aai0ziOtk3Bz0D012iCqn2wOPbuQ49hxgbxQcMilCMtx3 7MeRC+nau8tAhZ1c6YT+N8xlI X-Received: by 2002:a17:907:d047:b0:86d:6e9f:7e36 with SMTP id vb7-20020a170907d04700b0086d6e9f7e36mr2097346ejc.5.1674022441528; Tue, 17 Jan 2023 22:14:01 -0800 (PST) X-Received: by 2002:a17:907:d047:b0:86d:6e9f:7e36 with SMTP id vb7-20020a170907d04700b0086d6e9f7e36mr2097334ejc.5.1674022441366; Tue, 17 Jan 2023 22:14:01 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id sb25-20020a1709076d9900b0084c6581c16fsm14093965ejc.64.2023.01.17.22.14.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:00 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 09/14] drm/nouveau: fence: fail to emit when fence context is killed Date: Wed, 18 Jan 2023 07:12:51 +0100 Message-Id: <20230118061256.2689-10-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341358374934404?= X-GMAIL-MSGID: =?utf-8?q?1755341358374934404?= The new VM_BIND UAPI implementation introduced in subsequent commits will allow asynchronous jobs processing push buffers and emitting fences. If a fence context is killed, e.g. due to a channel fault, jobs which are already queued for execution might still emit new fences. In such a case a job would hang forever. To fix that, fail to emit a new fence on a killed fence context with -ENODEV to unblock the job. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_fence.c | 7 +++++++ drivers/gpu/drm/nouveau/nouveau_fence.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index ee5e9d40c166..62c70d9a32e6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -96,6 +96,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) if (nouveau_fence_signal(fence)) nvif_event_block(&fctx->event); } + fctx->killed = 1; spin_unlock_irqrestore(&fctx->lock, flags); } @@ -226,6 +227,12 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) dma_fence_get(&fence->base); spin_lock_irq(&fctx->lock); + if (unlikely(fctx->killed)) { + spin_unlock_irq(&fctx->lock); + dma_fence_put(&fence->base); + return -ENODEV; + } + if (nouveau_fence_update(chan, fctx)) nvif_event_block(&fctx->event); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 0ca2bc85adf6..00a08699bb58 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -45,7 +45,7 @@ struct nouveau_fence_chan { char name[32]; struct nvif_event event; - int notify_ref, dead; + int notify_ref, dead, killed; }; struct nouveau_fence_priv { From patchwork Wed Jan 18 06:12:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45025 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176593wrn; Tue, 17 Jan 2023 22:39:36 -0800 (PST) X-Google-Smtp-Source: AMrXdXvIS807zSH97J1+Sd1QHEkNSfgIyL+PMGOBd/qUhZor+OB3HvxMmCZdjnOTsBNYovmuLOVK X-Received: by 2002:aa7:8713:0:b0:58b:c803:686 with SMTP id b19-20020aa78713000000b0058bc8030686mr5734185pfo.24.1674023975964; Tue, 17 Jan 2023 22:39:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023975; cv=none; d=google.com; s=arc-20160816; b=Vdg14oqI/CwCwIh9hv6E60ll84WZcpwO3jT7sftrKt0hos/iXwAvCnsXTrOAyl2OJr wJZ6jIGafyU0v61rulswop+2AS8PiDrYdQx9ue0WXIKpuWUj9MmAatarEAMkgz/6ycMa GiJ5PUTCOsERgvET7Mh4oGBtHTbeF2WbI2UGXfUTVFvWmd6T+DsqBHyfuU9s7K9IZhkz yR2vOJu6LIY1/QHdKmbV8KXdDQyXG/92NEhSPnFIZwUc4h3Mdx+fnyNyxCb7z8qW2cCG HEmVKfAd8VOqShtWmfwEyPrIErhJ/ySGNG9Eww8hpiFUmY+JvWXG7RaftSbwazyyFZD6 Wtsg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=arClRUS1jAAdkcFM0OKNg8mvWVVAlTJxmoO3YVnMeNE=; b=LOIM7NQUTDPb4aPx2NWD6wTJ1rhN1RfatoP9Q4c3BzMuGmDC1x06JjbomlPaLjuUw7 KqIGFW2daq4Jn/9BxGYsVrMu9KX6v4C5zrBLSW1KrcuuUGajYNkfYYTItopG+osSo3DX dmjMOIO+uiLdwY3EWZKuRMnzvzzIz8XD14V4M/iqiyaT2vCco46+5SJxKPx9A3vIZepC WXNr5/RK8tSdXTqNWP+WaLFhrH/f6EDb2TpbwrMwR8aJNsdG1F4wI0qkx1LwN2TgDRzu Yuz7wnf3IcxgK8GXYswlyYtuzTrQF09OxMWOyVB3s8c7KV44ZrlS5jW2i2fBmxnvYNBK eDhQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=de5o+O8X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a38-20020a056a001d2600b0058b398c1a69si25196756pfx.59.2023.01.17.22.39.24; Tue, 17 Jan 2023 22:39:35 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=de5o+O8X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229572AbjARGi7 (ORCPT + 99 others); Wed, 18 Jan 2023 01:38:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229600AbjARG0L (ORCPT ); Wed, 18 Jan 2023 01:26:11 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA90154B1D for ; Tue, 17 Jan 2023 22:14:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022448; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=arClRUS1jAAdkcFM0OKNg8mvWVVAlTJxmoO3YVnMeNE=; b=de5o+O8XzWS6UEtcJITBWs4ALTPB9mUEsC+0Kz7QdMLhUJKKf0p6nkt8HuQ/8RIKj66uoG PCLJ7IfFq1cXPkjbeiy+gdKOdJYwE6J8S3pQEhPV+4dhr4hLCF3ghFKXLepiFhPupXL1/p R139ABrrgx192ROkaSREp8OWPSd4VvA= Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-626-g8JOfnjwOp6Haaz-Kbp5KQ-1; Wed, 18 Jan 2023 01:14:06 -0500 X-MC-Unique: g8JOfnjwOp6Haaz-Kbp5KQ-1 Received: by mail-ed1-f72.google.com with SMTP id h18-20020a05640250d200b0049e0e9382c2so6048183edb.13 for ; Tue, 17 Jan 2023 22:14:06 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=arClRUS1jAAdkcFM0OKNg8mvWVVAlTJxmoO3YVnMeNE=; b=CRNSg8UkU1L2BBERA7KLlA13RPuImue39FYMnbYWPMzhtMYBE1iRmw6+BjSGCRtD8c yZ5xDcWbGfESuo8Us+kE7kJ4p9ey/shfq5KFVZqFmQBq5k32Qj5mchQby07p12lyON3M G2K1tLfj8sjxmcJPCe3wMo7wnXhERK/H1oN/A/KZS+NmF4+LOyyicVZgZNhGYvPUNmH3 +udmYw+7kFfLgyb/Xqz4o1U2x0d0s0EhoA5vPFoT6FSSLLSddH3eCjivdXir/26Zo3hg Rd+RLRePso89p1b+n4UGDQwSn+e001sI+J6uVcQa+jGatgq884m9jywe/nRfvDopkumU Rk+A== X-Gm-Message-State: AFqh2koeWNvl4c0J4u7eEjP0AvK6/D0QecfdKGQpFPIFmB/6gjap4lev PflSDj4HkQY64ki58Jh1AZpnrybvBtmjXyk4nqO3OzELHRQa8BFiS7Ep05F1NW1z4yK6Vw4eaRK Tum/jreYq/Rb9cm0iVEnMidkG X-Received: by 2002:a17:906:d971:b0:870:7e7d:97a7 with SMTP id rp17-20020a170906d97100b008707e7d97a7mr5281477ejb.72.1674022445708; Tue, 17 Jan 2023 22:14:05 -0800 (PST) X-Received: by 2002:a17:906:d971:b0:870:7e7d:97a7 with SMTP id rp17-20020a170906d97100b008707e7d97a7mr5281469ejb.72.1674022445535; Tue, 17 Jan 2023 22:14:05 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id f22-20020a17090631d600b00779cde476e4sm14066480ejf.62.2023.01.17.22.14.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:05 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 10/14] drm/nouveau: chan: provide nouveau_channel_kill() Date: Wed, 18 Jan 2023 07:12:52 +0100 Message-Id: <20230118061256.2689-11-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341364928852144?= X-GMAIL-MSGID: =?utf-8?q?1755341364928852144?= The new VM_BIND UAPI implementation introduced in subsequent commits will allow asynchronous jobs processing push buffers and emitting fences. If a job times out, we need a way to recover from this situation. For now, simply kill the channel to unblock all hung up jobs and signal userspace that the device is dead on the next EXEC or VM_BIND ioctl. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_chan.c | 14 +++++++++++--- drivers/gpu/drm/nouveau/nouveau_chan.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 1068abe41024..6f47e997d9cf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -40,6 +40,14 @@ MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM"); int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); +void +nouveau_channel_kill(struct nouveau_channel *chan) +{ + atomic_set(&chan->killed, 1); + if (chan->fence) + nouveau_fence_context_kill(chan->fence, -ENODEV); +} + static int nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc) { @@ -47,9 +55,9 @@ nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc) struct nouveau_cli *cli = (void *)chan->user.client; NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid); - atomic_set(&chan->killed, 1); - if (chan->fence) - nouveau_fence_context_kill(chan->fence, -ENODEV); + + if (unlikely(!atomic_read(&chan->killed))) + nouveau_channel_kill(chan); return NVIF_EVENT_DROP; } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h index e06a8ffed31a..e483f4a254da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.h +++ b/drivers/gpu/drm/nouveau/nouveau_chan.h @@ -65,6 +65,7 @@ int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u32 vram, u32 gart, struct nouveau_channel **); void nouveau_channel_del(struct nouveau_channel **); int nouveau_channel_idle(struct nouveau_channel *); +void nouveau_channel_kill(struct nouveau_channel *); extern int nouveau_vram_pushbuf; From patchwork Wed Jan 18 06:12:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45027 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176675wrn; Tue, 17 Jan 2023 22:39:55 -0800 (PST) X-Google-Smtp-Source: AMrXdXsU+W4K3izpmRPgKuMhyfKiw8Ymgh+jYr5tl1vWb216033UlxKucJa/4BW5aDftqs4CEzGU X-Received: by 2002:a17:90a:898b:b0:225:c2b4:5742 with SMTP id v11-20020a17090a898b00b00225c2b45742mr29199612pjn.34.1674023995034; Tue, 17 Jan 2023 22:39:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023995; cv=none; d=google.com; s=arc-20160816; b=sqQ1HjpdVRaXNn0ZZGVvQpOwmAu5x3g87fs/reHJ8/38A11UZNS+BWoaDcTJUd3q5a H+X0oXHdv/VORPJKS41r243+6E7e3ct4ncFkh0VUO0QFU4KGY8i9TjftxLWQeoVS3ixx bSA4uF0w4bMlg8IJRzprzpx8n+ZP6CvdZYrDkskKlOrZaVRInpDeM1gCjCM81YtLl6vo v4x1Te7yzAdi78fcVcfsPPql9vB73dOndQsUT67hyeVPKhuuIPZwSP55jkoS4qhg29qT 6Z6jFxMHQwGBTf3OUeZ0v4HCYSvpMLm6URXXkUC3jskjTtsRkzCnur2MKLTeTHpMHH8i SNBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=BjQT6ug5vGiLF/xBpRpA85/y/iklQ7iPHa1/Bh9Ff60=; b=HoBt5VeEqCvQCQX7VLhYE0Zq+76SjPew4XrLArdXj+ZML3gFhs1/8fUdyJ205S2Jbw kYeBb8s1YqNgNNFsra9wlMniRsrMPR3kfKiENEcHtLm55Q8zgD2D1qJxNNWL4aE+bmps 1lRy2eCUR1pahdqHJfRVxu1NmRmHXJwg/NPqQZe+2GnP02St9GO883xbTxiUmebD/UoR bNRYnv68h5fwD+sE7rsoPwBAryoCpBztZr7WqsNTlfOC8P6wmxPSLLZqD1n8zJ/dXXzF aLlfIAK0HTMOeM/q/oCyRurPj8PnjhBPeFYNfTZ3Oj3vtA2NHK40HHR9F4eI5FOO0dzJ SVkQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=JITIfXoy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c5-20020a6566c5000000b004c494c3e40dsi13612666pgw.202.2023.01.17.22.39.42; Tue, 17 Jan 2023 22:39:55 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=JITIfXoy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229838AbjARGjO (ORCPT + 99 others); Wed, 18 Jan 2023 01:39:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229669AbjARG0R (ORCPT ); Wed, 18 Jan 2023 01:26:17 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F217554B32 for ; Tue, 17 Jan 2023 22:14:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022454; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BjQT6ug5vGiLF/xBpRpA85/y/iklQ7iPHa1/Bh9Ff60=; b=JITIfXoyL3qw/oeL6f+R/nvEVPqwCUbm8JWi9zKHEcVnksDIFVevs8m9E4uHMoTj3h8Sqn 9QoKmUWXYc/rLUCttBeoOSOZ2guXr5jOyyZXjJQE5GXWc/t5y3aC04jIFEr/+sLL/F0Kv3 +6xXuSGc7Ko8CwBCcvm/PO5dgOaAqpk= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-153-6c4LRBBQO86cqVerJ1ha2Q-1; Wed, 18 Jan 2023 01:14:12 -0500 X-MC-Unique: 6c4LRBBQO86cqVerJ1ha2Q-1 Received: by mail-ej1-f72.google.com with SMTP id sc9-20020a1709078a0900b0086910fdf624so10745066ejc.13 for ; Tue, 17 Jan 2023 22:14:11 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BjQT6ug5vGiLF/xBpRpA85/y/iklQ7iPHa1/Bh9Ff60=; b=VchBAjmbvGiv5Z+1QIUbrT4nG5zDkNxT4kLOkLYZshcb/3kNEz78S4nIF66r/4SIUp IsAYj8PmOaxK/DtTfM8hbZBGgHpaqV3Wp1RDAYawhSiXyhALr1OiVX1kCExCxeLNwKsn ScHOp1tsZhvi5aKB75o48v0f4vpNNnE7c9oqMHgxy9qPRgGI4gxb9YyJHZ+9tka3fHcL DXLU4b9+O5KFwaIuTCNY99VzykzJd/dBETfwCwdt+A2MIc9OPrAqs9dmCObWdtgleSgG /YOyrG0RwmaZ4VOwGcosCKo77TW4NGUOIXA8meG9+wcEefgSBGr2dt605fY/TMYIToPG AM6w== X-Gm-Message-State: AFqh2kq8fl+EUJIA9Mti2hlAKHG7XX0LjVPydEIep4F2pWB18gS3Fvke BFADnwOnMDzAQefCJWJ8CUP1lHg17Bc1GdNS8HEw7ZpHI/yX+Mfy3i+57KMTSc5qUL1H7xTGmoa h37voE0iSNLTvYMOYTXoy+fEB X-Received: by 2002:a17:906:1918:b0:7ad:ca80:5669 with SMTP id a24-20020a170906191800b007adca805669mr5854861eje.64.1674022450091; Tue, 17 Jan 2023 22:14:10 -0800 (PST) X-Received: by 2002:a17:906:1918:b0:7ad:ca80:5669 with SMTP id a24-20020a170906191800b007adca805669mr5854845eje.64.1674022449837; Tue, 17 Jan 2023 22:14:09 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id kz22-20020a17090777d600b007c1633cea13sm14338638ejc.12.2023.01.17.22.14.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:09 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 11/14] drm/nouveau: nvkm/vmm: implement raw ops to manage uvmm Date: Wed, 18 Jan 2023 07:12:53 +0100 Message-Id: <20230118061256.2689-12-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341384605233184?= X-GMAIL-MSGID: =?utf-8?q?1755341384605233184?= The new VM_BIND UAPI uses the DRM GPU VA manager to manage the VA space. Hence, we a need a way to manipulate the MMUs page tables without going through the internal range allocator implemented by nvkm/vmm. This patch adds a raw interface for nvkm/vmm to pass the resposibility for managing the address space and the corresponding map/unmap/sparse operations to the upper layers. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/include/nvif/if000c.h | 23 ++- drivers/gpu/drm/nouveau/include/nvif/vmm.h | 17 +- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 10 ++ drivers/gpu/drm/nouveau/nouveau_svm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_vmm.c | 4 +- drivers/gpu/drm/nouveau/nvif/vmm.c | 73 +++++++- .../gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c | 168 +++++++++++++++++- .../gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 32 +++- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h | 3 + 10 files changed, 319 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if000c.h b/drivers/gpu/drm/nouveau/include/nvif/if000c.h index 9c7ff56831c5..d30e32fb8628 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if000c.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if000c.h @@ -3,7 +3,10 @@ struct nvif_vmm_v0 { __u8 version; __u8 page_nr; - __u8 managed; +#define NVIF_VMM_V0_TYPE_UNMANAGED 0x00 +#define NVIF_VMM_V0_TYPE_MANAGED 0x01 +#define NVIF_VMM_V0_TYPE_RAW 0x02 + __u8 type; __u8 pad03[5]; __u64 addr; __u64 size; @@ -17,6 +20,7 @@ struct nvif_vmm_v0 { #define NVIF_VMM_V0_UNMAP 0x04 #define NVIF_VMM_V0_PFNMAP 0x05 #define NVIF_VMM_V0_PFNCLR 0x06 +#define NVIF_VMM_V0_RAW 0x07 #define NVIF_VMM_V0_MTHD(i) ((i) + 0x80) struct nvif_vmm_page_v0 { @@ -66,6 +70,23 @@ struct nvif_vmm_unmap_v0 { __u64 addr; }; +struct nvif_vmm_raw_v0 { + __u8 version; +#define NVIF_VMM_RAW_V0_MAP 0x0 +#define NVIF_VMM_RAW_V0_UNMAP 0x1 +#define NVIF_VMM_RAW_V0_SPARSE 0x2 + __u8 op; + __u8 sparse; + __u8 ref; + __u8 pad04[4]; + __u64 addr; + __u64 size; + __u64 offset; + __u64 memory; + __u64 handle; + __u8 data[]; +}; + struct nvif_vmm_pfnmap_v0 { __u8 version; __u8 page; diff --git a/drivers/gpu/drm/nouveau/include/nvif/vmm.h b/drivers/gpu/drm/nouveau/include/nvif/vmm.h index a2ee92201ace..4d0781740336 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/vmm.h +++ b/drivers/gpu/drm/nouveau/include/nvif/vmm.h @@ -4,6 +4,12 @@ struct nvif_mem; struct nvif_mmu; +enum nvif_vmm_type { + UNMANAGED, + MANAGED, + RAW, +}; + enum nvif_vmm_get { ADDR, PTES, @@ -30,8 +36,9 @@ struct nvif_vmm { int page_nr; }; -int nvif_vmm_ctor(struct nvif_mmu *, const char *name, s32 oclass, bool managed, - u64 addr, u64 size, void *argv, u32 argc, struct nvif_vmm *); +int nvif_vmm_ctor(struct nvif_mmu *, const char *name, s32 oclass, + enum nvif_vmm_type, u64 addr, u64 size, void *argv, u32 argc, + struct nvif_vmm *); void nvif_vmm_dtor(struct nvif_vmm *); int nvif_vmm_get(struct nvif_vmm *, enum nvif_vmm_get, bool sparse, u8 page, u8 align, u64 size, struct nvif_vma *); @@ -39,4 +46,10 @@ void nvif_vmm_put(struct nvif_vmm *, struct nvif_vma *); int nvif_vmm_map(struct nvif_vmm *, u64 addr, u64 size, void *argv, u32 argc, struct nvif_mem *, u64 offset); int nvif_vmm_unmap(struct nvif_vmm *, u64); +int nvif_vmm_raw_unmap(struct nvif_vmm *vmm, u64 handle, bool sparse); +int nvif_vmm_raw_map(struct nvif_vmm *vmm, u64 addr, u64 size, + void *argv, u32 argc, + struct nvif_mem *mem, u64 offset, + u64 *handle); +int nvif_vmm_raw_sparse(struct nvif_vmm *vmm, u64 addr, u64 size, bool ref); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 70e7887ef4b4..ec284c1792b3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -31,6 +31,16 @@ struct nvkm_vmm { u64 start; u64 limit; + struct { + struct { + u64 addr; + u64 size; + } p; + struct { + u64 addr; + u64 size; + } n; + } managed; struct nvkm_vmm_pt *pd; struct list_head join; diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index a74ba8d84ba7..186351ecf72f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -350,7 +350,7 @@ nouveau_svmm_init(struct drm_device *dev, void *data, * VMM instead of the standard one. */ ret = nvif_vmm_ctor(&cli->mmu, "svmVmm", - cli->vmm.vmm.object.oclass, true, + cli->vmm.vmm.object.oclass, MANAGED, args->unmanaged_addr, args->unmanaged_size, &(struct gp100_vmm_v0) { .fault_replay = true, diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.c b/drivers/gpu/drm/nouveau/nouveau_vmm.c index 67d6619fcd5e..a6602c012671 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vmm.c @@ -128,8 +128,8 @@ nouveau_vmm_fini(struct nouveau_vmm *vmm) int nouveau_vmm_init(struct nouveau_cli *cli, s32 oclass, struct nouveau_vmm *vmm) { - int ret = nvif_vmm_ctor(&cli->mmu, "drmVmm", oclass, false, PAGE_SIZE, - 0, NULL, 0, &vmm->vmm); + int ret = nvif_vmm_ctor(&cli->mmu, "drmVmm", oclass, UNMANAGED, + PAGE_SIZE, 0, NULL, 0, &vmm->vmm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvif/vmm.c b/drivers/gpu/drm/nouveau/nvif/vmm.c index 6053d6dc2184..a0ca5329b3ef 100644 --- a/drivers/gpu/drm/nouveau/nvif/vmm.c +++ b/drivers/gpu/drm/nouveau/nvif/vmm.c @@ -104,6 +104,63 @@ nvif_vmm_get(struct nvif_vmm *vmm, enum nvif_vmm_get type, bool sparse, return ret; } +int +nvif_vmm_raw_unmap(struct nvif_vmm *vmm, u64 handle, bool sparse) +{ + struct nvif_vmm_raw_v0 args = { + .version = 0, + .op = NVIF_VMM_RAW_V0_UNMAP, + .handle = handle, + .sparse = sparse, + }; + + return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW, + &args, sizeof(args)); +} + +int +nvif_vmm_raw_map(struct nvif_vmm *vmm, u64 addr, u64 size, void *argv, u32 argc, + struct nvif_mem *mem, u64 offset, u64 *handle) +{ + struct nvif_vmm_raw_v0 *args; + int ret; + + if (!(args = kzalloc(sizeof(*args) + argc, GFP_KERNEL))) + return -ENOMEM; + + args->version = 0; + args->op = NVIF_VMM_RAW_V0_MAP; + args->addr = addr; + args->size = size; + args->memory = nvif_handle(&mem->object); + args->offset = offset; + memcpy(args->data, argv, argc); + + ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW, + args, sizeof(*args) + argc); + + if (likely(!ret)) + *handle = args->handle; + + kfree(args); + return ret; +} + +int +nvif_vmm_raw_sparse(struct nvif_vmm *vmm, u64 addr, u64 size, bool ref) +{ + struct nvif_vmm_raw_v0 args = { + .version = 0, + .op = NVIF_VMM_RAW_V0_SPARSE, + .addr = addr, + .size = size, + .ref = ref, + }; + + return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW, + &args, sizeof(args)); +} + void nvif_vmm_dtor(struct nvif_vmm *vmm) { @@ -112,8 +169,9 @@ nvif_vmm_dtor(struct nvif_vmm *vmm) } int -nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, bool managed, - u64 addr, u64 size, void *argv, u32 argc, struct nvif_vmm *vmm) +nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, + enum nvif_vmm_type type, u64 addr, u64 size, void *argv, u32 argc, + struct nvif_vmm *vmm) { struct nvif_vmm_v0 *args; u32 argn = sizeof(*args) + argc; @@ -125,9 +183,18 @@ nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, bool managed, if (!(args = kmalloc(argn, GFP_KERNEL))) return -ENOMEM; args->version = 0; - args->managed = managed; args->addr = addr; args->size = size; + + switch (type) { + case UNMANAGED: args->type = NVIF_VMM_V0_TYPE_UNMANAGED; break; + case MANAGED: args->type = NVIF_VMM_V0_TYPE_MANAGED; break; + case RAW: args->type = NVIF_VMM_V0_TYPE_RAW; break; + default: + WARN_ON(1); + return -EINVAL; + } + memcpy(args->data, argv, argc); ret = nvif_object_ctor(&mmu->object, name ? name : "nvifVmm", 0, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c index 524cd3c0e3fe..c9fac5654baf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c @@ -42,6 +42,26 @@ nvkm_uvmm_search(struct nvkm_client *client, u64 handle) return nvkm_vmm_ref(nvkm_uvmm(object)->vmm); } +static bool +nvkm_uvmm_in_managed_range(struct nvkm_uvmm *uvmm, u64 start, u64 size) +{ + struct nvkm_vmm *vmm = uvmm->vmm; + + u64 p_start = vmm->managed.p.addr; + u64 p_end = p_start + vmm->managed.p.size; + u64 n_start = vmm->managed.n.addr; + u64 n_end = n_start + vmm->managed.n.size; + u64 end = start + size; + + if (start >= p_start && end <= p_end) + return true; + + if (start >= n_start && end <= n_end) + return true; + + return false; +} + static int nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { @@ -58,6 +78,9 @@ nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; + if (nvkm_uvmm_in_managed_range(uvmm, addr, size) && uvmm->raw) + return -EINVAL; + if (size) { mutex_lock(&vmm->mutex); ret = nvkm_vmm_pfn_unmap(vmm, addr, size); @@ -88,6 +111,9 @@ nvkm_uvmm_mthd_pfnmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; + if (nvkm_uvmm_in_managed_range(uvmm, addr, size) && uvmm->raw) + return -EINVAL; + if (size) { mutex_lock(&vmm->mutex); ret = nvkm_vmm_pfn_map(vmm, page, addr, size, phys); @@ -113,6 +139,9 @@ nvkm_uvmm_mthd_unmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; + if (nvkm_uvmm_in_managed_range(uvmm, addr, 0) && uvmm->raw) + return -EINVAL; + mutex_lock(&vmm->mutex); vma = nvkm_vmm_node_search(vmm, addr); if (ret = -ENOENT, !vma || vma->addr != addr) { @@ -159,6 +188,9 @@ nvkm_uvmm_mthd_map(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; + if (nvkm_uvmm_in_managed_range(uvmm, addr, size) && uvmm->raw) + return -EINVAL; + memory = nvkm_umem_search(client, handle); if (IS_ERR(memory)) { VMM_DEBUG(vmm, "memory %016llx %ld\n", handle, PTR_ERR(memory)); @@ -314,6 +346,131 @@ nvkm_uvmm_mthd_page(struct nvkm_uvmm *uvmm, void *argv, u32 argc) return 0; } +static int +nvkm_uvmm_mthd_raw_map(struct nvkm_uvmm *uvmm, struct nvif_vmm_raw_v0 *args, + void *argv, u32 argc) +{ + struct nvkm_client *client = uvmm->object.client; + u64 addr, size, handle, offset; + struct nvkm_vmm *vmm = uvmm->vmm; + struct nvkm_vma *vma; + struct nvkm_memory *memory; + int ret; + + addr = args->addr; + size = args->size; + handle = args->memory; + offset = args->offset; + + if (!nvkm_uvmm_in_managed_range(uvmm, addr, size)) + return -EINVAL; + + memory = nvkm_umem_search(client, handle); + if (IS_ERR(memory)) { + VMM_DEBUG(vmm, "memory %016llx %ld\n", handle, PTR_ERR(memory)); + return PTR_ERR(memory); + } + + vma = nvkm_vma_new(addr, size); + if (!vma) + return -ENOMEM; + + vma->mapref = true; + vma->used = true; + + mutex_lock(&vmm->mutex); + if (ret = -ENOENT, vma->busy) { + VMM_DEBUG(vmm, "denied %016llx: %d", addr, vma->busy); + goto fail; + } + vma->busy = true; + mutex_unlock(&vmm->mutex); + + ret = nvkm_memory_map(memory, offset, vmm, vma, argv, argc); + if (ret == 0) { + /* Successful map will clear vma->busy. */ + args->handle = (u64)(uintptr_t)vma; + nvkm_memory_unref(&memory); + return 0; + } + + mutex_lock(&vmm->mutex); + nvkm_memory_tags_put(vma->memory, vmm->mmu->subdev.device, &vma->tags); + nvkm_memory_unref(&vma->memory); + kfree(vma); +fail: + mutex_unlock(&vmm->mutex); + nvkm_memory_unref(&memory); + return ret; +} + +static int +nvkm_uvmm_mthd_raw_unmap(struct nvkm_uvmm *uvmm, struct nvif_vmm_raw_v0 *args) +{ + struct nvkm_vmm *vmm = uvmm->vmm; + struct nvkm_vma *vma; + + vma = (struct nvkm_vma *)args->handle; + if (!vma) + return -EINVAL; + + mutex_lock(&vmm->mutex); + if (vma->busy) { + VMM_DEBUG(vmm, "denied %016llx: %d", vma->addr, vma->busy); + mutex_unlock(&vmm->mutex); + return -ENOENT; + } + vma->sparse = args->sparse; + nvkm_vmm_raw_unmap_locked(vmm, vma); + mutex_unlock(&vmm->mutex); + + args->handle = 0; + kfree(vma); + return 0; +} + +static int +nvkm_uvmm_mthd_raw_sparse(struct nvkm_uvmm *uvmm, struct nvif_vmm_raw_v0 *args) +{ + struct nvkm_vmm *vmm = uvmm->vmm; + int ret; + + if (!nvkm_uvmm_in_managed_range(uvmm, args->addr, args->size)) + return -EINVAL; + + mutex_lock(&vmm->mutex); + ret = nvkm_vmm_raw_sparse_locked(vmm, args->addr, args->size, args->ref); + mutex_unlock(&vmm->mutex); + + return ret; +} + +static int +nvkm_uvmm_mthd_raw(struct nvkm_uvmm *uvmm, void *argv, u32 argc) +{ + union { + struct nvif_vmm_raw_v0 v0; + } *args = argv; + int ret = -ENOSYS; + + if (!uvmm->raw) + return -EINVAL; + + if ((ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, true))) + return ret; + + switch (args->v0.op) { + case NVIF_VMM_RAW_V0_MAP: + return nvkm_uvmm_mthd_raw_map(uvmm, &args->v0, argv, argc); + case NVIF_VMM_RAW_V0_UNMAP: + return nvkm_uvmm_mthd_raw_unmap(uvmm, &args->v0); + case NVIF_VMM_RAW_V0_SPARSE: + return nvkm_uvmm_mthd_raw_sparse(uvmm, &args->v0); + default: + return -EINVAL; + }; +} + static int nvkm_uvmm_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) { @@ -326,6 +483,7 @@ nvkm_uvmm_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) case NVIF_VMM_V0_UNMAP : return nvkm_uvmm_mthd_unmap (uvmm, argv, argc); case NVIF_VMM_V0_PFNMAP: return nvkm_uvmm_mthd_pfnmap(uvmm, argv, argc); case NVIF_VMM_V0_PFNCLR: return nvkm_uvmm_mthd_pfnclr(uvmm, argv, argc); + case NVIF_VMM_V0_RAW : return nvkm_uvmm_mthd_raw (uvmm, argv, argc); case NVIF_VMM_V0_MTHD(0x00) ... NVIF_VMM_V0_MTHD(0x7f): if (uvmm->vmm->func->mthd) { return uvmm->vmm->func->mthd(uvmm->vmm, @@ -366,10 +524,11 @@ nvkm_uvmm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_uvmm *uvmm; int ret = -ENOSYS; u64 addr, size; - bool managed; + bool managed, raw; if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, more))) { - managed = args->v0.managed != 0; + managed = args->v0.type == NVIF_VMM_V0_TYPE_MANAGED; + raw = args->v0.type == NVIF_VMM_V0_TYPE_RAW; addr = args->v0.addr; size = args->v0.size; } else @@ -377,12 +536,13 @@ nvkm_uvmm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, if (!(uvmm = kzalloc(sizeof(*uvmm), GFP_KERNEL))) return -ENOMEM; + uvmm->raw = raw; nvkm_object_ctor(&nvkm_uvmm, oclass, &uvmm->object); *pobject = &uvmm->object; if (!mmu->vmm) { - ret = mmu->func->vmm.ctor(mmu, managed, addr, size, argv, argc, - NULL, "user", &uvmm->vmm); + ret = mmu->func->vmm.ctor(mmu, managed || raw, addr, size, + argv, argc, NULL, "user", &uvmm->vmm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.h index 71dab55e18a9..7f6fb1fb46bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.h @@ -7,6 +7,7 @@ struct nvkm_uvmm { struct nvkm_object object; struct nvkm_vmm *vmm; + bool raw; }; int nvkm_uvmm_new(const struct nvkm_oclass *, void *argv, u32 argc, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index ae793f400ba1..255ab920cb15 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -744,7 +744,7 @@ nvkm_vmm_ptes_get(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page, return 0; } -static inline struct nvkm_vma * +struct nvkm_vma * nvkm_vma_new(u64 addr, u64 size) { struct nvkm_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); @@ -1101,6 +1101,9 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu, if (addr && (ret = nvkm_vmm_ctor_managed(vmm, 0, addr))) return ret; + vmm->managed.p.addr = 0; + vmm->managed.p.size = addr; + /* NVKM-managed area. */ if (size) { if (!(vma = nvkm_vma_new(addr, size))) @@ -1114,6 +1117,9 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu, size = vmm->limit - addr; if (size && (ret = nvkm_vmm_ctor_managed(vmm, addr, size))) return ret; + + vmm->managed.n.addr = addr; + vmm->managed.n.size = size; } else { /* Address-space fully managed by NVKM, requiring calls to * nvkm_vmm_get()/nvkm_vmm_put() to allocate address-space. @@ -1326,6 +1332,19 @@ nvkm_vmm_pfn_map(struct nvkm_vmm *vmm, u8 shift, u64 addr, u64 size, u64 *pfn) return 0; } +void +nvkm_vmm_raw_unmap_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma) +{ + const struct nvkm_vmm_page *page = &vmm->func->page[vma->refd]; + + nvkm_vmm_ptes_unmap_put(vmm, page, vma->addr, vma->size, vma->sparse, false); + vma->refd = NVKM_VMA_PAGE_NONE; + + nvkm_memory_tags_put(vma->memory, vmm->mmu->subdev.device, &vma->tags); + nvkm_memory_unref(&vma->memory); + vma->mapped = false; +} + void nvkm_vmm_unmap_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma) { @@ -1775,6 +1794,17 @@ nvkm_vmm_get(struct nvkm_vmm *vmm, u8 page, u64 size, struct nvkm_vma **pvma) return ret; } +int nvkm_vmm_raw_sparse_locked(struct nvkm_vmm *vmm, u64 addr, u64 size, bool ref) +{ + int ret; + + ret = nvkm_vmm_ptes_sparse(vmm, addr, size, ref); + if (ret) + return ret; + + return 0; +} + void nvkm_vmm_part(struct nvkm_vmm *vmm, struct nvkm_memory *inst) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h index f6188aa9171c..7bb1905b70f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h @@ -163,6 +163,7 @@ int nvkm_vmm_new_(const struct nvkm_vmm_func *, struct nvkm_mmu *, u32 pd_header, bool managed, u64 addr, u64 size, struct lock_class_key *, const char *name, struct nvkm_vmm **); +struct nvkm_vma *nvkm_vma_new(u64 addr, u64 size); struct nvkm_vma *nvkm_vmm_node_search(struct nvkm_vmm *, u64 addr); struct nvkm_vma *nvkm_vmm_node_split(struct nvkm_vmm *, struct nvkm_vma *, u64 addr, u64 size); @@ -172,6 +173,8 @@ int nvkm_vmm_get_locked(struct nvkm_vmm *, bool getref, bool mapref, void nvkm_vmm_put_locked(struct nvkm_vmm *, struct nvkm_vma *); void nvkm_vmm_unmap_locked(struct nvkm_vmm *, struct nvkm_vma *, bool pfn); void nvkm_vmm_unmap_region(struct nvkm_vmm *, struct nvkm_vma *); +void nvkm_vmm_raw_unmap_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma); +int nvkm_vmm_raw_sparse_locked(struct nvkm_vmm *, u64 addr, u64 size, bool ref); #define NVKM_VMM_PFN_ADDR 0xfffffffffffff000ULL #define NVKM_VMM_PFN_ADDR_SHIFT 12 From patchwork Wed Jan 18 06:12:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45026 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2176639wrn; Tue, 17 Jan 2023 22:39:49 -0800 (PST) X-Google-Smtp-Source: AMrXdXvYH8AO7ARB1FO9wUry31DTnj7Bd9YMvWG6quTHmHrWzSO4LtNUihS524v2hegzejQHWfxy X-Received: by 2002:a17:902:cec8:b0:192:ef8e:4258 with SMTP id d8-20020a170902cec800b00192ef8e4258mr6878575plg.14.1674023988807; Tue, 17 Jan 2023 22:39:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674023988; cv=none; d=google.com; s=arc-20160816; b=zfg2qmCEz8Q/F7VpdHpq5bDGY+6p1fqRWlFVAebaPupnfLtVgurYiD+IdYhmZ4VwgE fHSztFMsuKRzsdmWzfHrh+/IW6+sefhz0/7UJhyuL/BmZGTEn1ankPh7jC4HlalsQGgN lI6T85GxzTqAi5hVhFWaCtJ4cxi0HerpRc7K8noC9sQtihJf4j4A84ETgoStxy1GrzdV YDqlQNvXVgKXfEkDzwEzNGZsvdO2N+MPu2k0ej4dhTENK2baMBhz3twYFNUNPkRMMnRt q4SiKT6Sw+DMkisySqEEO0wMSzVmn04ewtXjYrFUCPrp4d5yPQSzFpmz1g3d/qACYONQ OE+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=XMcBA2BxKR6mgzQVCp1bnTeEdyEKJQVuyTzd+hiIz80=; b=On3yM3NE64+26wZCKZ1UmTF7m53oG+yM8ioxPgxK3wVv2jM1zOwUUf0NZBM0XfElhB 5QXdAyHh8i/AHM7XG2R8lq+Qpdmm+DxpS41m2ZGmVmll1yrmixCclAlfwB7+d/tkZat7 6EU8RYWg9bbgtdqu6ylPvtjftx5LCdAPJ0dJbkDhDIPIsEMFuLndBSrvIgQZoyKy0U7H 8IfHPnQeL9aner//m2F19F/Rv/ljWGUpLdXHKbZ+9JOpOnflrgOjBDO56qUnhMfXmXVG +AAxo990RFEorEWYsxAS7G0kr5VMNGA/FpQwvlWP2bH8XKgKU5aEhQ9ImKXVC2PDnFkL Jh3w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=PTiVbRTG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v185-20020a632fc2000000b004cc256ee218si5003754pgv.365.2023.01.17.22.39.36; Tue, 17 Jan 2023 22:39:48 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=PTiVbRTG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229685AbjARGjI (ORCPT + 99 others); Wed, 18 Jan 2023 01:39:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54742 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229511AbjARG0R (ORCPT ); Wed, 18 Jan 2023 01:26:17 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F3A6954B37 for ; Tue, 17 Jan 2023 22:14:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022457; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XMcBA2BxKR6mgzQVCp1bnTeEdyEKJQVuyTzd+hiIz80=; b=PTiVbRTGLJavbzESFBsOG7jKPzR0fLpqNSxnCCF3a4/ybNP0IfV13GaEhca4j4WGwfsFlf 1vd4NPo+SOKeXbMIpXDXYXzACqDc7ylpJ8L/8L/+DpVBGReR6z3rIM1CLQlOvvUyb3yXle aCvoF83p048ipIVoj/n+JXHKSwweMt4= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-375-rX89DFiCMuyeITuVZ5TZWQ-1; Wed, 18 Jan 2023 01:14:15 -0500 X-MC-Unique: rX89DFiCMuyeITuVZ5TZWQ-1 Received: by mail-ed1-f70.google.com with SMTP id m12-20020a056402430c00b0049e4ac58509so710244edc.16 for ; Tue, 17 Jan 2023 22:14:15 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=XMcBA2BxKR6mgzQVCp1bnTeEdyEKJQVuyTzd+hiIz80=; b=0m/i+lj3sEW1JtaGvUN6jhQZwKn52InYej/0aKcIPTpen9/sJOGB0aP627gCVBEAzm qgn1Pg4be9rCJGkzxIsqLEvhBEj4ohMQTD+8SuMqWcn+DcTxORqxEPpM27Mpv7/Z5mFH +jFT81cgnrB84NEQhegzalyjk9s6ZgJyYAQ3wQ6odNHwcP44GagRZYr39OaDfz//X62/ kUsCn7IMzIW7W1Ky8cWF+xp+K2EQrOfn5fbCi7WR6o0JAFWMDoJhBSs8PjZ2jTtiA0Ry dXuDGOILZ5EFq8D2wOOQzTgaapZ5gRggn47hvgNL4wUdbPHdLCf91YHlhyWGRa4pGyBm AoAw== X-Gm-Message-State: AFqh2kpFP/hkjYw/BiX2xVQc0eZHD4pEom2RgxMtaU2aqK1jDs68mmLI 3qV5L1Dytey0gtY+WHWPGKG3SzxRJigVfj7wu06dQ4uxYTvXva9cp0DAuaLVK6Ka8y6CBffyPfH rcaskRBVG+dSFIbk/q03nNood X-Received: by 2002:a17:906:3c03:b0:7c1:79f5:9545 with SMTP id h3-20020a1709063c0300b007c179f59545mr5524865ejg.42.1674022454421; Tue, 17 Jan 2023 22:14:14 -0800 (PST) X-Received: by 2002:a17:906:3c03:b0:7c1:79f5:9545 with SMTP id h3-20020a1709063c0300b007c179f59545mr5524840ejg.42.1674022454059; Tue, 17 Jan 2023 22:14:14 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id o16-20020a170906769000b0087758f5ecd1sm392404ejm.194.2023.01.17.22.14.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:13 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 12/14] drm/nouveau: implement uvmm for user mode bindings Date: Wed, 18 Jan 2023 07:12:54 +0100 Message-Id: <20230118061256.2689-13-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341378083264737?= X-GMAIL-MSGID: =?utf-8?q?1755341378083264737?= uvmm provides the driver abstraction around the DRM GPU VA manager connecting it to the nouveau infrastructure. It handles the split and merge operations provided by the DRM GPU VA manager for map operations colliding with existent mappings and takes care of the driver specific locking around the DRM GPU VA manager. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/Kbuild | 1 + drivers/gpu/drm/nouveau/nouveau_abi16.c | 7 + drivers/gpu/drm/nouveau/nouveau_bo.c | 147 +++--- drivers/gpu/drm/nouveau/nouveau_bo.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 + drivers/gpu/drm/nouveau/nouveau_drv.h | 48 ++ drivers/gpu/drm/nouveau/nouveau_gem.c | 51 ++- drivers/gpu/drm/nouveau/nouveau_mem.h | 5 + drivers/gpu/drm/nouveau/nouveau_prime.c | 2 +- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 575 ++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_uvmm.h | 68 +++ 11 files changed, 835 insertions(+), 73 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nouveau_uvmm.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_uvmm.h diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild index 5e5617006da5..ee281bb76463 100644 --- a/drivers/gpu/drm/nouveau/Kbuild +++ b/drivers/gpu/drm/nouveau/Kbuild @@ -47,6 +47,7 @@ nouveau-y += nouveau_prime.o nouveau-y += nouveau_sgdma.o nouveau-y += nouveau_ttm.o nouveau-y += nouveau_vmm.o +nouveau-y += nouveau_uvmm.o # DRM - modesetting nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 82dab51d8aeb..36cc80eb0e20 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -261,6 +261,13 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (!drm->channel) return nouveau_abi16_put(abi16, -ENODEV); + /* If uvmm wasn't initialized until now disable it completely to prevent + * userspace from mixing up UAPIs. + * + * The client lock is already acquired by nouveau_abi16_get(). + */ + __nouveau_cli_uvmm_disable(cli); + device = &abi16->device; engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4cdeda7fe2df..03bbee291fc9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -199,7 +199,7 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, u64 *size) struct nouveau_bo * nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, - u32 tile_mode, u32 tile_flags) + u32 tile_mode, u32 tile_flags, bool internal) { struct nouveau_drm *drm = cli->drm; struct nouveau_bo *nvbo; @@ -235,68 +235,103 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, nvbo->force_coherent = true; } - if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { - nvbo->kind = (tile_flags & 0x0000ff00) >> 8; - if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { - kfree(nvbo); - return ERR_PTR(-EINVAL); + nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG); + if (!nouveau_cli_uvmm(cli) || internal) { + /* for BO noVM allocs, don't assign kinds */ + if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { + nvbo->kind = (tile_flags & 0x0000ff00) >> 8; + if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { + kfree(nvbo); + return ERR_PTR(-EINVAL); + } + + nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; + } else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + nvbo->kind = (tile_flags & 0x00007f00) >> 8; + nvbo->comp = (tile_flags & 0x00030000) >> 16; + if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { + kfree(nvbo); + return ERR_PTR(-EINVAL); + } + } else { + nvbo->zeta = (tile_flags & 0x00000007); } + nvbo->mode = tile_mode; + + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail + * during buffer migration, we need to determine page + * size for the buffer up-front, and pre-allocate its + * page tables. + * + * Skip page sizes that can't support needed domains. + */ + if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE && + (domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram) + continue; + if ((domain & NOUVEAU_GEM_DOMAIN_GART) && + (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT)) + continue; - nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; - } else - if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { - nvbo->kind = (tile_flags & 0x00007f00) >> 8; - nvbo->comp = (tile_flags & 0x00030000) >> 16; - if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { + /* Select this page size if it's the first that supports + * the potential memory domains, or when it's compatible + * with the requested compression settings. + */ + if (pi < 0 || !nvbo->comp || vmm->page[i].comp) + pi = i; + + /* Stop once the buffer is larger than the current page size. */ + if (*size >= 1ULL << vmm->page[i].shift) + break; + } + + if (WARN_ON(pi < 0)) { kfree(nvbo); return ERR_PTR(-EINVAL); } - } else { - nvbo->zeta = (tile_flags & 0x00000007); - } - nvbo->mode = tile_mode; - nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG); - - /* Determine the desirable target GPU page size for the buffer. */ - for (i = 0; i < vmm->page_nr; i++) { - /* Because we cannot currently allow VMM maps to fail - * during buffer migration, we need to determine page - * size for the buffer up-front, and pre-allocate its - * page tables. - * - * Skip page sizes that can't support needed domains. - */ - if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE && - (domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram) - continue; - if ((domain & NOUVEAU_GEM_DOMAIN_GART) && - (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT)) - continue; - /* Select this page size if it's the first that supports - * the potential memory domains, or when it's compatible - * with the requested compression settings. - */ - if (pi < 0 || !nvbo->comp || vmm->page[i].comp) - pi = i; - - /* Stop once the buffer is larger than the current page size. */ - if (*size >= 1ULL << vmm->page[i].shift) - break; - } + /* Disable compression if suitable settings couldn't be found. */ + if (nvbo->comp && !vmm->page[pi].comp) { + if (mmu->object.oclass >= NVIF_CLASS_MMU_GF100) + nvbo->kind = mmu->kind[nvbo->kind]; + nvbo->comp = 0; + } + nvbo->page = vmm->page[pi].shift; + } else { + /* reject other tile flags when in VM mode. */ + if (tile_mode) + return ERR_PTR(-EINVAL); + if (tile_flags & ~NOUVEAU_GEM_TILE_NONCONTIG) + return ERR_PTR(-EINVAL); - if (WARN_ON(pi < 0)) { - kfree(nvbo); - return ERR_PTR(-EINVAL); - } + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail + * during buffer migration, we need to determine page + * size for the buffer up-front, and pre-allocate its + * page tables. + * + * Skip page sizes that can't support needed domains. + */ + if ((domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram) + continue; + if ((domain & NOUVEAU_GEM_DOMAIN_GART) && + (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT)) + continue; - /* Disable compression if suitable settings couldn't be found. */ - if (nvbo->comp && !vmm->page[pi].comp) { - if (mmu->object.oclass >= NVIF_CLASS_MMU_GF100) - nvbo->kind = mmu->kind[nvbo->kind]; - nvbo->comp = 0; + if (pi < 0) + pi = i; + /* Stop once the buffer is larger than the current page size. */ + if (*size >= 1ULL << vmm->page[i].shift) + break; + } + if (WARN_ON(pi < 0)) { + kfree(nvbo); + return ERR_PTR(-EINVAL); + } + nvbo->page = vmm->page[pi].shift; } - nvbo->page = vmm->page[pi].shift; nouveau_bo_fixup_align(nvbo, align, size); @@ -334,7 +369,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align, int ret; nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode, - tile_flags); + tile_flags, true); if (IS_ERR(nvbo)) return PTR_ERR(nvbo); @@ -937,11 +972,13 @@ static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, list_for_each_entry(vma, &nvbo->vma_list, head) { nouveau_vma_map(vma, mem); } + nouveau_uvmm_bo_map_all(nvbo, mem); } else { list_for_each_entry(vma, &nvbo->vma_list, head) { WARN_ON(ttm_bo_wait(bo, false, false)); nouveau_vma_unmap(vma); } + nouveau_uvmm_bo_unmap_all(nvbo); } if (new_reg) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 774dd93ca76b..cb85207d9e8f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -73,7 +73,7 @@ extern struct ttm_device_funcs nouveau_bo_driver; void nouveau_bo_move_init(struct nouveau_drm *); struct nouveau_bo *nouveau_bo_alloc(struct nouveau_cli *, u64 *size, int *align, - u32 domain, u32 tile_mode, u32 tile_flags); + u32 domain, u32 tile_mode, u32 tile_flags, bool internal); int nouveau_bo_init(struct nouveau_bo *, u64 size, int align, u32 domain, struct sg_table *sg, struct dma_resv *robj); int nouveau_bo_new(struct nouveau_cli *, u64 size, int align, u32 domain, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 80f154b6adab..989f30a31ba9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -70,6 +70,7 @@ #include "nouveau_platform.h" #include "nouveau_svm.h" #include "nouveau_dmem.h" +#include "nouveau_uvmm.h" DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", @@ -192,6 +193,7 @@ nouveau_cli_fini(struct nouveau_cli *cli) WARN_ON(!list_empty(&cli->worker)); usif_client_fini(cli); + nouveau_uvmm_fini(&cli->uvmm); nouveau_vmm_fini(&cli->svm); nouveau_vmm_fini(&cli->vmm); nvif_mmu_dtor(&cli->mmu); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 20a7f31b9082..d634f1054d65 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -64,6 +64,7 @@ struct platform_device; #include "nouveau_fence.h" #include "nouveau_bios.h" #include "nouveau_vmm.h" +#include "nouveau_uvmm.h" struct nouveau_drm_tile { struct nouveau_fence *fence; @@ -91,6 +92,8 @@ struct nouveau_cli { struct nvif_mmu mmu; struct nouveau_vmm vmm; struct nouveau_vmm svm; + struct nouveau_uvmm uvmm; + const struct nvif_mclass *mem; struct list_head head; @@ -112,15 +115,60 @@ struct nouveau_cli_work { struct dma_fence_cb cb; }; +static inline struct nouveau_uvmm * +nouveau_cli_uvmm(struct nouveau_cli *cli) +{ + if (!cli || !cli->uvmm.vmm.cli) + return NULL; + + return &cli->uvmm; +} + +static inline struct nouveau_uvmm * +nouveau_cli_uvmm_locked(struct nouveau_cli *cli) +{ + struct nouveau_uvmm *uvmm; + + mutex_lock(&cli->mutex); + uvmm = nouveau_cli_uvmm(cli); + mutex_unlock(&cli->mutex); + + return uvmm; +} + static inline struct nouveau_vmm * nouveau_cli_vmm(struct nouveau_cli *cli) { + struct nouveau_uvmm *uvmm; + + uvmm = nouveau_cli_uvmm(cli); + if (uvmm) + return &uvmm->vmm; + if (cli->svm.cli) return &cli->svm; return &cli->vmm; } +static inline void +__nouveau_cli_uvmm_disable(struct nouveau_cli *cli) +{ + struct nouveau_uvmm *uvmm; + + uvmm = nouveau_cli_uvmm(cli); + if (!uvmm) + cli->uvmm.disabled = true; +} + +static inline void +nouveau_cli_uvmm_disable(struct nouveau_cli *cli) +{ + mutex_lock(&cli->mutex); + __nouveau_cli_uvmm_disable(cli); + mutex_unlock(&cli->mutex); +} + void nouveau_cli_work_queue(struct nouveau_cli *, struct dma_fence *, struct nouveau_cli_work *); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5dad2d0dd5cb..3370a73e6a9b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -120,7 +120,11 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) goto out; } - ret = nouveau_vma_new(nvbo, vmm, &vma); + /* only create a VMA on binding */ + if (!nouveau_cli_uvmm(cli)) + ret = nouveau_vma_new(nvbo, vmm, &vma); + else + ret = 0; pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); out: @@ -180,6 +184,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); struct device *dev = drm->dev->dev; + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); struct nouveau_vmm *vmm = nouveau_cli_vmm(cli); struct nouveau_vma *vma; int ret; @@ -187,22 +192,26 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50) return; - ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); - if (ret) - return; + if (uvmm) { + nouveau_uvmm_cli_unmap_all(uvmm, gem); + } else { + ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); + if (ret) + return; - vma = nouveau_vma_find(nvbo, vmm); - if (vma) { - if (--vma->refs == 0) { - ret = pm_runtime_get_sync(dev); - if (!WARN_ON(ret < 0 && ret != -EACCES)) { - nouveau_gem_object_unmap(nvbo, vma); - pm_runtime_mark_last_busy(dev); + vma = nouveau_vma_find(nvbo, vmm); + if (vma) { + if (--vma->refs == 0) { + ret = pm_runtime_get_sync(dev); + if (!WARN_ON(ret < 0 && ret != -EACCES)) { + nouveau_gem_object_unmap(nvbo, vma); + pm_runtime_mark_last_busy(dev); + } + pm_runtime_put_autosuspend(dev); } - pm_runtime_put_autosuspend(dev); } + ttm_bo_unreserve(&nvbo->bo); } - ttm_bo_unreserve(&nvbo->bo); } const struct drm_gem_object_funcs nouveau_gem_object_funcs = { @@ -231,7 +240,7 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, domain |= NOUVEAU_GEM_DOMAIN_CPU; nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode, - tile_flags); + tile_flags, false); if (IS_ERR(nvbo)) return PTR_ERR(nvbo); @@ -279,13 +288,15 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, else rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; rep->offset = nvbo->offset; - if (vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) { + if (vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50 && + !nouveau_cli_uvmm(cli)) { vma = nouveau_vma_find(nvbo, vmm); if (!vma) return -EINVAL; rep->offset = vma->addr; - } + } else + rep->offset = 0; rep->size = nvbo->bo.base.size; rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.base.vma_node); @@ -310,6 +321,11 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct nouveau_bo *nvbo = NULL; int ret = 0; + /* If uvmm wasn't initialized until now disable it completely to prevent + * userspace from mixing up UAPIs. + */ + nouveau_cli_uvmm_disable(cli); + ret = nouveau_gem_new(cli, req->info.size, req->align, req->info.domain, req->info.tile_mode, req->info.tile_flags, &nvbo); @@ -710,6 +726,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (unlikely(!abi16)) return -ENOMEM; + if (unlikely(nouveau_cli_uvmm(cli))) + return -ENOSYS; + list_for_each_entry(temp, &abi16->channels, head) { if (temp->chan->chid == req->channel) { chan = temp->chan; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.h b/drivers/gpu/drm/nouveau/nouveau_mem.h index 76c86d8bb01e..5365a3d3a17f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.h +++ b/drivers/gpu/drm/nouveau/nouveau_mem.h @@ -35,4 +35,9 @@ int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); int nouveau_mem_host(struct ttm_resource *, struct ttm_tt *); void nouveau_mem_fini(struct nouveau_mem *); int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *); +int +nouveau_mem_map_fixed(struct nouveau_mem *mem, + struct nvif_vmm *vmm, + u8 kind, u64 addr, + u64 offset, u64 range); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index f42c2b1b0363..6a883b9a799a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -50,7 +50,7 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, dma_resv_lock(robj, NULL); nvbo = nouveau_bo_alloc(&drm->client, &size, &align, - NOUVEAU_GEM_DOMAIN_GART, 0, 0); + NOUVEAU_GEM_DOMAIN_GART, 0, 0, true); if (IS_ERR(nvbo)) { obj = ERR_CAST(nvbo); goto unlock; diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c new file mode 100644 index 000000000000..47a74e3ce882 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Danilo Krummrich + * + */ + +/* + * Locking: + * + * The uvmm mutex protects any operations on the GPU VA space provided by the + * DRM GPU VA manager. + * + * The DRM GEM GPUVA lock protects a GEM's GPUVA list. It also protects single + * map/unmap operations against a BO move, which itself walks the GEM's GPUVA + * list in order to map/unmap it's entries. + * + * We'd also need to protect the DRM_GPUVA_SWAPPED flag for each individual + * GPUVA, however this isn't necessary since any read or write to this flag + * happens when we already took the DRM GEM GPUVA lock of the backing GEM of + * the particular GPUVA. + */ + +#include "nouveau_drv.h" +#include "nouveau_gem.h" +#include "nouveau_mem.h" +#include "nouveau_uvmm.h" + +#include +#include + +#include +#include +#include + +#define NOUVEAU_VA_SPACE_BITS 47 /* FIXME */ +#define NOUVEAU_VA_SPACE_START 0x0 +#define NOUVEAU_VA_SPACE_END (1ULL << NOUVEAU_VA_SPACE_BITS) + +struct nouveau_uvmm_map_args { + u8 kind; + bool swapped; +}; + +int +nouveau_uvmm_validate_range(struct nouveau_uvmm *uvmm, u64 addr, u64 range) +{ + u64 end = addr + range; + u64 unmanaged_end = uvmm->unmanaged_addr + + uvmm->unmanaged_size; + + if (addr & ~PAGE_MASK) + return -EINVAL; + + if (range & ~PAGE_MASK) + return -EINVAL; + + if (end <= addr) + return -EINVAL; + + if (addr < NOUVEAU_VA_SPACE_START || + end > NOUVEAU_VA_SPACE_END) + return -EINVAL; + + if (addr < unmanaged_end && + end > uvmm->unmanaged_addr) + return -EINVAL; + + return 0; +} + +static int +nouveau_uvma_map(struct nouveau_uvma *uvma, + struct nouveau_mem *mem) +{ + struct nvif_vmm *vmm = &uvma->uvmm->vmm.vmm; + u64 addr = uvma->va.node.start << PAGE_SHIFT; + u64 offset = uvma->va.gem.offset << PAGE_SHIFT; + u64 range = uvma->va.node.size << PAGE_SHIFT; + union { + struct gf100_vmm_map_v0 gf100; + } args; + u32 argc = 0; + + switch (vmm->object.oclass) { + case NVIF_CLASS_VMM_GF100: + case NVIF_CLASS_VMM_GM200: + case NVIF_CLASS_VMM_GP100: + args.gf100.version = 0; + if (mem->mem.type & NVIF_MEM_VRAM) + args.gf100.vol = 0; + else + args.gf100.vol = 1; + args.gf100.ro = 0; + args.gf100.priv = 0; + args.gf100.kind = uvma->kind; + argc = sizeof(args.gf100); + break; + default: + WARN_ON(1); + return -ENOSYS; + } + + return nvif_vmm_raw_map(vmm, addr, range, + &args, argc, + &mem->mem, offset, + &uvma->handle); +} + +static int +nouveau_uvma_unmap(struct nouveau_uvma *uvma) +{ + struct nvif_vmm *vmm = &uvma->uvmm->vmm.vmm; + bool sparse = uvma->va.region->sparse; + + if (drm_gpuva_swapped(&uvma->va)) + return 0; + + return nvif_vmm_raw_unmap(vmm, uvma->handle, sparse); +} + +static void +nouveau_uvma_destroy(struct nouveau_uvma *uvma) +{ + drm_gpuva_destroy_locked(&uvma->va); + kfree(uvma); +} + +void +nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbo, struct nouveau_mem *mem) +{ + struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuva *va; + + drm_gem_gpuva_lock(obj); + drm_gem_for_each_gpuva(va, obj) { + struct nouveau_uvma *uvma = uvma_from_va(va); + + nouveau_uvma_map(uvma, mem); + drm_gpuva_swap(va, false); + } + drm_gem_gpuva_unlock(obj); +} + +void +nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo) +{ + struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuva *va; + + drm_gem_gpuva_lock(obj); + drm_gem_for_each_gpuva(va, obj) { + struct nouveau_uvma *uvma = uvma_from_va(va); + + nouveau_uvma_unmap(uvma); + drm_gpuva_swap(va, true); + } + drm_gem_gpuva_unlock(obj); +} + +void +nouveau_uvmm_cli_unmap_all(struct nouveau_uvmm *uvmm, + struct drm_gem_object *obj) +{ + struct drm_gpuva *va, *tmp; + + nouveau_uvmm_lock(uvmm); + drm_gem_gpuva_lock(obj); + drm_gem_for_each_gpuva_safe(va, tmp, obj) { + struct nouveau_uvma *uvma = uvma_from_va(va); + + if (&uvmm->umgr == va->mgr) { + nouveau_uvma_unmap(uvma); + nouveau_uvma_destroy(uvma); + } + } + drm_gem_gpuva_unlock(obj); + nouveau_uvmm_unlock(uvmm); +} + +static void +nouveau_uvmm_unmap_range(struct nouveau_uvmm *uvmm, + u64 addr, u64 range) +{ + struct drm_gpuva *va, *next; + u64 end = addr + range; + + addr >>= PAGE_SHIFT; + range >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + + drm_gpuva_for_each_va_safe(va, next, &uvmm->umgr) { + if (addr >= va->node.start && + end <= va->node.start + va->node.size) { + struct nouveau_uvma *uvma = uvma_from_va(va); + struct drm_gem_object *obj = va->gem.obj; + + drm_gem_gpuva_lock(obj); + nouveau_uvma_unmap(uvma); + nouveau_uvma_destroy(uvma); + drm_gem_gpuva_unlock(obj); + } + } +} + +static int +nouveau_uvma_new(struct nouveau_uvmm *uvmm, + struct drm_gem_object *obj, + u64 bo_offset, u64 addr, + u64 range, u8 kind, + struct nouveau_uvma **puvma) +{ + struct nouveau_uvma *uvma; + int ret; + + addr >>= PAGE_SHIFT; + bo_offset >>= PAGE_SHIFT; + range >>= PAGE_SHIFT; + + uvma = *puvma = kzalloc(sizeof(*uvma), GFP_KERNEL); + if (!uvma) + return -ENOMEM; + + uvma->uvmm = uvmm; + uvma->kind = kind; + uvma->va.gem.offset = bo_offset; + uvma->va.gem.obj = obj; + + ret = drm_gpuva_insert(&uvmm->umgr, &uvma->va, addr, range); + if (ret) { + kfree(uvma); + *puvma = NULL; + return ret; + } + drm_gpuva_link_locked(&uvma->va); + + return 0; +} + +int +nouveau_uvma_region_new(struct nouveau_uvmm *uvmm, + u64 addr, u64 range, + bool sparse) +{ + struct nouveau_uvma_region *reg; + struct nvif_vmm *vmm = &uvmm->vmm.vmm; + int ret; + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + reg->uvmm = uvmm; + reg->region.sparse = sparse; + + ret = drm_gpuva_region_insert(&uvmm->umgr, ®->region, + addr >> PAGE_SHIFT, + range >> PAGE_SHIFT); + if (ret) + goto err_free_region; + + if (sparse) { + ret = nvif_vmm_raw_sparse(vmm, addr, range, true); + if (ret) + goto err_destroy_region; + } + + return 0; + +err_destroy_region: + drm_gpuva_region_destroy(&uvmm->umgr, ®->region); +err_free_region: + kfree(reg); + return ret; +} + +static void +__nouveau_uvma_region_destroy(struct nouveau_uvma_region *reg) +{ + struct nouveau_uvmm *uvmm = reg->uvmm; + struct nvif_vmm *vmm = &uvmm->vmm.vmm; + u64 addr = reg->region.node.start << PAGE_SHIFT; + u64 range = reg->region.node.size << PAGE_SHIFT; + + nouveau_uvmm_unmap_range(uvmm, addr, range); + + if (reg->region.sparse) + nvif_vmm_raw_sparse(vmm, addr, range, false); + + drm_gpuva_region_destroy(&uvmm->umgr, ®->region); + kfree(reg); +} + +int +nouveau_uvma_region_destroy(struct nouveau_uvmm *uvmm, + u64 addr, u64 range) +{ + struct drm_gpuva_region *reg; + + reg = drm_gpuva_region_find(&uvmm->umgr, + addr >> PAGE_SHIFT, + range >> PAGE_SHIFT); + if (!reg) + return -ENOENT; + + __nouveau_uvma_region_destroy(uvma_region_from_va_region(reg)); + + return 0; +} + +static int +op_map(struct nouveau_uvmm *uvmm, + struct drm_gpuva_op_map *m, + struct nouveau_uvmm_map_args *args) +{ + struct nouveau_uvma *uvma; + struct nouveau_bo *nvbo = nouveau_gem_object(m->gem.obj); + int ret; + + ret = nouveau_uvma_new(uvmm, m->gem.obj, + m->gem.offset << PAGE_SHIFT, + m->va.addr << PAGE_SHIFT, + m->va.range << PAGE_SHIFT, + args->kind, &uvma); + if (ret) + return ret; + + drm_gpuva_swap(&uvma->va, args->swapped); + if (!args->swapped) { + ret = nouveau_uvma_map(uvma, nouveau_mem(nvbo->bo.resource)); + if (ret) { + nouveau_uvma_destroy(uvma); + return ret; + } + } + + return 0; +} + +static int +op_unmap(struct nouveau_uvmm *uvmm, + struct drm_gpuva_op_unmap *u) +{ + struct nouveau_uvma *uvma = uvma_from_va(u->va); + int ret; + + ret = nouveau_uvma_unmap(uvma); + if (ret) + return ret; + + nouveau_uvma_destroy(uvma); + + return 0; +} + +static struct drm_gem_object * +op_gem_obj(struct drm_gpuva_op *op) +{ + switch (op->op) { + case DRM_GPUVA_OP_MAP: + return op->map.gem.obj; + case DRM_GPUVA_OP_REMAP: + return op->remap.unmap->va->gem.obj; + case DRM_GPUVA_OP_UNMAP: + return op->unmap.va->gem.obj; + default: + WARN(1, "unknown operation"); + return NULL; + } +} + +static int +process_sm_ops(struct nouveau_uvmm *uvmm, struct drm_gpuva_ops *ops, + struct nouveau_uvmm_map_args *args) +{ + struct drm_gpuva_op *op; + struct drm_gem_object *obj; + int ret = 0; + + drm_gpuva_for_each_op(op, ops) { + obj = op_gem_obj(op); + if (!obj) + continue; + + drm_gem_gpuva_lock(obj); + + switch (op->op) { + case DRM_GPUVA_OP_MAP: + ret = op_map(uvmm, &op->map, args); + if (ret) + goto err_unlock; + + break; + case DRM_GPUVA_OP_REMAP: + { + struct drm_gpuva_op_remap *r = &op->remap; + struct drm_gpuva *va = r->unmap->va; + struct nouveau_uvmm_map_args remap_args = { + .kind = uvma_from_va(r->unmap->va)->kind, + .swapped = drm_gpuva_swapped(va), + }; + + ret = op_unmap(uvmm, r->unmap); + if (ret) + goto err_unlock; + + if (r->prev) { + ret = op_map(uvmm, r->prev, &remap_args); + if (ret) + goto err_unlock; + } + + if (r->next) { + ret = op_map(uvmm, r->next, &remap_args); + if (ret) + goto err_unlock; + } + + break; + } + case DRM_GPUVA_OP_UNMAP: + ret = op_unmap(uvmm, &op->unmap); + if (ret) + goto err_unlock; + + break; + } + + drm_gem_gpuva_unlock(obj); + } + + return 0; + +err_unlock: + drm_gem_gpuva_unlock(obj); + return ret; +} + +int +nouveau_uvmm_sm_map(struct nouveau_uvmm *uvmm, u64 addr, u64 range, + struct drm_gem_object *obj, u64 offset, u8 kind) +{ + struct drm_gpuva_ops *ops; + struct nouveau_uvmm_map_args args = { + .kind = kind, + .swapped = false, + }; + int ret; + + ops = drm_gpuva_sm_map_ops_create(&uvmm->umgr, + addr >> PAGE_SHIFT, + range >> PAGE_SHIFT, + obj, offset >> PAGE_SHIFT); + if (IS_ERR(ops)) + return PTR_ERR(ops); + + ret = process_sm_ops(uvmm, ops, &args); + drm_gpuva_ops_free(ops); + + return ret; +} + +int +nouveau_uvmm_sm_unmap(struct nouveau_uvmm *uvmm, u64 addr, u64 range) +{ + struct drm_gpuva_ops *ops; + int ret; + + ops = drm_gpuva_sm_unmap_ops_create(&uvmm->umgr, + addr >> PAGE_SHIFT, + range >> PAGE_SHIFT); + if (IS_ERR(ops)) + return PTR_ERR(ops); + + ret = process_sm_ops(uvmm, ops, NULL); + drm_gpuva_ops_free(ops); + + return ret; +} + +int nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, + struct drm_nouveau_vm_init *init) +{ + int ret; + u64 unmanaged_end = init->unmanaged_addr + init->unmanaged_size; + + mutex_lock(&cli->mutex); + + if (unlikely(cli->uvmm.disabled)) { + ret = -ENOSYS; + goto out_unlock; + } + + if (unmanaged_end <= init->unmanaged_addr) { + ret = -EINVAL; + goto out_unlock; + } + + if (unmanaged_end > NOUVEAU_VA_SPACE_END) { + ret = -EINVAL; + goto out_unlock; + } + + uvmm->unmanaged_addr = init->unmanaged_addr; + uvmm->unmanaged_size = init->unmanaged_size; + + drm_gpuva_manager_init(&uvmm->umgr, cli->name, + NOUVEAU_VA_SPACE_START >> PAGE_SHIFT, + NOUVEAU_VA_SPACE_END >> PAGE_SHIFT, + init->unmanaged_addr >> PAGE_SHIFT, + init->unmanaged_size >> PAGE_SHIFT); + + ret = nvif_vmm_ctor(&cli->mmu, "uvmm", + cli->vmm.vmm.object.oclass, RAW, + init->unmanaged_addr, init->unmanaged_size, + NULL, 0, &cli->uvmm.vmm.vmm); + if (ret) + goto out_free_gpuva_mgr; + + cli->uvmm.vmm.cli = cli; + mutex_unlock(&cli->mutex); + + mutex_init(&uvmm->mutex); + + return 0; + +out_free_gpuva_mgr: + drm_gpuva_manager_destroy(&uvmm->umgr); +out_unlock: + mutex_unlock(&cli->mutex); + return ret; +} + +void nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) +{ + struct nouveau_cli *cli = uvmm->vmm.cli; + struct drm_gpuva_region *reg, *next; + + if (!cli) + return; + + /* Destroying a region implies destroying all mappings within the + * region. + */ + nouveau_uvmm_lock(uvmm); + drm_gpuva_for_each_region_safe(reg, next, &uvmm->umgr) + if (®->node != &uvmm->umgr.kernel_alloc_node) + __nouveau_uvma_region_destroy(uvma_region_from_va_region(reg)); + nouveau_uvmm_unlock(uvmm); + + mutex_lock(&cli->mutex); + nouveau_vmm_fini(&uvmm->vmm); + drm_gpuva_manager_destroy(&uvmm->umgr); + mutex_unlock(&cli->mutex); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h new file mode 100644 index 000000000000..b0ad57004aa6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT + +#ifndef __NOUVEAU_UVMM_H__ +#define __NOUVEAU_UVMM_H__ + +#include + +#include "nouveau_drv.h" + +struct nouveau_uvmm { + struct nouveau_vmm vmm; + struct drm_gpuva_manager umgr; + struct mutex mutex; + + u64 unmanaged_addr; + u64 unmanaged_size; + + bool disabled; +}; + +struct nouveau_uvma_region { + struct drm_gpuva_region region; + struct nouveau_uvmm *uvmm; +}; + +struct nouveau_uvma { + struct drm_gpuva va; + struct nouveau_uvmm *uvmm; + u64 handle; + u8 kind; +}; + +#define uvmm_from_mgr(x) container_of((x), struct nouveau_uvmm, umgr) +#define uvma_from_va(x) container_of((x), struct nouveau_uvma, va) +#define uvma_region_from_va_region(x) container_of((x), struct nouveau_uvma_region, region) + +int nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, + struct drm_nouveau_vm_init *init); +void nouveau_uvmm_fini(struct nouveau_uvmm *uvmm); + +int nouveau_uvma_region_new(struct nouveau_uvmm *uvmm, + u64 addr, u64 range, + bool sparse); +int nouveau_uvma_region_destroy(struct nouveau_uvmm *uvmm, + u64 addr, u64 range); + +int nouveau_uvmm_sm_map(struct nouveau_uvmm *uvmm, u64 addr, u64 range, + struct drm_gem_object *obj, u64 offset, u8 kind); +int nouveau_uvmm_sm_unmap(struct nouveau_uvmm *uvmm, u64 addr, u64 range); + +void nouveau_uvmm_cli_unmap_all(struct nouveau_uvmm *uvmm, + struct drm_gem_object *obj); +void nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbov, struct nouveau_mem *mem); +void nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo); + +int nouveau_uvmm_validate_range(struct nouveau_uvmm *uvmm, u64 addr, u64 range); + +static inline void nouveau_uvmm_lock(struct nouveau_uvmm *uvmm) +{ + mutex_lock(&uvmm->mutex); +} + +static inline void nouveau_uvmm_unlock(struct nouveau_uvmm *uvmm) +{ + mutex_unlock(&uvmm->mutex); +} + +#endif From patchwork Wed Jan 18 06:12:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45028 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2177182wrn; Tue, 17 Jan 2023 22:41:38 -0800 (PST) X-Google-Smtp-Source: AMrXdXsaDWYlcfjwaTKPxgC1MFWDleE5LEh4q4WuPW2nuQXMwjJAfTVR+VFEAMiSIw1lv7nE5oq1 X-Received: by 2002:a17:90a:ca88:b0:228:d8b3:15e4 with SMTP id y8-20020a17090aca8800b00228d8b315e4mr5847077pjt.32.1674024098592; Tue, 17 Jan 2023 22:41:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674024098; cv=none; d=google.com; s=arc-20160816; b=zpIKvJ4EBBlrK4Xn27LRmgoOyFH2aDltE/NQbVEfK8DwMmFnqEhNdTcAB8YERb141o bhulXOqoXp8vB4bbpTvGln5StDKSwG1vUaBq7b0wkp/xsZRC3CuJctKkQIe9aipiGD+r SbPGFa8fImzKc3kJsZJgXYmsgVYsvds8mbsfLrhISZsKAQoC02x57koCuikyDyj20yiP 1wBeq4uIuwni4N0pAaiPug3FQdtl7tN/tTlBpmj5OCe/8yygXOfZVpPkyLfXBFmsVdPm 7j3Y7e1/lRbdUtnQu2IqlWFPyc7oSvcTj0+TWfw/zHgeAq4CQo5WFwhkVn9gejpNTohm CgDA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=hXHmTxbGZruPdr+kQujRuMeeWZGFqvkt+mVQWkiSsWQ=; b=oCRb/Y+1PLmn3q6hZprZoC1JodtLIIiBzd9RF1IlC/ZX9x/dHvnXF+EJFlPVPW9oHG o7so3/AOGN/Q07SMLFhEAAayOrzHq6n2950TWZQIs0bqTCeyKnS0CBKU1lC3g/Pxm7OM RIRZ7vjbLx30tA+bf45hIGvy4I5p11tnASGO50iKcnaG9kA/sRqmhPC51567szAcCRL9 vT7rVk1vQDYsEpxISVaMKILaBs4amtaTIW4VKrgFT5k2kB0qCwTIGNY8xDoiYhu4rEST tST9QmiOwCLqznMaYWIGTshn0VUwSCl8luPi1euZNCFa8/oQJ+tUFqdCK68UPw/HODEY 1/xw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=RFViQ9wg; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h2-20020a17090ac38200b002265c110dbasi1236929pjt.28.2023.01.17.22.41.25; Tue, 17 Jan 2023 22:41:38 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=RFViQ9wg; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229723AbjARGjY (ORCPT + 99 others); Wed, 18 Jan 2023 01:39:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57986 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229566AbjARG0V (ORCPT ); Wed, 18 Jan 2023 01:26:21 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 80D815528D for ; Tue, 17 Jan 2023 22:14:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022461; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hXHmTxbGZruPdr+kQujRuMeeWZGFqvkt+mVQWkiSsWQ=; b=RFViQ9wgwU4R3cgD4OInIQFuxl3KLBfPlio9oCdr3Jt+0uhzL2lDFdeIPyCwKyKFZQAY0F 1m7fCaH68xvREhPfxSTRpNdAZbFSCp9vgp98lsgKsQm0Yi0Sj0Bz3kUSaZmv0fPJNMd6oL RcAonyPTj3lze9V0Vux3ocFNNZ3JRVE= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-96-BPQNVc9-Pi6WDNS4p113cw-1; Wed, 18 Jan 2023 01:14:20 -0500 X-MC-Unique: BPQNVc9-Pi6WDNS4p113cw-1 Received: by mail-ed1-f70.google.com with SMTP id dz20-20020a0564021d5400b0049e15ded5fcso5871357edb.23 for ; Tue, 17 Jan 2023 22:14:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hXHmTxbGZruPdr+kQujRuMeeWZGFqvkt+mVQWkiSsWQ=; b=D4Tvp9ap0ZNgxgH5uh2SRJnHI3pru3dWRFY8/jD+yfpZgLISPYHas/IwSDcWYyagAB s6/RNY8LrvLusWBNx0HVamW7RClTq9dR2wTAEMiDE6nZFDPiw0lBob0EZnxNEi5kFeoE ku5SHIIjx9bSSdn2E922KDmOaV5zRpdFHnry3Ab92+05MXicQ+/U/PartatdEyDBIbGA oL3Y6E7+s/V7CMeOmJEfiKs/LlYJaSROZS16+9veMtyW1Iwc7ZQABXPEpAExjT/SQ8fe F3WOpggPdSPeKvYjUiaWQXutGBdXUbUuhqnsUeJAIEOvyE9szxM17gqCs+ZFlgzcRJWR oaLw== X-Gm-Message-State: AFqh2kqg2/AwnUFUd0wj26qEUcj1FmpF0jIzwlIUvkpc+JSlaXM9Xjdi Pg5suRumaiWWNUAzjIgM+68CkDNEGYz67zn+EClDHWOxgH4U2F1jGac9dv9+Im0L0hnEubwFYcG 8fgZ06h4X8ii2sl1B4Ea8G0Km X-Received: by 2002:a17:906:f1d6:b0:86e:7896:80d4 with SMTP id gx22-20020a170906f1d600b0086e789680d4mr5740873ejb.49.1674022458913; Tue, 17 Jan 2023 22:14:18 -0800 (PST) X-Received: by 2002:a17:906:f1d6:b0:86e:7896:80d4 with SMTP id gx22-20020a170906f1d600b0086e789680d4mr5740850ejb.49.1674022458437; Tue, 17 Jan 2023 22:14:18 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id k15-20020a17090632cf00b0087120324712sm3114542ejk.23.2023.01.17.22.14.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:17 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 13/14] drm/nouveau: implement new VM_BIND UAPI Date: Wed, 18 Jan 2023 07:12:55 +0100 Message-Id: <20230118061256.2689-14-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341493282671637?= X-GMAIL-MSGID: =?utf-8?q?1755341493282671637?= This commit provides the implementation for the new uapi motivated by the Vulkan API. It allows user mode drivers (UMDs) to: 1) Initialize a GPU virtual address (VA) space via the new DRM_IOCTL_NOUVEAU_VM_INIT ioctl for UMDs to specify the portion of VA space managed by the kernel and userspace, respectively. 2) Allocate and free a VA space region as well as bind and unbind memory to the GPUs VA space via the new DRM_IOCTL_NOUVEAU_VM_BIND ioctl. UMDs can request the named operations to be processed either synchronously or asynchronously. It supports DRM syncobjs (incl. timelines) as synchronization mechanism. The management of the GPU VA mappings is implemented with the DRM GPU VA manager. 3) Execute push buffers with the new DRM_IOCTL_NOUVEAU_EXEC ioctl. The execution happens asynchronously. It supports DRM syncobj (incl. timelines) as synchronization mechanism. DRM GEM object locking is handled with drm_exec. Both, DRM_IOCTL_NOUVEAU_VM_BIND and DRM_IOCTL_NOUVEAU_EXEC, use the DRM GPU scheduler for the asynchronous paths. Signed-off-by: Danilo Krummrich --- Documentation/gpu/driver-uapi.rst | 3 + drivers/gpu/drm/nouveau/Kbuild | 2 + drivers/gpu/drm/nouveau/Kconfig | 2 + drivers/gpu/drm/nouveau/nouveau_abi16.c | 16 + drivers/gpu/drm/nouveau/nouveau_abi16.h | 1 + drivers/gpu/drm/nouveau/nouveau_drm.c | 23 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 +- drivers/gpu/drm/nouveau/nouveau_exec.c | 310 ++++++++++ drivers/gpu/drm/nouveau/nouveau_exec.h | 55 ++ drivers/gpu/drm/nouveau/nouveau_sched.c | 780 ++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_sched.h | 98 +++ 11 files changed, 1295 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nouveau_exec.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_exec.h create mode 100644 drivers/gpu/drm/nouveau/nouveau_sched.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_sched.h diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst index 9c7ca6e33a68..c08bcbb95fb3 100644 --- a/Documentation/gpu/driver-uapi.rst +++ b/Documentation/gpu/driver-uapi.rst @@ -13,4 +13,7 @@ drm/nouveau uAPI VM_BIND / EXEC uAPI ------------------- +.. kernel-doc:: drivers/gpu/drm/nouveau/nouveau_exec.c + :doc: Overview + .. kernel-doc:: include/uapi/drm/nouveau_drm.h diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild index ee281bb76463..cf6b3a80c0c8 100644 --- a/drivers/gpu/drm/nouveau/Kbuild +++ b/drivers/gpu/drm/nouveau/Kbuild @@ -47,6 +47,8 @@ nouveau-y += nouveau_prime.o nouveau-y += nouveau_sgdma.o nouveau-y += nouveau_ttm.o nouveau-y += nouveau_vmm.o +nouveau-y += nouveau_exec.o +nouveau-y += nouveau_sched.o nouveau-y += nouveau_uvmm.o # DRM - modesetting diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index a0bb3987bf63..59e5c13be9b6 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -10,6 +10,8 @@ config DRM_NOUVEAU select DRM_KMS_HELPER select DRM_TTM select DRM_TTM_HELPER + select DRM_EXEC + select DRM_SCHED select I2C select I2C_ALGOBIT select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 36cc80eb0e20..694777a58bca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -35,6 +35,7 @@ #include "nouveau_chan.h" #include "nouveau_abi16.h" #include "nouveau_vmm.h" +#include "nouveau_sched.h" static struct nouveau_abi16 * nouveau_abi16(struct drm_file *file_priv) @@ -125,6 +126,17 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, { struct nouveau_abi16_ntfy *ntfy, *temp; + /* When a client exits without waiting for it's queued up jobs to + * finish it might happen that we fault the channel. This is due to + * drm_file_free() calling drm_gem_release() before the postclose() + * callback. Hence, we can't tear down this scheduler entity before + * uvmm mappings are unmapped. Currently, we can't detect this case. + * + * However, this should be rare and harmless, since the channel isn't + * needed anymore. + */ + nouveau_sched_entity_fini(&chan->sched_entity); + /* wait for all activity to stop before cleaning up */ if (chan->chan) nouveau_channel_idle(chan->chan); @@ -311,6 +323,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; + ret = nouveau_sched_entity_init(&chan->sched_entity, &drm->sched); + if (ret) + goto done; + init->channel = chan->chan->chid; if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 27eae85f33e6..8209eb28feaf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -26,6 +26,7 @@ struct nouveau_abi16_chan { struct nouveau_bo *ntfy; struct nouveau_vma *ntfy_vma; struct nvkm_mm heap; + struct nouveau_sched_entity sched_entity; }; struct nouveau_abi16 { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 989f30a31ba9..5d018207ff92 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -71,6 +71,7 @@ #include "nouveau_svm.h" #include "nouveau_dmem.h" #include "nouveau_uvmm.h" +#include "nouveau_sched.h" DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", @@ -192,6 +193,7 @@ nouveau_cli_fini(struct nouveau_cli *cli) flush_work(&cli->work); WARN_ON(!list_empty(&cli->worker)); + nouveau_sched_entity_fini(&cli->sched_entity); usif_client_fini(cli); nouveau_uvmm_fini(&cli->uvmm); nouveau_vmm_fini(&cli->svm); @@ -299,6 +301,11 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, } cli->mem = &mems[ret]; + + ret = nouveau_sched_entity_init(&cli->sched_entity, &drm->sched); + if (ret) + goto done; + return 0; done: if (ret) @@ -611,8 +618,13 @@ nouveau_drm_device_init(struct drm_device *dev) pm_runtime_put(dev->dev); } - return 0; + ret = nouveau_sched_init(&drm->sched, drm); + if (ret) + goto fail_sched_init; + return 0; +fail_sched_init: + nouveau_display_fini(dev, false, false); fail_dispinit: nouveau_display_destroy(dev); fail_dispctor: @@ -637,6 +649,8 @@ nouveau_drm_device_fini(struct drm_device *dev) struct nouveau_cli *cli, *temp_cli; struct nouveau_drm *drm = nouveau_drm(dev); + nouveau_sched_fini(&drm->sched); + if (nouveau_pmops_runtime()) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); @@ -1177,6 +1191,9 @@ nouveau_ioctls[] = { DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_VM_INIT, nouveau_ioctl_vm_init, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_VM_BIND, nouveau_ioctl_vm_bind, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_EXEC, nouveau_ioctl_exec, DRM_RENDER_ALLOW), }; long @@ -1224,7 +1241,9 @@ nouveau_driver_fops = { static struct drm_driver driver_stub = { .driver_features = - DRIVER_GEM | DRIVER_MODESET | DRIVER_RENDER + DRIVER_GEM | DRIVER_MODESET | DRIVER_RENDER | + DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE | + DRIVER_GEM_GPUVA #if defined(CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT) | DRIVER_KMS_LEGACY_CONTEXT #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d634f1054d65..94de792ef3ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -10,8 +10,8 @@ #define DRIVER_DATE "20120801" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 3 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 4 +#define DRIVER_PATCHLEVEL 0 /* * 1.1.1: @@ -63,6 +63,7 @@ struct platform_device; #include "nouveau_fence.h" #include "nouveau_bios.h" +#include "nouveau_sched.h" #include "nouveau_vmm.h" #include "nouveau_uvmm.h" @@ -94,6 +95,8 @@ struct nouveau_cli { struct nouveau_vmm svm; struct nouveau_uvmm uvmm; + struct nouveau_sched_entity sched_entity; + const struct nvif_mclass *mem; struct list_head head; @@ -305,6 +308,8 @@ struct nouveau_drm { struct mutex lock; bool component_registered; } audio; + + struct drm_gpu_scheduler sched; }; static inline struct nouveau_drm * diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c new file mode 100644 index 000000000000..512120bdb8a8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Danilo Krummrich + * + */ + +#include + +#include "nouveau_drv.h" +#include "nouveau_gem.h" +#include "nouveau_mem.h" +#include "nouveau_dma.h" +#include "nouveau_exec.h" +#include "nouveau_abi16.h" +#include "nouveau_chan.h" +#include "nouveau_sched.h" +#include "nouveau_uvmm.h" + + +/** + * DOC: Overview + * + * Nouveau's VM_BIND / EXEC UAPI consists of three ioctls: DRM_NOUVEAU_VM_INIT, + * DRM_NOUVEAU_VM_BIND and DRM_NOUVEAU_EXEC. + * + * In order to use the UAPI firstly a user client must initialize the VA space + * using the DRM_NOUVEAU_VM_INIT ioctl specifying which region of the VA space + * should be managed by the kernel and which by the UMD. + * + * The DRM_NOUVEAU_VM_BIND ioctl provides clients an interface to manage the + * userspace-managable portion of the VA space. It provides operations to + * allocate and free a VA space regions and operations to map and unmap memory + * within such a region. Bind operations crossing region boundaries are not + * permitted. + * + * When allocating a VA space region userspace may flag this region as sparse. + * If a region is flagged as sparse the kernel will take care that for the whole + * region sparse mappings are created. Subsequently requested actual memory + * backed mappings for a sparse region will take precedence over the sparse + * mappings. If the memory backed mappings are unmapped the kernel will make + * sure that sparse mappings will take their place again. + * + * When using the VM_BIND ioctl to request the kernel to map memory to a given + * virtual address in the GPU's VA space there is no guarantee that the actual + * mappings are created in the GPU's MMU. If the given memory is swapped out + * at the time the bind operation is executed the kernel will stash the mapping + * details into it's internal alloctor and create the actual MMU mappings once + * the memory is swapped back in. While this is transparent for userspace, it is + * guaranteed that all the backing memory is swapped back in and all the memory + * mappings, as requested by userspace previously, are actually mapped once the + * DRM_NOUVEAU_EXEC ioctl is called to submit an exec job. + * + * Contrary to VM_BIND map requests, unmap requests are allowed to span over VA + * space regions and completely untouched areas of the VA space. + * + * Generally, all rules for constellations like mapping and unmapping over + * boundaries of existing mappings are documented in the &drm_gpuva_manager. + * + * When a VA space region is freed, all existing mappings within this region are + * unmapped automatically. + * + * A VM_BIND job can be executed either synchronously or asynchronously. If + * exectued asynchronously, userspace may provide a list of syncobjs this job + * will wait for and/or a list of syncobj the kernel will trigger once the + * VM_BIND finished execution. If executed synchronously the ioctl will block + * until the bind job is finished and no syncobjs are permitted by the kernel. + * + * To execute a push buffer the UAPI provides the DRM_NOUVEAU_EXEC ioctl. EXEC + * jobs are always executed asynchronously, and, equal to VM_BIND jobs, provide + * the option to synchronize them with syncobjs. + * + * Besides that EXEC job can be scheduled for a specified channel to execute on. + * + * EXEC jobs wait for VM_BIND jobs they depend on when userspace submitts the + * EXEC job rather than when this EXEC job actually executes. This is due to the + * fact that at submission time of the EXEC job we'd otherwise not have the + * correct view of the VA space for this EXEC job, since VM_BIND jobs, this EXEC + * job depends on might still be in the queue. Without a recent (and hence + * for this particular job correct) view of the VA space, we'd potentially miss + * to lock, swap in and re-bind BOs that have been evicted previously. + */ + +static int +nouveau_exec_ucopy_syncs(struct nouveau_exec_base *base, + u32 inc, u64 ins, + u32 outc, u64 outs) +{ + struct drm_nouveau_sync **s; + int ret; + + if (inc) { + s = &base->in_sync.s; + + base->in_sync.count = inc; + *s = u_memcpya(ins, inc, sizeof(**s)); + if (IS_ERR(*s)) { + ret = PTR_ERR(*s); + goto err_out; + } + } + + if (outc) { + s = &base->out_sync.s; + + base->out_sync.count = outc; + *s = u_memcpya(outs, outc, sizeof(**s)); + if (IS_ERR(*s)) { + ret = PTR_ERR(*s); + goto err_free_ins; + } + } + + return 0; + +err_free_ins: + u_free(base->in_sync.s); +err_out: + return ret; +} + +int +nouveau_ioctl_vm_init(struct drm_device *dev, + void *data, + struct drm_file *file_priv) +{ + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct drm_nouveau_vm_init *init = data; + + return nouveau_uvmm_init(&cli->uvmm, cli, init); +} + +int nouveau_vm_bind(struct nouveau_exec_bind *bind) +{ + struct nouveau_bind_job *job; + int ret; + + ret = nouveau_bind_job_init(&job, bind); + if (ret) + return ret; + + ret = nouveau_job_submit(&job->base); + if (ret) + goto err_job_fini; + + return 0; + +err_job_fini: + nouveau_job_fini(&job->base); + return ret; +} + +int +nouveau_ioctl_vm_bind(struct drm_device *dev, + void *data, + struct drm_file *file_priv) +{ + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct nouveau_exec_bind bind = {}; + struct drm_nouveau_vm_bind *req = data; + int ret = 0; + + if (unlikely(!nouveau_cli_uvmm_locked(cli))) + return -ENOSYS; + + bind.flags = req->flags; + + bind.op.count = req->op_count; + bind.op.s = u_memcpya(req->op_ptr, req->op_count, + sizeof(*bind.op.s)); + if (IS_ERR(bind.op.s)) + return PTR_ERR(bind.op.s); + + ret = nouveau_exec_ucopy_syncs(&bind.base, + req->wait_count, req->wait_ptr, + req->sig_count, req->sig_ptr); + if (ret) + goto out_free_ops; + + bind.base.sched_entity = &cli->sched_entity; + bind.base.file_priv = file_priv; + + ret = nouveau_vm_bind(&bind); + if (ret) + goto out_free_syncs; + +out_free_syncs: + u_free(bind.base.out_sync.s); + u_free(bind.base.in_sync.s); +out_free_ops: + u_free(bind.op.s); + return ret; +} + +static int +nouveau_exec(struct nouveau_exec *exec) +{ + struct nouveau_exec_job *job; + int ret; + + ret = nouveau_exec_job_init(&job, exec); + if (ret) + return ret; + + ret = nouveau_job_submit(&job->base); + if (ret) + goto err_job_fini; + + return 0; + +err_job_fini: + nouveau_job_fini(&job->base); + return ret; +} + +int +nouveau_ioctl_exec(struct drm_device *dev, + void *data, + struct drm_file *file_priv) +{ + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv); + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct nouveau_abi16_chan *chan16; + struct nouveau_channel *chan = NULL; + struct nouveau_exec exec = {}; + struct drm_nouveau_exec *req = data; + int ret = 0; + + if (unlikely(!abi16)) + return -ENOMEM; + + /* abi16 locks already */ + if (unlikely(!nouveau_cli_uvmm(cli))) + return nouveau_abi16_put(abi16, -ENOSYS); + + list_for_each_entry(chan16, &abi16->channels, head) { + if (chan16->chan->chid == req->channel) { + chan = chan16->chan; + break; + } + } + + if (!chan) + return nouveau_abi16_put(abi16, -ENOENT); + + if (unlikely(atomic_read(&chan->killed))) + return nouveau_abi16_put(abi16, -ENODEV); + + if (!chan->dma.ib_max) + return nouveau_abi16_put(abi16, -ENOSYS); + + if (unlikely(req->push_count == 0)) + goto out; + + if (unlikely(req->push_count > NOUVEAU_GEM_MAX_PUSH)) { + NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n", + req->push_count, NOUVEAU_GEM_MAX_PUSH); + return nouveau_abi16_put(abi16, -EINVAL); + } + + exec.push.count = req->push_count; + exec.push.s = u_memcpya(req->push_ptr, req->push_count, + sizeof(*exec.push.s)); + if (IS_ERR(exec.push.s)) { + ret = PTR_ERR(exec.push.s); + goto out; + } + + ret = nouveau_exec_ucopy_syncs(&exec.base, + req->wait_count, req->wait_ptr, + req->sig_count, req->sig_ptr); + if (ret) + goto out_free_pushs; + + exec.base.sched_entity = &chan16->sched_entity; + exec.base.chan = chan; + exec.base.file_priv = file_priv; + + ret = nouveau_exec(&exec); + if (ret) + goto out_free_syncs; + +out_free_syncs: + u_free(exec.base.out_sync.s); + u_free(exec.base.in_sync.s); +out_free_pushs: + u_free(exec.push.s); +out: + return nouveau_abi16_put(abi16, ret); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.h b/drivers/gpu/drm/nouveau/nouveau_exec.h new file mode 100644 index 000000000000..3774fc338f5d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_exec.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +#ifndef __NOUVEAU_EXEC_H__ +#define __NOUVEAU_EXEC_H__ + +#include + +#include "nouveau_drv.h" + +struct nouveau_exec_base { + struct nouveau_channel *chan; + struct drm_file *file_priv; + struct nouveau_sched_entity *sched_entity; + + struct { + struct drm_nouveau_sync *s; + u32 count; + } in_sync; + + struct { + struct drm_nouveau_sync *s; + u32 count; + } out_sync; +}; + +struct nouveau_exec_bind { + struct nouveau_exec_base base; + unsigned int flags; + + struct { + struct drm_nouveau_vm_bind_op *s; + u32 count; + } op; +}; + +struct nouveau_exec { + struct nouveau_exec_base base; + struct drm_exec exec; + + struct { + struct drm_nouveau_exec_push *s; + u32 count; + } push; +}; + +int nouveau_ioctl_vm_init(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +int nouveau_ioctl_vm_bind(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +int nouveau_ioctl_exec(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c new file mode 100644 index 000000000000..2749aa1908ad --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -0,0 +1,780 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Danilo Krummrich + * + */ + +#include +#include +#include + +#include "nouveau_drv.h" +#include "nouveau_gem.h" +#include "nouveau_mem.h" +#include "nouveau_dma.h" +#include "nouveau_exec.h" +#include "nouveau_abi16.h" +#include "nouveau_chan.h" +#include "nouveau_sched.h" + +/* FIXME + * + * We want to make sure that jobs currently executing can't be deferred by + * other jobs competing for the hardware. Otherwise we might end up with job + * timouts just because of too many clients submitting too many jobs. We don't + * want jobs to time out because of system load, but because of the job being + * too bulky. + * + * For now allow for up to 16 concurrent jobs in flight until we know how many + * rings the hardware can process in parallel. + */ +#define NOUVEAU_SCHED_HW_SUBMISSIONS 16 +#define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 + +#define list_for_each_op(_op, _ops) list_for_each_entry(_op, _ops, entry) +#define list_for_each_op_safe(_op, _n, _ops) list_for_each_entry_safe(_op, _n, _ops, entry) + +enum bind_op { + OP_ALLOC = DRM_NOUVEAU_VM_BIND_OP_ALLOC, + OP_FREE = DRM_NOUVEAU_VM_BIND_OP_FREE, + OP_MAP = DRM_NOUVEAU_VM_BIND_OP_MAP, + OP_UNMAP = DRM_NOUVEAU_VM_BIND_OP_UNMAP, +}; + +struct bind_job_op { + struct list_head entry; + + enum bind_op op; + u32 flags; + + struct { + u64 addr; + u64 range; + } va; + + struct { + u32 handle; + u64 offset; + struct drm_gem_object *obj; + } gem; +}; + +static int +nouveau_base_job_init(struct nouveau_job *job, + struct nouveau_exec_base *base) +{ + struct nouveau_sched_entity *entity = base->sched_entity; + int ret; + + INIT_LIST_HEAD(&job->head); + job->file_priv = base->file_priv; + job->cli = nouveau_cli(base->file_priv); + job->chan = base->chan; + job->entity = entity; + + job->in_sync.count = base->in_sync.count; + if (job->in_sync.count) { + if (job->sync) + return -EINVAL; + + job->in_sync.s = kmemdup(base->in_sync.s, + sizeof(*base->in_sync.s) * + base->in_sync.count, + GFP_KERNEL); + if (!job->in_sync.s) + return -ENOMEM; + } + + job->out_sync.count = base->out_sync.count; + if (job->out_sync.count) { + if (job->sync) { + ret = -EINVAL; + goto err_free_in_sync; + } + + job->out_sync.s = kmemdup(base->out_sync.s, + sizeof(*base->out_sync.s) * + base->out_sync.count, + GFP_KERNEL); + if (!job->out_sync.s) { + ret = -ENOMEM; + goto err_free_in_sync; + } + } + + ret = drm_sched_job_init(&job->base, &entity->base, NULL); + if (ret) + goto err_free_out_sync; + + return 0; + +err_free_out_sync: + if (job->out_sync.s) + kfree(job->out_sync.s); +err_free_in_sync: + if (job->in_sync.s) + kfree(job->in_sync.s); +return ret; +} + +static void +nouveau_base_job_free(struct nouveau_job *job) +{ + if (job->in_sync.s) + kfree(job->in_sync.s); + + if (job->out_sync.s) + kfree(job->out_sync.s); +} + +static int +bind_submit_validate_op(struct nouveau_job *job, + struct bind_job_op *op) +{ + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); + struct drm_gem_object *obj = op->gem.obj; + + if (op->op == OP_MAP) { + if (op->gem.offset & ~PAGE_MASK) + return -EINVAL; + + if (obj->size <= op->gem.offset) + return -EINVAL; + + if (op->va.range > (obj->size - op->gem.offset)) + return -EINVAL; + } + + return nouveau_uvmm_validate_range(uvmm, op->va.addr, op->va.range); +} + +int +nouveau_bind_job_submit(struct nouveau_job *job) +{ + struct nouveau_bind_job *bind_job = to_nouveau_bind_job(job); + struct bind_job_op *op; + int ret; + + list_for_each_op(op, &bind_job->ops) { + switch (op->op) { + case OP_ALLOC: + case OP_FREE: + case OP_MAP: + case OP_UNMAP: + break; + default: + return -EINVAL; + } + + if (op->op == OP_MAP) { + op->gem.obj = drm_gem_object_lookup(job->file_priv, + op->gem.handle); + if (!op->gem.obj) + return -ENOENT; + } + + ret = bind_submit_validate_op(job, op); + if (ret) + return ret; + } + + return 0; +} + +static struct dma_fence * +nouveau_bind_job_run(struct nouveau_job *job) +{ + struct nouveau_bind_job *bind_job = to_nouveau_bind_job(job); + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); + struct bind_job_op *op; + int ret = 0; + + nouveau_uvmm_lock(uvmm); + list_for_each_op(op, &bind_job->ops) { + switch (op->op) { + case OP_ALLOC: { + bool sparse = op->flags & DRM_NOUVEAU_VM_BIND_SPARSE; + + ret = nouveau_uvma_region_new(uvmm, + op->va.addr, + op->va.range, + sparse); + if (ret) + goto out_unlock; + break; + } + case OP_FREE: + ret = nouveau_uvma_region_destroy(uvmm, + op->va.addr, + op->va.range); + if (ret) + goto out_unlock; + break; + case OP_MAP: + ret = nouveau_uvmm_sm_map(uvmm, + op->va.addr, op->va.range, + op->gem.obj, op->gem.offset, + op->flags && 0xff); + if (ret) + goto out_unlock; + break; + case OP_UNMAP: + ret = nouveau_uvmm_sm_unmap(uvmm, + op->va.addr, + op->va.range); + if (ret) + goto out_unlock; + break; + } + } + +out_unlock: + nouveau_uvmm_unlock(uvmm); + if (ret) + NV_PRINTK(err, job->cli, "bind job failed: %d\n", ret); + return ERR_PTR(ret); +} + +static void +nouveau_bind_job_free(struct nouveau_job *job) +{ + struct nouveau_bind_job *bind_job = to_nouveau_bind_job(job); + struct bind_job_op *op, *next; + + list_for_each_op_safe(op, next, &bind_job->ops) { + struct drm_gem_object *obj = op->gem.obj; + + if (obj) + drm_gem_object_put(obj); + + list_del(&op->entry); + kfree(op); + } + + nouveau_base_job_free(job); + kfree(bind_job); +} + +static struct nouveau_job_ops nouveau_bind_job_ops = { + .submit = nouveau_bind_job_submit, + .run = nouveau_bind_job_run, + .free = nouveau_bind_job_free, +}; + +static int +bind_job_op_from_uop(struct bind_job_op **pop, + struct drm_nouveau_vm_bind_op *uop) +{ + struct bind_job_op *op; + + op = *pop = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->op = uop->op; + op->flags = uop->flags; + op->va.addr = uop->addr; + op->va.range = uop->range; + + if (op->op == DRM_NOUVEAU_VM_BIND_OP_MAP) { + op->gem.handle = uop->handle; + op->gem.offset = uop->bo_offset; + } + + return 0; +} + +static void +bind_job_ops_free(struct list_head *ops) +{ + struct bind_job_op *op, *next; + + list_for_each_op_safe(op, next, ops) { + list_del(&op->entry); + kfree(op); + } +} + +int +nouveau_bind_job_init(struct nouveau_bind_job **pjob, + struct nouveau_exec_bind *bind) +{ + struct nouveau_bind_job *job; + struct bind_job_op *op; + int i, ret; + + job = *pjob = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + INIT_LIST_HEAD(&job->ops); + + for (i = 0; i < bind->op.count; i++) { + ret = bind_job_op_from_uop(&op, &bind->op.s[i]); + if (ret) + goto err_free; + + list_add_tail(&op->entry, &job->ops); + } + + job->base.sync = !(bind->flags & DRM_NOUVEAU_VM_BIND_RUN_ASYNC); + job->base.ops = &nouveau_bind_job_ops; + + ret = nouveau_base_job_init(&job->base, &bind->base); + if (ret) + goto err_free; + + return 0; + +err_free: + bind_job_ops_free(&job->ops); + kfree(job); + *pjob = NULL; + + return ret; +} + +static int +sync_find_fence(struct nouveau_job *job, + struct drm_nouveau_sync *sync, + struct dma_fence **fence) +{ + u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; + u64 point = 0; + int ret; + + if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && + stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) + return -EOPNOTSUPP; + + if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) + point = sync->timeline_value; + + ret = drm_syncobj_find_fence(job->file_priv, + sync->handle, point, + sync->flags, fence); + if (ret) + return ret; + + return 0; +} + +static int +exec_job_binds_wait(struct nouveau_job *job) +{ + struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + struct nouveau_cli *cli = exec_job->base.cli; + struct nouveau_sched_entity *bind_entity = &cli->sched_entity; + signed long ret; + int i; + + for (i = 0; i < job->in_sync.count; i++) { + struct nouveau_job *it; + struct drm_nouveau_sync *sync = &job->in_sync.s[i]; + struct dma_fence *fence; + bool found; + + ret = sync_find_fence(job, sync, &fence); + if (ret) + return ret; + + mutex_lock(&bind_entity->job.mutex); + found = false; + list_for_each_entry(it, &bind_entity->job.list, head) { + if (fence == it->done_fence) { + found = true; + break; + } + } + mutex_unlock(&bind_entity->job.mutex); + + /* If the fence is not from a VM_BIND job, don't wait for it. */ + if (!found) + continue; + + ret = dma_fence_wait_timeout(fence, true, + msecs_to_jiffies(500)); + if (ret < 0) + return ret; + else if (ret == 0) + return -ETIMEDOUT; + } + + return 0; +} + +int +nouveau_exec_job_submit(struct nouveau_job *job) +{ + struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + struct nouveau_cli *cli = exec_job->base.cli; + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); + struct drm_exec *exec = &job->exec; + struct drm_gem_object *obj; + unsigned long index; + int ret; + + ret = exec_job_binds_wait(job); + if (ret) + return ret; + + nouveau_uvmm_lock(uvmm); + drm_exec_while_not_all_locked(exec) { + struct drm_gpuva *va; + + drm_gpuva_for_each_va(va, &uvmm->umgr) { + ret = drm_exec_prepare_obj(exec, va->gem.obj, 1); + drm_exec_break_on_contention(exec); + if (ret) + return ret; + } + } + nouveau_uvmm_unlock(uvmm); + + drm_exec_for_each_locked_object(exec, index, obj) { + struct dma_resv *resv = obj->resv; + struct nouveau_bo *nvbo = nouveau_gem_object(obj); + + ret = nouveau_bo_validate(nvbo, true, false); + if (ret) + return ret; + + dma_resv_add_fence(resv, job->done_fence, DMA_RESV_USAGE_WRITE); + } + + return 0; +} + +static struct dma_fence * +nouveau_exec_job_run(struct nouveau_job *job) +{ + struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + struct nouveau_fence *fence; + int i, ret; + + ret = nouveau_dma_wait(job->chan, exec_job->push.count + 1, 16); + if (ret) { + NV_PRINTK(err, job->cli, "nv50cal_space: %d\n", ret); + return ERR_PTR(ret); + } + + for (i = 0; i < exec_job->push.count; i++) { + nv50_dma_push(job->chan, exec_job->push.s[i].va, + exec_job->push.s[i].va_len); + } + + ret = nouveau_fence_new(job->chan, false, &fence); + if (ret) { + NV_PRINTK(err, job->cli, "error fencing pushbuf: %d\n", ret); + WIND_RING(job->chan); + return ERR_PTR(ret); + } + + return &fence->base; +} +static void +nouveau_exec_job_free(struct nouveau_job *job) +{ + struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + + nouveau_base_job_free(job); + + kfree(exec_job->push.s); + kfree(exec_job); +} + +static struct nouveau_job_ops nouveau_exec_job_ops = { + .submit = nouveau_exec_job_submit, + .run = nouveau_exec_job_run, + .free = nouveau_exec_job_free, +}; + +int +nouveau_exec_job_init(struct nouveau_exec_job **pjob, + struct nouveau_exec *exec) +{ + struct nouveau_exec_job *job; + int ret; + + job = *pjob = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + job->push.count = exec->push.count; + job->push.s = kmemdup(exec->push.s, + sizeof(*exec->push.s) * + exec->push.count, + GFP_KERNEL); + if (!job->push.s) { + ret = -ENOMEM; + goto err_free_job; + } + + job->base.ops = &nouveau_exec_job_ops; + ret = nouveau_base_job_init(&job->base, &exec->base); + if (ret) + goto err_free_pushs; + + return 0; + +err_free_pushs: + kfree(job->push.s); +err_free_job: + kfree(job); + *pjob = NULL; + + return ret; +} + +void nouveau_job_fini(struct nouveau_job *job) +{ + dma_fence_put(job->done_fence); + drm_sched_job_cleanup(&job->base); + job->ops->free(job); +} + +static int +nouveau_job_add_deps(struct nouveau_job *job) +{ + struct dma_fence *in_fence = NULL; + int ret, i; + + for (i = 0; i < job->in_sync.count; i++) { + struct drm_nouveau_sync *sync = &job->in_sync.s[i]; + + ret = sync_find_fence(job, sync, &in_fence); + if (ret) { + NV_PRINTK(warn, job->cli, + "Failed to find syncobj (-> in): handle=%d\n", + sync->handle); + return ret; + } + + ret = drm_sched_job_add_dependency(&job->base, in_fence); + if (ret) + return ret; + } + + return 0; +} + +static int +nouveau_job_fence_attach(struct nouveau_job *job, struct dma_fence *fence) +{ + struct drm_syncobj *out_sync; + int i; + + for (i = 0; i < job->out_sync.count; i++) { + struct drm_nouveau_sync *sync = &job->out_sync.s[i]; + u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; + + if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && + stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) + return -EOPNOTSUPP; + + out_sync = drm_syncobj_find(job->file_priv, sync->handle); + if (!out_sync) { + NV_PRINTK(warn, job->cli, + "Failed to find syncobj (-> out): handle=%d\n", + sync->handle); + return -ENOENT; + } + + if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { + struct dma_fence_chain *chain; + + chain = dma_fence_chain_alloc(); + if (!chain) { + drm_syncobj_put(out_sync); + return -ENOMEM; + } + + drm_syncobj_add_point(out_sync, chain, fence, + sync->timeline_value); + } else { + drm_syncobj_replace_fence(out_sync, fence); + } + + drm_syncobj_put(out_sync); + } + + return 0; +} + +static struct dma_fence * +nouveau_job_run(struct nouveau_job *job) +{ + return job->ops->run(job); +} + +static int +nouveau_job_run_sync(struct nouveau_job *job) +{ + struct dma_fence *fence; + int ret; + + fence = nouveau_job_run(job); + if (IS_ERR(fence)) { + return PTR_ERR(fence); + } else if (fence) { + ret = dma_fence_wait(fence, true); + if (ret) + return ret; + } + + dma_fence_signal(job->done_fence); + + return 0; +} + +int +nouveau_job_submit(struct nouveau_job *job) +{ + struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); + int ret; + + drm_exec_init(&job->exec, true); + + ret = nouveau_job_add_deps(job); + if (ret) + goto out; + + drm_sched_job_arm(&job->base); + job->done_fence = dma_fence_get(&job->base.s_fence->finished); + + ret = nouveau_job_fence_attach(job, job->done_fence); + if (ret) + goto out; + + if (job->ops->submit) { + ret = job->ops->submit(job); + if (ret) + goto out; + } + + if (job->sync) { + drm_exec_fini(&job->exec); + + /* We're requested to run a synchronous job, hence don't push + * the job, bypassing the job scheduler, and execute the jobs + * run() function right away. + * + * As a consequence of bypassing the job scheduler we need to + * handle fencing and job cleanup ourselfes. + */ + ret = nouveau_job_run_sync(job); + + /* If the job fails, the caller will do the cleanup for us. */ + if (!ret) + nouveau_job_fini(job); + + return ret; + } else { + mutex_lock(&entity->job.mutex); + drm_sched_entity_push_job(&job->base); + list_add_tail(&job->head, &entity->job.list); + mutex_unlock(&entity->job.mutex); + } + +out: + drm_exec_fini(&job->exec); + return ret; +} + +static struct dma_fence * +nouveau_sched_run_job(struct drm_sched_job *sched_job) +{ + struct nouveau_job *job = to_nouveau_job(sched_job); + + return nouveau_job_run(job); +} + +static enum drm_gpu_sched_stat +nouveau_sched_timedout_job(struct drm_sched_job *sched_job) +{ + struct nouveau_job *job = to_nouveau_job(sched_job); + struct nouveau_channel *chan = job->chan; + + if (unlikely(!atomic_read(&chan->killed))) + nouveau_channel_kill(chan); + + NV_PRINTK(warn, job->cli, "job timeout, channel %d killed!\n", + chan->chid); + + nouveau_sched_entity_fini(job->entity); + + return DRM_GPU_SCHED_STAT_ENODEV; +} + +static void +nouveau_sched_free_job(struct drm_sched_job *sched_job) +{ + struct nouveau_job *job = to_nouveau_job(sched_job); + struct nouveau_sched_entity *entity = job->entity; + + mutex_lock(&entity->job.mutex); + list_del(&job->head); + mutex_unlock(&entity->job.mutex); + + nouveau_job_fini(job); +} + +int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, + struct drm_gpu_scheduler *sched) +{ + + INIT_LIST_HEAD(&entity->job.list); + mutex_init(&entity->job.mutex); + + return drm_sched_entity_init(&entity->base, + DRM_SCHED_PRIORITY_NORMAL, + &sched, 1, NULL); +} + +void +nouveau_sched_entity_fini(struct nouveau_sched_entity *entity) +{ + drm_sched_entity_destroy(&entity->base); +} + +static const struct drm_sched_backend_ops nouveau_sched_ops = { + .run_job = nouveau_sched_run_job, + .timedout_job = nouveau_sched_timedout_job, + .free_job = nouveau_sched_free_job, +}; + +int nouveau_sched_init(struct drm_gpu_scheduler *sched, + struct nouveau_drm *drm) +{ + long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); + + return drm_sched_init(sched, &nouveau_sched_ops, + NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, + NULL, NULL, "nouveau", drm->dev->dev); +} + +void nouveau_sched_fini(struct drm_gpu_scheduler *sched) +{ + drm_sched_fini(sched); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h new file mode 100644 index 000000000000..7fc5b7eea810 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT + +#ifndef NOUVEAU_SCHED_H +#define NOUVEAU_SCHED_H + +#include + +#include +#include + +#include "nouveau_drv.h" +#include "nouveau_exec.h" + +#define to_nouveau_job(sched_job) \ + container_of((sched_job), struct nouveau_job, base) + +#define to_nouveau_exec_job(job) \ + container_of((job), struct nouveau_exec_job, base) + +#define to_nouveau_bind_job(job) \ + container_of((job), struct nouveau_bind_job, base) + +struct nouveau_job { + struct drm_sched_job base; + struct list_head head; + + struct nouveau_sched_entity *entity; + + struct drm_file *file_priv; + struct nouveau_cli *cli; + struct nouveau_channel *chan; + + struct drm_exec exec; + struct dma_fence *done_fence; + + bool sync; + + struct { + struct drm_nouveau_sync *s; + u32 count; + } in_sync; + + struct { + struct drm_nouveau_sync *s; + u32 count; + } out_sync; + + struct nouveau_job_ops { + int (*submit)(struct nouveau_job *); + struct dma_fence *(*run)(struct nouveau_job *); + void (*free)(struct nouveau_job *); + } *ops; +}; + +struct nouveau_exec_job { + struct nouveau_job base; + + struct { + struct drm_nouveau_exec_push *s; + u32 count; + } push; +}; + +struct nouveau_bind_job { + struct nouveau_job base; + + /* struct bind_job_op */ + struct list_head ops; +}; + +int nouveau_bind_job_init(struct nouveau_bind_job **job, + struct nouveau_exec_bind *bind); +int nouveau_exec_job_init(struct nouveau_exec_job **job, + struct nouveau_exec *exec); + +int nouveau_job_submit(struct nouveau_job *job); +void nouveau_job_fini(struct nouveau_job *job); + +#define to_nouveau_sched_entity(entity) \ + container_of((entity), struct nouveau_sched_entity, base) + +struct nouveau_sched_entity { + struct drm_sched_entity base; + struct { + struct list_head list; + struct mutex mutex; + } job; +}; + +int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, + struct drm_gpu_scheduler *sched); +void nouveau_sched_entity_fini(struct nouveau_sched_entity *entity); + +int nouveau_sched_init(struct drm_gpu_scheduler *sched, + struct nouveau_drm *drm); +void nouveau_sched_fini(struct drm_gpu_scheduler *sched); + +#endif From patchwork Wed Jan 18 06:12:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 45030 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2177270wrn; Tue, 17 Jan 2023 22:41:54 -0800 (PST) X-Google-Smtp-Source: AMrXdXtOoFOhKkg+WcZiq+ahrp9GFlBXcaE5HO+8ZvPgPmn9tHNViySfKdTKuIMVHFkM4uUf65QU X-Received: by 2002:a05:6a20:428b:b0:a5:798c:f929 with SMTP id o11-20020a056a20428b00b000a5798cf929mr8218215pzj.10.1674024114381; Tue, 17 Jan 2023 22:41:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674024114; cv=none; d=google.com; s=arc-20160816; b=W/zPYGE4O6byOa0xz8bW32pno2GNPZyEee9LZAsjSlefnQeXsjghOSgeBgb0RJ20BG N1t1/QQ9y/+8WJCRgFyo5t2RbwHCJwUWtuch0vA7LHqZTppFYyPoOwcNSEq6pBUapMPR AeTeCSX/mckAux6soFKVBKWwCBgWNqO8qwOrXaJm2uUnidAt0oegReEi1agGv7FWnNx9 dPvQZQNzVbBRe6DCZuIyg8tnAeuUCmyDr1nKIGydfyXSoy3to3sJdRz8O0/ZSWxGySzI Qy85VFT784vNzmgSdPWVjz9DawM6dS/wTT2pIJ5B1kBZ95A0TopAFslKEgYB5/v5vPvj n49Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=VHl/4diKtyJnEE11WWdgE7GtYAgDLsei1RwmYtZIKRg=; b=dCUUxViU/Rz0m4chiyq/NChva0ICcomwsRYYbBFF3FkuNfdy26zxXBgBOhH5bwcyew u/wQt0gWg2+GSFYEbYp5nT5+6RDVeQr7gCbPH09xEU6ORDqk1oV7JQZQQZTDmHM5qEVH DxScAIyKj2ds4EuVJSZBsFO6Ovig0f+VSxMMtVhD2R+WaqU2uGhiAsIzyYj4THe203zM UU7+B2RLjAtApVXwPXRk8Z2pwn4pu8VJYw2yFKebz1o8Jojy+gIynb6t8+h3+7KfGvDK t0yP748eUeBTHUwFitZKFgWfVcL7CTlG4Bl2MKIYwY6J1ZDI8OXVpKvvkl2R7P8IsKuZ d7GA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=WQ0V9+KW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id m12-20020a63580c000000b0046ff26f21f0si34189789pgb.503.2023.01.17.22.41.42; Tue, 17 Jan 2023 22:41:54 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=WQ0V9+KW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230094AbjARGke (ORCPT + 99 others); Wed, 18 Jan 2023 01:40:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229599AbjARG0e (ORCPT ); Wed, 18 Jan 2023 01:26:34 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 737D7552A2 for ; Tue, 17 Jan 2023 22:14:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674022465; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VHl/4diKtyJnEE11WWdgE7GtYAgDLsei1RwmYtZIKRg=; b=WQ0V9+KW6VMn0ifr33bQKJq0glGdLjCYvkPabaE/d7GNcdXQ5nT1+NKBwDABRTO7v1Ev7J bmVNrtwFkj9BkXTcy77wUZk7N80I66VbWGLi5OOznpVCV9PDIAPg0fFezzVIIHwjYxuryf wksqYH568um1VSSvhkXW/UEmZSrKpdU= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-496-mT75pktpPX-JWLRokZSLBA-1; Wed, 18 Jan 2023 01:14:24 -0500 X-MC-Unique: mT75pktpPX-JWLRokZSLBA-1 Received: by mail-ej1-f71.google.com with SMTP id dr5-20020a170907720500b00808d17c4f27so22931229ejc.6 for ; Tue, 17 Jan 2023 22:14:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VHl/4diKtyJnEE11WWdgE7GtYAgDLsei1RwmYtZIKRg=; b=vo9GHiHIB/qyOvfzQXqvG+nHtOnjQKbQITdcGBrc/JRaPkf7gwlBHQSZXyG4/cwoKu BwiezMwv0tdfo9JnJnfWTVJwHj0j/FWwrJuYOQMM5I5ercCV8UkyXtCqDXWlbQc9u4V2 FT0fYtwRhtCiH6yTpm6hSIGRyPEuew+3p41C7PcE4NJoLjijamRHdqi+KLoO9yL6AELD L86GfY4z6vSqBOmu/A7mUyzyPWpV4XE6Eu9LQcZGlGEBPjK9otbP+W/+qvIK9brr+1P/ uMYE5+KUojoPk7tf1usJ3GjWggg48I7Q3s5h1OcGZarSx3e940RMergYuZXxDPP6ZuLU royQ== X-Gm-Message-State: AFqh2kq3B6by6RvjMCfXplZsPGioQFLZ6jOVxF1ghZfoi9EpuEKWs2rA pJrjia/COwJf+kHtxySmb1gKAVb4rzRQv+THsKjSlZ5CJeSxp133uIAQS6K4nSIp7bpPXAFfnf+ IlWb/iyG3xX//mzBVDdzOB/M2 X-Received: by 2002:aa7:c1ce:0:b0:49e:89e:3b36 with SMTP id d14-20020aa7c1ce000000b0049e089e3b36mr5877842edp.30.1674022462952; Tue, 17 Jan 2023 22:14:22 -0800 (PST) X-Received: by 2002:aa7:c1ce:0:b0:49e:89e:3b36 with SMTP id d14-20020aa7c1ce000000b0049e089e3b36mr5877825edp.30.1674022462771; Tue, 17 Jan 2023 22:14:22 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:de78:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id u2-20020a1709061da200b0083f91a32131sm14105071ejh.0.2023.01.17.22.14.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jan 2023 22:14:22 -0800 (PST) From: Danilo Krummrich To: daniel@ffwll.ch, airlied@redhat.com, christian.koenig@amd.com, bskeggs@redhat.com, jason@jlekstrand.net, tzimmermann@suse.de, mripard@kernel.org, corbet@lwn.net Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH drm-next 14/14] drm/nouveau: debugfs: implement DRM GPU VA debugfs Date: Wed, 18 Jan 2023 07:12:56 +0100 Message-Id: <20230118061256.2689-15-dakr@redhat.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230118061256.2689-1-dakr@redhat.com> References: <20230118061256.2689-1-dakr@redhat.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755341509923665184?= X-GMAIL-MSGID: =?utf-8?q?1755341509923665184?= Provide the driver indirection iterating over all DRM GPU VA spaces to enable the common 'gpuvas' debugfs file for dumping DRM GPU VA spaces. Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_debugfs.c | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 2a36d1ca8fda..7f6ccc5d1d86 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -202,6 +202,29 @@ nouveau_debugfs_pstate_open(struct inode *inode, struct file *file) return single_open(file, nouveau_debugfs_pstate_get, inode->i_private); } +static int +nouveau_debugfs_gpuva(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct nouveau_drm *drm = nouveau_drm(node->minor->dev); + struct nouveau_cli *cli; + + mutex_lock(&drm->clients_lock); + list_for_each_entry(cli, &drm->clients, head) { + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); + + if (!uvmm) + continue; + + nouveau_uvmm_lock(uvmm); + drm_debugfs_gpuva_info(m, &uvmm->umgr); + nouveau_uvmm_unlock(uvmm); + } + mutex_unlock(&drm->clients_lock); + + return 0; +} + static const struct file_operations nouveau_pstate_fops = { .owner = THIS_MODULE, .open = nouveau_debugfs_pstate_open, @@ -213,6 +236,7 @@ static const struct file_operations nouveau_pstate_fops = { static struct drm_info_list nouveau_debugfs_list[] = { { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL }, { "strap_peek", nouveau_debugfs_strap_peek, 0, NULL }, + DRM_DEBUGFS_GPUVA_INFO(nouveau_debugfs_gpuva, NULL), }; #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)