From 7b812171257d4b8d9ef69321134c72b647e1ce9c Mon Sep 17 00:00:00 2001 From: Desmond Cheong Zhi Xi Date: Fri, 13 Aug 2021 16:54:50 +0800 Subject: drm: unexport drm_ioctl_permit Since the last user of drm_ioctl_permit was removed, and it's now only used in drm_ioctl.c, unexport the symbol. Reported-by: Daniel Vetter Signed-off-by: Desmond Cheong Zhi Xi Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210813085450.32494-3-desmondcheongzx@gmail.com --- include/drm/drm_ioctl.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h index afb27cb6a7bd..6ed61c371f6c 100644 --- a/include/drm/drm_ioctl.h +++ b/include/drm/drm_ioctl.h @@ -167,7 +167,6 @@ struct drm_ioctl_desc { .name = #ioctl \ } -int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long drm_ioctl_kernel(struct file *, drm_ioctl_t, void *, u32); #ifdef CONFIG_COMPAT -- cgit v1.2.3 From 32a4eb04d59ae8d5bb5baa5a8528e31094ae8e84 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 10 Jun 2021 13:12:34 +0200 Subject: drm/fourcc: Add macros to determine the modifier vendor When working with framebuffer modifiers, it can be useful to extract the vendor identifier or check a modifier against a given vendor identifier. Add one macro that extracts the vendor identifier and a helper to check a modifier against a given vendor identifier. Reviewed-by: Daniel Vetter Acked-by: Daniel Stone Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20210610111236.3814211-1-thierry.reding@gmail.com --- include/uapi/drm/drm_fourcc.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 9f4bb4a6f358..45a914850be0 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -373,6 +373,12 @@ extern "C" { #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) +#define fourcc_mod_get_vendor(modifier) \ + (((modifier) >> 56) & 0xff) + +#define fourcc_mod_is_vendor(modifier, vendor) \ + (fourcc_mod_get_vendor(modifier) == DRM_FORMAT_MOD_VENDOR_## vendor) + #define fourcc_mod_code(vendor, val) \ ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL)) -- cgit v1.2.3 From 992c238188a83befa0094a8c00bfead31aa302ed Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Jul 2021 19:51:50 +0200 Subject: dma-buf: nuke seqno-fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entirely unused. Signed-off-by: Christian König Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210729070330.41443-1-christian.koenig@amd.com --- drivers/dma-buf/Makefile | 2 +- drivers/dma-buf/seqno-fence.c | 71 --------------------------- include/linux/seqno-fence.h | 109 ------------------------------------------ 3 files changed, 1 insertion(+), 181 deletions(-) delete mode 100644 drivers/dma-buf/seqno-fence.c delete mode 100644 include/linux/seqno-fence.h (limited to 'include') diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 40d81f23cacf..1ef021273a06 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ - dma-resv.o seqno-fence.o + dma-resv.o obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o obj-$(CONFIG_DMABUF_HEAPS) += heaps/ obj-$(CONFIG_SYNC_FILE) += sync_file.o diff --git a/drivers/dma-buf/seqno-fence.c b/drivers/dma-buf/seqno-fence.c deleted file mode 100644 index bfe14e94c488..000000000000 --- a/drivers/dma-buf/seqno-fence.c +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * seqno-fence, using a dma-buf to synchronize fencing - * - * Copyright (C) 2012 Texas Instruments - * Copyright (C) 2012-2014 Canonical Ltd - * Authors: - * Rob Clark - * Maarten Lankhorst - */ - -#include -#include -#include - -static const char *seqno_fence_get_driver_name(struct dma_fence *fence) -{ - struct seqno_fence *seqno_fence = to_seqno_fence(fence); - - return seqno_fence->ops->get_driver_name(fence); -} - -static const char *seqno_fence_get_timeline_name(struct dma_fence *fence) -{ - struct seqno_fence *seqno_fence = to_seqno_fence(fence); - - return seqno_fence->ops->get_timeline_name(fence); -} - -static bool seqno_enable_signaling(struct dma_fence *fence) -{ - struct seqno_fence *seqno_fence = to_seqno_fence(fence); - - return seqno_fence->ops->enable_signaling(fence); -} - -static bool seqno_signaled(struct dma_fence *fence) -{ - struct seqno_fence *seqno_fence = to_seqno_fence(fence); - - return seqno_fence->ops->signaled && seqno_fence->ops->signaled(fence); -} - -static void seqno_release(struct dma_fence *fence) -{ - struct seqno_fence *f = to_seqno_fence(fence); - - dma_buf_put(f->sync_buf); - if (f->ops->release) - f->ops->release(fence); - else - dma_fence_free(&f->base); -} - -static signed long seqno_wait(struct dma_fence *fence, bool intr, - signed long timeout) -{ - struct seqno_fence *f = to_seqno_fence(fence); - - return f->ops->wait(fence, intr, timeout); -} - -const struct dma_fence_ops seqno_fence_ops = { - .get_driver_name = seqno_fence_get_driver_name, - .get_timeline_name = seqno_fence_get_timeline_name, - .enable_signaling = seqno_enable_signaling, - .signaled = seqno_signaled, - .wait = seqno_wait, - .release = seqno_release, -}; -EXPORT_SYMBOL(seqno_fence_ops); diff --git a/include/linux/seqno-fence.h b/include/linux/seqno-fence.h deleted file mode 100644 index 3cca2b8fac43..000000000000 --- a/include/linux/seqno-fence.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * seqno-fence, using a dma-buf to synchronize fencing - * - * Copyright (C) 2012 Texas Instruments - * Copyright (C) 2012 Canonical Ltd - * Authors: - * Rob Clark - * Maarten Lankhorst - */ - -#ifndef __LINUX_SEQNO_FENCE_H -#define __LINUX_SEQNO_FENCE_H - -#include -#include - -enum seqno_fence_condition { - SEQNO_FENCE_WAIT_GEQUAL, - SEQNO_FENCE_WAIT_NONZERO -}; - -struct seqno_fence { - struct dma_fence base; - - const struct dma_fence_ops *ops; - struct dma_buf *sync_buf; - uint32_t seqno_ofs; - enum seqno_fence_condition condition; -}; - -extern const struct dma_fence_ops seqno_fence_ops; - -/** - * to_seqno_fence - cast a fence to a seqno_fence - * @fence: fence to cast to a seqno_fence - * - * Returns NULL if the fence is not a seqno_fence, - * or the seqno_fence otherwise. - */ -static inline struct seqno_fence * -to_seqno_fence(struct dma_fence *fence) -{ - if (fence->ops != &seqno_fence_ops) - return NULL; - return container_of(fence, struct seqno_fence, base); -} - -/** - * seqno_fence_init - initialize a seqno fence - * @fence: seqno_fence to initialize - * @lock: pointer to spinlock to use for fence - * @sync_buf: buffer containing the memory location to signal on - * @context: the execution context this fence is a part of - * @seqno_ofs: the offset within @sync_buf - * @seqno: the sequence # to signal on - * @cond: fence wait condition - * @ops: the fence_ops for operations on this seqno fence - * - * This function initializes a struct seqno_fence with passed parameters, - * and takes a reference on sync_buf which is released on fence destruction. - * - * A seqno_fence is a dma_fence which can complete in software when - * enable_signaling is called, but it also completes when - * (s32)((sync_buf)[seqno_ofs] - seqno) >= 0 is true - * - * The seqno_fence will take a refcount on the sync_buf until it's - * destroyed, but actual lifetime of sync_buf may be longer if one of the - * callers take a reference to it. - * - * Certain hardware have instructions to insert this type of wait condition - * in the command stream, so no intervention from software would be needed. - * This type of fence can be destroyed before completed, however a reference - * on the sync_buf dma-buf can be taken. It is encouraged to re-use the same - * dma-buf for sync_buf, since mapping or unmapping the sync_buf to the - * device's vm can be expensive. - * - * It is recommended for creators of seqno_fence to call dma_fence_signal() - * before destruction. This will prevent possible issues from wraparound at - * time of issue vs time of check, since users can check dma_fence_is_signaled() - * before submitting instructions for the hardware to wait on the fence. - * However, when ops.enable_signaling is not called, it doesn't have to be - * done as soon as possible, just before there's any real danger of seqno - * wraparound. - */ -static inline void -seqno_fence_init(struct seqno_fence *fence, spinlock_t *lock, - struct dma_buf *sync_buf, uint32_t context, - uint32_t seqno_ofs, uint32_t seqno, - enum seqno_fence_condition cond, - const struct dma_fence_ops *ops) -{ - BUG_ON(!fence || !sync_buf || !ops); - BUG_ON(!ops->wait || !ops->enable_signaling || - !ops->get_driver_name || !ops->get_timeline_name); - - /* - * ops is used in dma_fence_init for get_driver_name, so needs to be - * initialized first - */ - fence->ops = ops; - dma_fence_init(&fence->base, &seqno_fence_ops, lock, context, seqno); - get_dma_buf(sync_buf); - fence->sync_buf = sync_buf; - fence->seqno_ofs = seqno_ofs; - fence->condition = cond; -} - -#endif /* __LINUX_SEQNO_FENCE_H */ -- cgit v1.2.3 From 48c429c6d18db115c277b75000152d8fa4cd35d0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 17 Aug 2021 23:51:55 +0200 Subject: drm/connector: Add a fwnode pointer to drm_connector and register with ACPI (v2) Add a fwnode pointer to struct drm_connector and register an acpi_bus_type for the connectors with the ACPI subsystem (when CONFIG_ACPI is enabled). The adding of the fwnode pointer allows drivers to associate a fwnode that represents a connector with that connector. When the new fwnode pointer points to an ACPI-companion, then the new acpi_bus_type will cause the ACPI subsys to bind the device instantiated for the connector with the fwnode by calling acpi_bind_one(). This will result in a firmware_node symlink under /sys/class/card#-/ which helps to verify that the fwnode-s and connectors are properly matched. Changes in v2: - Make drm_connector_cleanup() call fwnode_handle_put() on connector->fwnode and document this Co-developed-by: Heikki Krogerus Signed-off-by: Heikki Krogerus Tested-by: Heikki Krogerus Signed-off-by: Hans de Goede Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20210817215201.795062-3-hdegoede@redhat.com --- drivers/gpu/drm/drm_connector.c | 2 ++ drivers/gpu/drm/drm_sysfs.c | 37 +++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 8 ++++++++ 3 files changed, 47 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 2ba257b1ae20..3ad359a216ff 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -474,6 +474,8 @@ void drm_connector_cleanup(struct drm_connector *connector) drm_mode_object_unregister(dev, &connector->base); kfree(connector->name); connector->name = NULL; + fwnode_handle_put(connector->fwnode); + connector->fwnode = NULL; spin_lock_irq(&dev->mode_config.connector_list_lock); list_del(&connector->head); dev->mode_config.num_connector--; diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index fb97279211d4..76ff6ec3421b 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -10,6 +10,7 @@ * Copyright (c) 2003-2004 IBM Corp. */ +#include #include #include #include @@ -56,6 +57,39 @@ static struct device_type drm_sysfs_device_connector = { struct class *drm_class; +#ifdef CONFIG_ACPI +static bool drm_connector_acpi_bus_match(struct device *dev) +{ + return dev->type == &drm_sysfs_device_connector; +} + +static struct acpi_device *drm_connector_acpi_find_companion(struct device *dev) +{ + struct drm_connector *connector = to_drm_connector(dev); + + return to_acpi_device_node(connector->fwnode); +} + +static struct acpi_bus_type drm_connector_acpi_bus = { + .name = "drm_connector", + .match = drm_connector_acpi_bus_match, + .find_companion = drm_connector_acpi_find_companion, +}; + +static void drm_sysfs_acpi_register(void) +{ + register_acpi_bus_type(&drm_connector_acpi_bus); +} + +static void drm_sysfs_acpi_unregister(void) +{ + unregister_acpi_bus_type(&drm_connector_acpi_bus); +} +#else +static void drm_sysfs_acpi_register(void) { } +static void drm_sysfs_acpi_unregister(void) { } +#endif + static char *drm_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); @@ -89,6 +123,8 @@ int drm_sysfs_init(void) } drm_class->devnode = drm_devnode; + + drm_sysfs_acpi_register(); return 0; } @@ -101,6 +137,7 @@ void drm_sysfs_destroy(void) { if (IS_ERR_OR_NULL(drm_class)) return; + drm_sysfs_acpi_unregister(); class_remove_file(drm_class, &class_attr_version.attr); class_destroy(drm_class); drm_class = NULL; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 1647960c9e50..69dd488a2154 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1228,6 +1228,14 @@ struct drm_connector { struct device *kdev; /** @attr: sysfs attributes */ struct device_attribute *attr; + /** + * @fwnode: associated fwnode supplied by platform firmware + * + * Drivers can set this to associate a fwnode with a connector, drivers + * are expected to get a reference on the fwnode when setting this. + * drm_connector_cleanup() will call fwnode_handle_put() on this. + */ + struct fwnode_handle *fwnode; /** * @head: -- cgit v1.2.3 From 3d3f7c1e68691574c1d87cd0f9f2348323bc0199 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 17 Aug 2021 23:51:56 +0200 Subject: drm/connector: Add drm_connector_find_by_fwnode() function (v3) Add a function to find a connector based on a fwnode. This will be used by the new drm_connector_oob_hotplug_event() function which is added by the next patch in this patch-set. Changes in v2: - Complete rewrite to use a global connector list in drm_connector.c rather then using a class-dev-iter in drm_sysfs.c Changes in v3: - Add forward declaration for struct fwnode_handle to drm_crtc_internal.h (fixes warning reported by kernel test robot ) Tested-by: Heikki Krogerus Signed-off-by: Hans de Goede Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20210817215201.795062-4-hdegoede@redhat.com --- drivers/gpu/drm/drm_connector.c | 50 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_internal.h | 2 ++ include/drm/drm_connector.h | 8 ++++++ 3 files changed, 60 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 3ad359a216ff..7d72bcefa4d6 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -65,6 +65,14 @@ * support can instead use e.g. drm_helper_hpd_irq_event(). */ +/* + * Global connector list for drm_connector_find_by_fwnode(). + * Note drm_connector_[un]register() first take connector->lock and then + * take the connector_list_lock. + */ +static DEFINE_MUTEX(connector_list_lock); +static LIST_HEAD(connector_list); + struct drm_conn_prop_enum_list { int type; const char *name; @@ -267,6 +275,7 @@ int drm_connector_init(struct drm_device *dev, goto out_put_type_id; } + INIT_LIST_HEAD(&connector->global_connector_list_entry); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); mutex_init(&connector->mutex); @@ -534,6 +543,9 @@ int drm_connector_register(struct drm_connector *connector) /* Let userspace know we have a new connector */ drm_sysfs_hotplug_event(connector->dev); + mutex_lock(&connector_list_lock); + list_add_tail(&connector->global_connector_list_entry, &connector_list); + mutex_unlock(&connector_list_lock); goto unlock; err_debugfs: @@ -562,6 +574,10 @@ void drm_connector_unregister(struct drm_connector *connector) return; } + mutex_lock(&connector_list_lock); + list_del_init(&connector->global_connector_list_entry); + mutex_unlock(&connector_list_lock); + if (connector->funcs->early_unregister) connector->funcs->early_unregister(connector); @@ -2545,6 +2561,40 @@ out: return ret; } +/** + * drm_connector_find_by_fwnode - Find a connector based on the associated fwnode + * @fwnode: fwnode for which to find the matching drm_connector + * + * This functions looks up a drm_connector based on its associated fwnode. When + * a connector is found a reference to the connector is returned. The caller must + * call drm_connector_put() to release this reference when it is done with the + * connector. + * + * Returns: A reference to the found connector or an ERR_PTR(). + */ +struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) +{ + struct drm_connector *connector, *found = ERR_PTR(-ENODEV); + + if (!fwnode) + return ERR_PTR(-ENODEV); + + mutex_lock(&connector_list_lock); + + list_for_each_entry(connector, &connector_list, global_connector_list_entry) { + if (connector->fwnode == fwnode || + (connector->fwnode && connector->fwnode->secondary == fwnode)) { + drm_connector_get(connector); + found = connector; + break; + } + } + + mutex_unlock(&connector_list_lock); + + return found; +} + /** * DOC: Tile group diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index edb772947cb4..63279e984342 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -58,6 +58,7 @@ struct drm_property; struct edid; struct kref; struct work_struct; +struct fwnode_handle; /* drm_crtc.c */ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, @@ -186,6 +187,7 @@ int drm_connector_set_obj_prop(struct drm_mode_object *obj, int drm_connector_create_standard_properties(struct drm_device *dev); const char *drm_get_connector_force_name(enum drm_connector_force force); void drm_connector_free_work_fn(struct work_struct *work); +struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode); /* IOCTL */ int drm_connector_property_set_ioctl(struct drm_device *dev, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 69dd488a2154..8132c48b56ae 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1247,6 +1247,14 @@ struct drm_connector { */ struct list_head head; + /** + * @global_connector_list_entry: + * + * Connector entry in the global connector-list, used by + * drm_connector_find_by_fwnode(). + */ + struct list_head global_connector_list_entry; + /** @base: base KMS object */ struct drm_mode_object base; -- cgit v1.2.3 From 72ad49682dde3d9de5708b8699dc8e0b44962322 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 17 Aug 2021 23:51:57 +0200 Subject: drm/connector: Add support for out-of-band hotplug notification (v3) Add a new drm_connector_oob_hotplug_event() function and oob_hotplug_event drm_connector_funcs member. On some hardware a hotplug event notification may come from outside the display driver / device. An example of this is some USB Type-C setups where the hardware muxes the DisplayPort data and aux-lines but does not pass the altmode HPD status bit to the GPU's DP HPD pin. In cases like this the new drm_connector_oob_hotplug_event() function can be used to report these out-of-band events. Changes in v2: - Make drm_connector_oob_hotplug_event() take a fwnode as argument and have it call drm_connector_find_by_fwnode() internally. This allows making drm_connector_find_by_fwnode() a drm-internal function and avoids code outside the drm subsystem potentially holding on the a drm_connector reference for a longer period. Changes in v3: - Drop the data argument to the drm_connector_oob_hotplug_event function since it is not used atm. This can be re-added later when a use for it actually arises. Tested-by: Heikki Krogerus Signed-off-by: Hans de Goede Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20210817215201.795062-5-hdegoede@redhat.com --- drivers/gpu/drm/drm_connector.c | 27 +++++++++++++++++++++++++++ include/drm/drm_connector.h | 9 +++++++++ 2 files changed, 36 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 7d72bcefa4d6..e0a30e0ee86a 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2595,6 +2595,33 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) return found; } +/** + * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector + * @connector: connector to report the event on + * + * On some hardware a hotplug event notification may come from outside the display + * driver / device. An example of this is some USB Type-C setups where the hardware + * muxes the DisplayPort data and aux-lines but does not pass the altmode HPD + * status bit to the GPU's DP HPD pin. + * + * This function can be used to report these out-of-band events after obtaining + * a drm_connector reference through calling drm_connector_find_by_fwnode(). + */ +void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) +{ + struct drm_connector *connector; + + connector = drm_connector_find_by_fwnode(connector_fwnode); + if (IS_ERR(connector)) + return; + + if (connector->funcs->oob_hotplug_event) + connector->funcs->oob_hotplug_event(connector); + + drm_connector_put(connector); +} +EXPORT_SYMBOL(drm_connector_oob_hotplug_event); + /** * DOC: Tile group diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8132c48b56ae..79fa34e5ccdb 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1084,6 +1084,14 @@ struct drm_connector_funcs { */ void (*atomic_print_state)(struct drm_printer *p, const struct drm_connector_state *state); + + /** + * @oob_hotplug_event: + * + * This will get called when a hotplug-event for a drm-connector + * has been received from a source outside the display driver / device. + */ + void (*oob_hotplug_event)(struct drm_connector *connector); }; /** @@ -1666,6 +1674,7 @@ drm_connector_is_unregistered(struct drm_connector *connector) DRM_CONNECTOR_UNREGISTERED; } +void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode); const char *drm_get_connector_type_name(unsigned int connector_type); const char *drm_get_connector_status_name(enum drm_connector_status status); const char *drm_get_subpixel_order_name(enum subpixel_order order); -- cgit v1.2.3 From d5f45d1e2f08685c34483719b39f91010d6222e8 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Jul 2021 15:05:52 +0200 Subject: drm/ttm: remove ttm_tt_destroy_common v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the functionality into ttm_tt_fini and ttm_bo_tt_destroy instead. We don't need this any more since we removed the unbind from the destroy code paths in the drivers. Also add a warning to ttm_tt_fini() if we try to fini a still populated TT object. v2: instead of reverting the patch move the functionality to different places. Signed-off-by: Christian König Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20210728130552.2074-5-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 1 - drivers/gpu/drm/drm_gem_vram_helper.c | 1 - drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 1 - drivers/gpu/drm/nouveau/nouveau_bo.c | 1 - drivers/gpu/drm/nouveau/nouveau_sgdma.c | 1 - drivers/gpu/drm/qxl/qxl_ttm.c | 1 - drivers/gpu/drm/radeon/radeon_ttm.c | 2 -- drivers/gpu/drm/ttm/ttm_bo.c | 1 + drivers/gpu/drm/ttm/ttm_tt.c | 17 ++++++----------- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | 1 - include/drm/ttm/ttm_tt.h | 7 ------- 11 files changed, 7 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 75d45623388a..489e22190e29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1066,7 +1066,6 @@ static void amdgpu_ttm_backend_destroy(struct ttm_device *bdev, { struct amdgpu_ttm_tt *gtt = (void *)ttm; - ttm_tt_destroy_common(bdev, ttm); if (gtt->usertask) put_task_struct(gtt->usertask); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 43cf7e887d1a..bfa386b98134 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -846,7 +846,6 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs = { static void bo_driver_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *tt) { - ttm_tt_destroy_common(bdev, tt); ttm_tt_fini(tt); kfree(tt); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index bf33724bed5c..e646aac9d7a4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -118,7 +118,6 @@ static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) { struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm); - ttm_tt_destroy_common(bdev, ttm); kfree(i915_tt); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index c33a56c2f068..33dca2565cca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1292,7 +1292,6 @@ nouveau_ttm_tt_destroy(struct ttm_device *bdev, #if IS_ENABLED(CONFIG_AGP) struct nouveau_drm *drm = nouveau_bdev(bdev); if (drm->agp.bridge) { - ttm_tt_destroy_common(bdev, ttm); ttm_agp_destroy(ttm); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index bde92a9dae7a..85c03c83259b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -21,7 +21,6 @@ nouveau_sgdma_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; if (ttm) { - ttm_tt_destroy_common(bdev, ttm); ttm_tt_fini(&nvbe->ttm); kfree(nvbe); } diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 37a1b6a6ad6d..b2e33d5ba5d0 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -101,7 +101,6 @@ int qxl_ttm_io_mem_reserve(struct ttm_device *bdev, */ static void qxl_ttm_backend_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) { - ttm_tt_destroy_common(bdev, ttm); ttm_tt_fini(ttm); kfree(ttm); } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index ee343b76db54..7793249bc549 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -488,7 +488,6 @@ static void radeon_ttm_backend_destroy(struct ttm_device *bdev, struct ttm_tt *t { struct radeon_ttm_tt *gtt = (void *)ttm; - ttm_tt_destroy_common(bdev, ttm); ttm_tt_fini(>t->ttm); kfree(gtt); } @@ -651,7 +650,6 @@ static void radeon_ttm_tt_destroy(struct ttm_device *bdev, struct radeon_device *rdev = radeon_get_rdev(bdev); if (rdev->flags & RADEON_IS_AGP) { - ttm_tt_destroy_common(bdev, ttm); ttm_agp_destroy(ttm); return; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index ea4add2b9717..49f4bc97c35a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1224,6 +1224,7 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo) if (bo->ttm == NULL) return; + ttm_tt_unpopulate(bo->bdev, bo->ttm); ttm_tt_destroy(bo->bdev, bo->ttm); bo->ttm = NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 24031a8acd2d..506b3c926a68 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -123,17 +123,6 @@ static int ttm_sg_tt_alloc_page_directory(struct ttm_tt *ttm) return 0; } -void ttm_tt_destroy_common(struct ttm_device *bdev, struct ttm_tt *ttm) -{ - ttm_tt_unpopulate(bdev, ttm); - - if (ttm->swap_storage) - fput(ttm->swap_storage); - - ttm->swap_storage = NULL; -} -EXPORT_SYMBOL(ttm_tt_destroy_common); - void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) { bdev->funcs->ttm_tt_destroy(bdev, ttm); @@ -168,6 +157,12 @@ EXPORT_SYMBOL(ttm_tt_init); void ttm_tt_fini(struct ttm_tt *ttm) { + WARN_ON(ttm->page_flags & TTM_PAGE_FLAG_PRIV_POPULATED); + + if (ttm->swap_storage) + fput(ttm->swap_storage); + ttm->swap_storage = NULL; + if (ttm->pages) kvfree(ttm->pages); else diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 904031d03dbe..f35bdc1cb197 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -526,7 +526,6 @@ static void vmw_ttm_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, dma_ttm); - ttm_tt_destroy_common(bdev, ttm); vmw_ttm_unmap_dma(vmw_be); ttm_tt_fini(ttm); if (vmw_be->mob) diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 818680c6a8ed..e402dab1d0f6 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -134,13 +134,6 @@ void ttm_tt_fini(struct ttm_tt *ttm); */ void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm); -/** - * ttm_tt_destroy_common: - * - * Called from driver to destroy common path. - */ -void ttm_tt_destroy_common(struct ttm_device *bdev, struct ttm_tt *ttm); - /** * ttm_tt_swapin: * -- cgit v1.2.3 From 880121be1179a0db3eb4fdb198108d9475b8be4c Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 15 Apr 2021 13:56:23 +0200 Subject: mm/vmscan: add sync_shrinkers function v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While unplugging a device the TTM shrinker implementation needs a barrier to make sure that all concurrent shrink operations are done and no other CPU is referring to a device specific pool any more. Taking and releasing the shrinker semaphore on the write side after unmapping and freeing all pages from the device pool should make sure that no shrinker is running in paralell. This allows us to avoid the contented mutex in the TTM pool implementation for every alloc/free operation. v2: rework the commit message to make clear why we need this v3: rename the function and add more doc as suggested by Daniel Signed-off-by: Christian König Acked-by: Huang Rui Acked-by: Andrew Morton Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210820120528.81114-2-christian.koenig@amd.com --- include/linux/shrinker.h | 1 + mm/vmscan.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 9814fff58a69..76fbf92b04d9 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -93,4 +93,5 @@ extern void register_shrinker_prepared(struct shrinker *shrinker); extern int register_shrinker(struct shrinker *shrinker); extern void unregister_shrinker(struct shrinker *shrinker); extern void free_prealloced_shrinker(struct shrinker *shrinker); +extern void synchronize_shrinkers(void); #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 4620df62f0ff..5d22a63472f0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -638,6 +638,21 @@ void unregister_shrinker(struct shrinker *shrinker) } EXPORT_SYMBOL(unregister_shrinker); +/** + * synchronize_shrinkers - Wait for all running shrinkers to complete. + * + * This is equivalent to calling unregister_shrink() and register_shrinker(), + * but atomically and with less overhead. This is useful to guarantee that all + * shrinker invocations have seen an update, before freeing memory, similar to + * rcu. + */ +void synchronize_shrinkers(void) +{ + down_write(&shrinker_rwsem); + up_write(&shrinker_rwsem); +} +EXPORT_SYMBOL(synchronize_shrinkers); + #define SHRINK_BATCH 128 static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, -- cgit v1.2.3 From 4087d2fb286c85a1bde72e7523c496080ef39035 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Sun, 29 Aug 2021 12:04:01 -0400 Subject: drm/plane: Fix comment typo Minor typofix noticed when reading the KMS documentation. Signed-off-by: Alyssa Rosenzweig Signed-off-by: Simon Ser Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20210829160401.4588-1-alyssa@rosenzweig.io --- include/drm/drm_plane.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index fed97e35626f..0c1102dc4d88 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -43,7 +43,7 @@ enum drm_scaling_filter { /** * struct drm_plane_state - mutable plane state * - * Please not that the destination coordinates @crtc_x, @crtc_y, @crtc_h and + * Please note that the destination coordinates @crtc_x, @crtc_y, @crtc_h and * @crtc_w and the source coordinates @src_x, @src_y, @src_h and @src_w are the * raw coordinates provided by userspace. Drivers should use * drm_atomic_helper_check_plane_state() and only use the derived rectangles in -- cgit v1.2.3 From dbe48d030b285a1305a874bee523681709fba162 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 17 Aug 2021 10:49:16 +0200 Subject: drm/sched: Split drm_sched_job_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a very confusingly named function, because not just does it init an object, it arms it and provides a point of no return for pushing a job into the scheduler. It would be nice if that's a bit clearer in the interface. But the real reason is that I want to push the dependency tracking helpers into the scheduler code, and that means drm_sched_job_init must be called a lot earlier, without arming the job. v2: - don't change .gitignore (Steven) - don't forget v3d (Emma) v3: Emma noticed that I leak the memory allocated in drm_sched_job_init if we bail out before the point of no return in subsequent driver patches. To be able to fix this change drm_sched_job_cleanup() so it can handle being called both before and after drm_sched_job_arm(). Also improve the kerneldoc for this. v4: - Fix the drm_sched_job_cleanup logic, I inverted the booleans, as usual (Melissa) - Christian pointed out that drm_sched_entity_select_rq() also needs to be moved into drm_sched_job_arm, which made me realize that the job->id definitely needs to be moved too. Shuffle things to fit between job_init and job_arm. v5: Reshuffle the split between init/arm once more, amdgpu abuses drm_sched.ready to signal gpu reset failures. Also document this somewhat. (Christian) v6: Rebase on top of the msm drm/sched support. Note that the drm_sched_job_init() call is completely misplaced, and hence also the split-out drm_sched_entity_push_job(). I've put in a FIXME which the next patch will address. v7: Drop the FIXME in msm, after discussions with Rob I agree it shouldn't be a problem where it is now. Acked-by: Christian König Acked-by: Melissa Wen Cc: Melissa Wen Acked-by: Emma Anholt Acked-by: Steven Price (v2) Reviewed-by: Boris Brezillon (v5) Signed-off-by: Daniel Vetter Cc: Lucas Stach Cc: Russell King Cc: Christian Gmeiner Cc: Qiang Yu Cc: Rob Herring Cc: Tomeu Vizoso Cc: Steven Price Cc: Alyssa Rosenzweig Cc: David Airlie Cc: Daniel Vetter Cc: Sumit Semwal Cc: "Christian König" Cc: Masahiro Yamada Cc: Kees Cook Cc: Adam Borowski Cc: Nick Terrell Cc: Mauro Carvalho Chehab Cc: Paul Menzel Cc: Sami Tolvanen Cc: Viresh Kumar Cc: Alex Deucher Cc: Dave Airlie Cc: Nirmoy Das Cc: Deepak R Varma Cc: Lee Jones Cc: Kevin Wang Cc: Chen Li Cc: Luben Tuikov Cc: "Marek Olšák" Cc: Dennis Li Cc: Maarten Lankhorst Cc: Andrey Grodzovsky Cc: Sonny Jiang Cc: Boris Brezillon Cc: Tian Tao Cc: etnaviv@lists.freedesktop.org Cc: lima@lists.freedesktop.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Cc: Emma Anholt Cc: Rob Clark Cc: Sean Paul Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20210817084917.3555822-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 + drivers/gpu/drm/etnaviv/etnaviv_sched.c | 2 + drivers/gpu/drm/lima/lima_sched.c | 2 + drivers/gpu/drm/msm/msm_gem_submit.c | 2 + drivers/gpu/drm/panfrost/panfrost_job.c | 2 + drivers/gpu/drm/scheduler/sched_entity.c | 6 +-- drivers/gpu/drm/scheduler/sched_fence.c | 19 +++++---- drivers/gpu/drm/scheduler/sched_main.c | 69 +++++++++++++++++++++++++++----- drivers/gpu/drm/v3d/v3d_gem.c | 2 + include/drm/gpu_scheduler.h | 7 +++- 11 files changed, 93 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index a152363b0254..2b7f4b77a572 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1222,6 +1222,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, if (r) goto error_unlock; + drm_sched_job_arm(&job->base); + /* No memory allocation is allowed while holding the notifier lock. * The lock is held until amdgpu_cs_submit is finished and fence is * added to BOs. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index d33e6d97cc89..5ddb955d2315 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -170,6 +170,8 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, if (r) return r; + drm_sched_job_arm(&job->base); + *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); drm_sched_entity_push_job(&job->base, entity); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index feb6da1b6ceb..05f412204118 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -163,6 +163,8 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, if (ret) goto out_unlock; + drm_sched_job_arm(&submit->sched_job); + submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, submit->out_fence, 0, diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index dba8329937a3..38f755580507 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -129,6 +129,8 @@ int lima_sched_task_init(struct lima_sched_task *task, return err; } + drm_sched_job_arm(&task->base); + task->num_bos = num_bos; task->vm = lima_vm_get(vm); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index fdc5367aecaa..4d1c4d5f6a2a 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -52,6 +52,8 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, return ERR_PTR(ret); } + drm_sched_job_arm(&job->base); + xa_init_flags(&submit->deps, XA_FLAGS_ALLOC); kref_init(&submit->ref); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 763b7abfc88e..aaa662cbc43b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -288,6 +288,8 @@ int panfrost_job_push(struct panfrost_job *job) goto unlock; } + drm_sched_job_arm(&job->base); + job->render_done_fence = dma_fence_get(&job->base.s_fence->finished); ret = panfrost_acquire_object_fences(job->bos, job->bo_count, diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 79554aa4dbb1..f7347c284886 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -485,9 +485,9 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) * @sched_job: job to submit * @entity: scheduler entity * - * Note: To guarantee that the order of insertion to queue matches - * the job's fence sequence number this function should be - * called with drm_sched_job_init under common lock. + * Note: To guarantee that the order of insertion to queue matches the job's + * fence sequence number this function should be called with drm_sched_job_arm() + * under common lock. * * Returns 0 for success, negative error code otherwise. */ diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index 69de2c76731f..bcea035cf4c6 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -90,7 +90,7 @@ static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f) * * Free up the fence memory after the RCU grace period. */ -static void drm_sched_fence_free(struct rcu_head *rcu) +void drm_sched_fence_free(struct rcu_head *rcu) { struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); struct drm_sched_fence *fence = to_drm_sched_fence(f); @@ -152,27 +152,32 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f) } EXPORT_SYMBOL(to_drm_sched_fence); -struct drm_sched_fence *drm_sched_fence_create(struct drm_sched_entity *entity, - void *owner) +struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity, + void *owner) { struct drm_sched_fence *fence = NULL; - unsigned seq; fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL); if (fence == NULL) return NULL; fence->owner = owner; - fence->sched = entity->rq->sched; spin_lock_init(&fence->lock); + return fence; +} + +void drm_sched_fence_init(struct drm_sched_fence *fence, + struct drm_sched_entity *entity) +{ + unsigned seq; + + fence->sched = entity->rq->sched; seq = atomic_inc_return(&entity->fence_seq); dma_fence_init(&fence->scheduled, &drm_sched_fence_ops_scheduled, &fence->lock, entity->fence_context, seq); dma_fence_init(&fence->finished, &drm_sched_fence_ops_finished, &fence->lock, entity->fence_context + 1, seq); - - return fence; } module_init(drm_sched_fence_slab_init); diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 67382621b429..719b1a6dbb90 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -48,9 +48,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -564,7 +566,6 @@ EXPORT_SYMBOL(drm_sched_resubmit_jobs_ext); /** * drm_sched_job_init - init a scheduler job - * * @job: scheduler job to init * @entity: scheduler entity to use * @owner: job owner for debugging @@ -572,27 +573,28 @@ EXPORT_SYMBOL(drm_sched_resubmit_jobs_ext); * Refer to drm_sched_entity_push_job() documentation * for locking considerations. * + * Drivers must make sure drm_sched_job_cleanup() if this function returns + * successfully, even when @job is aborted before drm_sched_job_arm() is called. + * + * WARNING: amdgpu abuses &drm_sched.ready to signal when the hardware + * has died, which can mean that there's no valid runqueue for a @entity. + * This function returns -ENOENT in this case (which probably should be -EIO as + * a more meanigful return value). + * * Returns 0 for success, negative error code otherwise. */ int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, void *owner) { - struct drm_gpu_scheduler *sched; - drm_sched_entity_select_rq(entity); if (!entity->rq) return -ENOENT; - sched = entity->rq->sched; - - job->sched = sched; job->entity = entity; - job->s_priority = entity->rq - sched->sched_rq; - job->s_fence = drm_sched_fence_create(entity, owner); + job->s_fence = drm_sched_fence_alloc(entity, owner); if (!job->s_fence) return -ENOMEM; - job->id = atomic64_inc_return(&sched->job_id_count); INIT_LIST_HEAD(&job->list); @@ -601,13 +603,58 @@ int drm_sched_job_init(struct drm_sched_job *job, EXPORT_SYMBOL(drm_sched_job_init); /** - * drm_sched_job_cleanup - clean up scheduler job resources + * drm_sched_job_arm - arm a scheduler job for execution + * @job: scheduler job to arm + * + * This arms a scheduler job for execution. Specifically it initializes the + * &drm_sched_job.s_fence of @job, so that it can be attached to struct dma_resv + * or other places that need to track the completion of this job. + * + * Refer to drm_sched_entity_push_job() documentation for locking + * considerations. * + * This can only be called if drm_sched_job_init() succeeded. + */ +void drm_sched_job_arm(struct drm_sched_job *job) +{ + struct drm_gpu_scheduler *sched; + struct drm_sched_entity *entity = job->entity; + + BUG_ON(!entity); + + sched = entity->rq->sched; + + job->sched = sched; + job->s_priority = entity->rq - sched->sched_rq; + job->id = atomic64_inc_return(&sched->job_id_count); + + drm_sched_fence_init(job->s_fence, job->entity); +} +EXPORT_SYMBOL(drm_sched_job_arm); + +/** + * drm_sched_job_cleanup - clean up scheduler job resources * @job: scheduler job to clean up + * + * Cleans up the resources allocated with drm_sched_job_init(). + * + * Drivers should call this from their error unwind code if @job is aborted + * before drm_sched_job_arm() is called. + * + * After that point of no return @job is committed to be executed by the + * scheduler, and this function should be called from the + * &drm_sched_backend_ops.free_job callback. */ void drm_sched_job_cleanup(struct drm_sched_job *job) { - dma_fence_put(&job->s_fence->finished); + if (kref_read(&job->s_fence->finished.refcount)) { + /* drm_sched_job_arm() has been called */ + dma_fence_put(&job->s_fence->finished); + } else { + /* aborted job before committing to run it */ + drm_sched_fence_free(&job->s_fence->finished.rcu); + } + job->s_fence = NULL; } EXPORT_SYMBOL(drm_sched_job_cleanup); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 5689da118197..2e808097b4d1 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -480,6 +480,8 @@ v3d_push_job(struct v3d_file_priv *v3d_priv, if (ret) return ret; + drm_sched_job_arm(&job->base); + job->done_fence = dma_fence_get(&job->base.s_fence->finished); /* put by scheduler job completion */ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 88ae7f331bb1..83afc3aa8e2f 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -348,6 +348,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched); int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, void *owner); +void drm_sched_job_arm(struct drm_sched_job *job); void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list); @@ -387,8 +388,12 @@ void drm_sched_entity_set_priority(struct drm_sched_entity *entity, enum drm_sched_priority priority); bool drm_sched_entity_is_ready(struct drm_sched_entity *entity); -struct drm_sched_fence *drm_sched_fence_create( +struct drm_sched_fence *drm_sched_fence_alloc( struct drm_sched_entity *s_entity, void *owner); +void drm_sched_fence_init(struct drm_sched_fence *fence, + struct drm_sched_entity *entity); +void drm_sched_fence_free(struct rcu_head *rcu); + void drm_sched_fence_scheduled(struct drm_sched_fence *fence); void drm_sched_fence_finished(struct drm_sched_fence *fence); -- cgit v1.2.3 From ebd5f74255b9f5f8a154ba5535f83387ae599d46 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Aug 2021 12:46:49 +0200 Subject: drm/sched: Add dependency tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of just a callback we can just glue in the gem helpers that panfrost, v3d and lima currently use. There's really not that many ways to skin this cat. v2/3: Rebased. v4: Repaint this shed. The functions are now called _add_dependency() and _add_implicit_dependency() Reviewed-by: Christian König Reviewed-by: Boris Brezillon (v3) Reviewed-by: Steven Price (v1) Acked-by: Melissa Wen Signed-off-by: Daniel Vetter Cc: David Airlie Cc: Daniel Vetter Cc: Sumit Semwal Cc: "Christian König" Cc: Andrey Grodzovsky Cc: Lee Jones Cc: Nirmoy Das Cc: Boris Brezillon Cc: Luben Tuikov Cc: Alex Deucher Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20210805104705.862416-5-daniel.vetter@ffwll.ch --- drivers/gpu/drm/scheduler/sched_entity.c | 18 +++++- drivers/gpu/drm/scheduler/sched_main.c | 104 +++++++++++++++++++++++++++++++ include/drm/gpu_scheduler.h | 33 +++++++++- 3 files changed, 149 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 89e3f6eaf519..381fbf462ea7 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -211,6 +211,19 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, job->sched->ops->free_job(job); } +static struct dma_fence * +drm_sched_job_dependency(struct drm_sched_job *job, + struct drm_sched_entity *entity) +{ + if (!xa_empty(&job->dependencies)) + return xa_erase(&job->dependencies, job->last_dependency++); + + if (job->sched->ops->dependency) + return job->sched->ops->dependency(job, entity); + + return NULL; +} + /** * drm_sched_entity_kill_jobs - Make sure all remaining jobs are killed * @@ -229,7 +242,7 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) struct drm_sched_fence *s_fence = job->s_fence; /* Wait for all dependencies to avoid data corruptions */ - while ((f = job->sched->ops->dependency(job, entity))) + while ((f = drm_sched_job_dependency(job, entity))) dma_fence_wait(f, false); drm_sched_fence_scheduled(s_fence); @@ -419,7 +432,6 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) */ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) { - struct drm_gpu_scheduler *sched = entity->rq->sched; struct drm_sched_job *sched_job; sched_job = to_drm_sched_job(spsc_queue_peek(&entity->job_queue)); @@ -427,7 +439,7 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) return NULL; while ((entity->dependency = - sched->ops->dependency(sched_job, entity))) { + drm_sched_job_dependency(sched_job, entity))) { trace_drm_sched_job_wait_dep(sched_job, entity->dependency); if (drm_sched_entity_add_dependency_cb(entity)) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 719b1a6dbb90..fbbd3b03902f 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -598,6 +598,8 @@ int drm_sched_job_init(struct drm_sched_job *job, INIT_LIST_HEAD(&job->list); + xa_init_flags(&job->dependencies, XA_FLAGS_ALLOC); + return 0; } EXPORT_SYMBOL(drm_sched_job_init); @@ -632,6 +634,99 @@ void drm_sched_job_arm(struct drm_sched_job *job) } EXPORT_SYMBOL(drm_sched_job_arm); +/** + * drm_sched_job_add_dependency - adds the fence as a job dependency + * @job: scheduler job to add the dependencies to + * @fence: the dma_fence to add to the list of dependencies. + * + * Note that @fence is consumed in both the success and error cases. + * + * Returns: + * 0 on success, or an error on failing to expand the array. + */ +int drm_sched_job_add_dependency(struct drm_sched_job *job, + struct dma_fence *fence) +{ + struct dma_fence *entry; + unsigned long index; + u32 id = 0; + int ret; + + if (!fence) + return 0; + + /* Deduplicate if we already depend on a fence from the same context. + * This lets the size of the array of deps scale with the number of + * engines involved, rather than the number of BOs. + */ + xa_for_each(&job->dependencies, index, entry) { + if (entry->context != fence->context) + continue; + + if (dma_fence_is_later(fence, entry)) { + dma_fence_put(entry); + xa_store(&job->dependencies, index, fence, GFP_KERNEL); + } else { + dma_fence_put(fence); + } + return 0; + } + + ret = xa_alloc(&job->dependencies, &id, fence, xa_limit_32b, GFP_KERNEL); + if (ret != 0) + dma_fence_put(fence); + + return ret; +} +EXPORT_SYMBOL(drm_sched_job_add_dependency); + +/** + * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job + * dependencies + * @job: scheduler job to add the dependencies to + * @obj: the gem object to add new dependencies from. + * @write: whether the job might write the object (so we need to depend on + * shared fences in the reservation object). + * + * This should be called after drm_gem_lock_reservations() on your array of + * GEM objects used in the job but before updating the reservations with your + * own fences. + * + * Returns: + * 0 on success, or an error on failing to expand the array. + */ +int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, + struct drm_gem_object *obj, + bool write) +{ + int ret; + struct dma_fence **fences; + unsigned int i, fence_count; + + if (!write) { + struct dma_fence *fence = dma_resv_get_excl_unlocked(obj->resv); + + return drm_sched_job_add_dependency(job, fence); + } + + ret = dma_resv_get_fences(obj->resv, NULL, &fence_count, &fences); + if (ret || !fence_count) + return ret; + + for (i = 0; i < fence_count; i++) { + ret = drm_sched_job_add_dependency(job, fences[i]); + if (ret) + break; + } + + for (; i < fence_count; i++) + dma_fence_put(fences[i]); + kfree(fences); + return ret; +} +EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies); + + /** * drm_sched_job_cleanup - clean up scheduler job resources * @job: scheduler job to clean up @@ -647,6 +742,9 @@ EXPORT_SYMBOL(drm_sched_job_arm); */ void drm_sched_job_cleanup(struct drm_sched_job *job) { + struct dma_fence *fence; + unsigned long index; + if (kref_read(&job->s_fence->finished.refcount)) { /* drm_sched_job_arm() has been called */ dma_fence_put(&job->s_fence->finished); @@ -656,6 +754,12 @@ void drm_sched_job_cleanup(struct drm_sched_job *job) } job->s_fence = NULL; + + xa_for_each(&job->dependencies, index, fence) { + dma_fence_put(fence); + } + xa_destroy(&job->dependencies); + } EXPORT_SYMBOL(drm_sched_job_cleanup); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 83afc3aa8e2f..a47946f904b6 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -27,9 +27,12 @@ #include #include #include +#include #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) +struct drm_gem_object; + struct drm_gpu_scheduler; struct drm_sched_rq; @@ -198,6 +201,17 @@ struct drm_sched_job { enum drm_sched_priority s_priority; struct drm_sched_entity *entity; struct dma_fence_cb cb; + /** + * @dependencies: + * + * Contains the dependencies as struct dma_fence for this job, see + * drm_sched_job_add_dependency() and + * drm_sched_job_add_implicit_dependencies(). + */ + struct xarray dependencies; + + /** @last_dependency: tracks @dependencies as they signal */ + unsigned long last_dependency; }; static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, @@ -220,9 +234,15 @@ enum drm_gpu_sched_stat { */ struct drm_sched_backend_ops { /** - * @dependency: Called when the scheduler is considering scheduling - * this job next, to get another struct dma_fence for this job to - * block on. Once it returns NULL, run_job() may be called. + * @dependency: + * + * Called when the scheduler is considering scheduling this job next, to + * get another struct dma_fence for this job to block on. Once it + * returns NULL, run_job() may be called. + * + * If a driver exclusively uses drm_sched_job_add_dependency() and + * drm_sched_job_add_implicit_dependencies() this can be ommitted and + * left as NULL. */ struct dma_fence *(*dependency)(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity); @@ -349,6 +369,13 @@ int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, void *owner); void drm_sched_job_arm(struct drm_sched_job *job); +int drm_sched_job_add_dependency(struct drm_sched_job *job, + struct dma_fence *fence); +int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, + struct drm_gem_object *obj, + bool write); + + void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list); -- cgit v1.2.3 From 0e10e9a1db230ae98c8ccfeaf0734545421c3995 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Aug 2021 12:46:50 +0200 Subject: drm/sched: drop entity parameter from drm_sched_push_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally a job was only bound to the queue when we pushed this, but now that's done in drm_sched_job_init, making that parameter entirely redundant. Remove it. The same applies to the context parameter in lima_sched_context_queue_task, simplify that too. v2: Rebase on top of msm adopting drm/sched Reviewed-by: Christian König Acked-by: Emma Anholt Acked-by: Melissa Wen Reviewed-by: Steven Price (v1) Reviewed-by: Boris Brezillon (v1) Signed-off-by: Daniel Vetter Cc: Lucas Stach Cc: Russell King Cc: Christian Gmeiner Cc: Qiang Yu Cc: Rob Herring Cc: Tomeu Vizoso Cc: Steven Price Cc: Alyssa Rosenzweig Cc: Emma Anholt Cc: David Airlie Cc: Daniel Vetter Cc: Sumit Semwal Cc: "Christian König" Cc: Alex Deucher Cc: Nirmoy Das Cc: Dave Airlie Cc: Chen Li Cc: Lee Jones Cc: Deepak R Varma Cc: Kevin Wang Cc: Luben Tuikov Cc: "Marek Olšák" Cc: Maarten Lankhorst Cc: Andrey Grodzovsky Cc: Dennis Li Cc: Boris Brezillon Cc: etnaviv@lists.freedesktop.org Cc: lima@lists.freedesktop.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Cc: Rob Clark Cc: Sean Paul Cc: Melissa Wen Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20210805104705.862416-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 2 +- drivers/gpu/drm/lima/lima_gem.c | 3 +-- drivers/gpu/drm/lima/lima_sched.c | 5 ++--- drivers/gpu/drm/lima/lima_sched.h | 3 +-- drivers/gpu/drm/msm/msm_gem_submit.c | 2 +- drivers/gpu/drm/panfrost/panfrost_job.c | 2 +- drivers/gpu/drm/scheduler/sched_entity.c | 6 ++---- drivers/gpu/drm/v3d/v3d_gem.c | 2 +- include/drm/gpu_scheduler.h | 3 +-- 11 files changed, 13 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 2b7f4b77a572..617e39122ea3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1261,7 +1261,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, trace_amdgpu_cs_ioctl(job); amdgpu_vm_bo_trace_cs(&fpriv->vm, &p->ticket); - drm_sched_entity_push_job(&job->base, entity); + drm_sched_entity_push_job(&job->base); amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 5ddb955d2315..b8609cccc9c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -174,7 +174,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); - drm_sched_entity_push_job(&job->base, entity); + drm_sched_entity_push_job(&job->base); return 0; } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 05f412204118..180bb633d5c5 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -178,7 +178,7 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, /* the scheduler holds on to the job now */ kref_get(&submit->refcount); - drm_sched_entity_push_job(&submit->sched_job, sched_entity); + drm_sched_entity_push_job(&submit->sched_job); out_unlock: mutex_unlock(&submit->gpu->fence_lock); diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index de62966243cd..c528f40981bb 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c @@ -359,8 +359,7 @@ int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) goto err_out2; } - fence = lima_sched_context_queue_task( - submit->ctx->context + submit->pipe, submit->task); + fence = lima_sched_context_queue_task(submit->task); for (i = 0; i < submit->nr_bos; i++) { if (submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE) diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index 38f755580507..e968b5a8f0b0 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -177,13 +177,12 @@ void lima_sched_context_fini(struct lima_sched_pipe *pipe, drm_sched_entity_fini(&context->base); } -struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, - struct lima_sched_task *task) +struct dma_fence *lima_sched_context_queue_task(struct lima_sched_task *task) { struct dma_fence *fence = dma_fence_get(&task->base.s_fence->finished); trace_lima_task_submit(task); - drm_sched_entity_push_job(&task->base, &context->base); + drm_sched_entity_push_job(&task->base); return fence; } diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h index 90f03c48ef4a..ac70006b0e26 100644 --- a/drivers/gpu/drm/lima/lima_sched.h +++ b/drivers/gpu/drm/lima/lima_sched.h @@ -98,8 +98,7 @@ int lima_sched_context_init(struct lima_sched_pipe *pipe, atomic_t *guilty); void lima_sched_context_fini(struct lima_sched_pipe *pipe, struct lima_sched_context *context); -struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, - struct lima_sched_task *task); +struct dma_fence *lima_sched_context_queue_task(struct lima_sched_task *task); int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name); void lima_sched_pipe_fini(struct lima_sched_pipe *pipe); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 71b8c8f752a3..37a8059ac798 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -908,7 +908,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, /* The scheduler owns a ref now: */ msm_gem_submit_get(submit); - drm_sched_entity_push_job(&submit->base, &queue->entity); + drm_sched_entity_push_job(&submit->base); args->fence = submit->fence_id; diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index aaa662cbc43b..42aa01445ee4 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -301,7 +301,7 @@ int panfrost_job_push(struct panfrost_job *job) kref_get(&job->refcount); /* put by scheduler job completion */ - drm_sched_entity_push_job(&job->base, entity); + drm_sched_entity_push_job(&job->base); mutex_unlock(&pfdev->sched_lock); diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 381fbf462ea7..e4d33db1eb45 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -516,9 +516,7 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) /** * drm_sched_entity_push_job - Submit a job to the entity's job queue - * * @sched_job: job to submit - * @entity: scheduler entity * * Note: To guarantee that the order of insertion to queue matches the job's * fence sequence number this function should be called with drm_sched_job_arm() @@ -526,9 +524,9 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) * * Returns 0 for success, negative error code otherwise. */ -void drm_sched_entity_push_job(struct drm_sched_job *sched_job, - struct drm_sched_entity *entity) +void drm_sched_entity_push_job(struct drm_sched_job *sched_job) { + struct drm_sched_entity *entity = sched_job->entity; bool first; trace_drm_sched_job(sched_job, entity); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 2e808097b4d1..957228bef29c 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -487,7 +487,7 @@ v3d_push_job(struct v3d_file_priv *v3d_priv, /* put by scheduler job completion */ kref_get(&job->refcount); - drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[queue]); + drm_sched_entity_push_job(&job->base); return 0; } diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index a47946f904b6..b72f73b375a2 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -409,8 +409,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity); void drm_sched_entity_destroy(struct drm_sched_entity *entity); void drm_sched_entity_select_rq(struct drm_sched_entity *entity); struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity); -void drm_sched_entity_push_job(struct drm_sched_job *sched_job, - struct drm_sched_entity *entity); +void drm_sched_entity_push_job(struct drm_sched_job *sched_job); void drm_sched_entity_set_priority(struct drm_sched_entity *entity, enum drm_sched_priority priority); bool drm_sched_entity_is_ready(struct drm_sched_entity *entity); -- cgit v1.2.3 From 981b04d9685612b3831a89772f477058d2b3bd79 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Aug 2021 12:46:51 +0200 Subject: drm/sched: improve docs around drm_sched_entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I found a few too many things that are tricky and not documented, so I started typing. I found a few more things that looked broken while typing, see the varios FIXME in drm_sched_entity. Also some of the usual logics: - actually include sched_entity.c declarations, that was lost in the move here: 620e762f9a98 ("drm/scheduler: move entity handling into separate file") - Ditch the kerneldoc for internal functions, keep the comments where they're describing more than what the function name already implies. - Switch drm_sched_entity to inline docs. Acked-by: Melissa Wen Reviewed-by: Boris Brezillon (v1) Signed-off-by: Daniel Vetter Cc: Lucas Stach Cc: David Airlie Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: "Christian König" Cc: Boris Brezillon Cc: Steven Price Cc: Emma Anholt Cc: Lee Jones Cc: Andrey Grodzovsky Link: https://patchwork.freedesktop.org/patch/msgid/20210805104705.862416-7-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-mm.rst | 3 + drivers/gpu/drm/scheduler/sched_entity.c | 85 ++++++------------ include/drm/gpu_scheduler.h | 145 +++++++++++++++++++++++++------ 3 files changed, 146 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index d5a73fa2c9ef..0198fa43d254 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -504,3 +504,6 @@ Scheduler Function References .. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c :export: + +.. kernel-doc:: drivers/gpu/drm/scheduler/sched_entity.c + :export: diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index e4d33db1eb45..27e1573af96e 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -45,8 +45,14 @@ * @guilty: atomic_t set to 1 when a job on this queue * is found to be guilty causing a timeout * - * Note: the sched_list should have at least one element to schedule - * the entity + * Note that the &sched_list must have at least one element to schedule the entity. + * + * For changing @priority later on at runtime see + * drm_sched_entity_set_priority(). For changing the set of schedulers + * @sched_list at runtime see drm_sched_entity_modify_sched(). + * + * An entity is cleaned up by callind drm_sched_entity_fini(). See also + * drm_sched_entity_destroy(). * * Returns 0 on success or a negative error code on failure. */ @@ -92,6 +98,11 @@ EXPORT_SYMBOL(drm_sched_entity_init); * @sched_list: the list of new drm scheds which will replace * existing entity->sched_list * @num_sched_list: number of drm sched in sched_list + * + * Note that this must be called under the same common lock for @entity as + * drm_sched_job_arm() and drm_sched_entity_push_job(), or the driver needs to + * guarantee through some other means that this is never called while new jobs + * can be pushed to @entity. */ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, @@ -104,13 +115,6 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, } EXPORT_SYMBOL(drm_sched_entity_modify_sched); -/** - * drm_sched_entity_is_idle - Check if entity is idle - * - * @entity: scheduler entity - * - * Returns true if the entity does not have any unscheduled jobs. - */ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) { rmb(); /* for list_empty to work without lock */ @@ -123,13 +127,7 @@ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) return false; } -/** - * drm_sched_entity_is_ready - Check if entity is ready - * - * @entity: scheduler entity - * - * Return true if entity could provide a job. - */ +/* Return true if entity could provide a job. */ bool drm_sched_entity_is_ready(struct drm_sched_entity *entity) { if (spsc_queue_peek(&entity->job_queue) == NULL) @@ -192,14 +190,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) } EXPORT_SYMBOL(drm_sched_entity_flush); -/** - * drm_sched_entity_kill_jobs_cb - helper for drm_sched_entity_kill_jobs - * - * @f: signaled fence - * @cb: our callback structure - * - * Signal the scheduler finished fence when the entity in question is killed. - */ +/* Signal the scheduler finished fence when the entity in question is killed. */ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, struct dma_fence_cb *cb) { @@ -224,14 +215,6 @@ drm_sched_job_dependency(struct drm_sched_job *job, return NULL; } -/** - * drm_sched_entity_kill_jobs - Make sure all remaining jobs are killed - * - * @entity: entity which is cleaned up - * - * Makes sure that all remaining jobs in an entity are killed before it is - * destroyed. - */ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) { struct drm_sched_job *job; @@ -273,9 +256,11 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) * * @entity: scheduler entity * - * This should be called after @drm_sched_entity_do_release. It goes over the - * entity and signals all jobs with an error code if the process was killed. + * Cleanups up @entity which has been initialized by drm_sched_entity_init(). * + * If there are potentially job still in flight or getting newly queued + * drm_sched_entity_flush() must be called first. This function then goes over + * the entity and signals all jobs with an error code if the process was killed. */ void drm_sched_entity_fini(struct drm_sched_entity *entity) { @@ -315,10 +300,10 @@ EXPORT_SYMBOL(drm_sched_entity_fini); /** * drm_sched_entity_destroy - Destroy a context entity - * * @entity: scheduler entity * - * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() + * Calls drm_sched_entity_flush() and drm_sched_entity_fini() as a + * convenience wrapper. */ void drm_sched_entity_destroy(struct drm_sched_entity *entity) { @@ -327,9 +312,7 @@ void drm_sched_entity_destroy(struct drm_sched_entity *entity) } EXPORT_SYMBOL(drm_sched_entity_destroy); -/* - * drm_sched_entity_clear_dep - callback to clear the entities dependency - */ +/* drm_sched_entity_clear_dep - callback to clear the entities dependency */ static void drm_sched_entity_clear_dep(struct dma_fence *f, struct dma_fence_cb *cb) { @@ -371,11 +354,7 @@ void drm_sched_entity_set_priority(struct drm_sched_entity *entity, } EXPORT_SYMBOL(drm_sched_entity_set_priority); -/** - * drm_sched_entity_add_dependency_cb - add callback for the entities dependency - * - * @entity: entity with dependency - * +/* * Add a callback to the current dependency of the entity to wake up the * scheduler when the entity becomes available. */ @@ -423,13 +402,6 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) return false; } -/** - * drm_sched_entity_pop_job - get a ready to be scheduled job from the entity - * - * @entity: entity to get the job from - * - * Process all dependencies and try to get one job from the entities queue. - */ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) { struct drm_sched_job *sched_job; @@ -465,14 +437,6 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) return sched_job; } -/** - * drm_sched_entity_select_rq - select a new rq for the entity - * - * @entity: scheduler entity - * - * Check all prerequisites and select a new rq for the entity for load - * balancing. - */ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) { struct dma_fence *fence; @@ -520,7 +484,8 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) * * Note: To guarantee that the order of insertion to queue matches the job's * fence sequence number this function should be called with drm_sched_job_arm() - * under common lock. + * under common lock for the struct drm_sched_entity that was set up for + * @sched_job in drm_sched_job_init(). * * Returns 0 for success, negative error code otherwise. */ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index b72f73b375a2..7f77a455722c 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -53,56 +53,147 @@ enum drm_sched_priority { * struct drm_sched_entity - A wrapper around a job queue (typically * attached to the DRM file_priv). * - * @list: used to append this struct to the list of entities in the - * runqueue. - * @rq: runqueue on which this entity is currently scheduled. - * @sched_list: A list of schedulers (drm_gpu_schedulers). - * Jobs from this entity can be scheduled on any scheduler - * on this list. - * @num_sched_list: number of drm_gpu_schedulers in the sched_list. - * @priority: priority of the entity - * @rq_lock: lock to modify the runqueue to which this entity belongs. - * @job_queue: the list of jobs of this entity. - * @fence_seq: a linearly increasing seqno incremented with each - * new &drm_sched_fence which is part of the entity. - * @fence_context: a unique context for all the fences which belong - * to this entity. - * The &drm_sched_fence.scheduled uses the - * fence_context but &drm_sched_fence.finished uses - * fence_context + 1. - * @dependency: the dependency fence of the job which is on the top - * of the job queue. - * @cb: callback for the dependency fence above. - * @guilty: points to ctx's guilty. - * @fini_status: contains the exit status in case the process was signalled. - * @last_scheduled: points to the finished fence of the last scheduled job. - * @last_user: last group leader pushing a job into the entity. - * @stopped: Marks the enity as removed from rq and destined for termination. - * @entity_idle: Signals when enityt is not in use - * * Entities will emit jobs in order to their corresponding hardware * ring, and the scheduler will alternate between entities based on * scheduling policy. */ struct drm_sched_entity { + /** + * @list: + * + * Used to append this struct to the list of entities in the runqueue + * @rq under &drm_sched_rq.entities. + * + * Protected by &drm_sched_rq.lock of @rq. + */ struct list_head list; + + /** + * @rq: + * + * Runqueue on which this entity is currently scheduled. + * + * FIXME: Locking is very unclear for this. Writers are protected by + * @rq_lock, but readers are generally lockless and seem to just race + * with not even a READ_ONCE. + */ struct drm_sched_rq *rq; + + /** + * @sched_list: + * + * A list of schedulers (struct drm_gpu_scheduler). Jobs from this entity can + * be scheduled on any scheduler on this list. + * + * This can be modified by calling drm_sched_entity_modify_sched(). + * Locking is entirely up to the driver, see the above function for more + * details. + * + * This will be set to NULL if &num_sched_list equals 1 and @rq has been + * set already. + * + * FIXME: This means priority changes through + * drm_sched_entity_set_priority() will be lost henceforth in this case. + */ struct drm_gpu_scheduler **sched_list; + + /** + * @num_sched_list: + * + * Number of drm_gpu_schedulers in the @sched_list. + */ unsigned int num_sched_list; + + /** + * @priority: + * + * Priority of the entity. This can be modified by calling + * drm_sched_entity_set_priority(). Protected by &rq_lock. + */ enum drm_sched_priority priority; + + /** + * @rq_lock: + * + * Lock to modify the runqueue to which this entity belongs. + */ spinlock_t rq_lock; + /** + * @job_queue: the list of jobs of this entity. + */ struct spsc_queue job_queue; + /** + * @fence_seq: + * + * A linearly increasing seqno incremented with each new + * &drm_sched_fence which is part of the entity. + * + * FIXME: Callers of drm_sched_job_arm() need to ensure correct locking, + * this doesn't need to be atomic. + */ atomic_t fence_seq; + + /** + * @fence_context: + * + * A unique context for all the fences which belong to this entity. The + * &drm_sched_fence.scheduled uses the fence_context but + * &drm_sched_fence.finished uses fence_context + 1. + */ uint64_t fence_context; + /** + * @dependency: + * + * The dependency fence of the job which is on the top of the job queue. + */ struct dma_fence *dependency; + + /** + * @cb: + * + * Callback for the dependency fence above. + */ struct dma_fence_cb cb; + + /** + * @guilty: + * + * Points to entities' guilty. + */ atomic_t *guilty; + + /** + * @last_scheduled: + * + * Points to the finished fence of the last scheduled job. Only written + * by the scheduler thread, can be accessed locklessly from + * drm_sched_job_arm() iff the queue is empty. + */ struct dma_fence *last_scheduled; + + /** + * @last_user: last group leader pushing a job into the entity. + */ struct task_struct *last_user; + + /** + * @stopped: + * + * Marks the enity as removed from rq and destined for + * termination. This is set by calling drm_sched_entity_flush() and by + * drm_sched_fini(). + */ bool stopped; + + /** + * @entity_idle: + * + * Signals when entity is not in use, used to sequence entity cleanup in + * drm_sched_entity_fini(). + */ struct completion entity_idle; }; -- cgit v1.2.3 From d9edf92d496b61e5ac75b2b0aba5ea6c7f7ecdca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Aug 2021 12:47:05 +0200 Subject: dma-resv: Give the docs a do-over MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Specifically document the new/clarified rules around how the shared fences do not have any ordering requirements against the exclusive fence. But also document all the things a bit better, given how central struct dma_resv to dynamic buffer management the docs have been very inadequat. - Lots more links to other pieces of the puzzle. Unfortunately ttm_buffer_object has no docs, so no links :-( - Explain/complain a bit about dma_resv_locking_ctx(). I still don't like that one, but fixing the ttm call chains is going to be horrible. Plus we want to plug in real slowpath locking when we do that anyway. - Main part of the patch is some actual docs for struct dma_resv. Overall I think we still have a lot of bad naming in this area (e.g. dma_resv.fence is singular, but contains the multiple shared fences), but I think that's more indicative of how the semantics and rules are just not great. Another thing that's real awkard is how chaining exclusive fences right now means direct dma_resv.exclusive_fence pointer access with an rcu_assign_pointer. Not so great either. v2: - Fix a pile of typos (Matt, Jason) - Hammer it in that breaking the rules leads to use-after-free issues around dma-buf sharing (Christian) Reviewed-by: Christian König Cc: Jason Ekstrand Cc: Matthew Auld Reviewed-by: Matthew Auld Signed-off-by: Daniel Vetter Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20210805104705.862416-21-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-resv.c | 24 ++++++++--- include/linux/dma-buf.h | 7 +++ include/linux/dma-resv.h | 104 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 124 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index e744fd87c63c..84fbe60629e3 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -48,6 +48,8 @@ * write operations) or N shared fences (read operations). The RCU * mechanism is used to protect read access to fences from locked * write-side updates. + * + * See struct dma_resv for more details. */ DEFINE_WD_CLASS(reservation_ww_class); @@ -137,7 +139,11 @@ EXPORT_SYMBOL(dma_resv_fini); * @num_fences: number of fences we want to add * * Should be called before dma_resv_add_shared_fence(). Must - * be called with obj->lock held. + * be called with @obj locked through dma_resv_lock(). + * + * Note that the preallocated slots need to be re-reserved if @obj is unlocked + * at any time before calling dma_resv_add_shared_fence(). This is validated + * when CONFIG_DEBUG_MUTEXES is enabled. * * RETURNS * Zero for success, or -errno @@ -234,8 +240,10 @@ EXPORT_SYMBOL(dma_resv_reset_shared_max); * @obj: the reservation object * @fence: the shared fence to add * - * Add a fence to a shared slot, obj->lock must be held, and + * Add a fence to a shared slot, @obj must be locked with dma_resv_lock(), and * dma_resv_reserve_shared() has been called. + * + * See also &dma_resv.fence for a discussion of the semantics. */ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence) { @@ -278,9 +286,11 @@ EXPORT_SYMBOL(dma_resv_add_shared_fence); /** * dma_resv_add_excl_fence - Add an exclusive fence. * @obj: the reservation object - * @fence: the shared fence to add + * @fence: the exclusive fence to add * - * Add a fence to the exclusive slot. The obj->lock must be held. + * Add a fence to the exclusive slot. @obj must be locked with dma_resv_lock(). + * Note that this function replaces all fences attached to @obj, see also + * &dma_resv.fence_excl for a discussion of the semantics. */ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence) { @@ -609,9 +619,11 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) * fence * * Callers are not required to hold specific locks, but maybe hold - * dma_resv_lock() already + * dma_resv_lock() already. + * * RETURNS - * true if all fences signaled, else false + * + * True if all fences signaled, else false. */ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) { diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 8b32b4bdd590..66470c37e471 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -420,6 +420,13 @@ struct dma_buf { * - Dynamic importers should set fences for any access that they can't * disable immediately from their &dma_buf_attach_ops.move_notify * callback. + * + * IMPORTANT: + * + * All drivers must obey the struct dma_resv rules, specifically the + * rules for updating fences, see &dma_resv.fence_excl and + * &dma_resv.fence. If these dependency rules are broken access tracking + * can be lost resulting in use after free issues. */ struct dma_resv *resv; diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index e1ca2080a1ff..9100dd3dc21f 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -62,16 +62,90 @@ struct dma_resv_list { /** * struct dma_resv - a reservation object manages fences for a buffer - * @lock: update side lock - * @seq: sequence count for managing RCU read-side synchronization - * @fence_excl: the exclusive fence, if there is one currently - * @fence: list of current shared fences + * + * There are multiple uses for this, with sometimes slightly different rules in + * how the fence slots are used. + * + * One use is to synchronize cross-driver access to a struct dma_buf, either for + * dynamic buffer management or just to handle implicit synchronization between + * different users of the buffer in userspace. See &dma_buf.resv for a more + * in-depth discussion. + * + * The other major use is to manage access and locking within a driver in a + * buffer based memory manager. struct ttm_buffer_object is the canonical + * example here, since this is where reservation objects originated from. But + * use in drivers is spreading and some drivers also manage struct + * drm_gem_object with the same scheme. */ struct dma_resv { + /** + * @lock: + * + * Update side lock. Don't use directly, instead use the wrapper + * functions like dma_resv_lock() and dma_resv_unlock(). + * + * Drivers which use the reservation object to manage memory dynamically + * also use this lock to protect buffer object state like placement, + * allocation policies or throughout command submission. + */ struct ww_mutex lock; + + /** + * @seq: + * + * Sequence count for managing RCU read-side synchronization, allows + * read-only access to @fence_excl and @fence while ensuring we take a + * consistent snapshot. + */ seqcount_ww_mutex_t seq; + /** + * @fence_excl: + * + * The exclusive fence, if there is one currently. + * + * There are two ways to update this fence: + * + * - First by calling dma_resv_add_excl_fence(), which replaces all + * fences attached to the reservation object. To guarantee that no + * fences are lost, this new fence must signal only after all previous + * fences, both shared and exclusive, have signalled. In some cases it + * is convenient to achieve that by attaching a struct dma_fence_array + * with all the new and old fences. + * + * - Alternatively the fence can be set directly, which leaves the + * shared fences unchanged. To guarantee that no fences are lost, this + * new fence must signal only after the previous exclusive fence has + * signalled. Since the shared fences are staying intact, it is not + * necessary to maintain any ordering against those. If semantically + * only a new access is added without actually treating the previous + * one as a dependency the exclusive fences can be strung together + * using struct dma_fence_chain. + * + * Note that actual semantics of what an exclusive or shared fence mean + * is defined by the user, for reservation objects shared across drivers + * see &dma_buf.resv. + */ struct dma_fence __rcu *fence_excl; + + /** + * @fence: + * + * List of current shared fences. + * + * There are no ordering constraints of shared fences against the + * exclusive fence slot. If a waiter needs to wait for all access, it + * has to wait for both sets of fences to signal. + * + * A new fence is added by calling dma_resv_add_shared_fence(). Since + * this often needs to be done past the point of no return in command + * submission it cannot fail, and therefore sufficient slots need to be + * reserved by calling dma_resv_reserve_shared(). + * + * Note that actual semantics of what an exclusive or shared fence mean + * is defined by the user, for reservation objects shared across drivers + * see &dma_buf.resv. + */ struct dma_resv_list __rcu *fence; }; @@ -98,6 +172,13 @@ static inline void dma_resv_reset_shared_max(struct dma_resv *obj) {} * undefined order, a #ww_acquire_ctx is passed to unwind if a cycle * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. + * + * When a die situation is indicated by returning -EDEADLK all locks held by + * @ctx must be unlocked and then dma_resv_lock_slow() called on @obj. + * + * Unlocked by calling dma_resv_unlock(). + * + * See also dma_resv_lock_interruptible() for the interruptible variant. */ static inline int dma_resv_lock(struct dma_resv *obj, struct ww_acquire_ctx *ctx) @@ -119,6 +200,12 @@ static inline int dma_resv_lock(struct dma_resv *obj, * undefined order, a #ww_acquire_ctx is passed to unwind if a cycle * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. + * + * When a die situation is indicated by returning -EDEADLK all locks held by + * @ctx must be unlocked and then dma_resv_lock_slow_interruptible() called on + * @obj. + * + * Unlocked by calling dma_resv_unlock(). */ static inline int dma_resv_lock_interruptible(struct dma_resv *obj, struct ww_acquire_ctx *ctx) @@ -134,6 +221,8 @@ static inline int dma_resv_lock_interruptible(struct dma_resv *obj, * Acquires the reservation object after a die case. This function * will sleep until the lock becomes available. See dma_resv_lock() as * well. + * + * See also dma_resv_lock_slow_interruptible() for the interruptible variant. */ static inline void dma_resv_lock_slow(struct dma_resv *obj, struct ww_acquire_ctx *ctx) @@ -167,7 +256,7 @@ static inline int dma_resv_lock_slow_interruptible(struct dma_resv *obj, * if they overlap with a writer. * * Also note that since no context is provided, no deadlock protection is - * possible. + * possible, which is also not needed for a trylock. * * Returns true if the lock was acquired, false otherwise. */ @@ -193,6 +282,11 @@ static inline bool dma_resv_is_locked(struct dma_resv *obj) * * Returns the context used to lock a reservation object or NULL if no context * was used or the object is not locked at all. + * + * WARNING: This interface is pretty horrible, but TTM needs it because it + * doesn't pass the struct ww_acquire_ctx around in some very long callchains. + * Everyone else just uses it to check whether they're holding a reservation or + * not. */ static inline struct ww_acquire_ctx *dma_resv_locking_ctx(struct dma_resv *obj) { -- cgit v1.2.3 From 32eadf52d4491f005d188ade02d17c60916df8c2 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Tue, 24 Aug 2021 16:13:13 -0400 Subject: drm/ttm: Create pinned list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This list will be used to capture all non VRAM BOs not on LRU so when device is hot unplugged we can iterate the list and unmap DMA mappings before device is removed. v2: Reanme function to ttm_bo_move_to_pinned v3: Move the pinned list to ttm device Signed-off-by: Andrey Grodzovsky Suggested-by: Christian König Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/451614/?series=93971 --- drivers/gpu/drm/ttm/ttm_bo.c | 18 ++++++++++++++---- drivers/gpu/drm/ttm/ttm_device.c | 1 + include/drm/ttm/ttm_device.h | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 49f4bc97c35a..3573f9e393be 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -69,7 +69,17 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, } } -static void ttm_bo_del_from_lru(struct ttm_buffer_object *bo) +static inline void ttm_bo_move_to_pinned(struct ttm_buffer_object *bo) +{ + struct ttm_device *bdev = bo->bdev; + + list_move_tail(&bo->lru, &bdev->pinned); + + if (bdev->funcs->del_from_lru_notify) + bdev->funcs->del_from_lru_notify(bo); +} + +static inline void ttm_bo_del_from_lru(struct ttm_buffer_object *bo) { struct ttm_device *bdev = bo->bdev; @@ -98,7 +108,7 @@ void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo, dma_resv_assert_held(bo->base.resv); if (bo->pin_count) { - ttm_bo_del_from_lru(bo); + ttm_bo_move_to_pinned(bo); return; } @@ -342,7 +352,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, return ret; } - ttm_bo_del_from_lru(bo); + ttm_bo_move_to_pinned(bo); list_del_init(&bo->ddestroy); spin_unlock(&bo->bdev->lru_lock); ttm_bo_cleanup_memtype_use(bo); @@ -1165,7 +1175,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, return 0; } - ttm_bo_del_from_lru(bo); + ttm_bo_move_to_pinned(bo); /* TODO: Cleanup the locking */ spin_unlock(&bo->bdev->lru_lock); diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 519deea8e39b..9eb8f54b66fc 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -210,6 +210,7 @@ int ttm_device_init(struct ttm_device *bdev, struct ttm_device_funcs *funcs, INIT_DELAYED_WORK(&bdev->wq, ttm_device_delayed_workqueue); spin_lock_init(&bdev->lru_lock); INIT_LIST_HEAD(&bdev->ddestroy); + INIT_LIST_HEAD(&bdev->pinned); bdev->dev_mapping = mapping; mutex_lock(&ttm_global_mutex); list_add_tail(&bdev->device_list, &glob->device_list); diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h index cd592f8e941b..03fb44d061e0 100644 --- a/include/drm/ttm/ttm_device.h +++ b/include/drm/ttm/ttm_device.h @@ -265,6 +265,7 @@ struct ttm_device { */ spinlock_t lru_lock; struct list_head ddestroy; + struct list_head pinned; /* * Protected by load / firstopen / lastclose /unload sync. -- cgit v1.2.3 From c97f082c135210da06a82c373fb660f8bfd57d95 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Fri, 27 Aug 2021 16:39:08 -0400 Subject: drm/ttm: Clear all DMA mappings on demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Used by drivers supporting hot unplug to handle all DMA IOMMU group related dependencies before the group is removed during device removal and we try to access it after free when last device pointer from user space is dropped. v3: Switch to ttm_bo_get_unless_zerom Iterate bdev for pinned list Switch to ttm_tt_unpopulate Signed-off-by: Andrey Grodzovsky Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210827203910.5565-3-andrey.grodzovsky@amd.com --- drivers/gpu/drm/ttm/ttm_device.c | 47 ++++++++++++++++++++++++++++++++++++++++ include/drm/ttm/ttm_device.h | 1 + 2 files changed, 48 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 9eb8f54b66fc..a021d029b730 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -248,3 +248,50 @@ void ttm_device_fini(struct ttm_device *bdev) ttm_global_release(); } EXPORT_SYMBOL(ttm_device_fini); + +void ttm_device_clear_dma_mappings(struct ttm_device *bdev) +{ + struct ttm_resource_manager *man; + struct ttm_buffer_object *bo; + unsigned int i, j; + + spin_lock(&bdev->lru_lock); + while (!list_empty(&bdev->pinned)) { + bo = list_first_entry(&bdev->pinned, struct ttm_buffer_object, lru); + /* Take ref against racing releases once lru_lock is unlocked */ + if (ttm_bo_get_unless_zero(bo)) { + list_del_init(&bo->lru); + spin_unlock(&bdev->lru_lock); + + if (bo->ttm) + ttm_tt_unpopulate(bo->bdev, bo->ttm); + + ttm_bo_put(bo); + spin_lock(&bdev->lru_lock); + } + } + + for (i = TTM_PL_SYSTEM; i < TTM_NUM_MEM_TYPES; ++i) { + man = ttm_manager_type(bdev, i); + if (!man || !man->use_tt) + continue; + + for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) { + while (!list_empty(&man->lru[j])) { + bo = list_first_entry(&man->lru[j], struct ttm_buffer_object, lru); + if (ttm_bo_get_unless_zero(bo)) { + list_del_init(&bo->lru); + spin_unlock(&bdev->lru_lock); + + if (bo->ttm) + ttm_tt_unpopulate(bo->bdev, bo->ttm); + + ttm_bo_put(bo); + spin_lock(&bdev->lru_lock); + } + } + } + } + spin_unlock(&bdev->lru_lock); +} +EXPORT_SYMBOL(ttm_device_clear_dma_mappings); diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h index 03fb44d061e0..07d722950d5b 100644 --- a/include/drm/ttm/ttm_device.h +++ b/include/drm/ttm/ttm_device.h @@ -299,5 +299,6 @@ int ttm_device_init(struct ttm_device *bdev, struct ttm_device_funcs *funcs, struct drm_vma_offset_manager *vma_manager, bool use_dma_alloc, bool use_dma32); void ttm_device_fini(struct ttm_device *bdev); +void ttm_device_clear_dma_mappings(struct ttm_device *bdev); #endif -- cgit v1.2.3 From d72277b6c37db66b457fd6b77aabd5e930d58687 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Jul 2021 08:39:31 +0200 Subject: dma-buf: nuke DMA_FENCE_TRACE macros v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the DRM GPU scheduler, radeon and amdgpu where using them and they depend on a non existing config option to actually emit some code. v2: keep the signal path as is for now Signed-off-by: Christian König Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210818105443.1578-1-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 10 +--------- drivers/gpu/drm/radeon/radeon_fence.c | 24 ++++-------------------- drivers/gpu/drm/scheduler/sched_fence.c | 18 ++---------------- include/linux/dma-fence.h | 22 ---------------------- 4 files changed, 7 insertions(+), 67 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 0b1c48590c43..c65994e382bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -246,7 +246,6 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) struct amdgpu_fence_driver *drv = &ring->fence_drv; struct amdgpu_device *adev = ring->adev; uint32_t seq, last_seq; - int r; do { last_seq = atomic_read(&ring->fence_drv.last_seq); @@ -278,12 +277,7 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) if (!fence) continue; - r = dma_fence_signal(fence); - if (!r) - DMA_FENCE_TRACE(fence, "signaled from irq context\n"); - else - BUG(); - + dma_fence_signal(fence); dma_fence_put(fence); pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); @@ -639,8 +633,6 @@ static bool amdgpu_fence_enable_signaling(struct dma_fence *f) if (!timer_pending(&ring->fence_drv.fallback_timer)) amdgpu_fence_schedule_fallback(ring); - DMA_FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx); - return true; } diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 18f2c2e0dfb3..3f351d222cbb 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -176,18 +176,11 @@ static int radeon_fence_check_signaled(wait_queue_entry_t *wait, unsigned mode, */ seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq); if (seq >= fence->seq) { - int ret = dma_fence_signal_locked(&fence->base); - - if (!ret) - DMA_FENCE_TRACE(&fence->base, "signaled from irq context\n"); - else - DMA_FENCE_TRACE(&fence->base, "was already signaled\n"); - + dma_fence_signal_locked(&fence->base); radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring); __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake); dma_fence_put(&fence->base); - } else - DMA_FENCE_TRACE(&fence->base, "pending\n"); + } return 0; } @@ -422,8 +415,6 @@ static bool radeon_fence_enable_signaling(struct dma_fence *f) fence->fence_wake.func = radeon_fence_check_signaled; __add_wait_queue(&rdev->fence_queue, &fence->fence_wake); dma_fence_get(f); - - DMA_FENCE_TRACE(&fence->base, "armed on ring %i!\n", fence->ring); return true; } @@ -441,11 +432,7 @@ bool radeon_fence_signaled(struct radeon_fence *fence) return true; if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { - int ret; - - ret = dma_fence_signal(&fence->base); - if (!ret) - DMA_FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n"); + dma_fence_signal(&fence->base); return true; } return false; @@ -550,7 +537,6 @@ long radeon_fence_wait_timeout(struct radeon_fence *fence, bool intr, long timeo { uint64_t seq[RADEON_NUM_RINGS] = {}; long r; - int r_sig; /* * This function should not be called on !radeon fences. @@ -567,9 +553,7 @@ long radeon_fence_wait_timeout(struct radeon_fence *fence, bool intr, long timeo return r; } - r_sig = dma_fence_signal(&fence->base); - if (!r_sig) - DMA_FENCE_TRACE(&fence->base, "signaled from fence_wait\n"); + dma_fence_signal(&fence->base); return r; } diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index bcea035cf4c6..db3fd1303fc4 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -50,26 +50,12 @@ static void __exit drm_sched_fence_slab_fini(void) void drm_sched_fence_scheduled(struct drm_sched_fence *fence) { - int ret = dma_fence_signal(&fence->scheduled); - - if (!ret) - DMA_FENCE_TRACE(&fence->scheduled, - "signaled from irq context\n"); - else - DMA_FENCE_TRACE(&fence->scheduled, - "was already signaled\n"); + dma_fence_signal(&fence->scheduled); } void drm_sched_fence_finished(struct drm_sched_fence *fence) { - int ret = dma_fence_signal(&fence->finished); - - if (!ret) - DMA_FENCE_TRACE(&fence->finished, - "signaled from irq context\n"); - else - DMA_FENCE_TRACE(&fence->finished, - "was already signaled\n"); + dma_fence_signal(&fence->finished); } static const char *drm_sched_fence_get_driver_name(struct dma_fence *fence) diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 6ffb4b2c6371..4cc119ab272f 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -590,26 +590,4 @@ struct dma_fence *dma_fence_get_stub(void); struct dma_fence *dma_fence_allocate_private_stub(void); u64 dma_fence_context_alloc(unsigned num); -#define DMA_FENCE_TRACE(f, fmt, args...) \ - do { \ - struct dma_fence *__ff = (f); \ - if (IS_ENABLED(CONFIG_DMA_FENCE_TRACE)) \ - pr_info("f %llu#%llu: " fmt, \ - __ff->context, __ff->seqno, ##args); \ - } while (0) - -#define DMA_FENCE_WARN(f, fmt, args...) \ - do { \ - struct dma_fence *__ff = (f); \ - pr_warn("f %llu#%llu: " fmt, __ff->context, __ff->seqno,\ - ##args); \ - } while (0) - -#define DMA_FENCE_ERR(f, fmt, args...) \ - do { \ - struct dma_fence *__ff = (f); \ - pr_err("f %llu#%llu: " fmt, __ff->context, __ff->seqno, \ - ##args); \ - } while (0) - #endif /* __LINUX_DMA_FENCE_H */ -- cgit v1.2.3 From b83dcd753dbe42d5e7467ab65124f3d0a6002dc3 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 21 Jul 2021 11:01:04 +0200 Subject: dma-buf: clarify dma_fence_ops->wait documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This callback is pretty much deprecated and should not be used by new implementations. Clarify that in the documentation as well. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210901120240.7339-2-christian.koenig@amd.com --- include/linux/dma-fence.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 4cc119ab272f..a706b7bf51d7 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -214,19 +214,15 @@ struct dma_fence_ops { * Custom wait implementation, defaults to dma_fence_default_wait() if * not set. * - * The dma_fence_default_wait implementation should work for any fence, as long - * as @enable_signaling works correctly. This hook allows drivers to - * have an optimized version for the case where a process context is - * already available, e.g. if @enable_signaling for the general case - * needs to set up a worker thread. + * Deprecated and should not be used by new implementations. Only used + * by existing implementations which need special handling for their + * hardware reset procedure. * * Must return -ERESTARTSYS if the wait is intr = true and the wait was * interrupted, and remaining jiffies if fence has signaled, or 0 if wait * timed out. Can also return other error values on custom implementations, * which should be treated as if the fence is signaled. For example a hardware * lockup could be reported like that. - * - * This callback is optional. */ signed long (*wait)(struct dma_fence *fence, bool intr, signed long timeout); -- cgit v1.2.3 From 98cca519df6da699240403721f5d251ecf702b3b Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 30 Aug 2021 13:17:10 +0200 Subject: drm/ttm: cleanup ttm_resource_compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move that function into the resource handling and remove an unused parameter. Signed-off-by: Christian König Reviewed-by: Huang Rui Link: https://patchwork.freedesktop.org/patch/msgid/20210831112110.113196-1-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_bo.c | 48 +------------------------------------ drivers/gpu/drm/ttm/ttm_resource.c | 49 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 15 +++++------- include/drm/ttm/ttm_bo_api.h | 12 ---------- include/drm/ttm/ttm_resource.h | 3 +++ 5 files changed, 59 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3573f9e393be..0a3127436f61 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -924,57 +924,11 @@ out: return ret; } -static bool ttm_bo_places_compat(const struct ttm_place *places, - unsigned num_placement, - struct ttm_resource *mem, - uint32_t *new_flags) -{ - unsigned i; - - if (mem->placement & TTM_PL_FLAG_TEMPORARY) - return false; - - for (i = 0; i < num_placement; i++) { - const struct ttm_place *heap = &places[i]; - - if ((mem->start < heap->fpfn || - (heap->lpfn != 0 && (mem->start + mem->num_pages) > heap->lpfn))) - continue; - - *new_flags = heap->flags; - if ((mem->mem_type == heap->mem_type) && - (!(*new_flags & TTM_PL_FLAG_CONTIGUOUS) || - (mem->placement & TTM_PL_FLAG_CONTIGUOUS))) - return true; - } - return false; -} - -bool ttm_bo_mem_compat(struct ttm_placement *placement, - struct ttm_resource *mem, - uint32_t *new_flags) -{ - if (ttm_bo_places_compat(placement->placement, placement->num_placement, - mem, new_flags)) - return true; - - if ((placement->busy_placement != placement->placement || - placement->num_busy_placement > placement->num_placement) && - ttm_bo_places_compat(placement->busy_placement, - placement->num_busy_placement, - mem, new_flags)) - return true; - - return false; -} -EXPORT_SYMBOL(ttm_bo_mem_compat); - int ttm_bo_validate(struct ttm_buffer_object *bo, struct ttm_placement *placement, struct ttm_operation_ctx *ctx) { int ret; - uint32_t new_flags; dma_resv_assert_held(bo->base.resv); @@ -987,7 +941,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, /* * Check whether we need to move buffer. */ - if (!ttm_bo_mem_compat(placement, bo->resource, &new_flags)) { + if (!ttm_resource_compat(bo->resource, placement)) { ret = ttm_bo_move_buffer(bo, placement, ctx); if (ret) return ret; diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 2431717376e7..035d71332d18 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -67,6 +67,55 @@ void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res) } EXPORT_SYMBOL(ttm_resource_free); +static bool ttm_resource_places_compat(struct ttm_resource *res, + const struct ttm_place *places, + unsigned num_placement) +{ + unsigned i; + + if (res->placement & TTM_PL_FLAG_TEMPORARY) + return false; + + for (i = 0; i < num_placement; i++) { + const struct ttm_place *heap = &places[i]; + + if (res->start < heap->fpfn || (heap->lpfn && + (res->start + res->num_pages) > heap->lpfn)) + continue; + + if ((res->mem_type == heap->mem_type) && + (!(heap->flags & TTM_PL_FLAG_CONTIGUOUS) || + (res->placement & TTM_PL_FLAG_CONTIGUOUS))) + return true; + } + return false; +} + +/** + * ttm_resource_compat - check if resource is compatible with placement + * + * @res: the resource to check + * @placement: the placement to check against + * + * Returns true if the placement is compatible. + */ +bool ttm_resource_compat(struct ttm_resource *res, + struct ttm_placement *placement) +{ + if (ttm_resource_places_compat(res, placement->placement, + placement->num_placement)) + return true; + + if ((placement->busy_placement != placement->placement || + placement->num_busy_placement > placement->num_placement) && + ttm_resource_places_compat(res, placement->busy_placement, + placement->num_busy_placement)) + return true; + + return false; +} +EXPORT_SYMBOL(ttm_resource_compat); + /** * ttm_resource_manager_init * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 9e3e1429db94..fd007f1c1776 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -94,7 +94,6 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; int ret; - uint32_t new_flags; vmw_execbuf_release_pinned_bo(dev_priv); @@ -103,8 +102,8 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, goto err; if (buf->base.pin_count > 0) - ret = ttm_bo_mem_compat(placement, bo->resource, - &new_flags) == true ? 0 : -EINVAL; + ret = ttm_resource_compat(bo->resource, placement) + ? 0 : -EINVAL; else ret = ttm_bo_validate(bo, placement, &ctx); @@ -136,7 +135,6 @@ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; int ret; - uint32_t new_flags; vmw_execbuf_release_pinned_bo(dev_priv); @@ -145,8 +143,8 @@ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, goto err; if (buf->base.pin_count > 0) { - ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, bo->resource, - &new_flags) == true ? 0 : -EINVAL; + ret = ttm_resource_compat(bo->resource, &vmw_vram_gmr_placement) + ? 0 : -EINVAL; goto out_unreserve; } @@ -208,7 +206,6 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, struct ttm_placement placement; struct ttm_place place; int ret = 0; - uint32_t new_flags; place = vmw_vram_placement.placement[0]; place.lpfn = bo->resource->num_pages; @@ -236,8 +233,8 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, } if (buf->base.pin_count > 0) - ret = ttm_bo_mem_compat(&placement, bo->resource, - &new_flags) == true ? 0 : -EINVAL; + ret = ttm_resource_compat(bo->resource, &placement) + ? 0 : -EINVAL; else ret = ttm_bo_validate(bo, &placement, &ctx); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index f681bbdbc698..76d7c33884da 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -264,18 +264,6 @@ static inline int ttm_bo_wait_ctx(struct ttm_buffer_object *bo, struct ttm_opera return ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); } -/** - * ttm_bo_mem_compat - Check if proposed placement is compatible with a bo - * - * @placement: Return immediately if buffer is busy. - * @mem: The struct ttm_resource indicating the region where the bo resides - * @new_flags: Describes compatible placement found - * - * Returns true if the placement is compatible - */ -bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_resource *mem, - uint32_t *new_flags); - /** * ttm_bo_validate * diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h index 140b6b9a8bbe..32c5edd9e8b5 100644 --- a/include/drm/ttm/ttm_resource.h +++ b/include/drm/ttm/ttm_resource.h @@ -40,6 +40,7 @@ struct ttm_resource_manager; struct ttm_resource; struct ttm_place; struct ttm_buffer_object; +struct ttm_placement; struct dma_buf_map; struct io_mapping; struct sg_table; @@ -266,6 +267,8 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo, const struct ttm_place *place, struct ttm_resource **res); void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res); +bool ttm_resource_compat(struct ttm_resource *res, + struct ttm_placement *placement); void ttm_resource_manager_init(struct ttm_resource_manager *man, unsigned long p_size); -- cgit v1.2.3 From a9fc4315553df6087c19537abe3340afcf0621fd Mon Sep 17 00:00:00 2001 From: zhangzhijie Date: Fri, 3 Sep 2021 11:24:02 +0800 Subject: drm: Improve the output_poll_changed description this callback was used by drm_kms_helper_hotplug_event() V2: (Thanks for Daniel's suggestions) - remove the FIXME below.since with the drm_client - infrastructure and the generic fbdev emulation we've - resolved this all very neatly now. V3: Add comments that This hook is deprecated - new implementation methods instead of this hook v4: used by drm_kms_helper_hotplug_event() - drm_fb_helper_hotplug_changed() is not found instead by drm_kms_helper_hotplug_event() Signed-off-by: ZhiJie.Zhang Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210903032402.11935-1-zhangzhijie@loongson.cn --- include/drm/drm_mode_config.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 1ddf7783fdf7..48b7de80daf5 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -103,14 +103,13 @@ struct drm_mode_config_funcs { * Callback used by helpers to inform the driver of output configuration * changes. * - * Drivers implementing fbdev emulation with the helpers can call - * drm_fb_helper_hotplug_changed from this hook to inform the fbdev - * helper of output changes. + * Drivers implementing fbdev emulation use drm_kms_helper_hotplug_event() + * to call this hook to inform the fbdev helper of output changes. * - * FIXME: - * - * Except that there's no vtable for device-level helper callbacks - * there's no reason this is a core function. + * This hook is deprecated, drivers should instead use + * drm_fbdev_generic_setup() which takes care of any necessary + * hotplug event forwarding already without further involvement by + * the driver. */ void (*output_poll_changed)(struct drm_device *dev); -- cgit v1.2.3 From d4c16733e7960aa50d6d3bc4a03ee1578baaa47b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 3 Sep 2021 14:05:54 +0200 Subject: drm/sched: Fix drm_sched_fence_free() so it can be passed an uninitialized fence drm_sched_job_cleanup() will pass an uninitialized fence to drm_sched_fence_free(), which will cause to_drm_sched_fence() to return a NULL fence object, causing a NULL pointer deref when this NULL object is passed to kmem_cache_free(). Let's create a new drm_sched_fence_free() function that takes a drm_sched_fence pointer and suffix the old function with _rcu. While at it, complain if drm_sched_fence_free() is passed an initialized fence or if drm_sched_fence_free_rcu() is passed an uninitialized fence. Fixes: dbe48d030b28 ("drm/sched: Split drm_sched_job_init") Signed-off-by: Boris Brezillon Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210903120554.444101-1-boris.brezillon@collabora.com --- drivers/gpu/drm/scheduler/sched_fence.c | 27 ++++++++++++++++++--------- drivers/gpu/drm/scheduler/sched_main.c | 2 +- include/drm/gpu_scheduler.h | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index db3fd1303fc4..7fd869520ef2 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -69,19 +69,28 @@ static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f) return (const char *)fence->sched->name; } +static void drm_sched_fence_free_rcu(struct rcu_head *rcu) +{ + struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); + struct drm_sched_fence *fence = to_drm_sched_fence(f); + + if (!WARN_ON_ONCE(!fence)) + kmem_cache_free(sched_fence_slab, fence); +} + /** - * drm_sched_fence_free - free up the fence memory + * drm_sched_fence_free - free up an uninitialized fence * - * @rcu: RCU callback head + * @fence: fence to free * - * Free up the fence memory after the RCU grace period. + * Free up the fence memory. Should only be used if drm_sched_fence_init() + * has not been called yet. */ -void drm_sched_fence_free(struct rcu_head *rcu) +void drm_sched_fence_free(struct drm_sched_fence *fence) { - struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); - struct drm_sched_fence *fence = to_drm_sched_fence(f); - - kmem_cache_free(sched_fence_slab, fence); + /* This function should not be called if the fence has been initialized. */ + if (!WARN_ON_ONCE(fence->sched)) + kmem_cache_free(sched_fence_slab, fence); } /** @@ -97,7 +106,7 @@ static void drm_sched_fence_release_scheduled(struct dma_fence *f) struct drm_sched_fence *fence = to_drm_sched_fence(f); dma_fence_put(fence->parent); - call_rcu(&fence->finished.rcu, drm_sched_fence_free); + call_rcu(&fence->finished.rcu, drm_sched_fence_free_rcu); } /** diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index fbbd3b03902f..6987d412a946 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -750,7 +750,7 @@ void drm_sched_job_cleanup(struct drm_sched_job *job) dma_fence_put(&job->s_fence->finished); } else { /* aborted job before committing to run it */ - drm_sched_fence_free(&job->s_fence->finished.rcu); + drm_sched_fence_free(job->s_fence); } job->s_fence = NULL; diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 7f77a455722c..f011e4c407f2 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -509,7 +509,7 @@ struct drm_sched_fence *drm_sched_fence_alloc( struct drm_sched_entity *s_entity, void *owner); void drm_sched_fence_init(struct drm_sched_fence *fence, struct drm_sched_entity *entity); -void drm_sched_fence_free(struct rcu_head *rcu); +void drm_sched_fence_free(struct drm_sched_fence *fence); void drm_sched_fence_scheduled(struct drm_sched_fence *fence); void drm_sched_fence_finished(struct drm_sched_fence *fence); -- cgit v1.2.3 From be77a2f4cfd20aa4a28fc98227bfbfd5e0c232e2 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 7 Sep 2021 09:14:43 +0200 Subject: drm/ttm: add kerneldoc for enum ttm_caching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Briefly describe what this is all about. Signed-off-by: Christian König Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-4-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 3 +++ include/drm/ttm/ttm_caching.h | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 6b7717af4f88..f22c9f9a2c0e 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -31,6 +31,9 @@ The Translation Table Manager (TTM) .. kernel-doc:: drivers/gpu/drm/ttm/ttm_module.c :doc: TTM +.. kernel-doc:: include/drm/ttm/ttm_caching.h + :internal: + The Graphics Execution Manager (GEM) ==================================== diff --git a/include/drm/ttm/ttm_caching.h b/include/drm/ttm/ttm_caching.h index 3c9dd65f5aaf..235a743d90e1 100644 --- a/include/drm/ttm/ttm_caching.h +++ b/include/drm/ttm/ttm_caching.h @@ -27,9 +27,26 @@ #define TTM_NUM_CACHING_TYPES 3 +/** + * enum ttm_caching - CPU caching and BUS snooping behavior. + */ enum ttm_caching { + /** + * @ttm_uncached: Most defensive option for device mappings, + * don't even allow write combining. + */ ttm_uncached, + + /** + * @ttm_write_combined: Don't cache read accesses, but allow at least + * writes to be combined. + */ ttm_write_combined, + + /** + * @ttm_cached: Fully cached like normal system memory, requires that + * devices snoop the CPU cache on accesses. + */ ttm_cached }; -- cgit v1.2.3 From c5fd9986719e4a75340b38ef4f6157e2c5fbe74d Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 3 Sep 2021 13:44:46 +0200 Subject: drm/ttm: enable TTM device object kerneldoc v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the remaining warnings, switch to inline structure documentation and finally enable this. v2: adjust based on suggestions from Alex Signed-off-by: Christian König Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-5-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 9 ++++++ include/drm/ttm/ttm_device.h | 72 ++++++++++++++++++++++++-------------------- 2 files changed, 48 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index f22c9f9a2c0e..3da81b7b4e71 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -34,6 +34,15 @@ The Translation Table Manager (TTM) .. kernel-doc:: include/drm/ttm/ttm_caching.h :internal: +TTM device object reference +--------------------------- + +.. kernel-doc:: include/drm/ttm/ttm_device.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/ttm/ttm_device.c + :export: + The Graphics Execution Manager (GEM) ==================================== diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h index 07d722950d5b..3cc1d9b76131 100644 --- a/include/drm/ttm/ttm_device.h +++ b/include/drm/ttm/ttm_device.h @@ -39,31 +39,23 @@ struct ttm_operation_ctx; /** * struct ttm_global - Buffer object driver global data. - * - * @dummy_read_page: Pointer to a dummy page used for mapping requests - * of unpopulated pages. - * @shrink: A shrink callback object used for buffer object swap. - * @device_list_mutex: Mutex protecting the device list. - * This mutex is held while traversing the device list for pm options. - * @lru_lock: Spinlock protecting the bo subsystem lru lists. - * @device_list: List of buffer object devices. - * @swap_lru: Lru list of buffer objects used for swapping. */ extern struct ttm_global { /** - * Constant after init. + * @dummy_read_page: Pointer to a dummy page used for mapping requests + * of unpopulated pages. Constant after init. */ - struct page *dummy_read_page; /** - * Protected by ttm_global_mutex. + * @device_list: List of buffer object devices. Protected by + * ttm_global_mutex. */ struct list_head device_list; /** - * Internal protection. + * @bo_count: Number of buffer objects allocated by devices. */ atomic_t bo_count; } ttm_glob; @@ -230,50 +222,64 @@ struct ttm_device_funcs { /** * struct ttm_device - Buffer object driver device-specific data. - * - * @device_list: Our entry in the global device list. - * @funcs: Function table for the device. - * @sysman: Resource manager for the system domain. - * @man_drv: An array of resource_managers. - * @vma_manager: Address space manager. - * @pool: page pool for the device. - * @dev_mapping: A pointer to the struct address_space representing the - * device address space. - * @wq: Work queue structure for the delayed delete workqueue. */ struct ttm_device { - /* + /** + * @device_list: Our entry in the global device list. * Constant after bo device init */ struct list_head device_list; + + /** + * @funcs: Function table for the device. + * Constant after bo device init + */ struct ttm_device_funcs *funcs; - /* + /** + * @sysman: Resource manager for the system domain. * Access via ttm_manager_type. */ struct ttm_resource_manager sysman; + + /** + * @man_drv: An array of resource_managers, one per resource type. + */ struct ttm_resource_manager *man_drv[TTM_NUM_MEM_TYPES]; - /* - * Protected by internal locks. + /** + * @vma_manager: Address space manager for finding BOs to mmap. */ struct drm_vma_offset_manager *vma_manager; + + /** + * @pool: page pool for the device. + */ struct ttm_pool pool; - /* - * Protection for the per manager LRU and ddestroy lists. + /** + * @lru_lock: Protection for the per manager LRU and ddestroy lists. */ spinlock_t lru_lock; + + /** + * @ddestroy: Destroyed but not yet cleaned up buffer objects. + */ struct list_head ddestroy; + + /** + * @pinned: Buffer objects which are pinned and so not on any LRU list. + */ struct list_head pinned; - /* - * Protected by load / firstopen / lastclose /unload sync. + /** + * @dev_mapping: A pointer to the struct address_space for invalidating + * CPU mappings on buffer move. Protected by load/unload sync. */ struct address_space *dev_mapping; - /* - * Internal protection. + /** + * @wq: Work queue structure for the delayed delete workqueue. */ struct delayed_work wq; }; -- cgit v1.2.3 From 324317add204db3f938da3539784a91d40f7141c Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 3 Sep 2021 13:55:01 +0200 Subject: drm/ttm: enable TTM resource object kerneldoc v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the last two remaining warnings and finally enable this. v2: add caching enum link Signed-off-by: Christian König Reviewed-by: Matthew Auld Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-6-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 9 +++++++++ include/drm/ttm/ttm_resource.h | 6 ++---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 3da81b7b4e71..66d24b745c62 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -43,6 +43,15 @@ TTM device object reference .. kernel-doc:: drivers/gpu/drm/ttm/ttm_device.c :export: +TTM resource object reference +----------------------------- + +.. kernel-doc:: include/drm/ttm/ttm_resource.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/ttm/ttm_resource.c + :export: + The Graphics Execution Manager (GEM) ==================================== diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h index 32c5edd9e8b5..5952051091cd 100644 --- a/include/drm/ttm/ttm_resource.h +++ b/include/drm/ttm/ttm_resource.h @@ -103,10 +103,7 @@ struct ttm_resource_manager_func { * struct ttm_resource_manager * * @use_type: The memory type is enabled. - * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory - * managed by this memory type. - * @gpu_offset: If used, the GPU offset of the first managed page of - * fixed memory or the first managed location in an aperture. + * @use_tt: If a TT object should be used for the backing store. * @size: Size of the managed region. * @func: structure pointer implementing the range manager. See above * @move_lock: lock for move fence @@ -144,6 +141,7 @@ struct ttm_resource_manager { * @addr: mapped virtual address * @offset: physical addr * @is_iomem: is this io memory ? + * @caching: See enum ttm_caching * * Structure indicating the bus placement of an object. */ -- cgit v1.2.3 From d7fe6f8afead5838bd43adf10a06a66896bfe756 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 3 Sep 2021 14:14:41 +0200 Subject: drm/ttm: enable TTM placement kerneldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the last remaining warning and finally enable this. Signed-off-by: Christian König Reviewed-by: Matthew Auld Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-7-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 6 ++++++ include/drm/ttm/ttm_placement.h | 1 + 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 66d24b745c62..1c9930fb5e7d 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -43,6 +43,12 @@ TTM device object reference .. kernel-doc:: drivers/gpu/drm/ttm/ttm_device.c :export: +TTM resource placement reference +-------------------------------- + +.. kernel-doc:: include/drm/ttm/ttm_placement.h + :internal: + TTM resource object reference ----------------------------- diff --git a/include/drm/ttm/ttm_placement.h b/include/drm/ttm/ttm_placement.h index 8995c9e4ec1b..76d1b9119a2b 100644 --- a/include/drm/ttm/ttm_placement.h +++ b/include/drm/ttm/ttm_placement.h @@ -58,6 +58,7 @@ * * @fpfn: first valid page frame number to put the object * @lpfn: last valid page frame number to put the object + * @mem_type: One of TTM_PL_* where the resource should be allocated from. * @flags: memory domain and caching flags for the object * * Structure indicating a possible place to put an object. -- cgit v1.2.3 From 4f4859d084f7b8c72ca3639f6169b74d0340ddb9 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 3 Sep 2021 14:19:38 +0200 Subject: drm/ttm: enable TTM TT object kerneldoc v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the remaining warnings and finally enable this. v2: add caching enum link Signed-off-by: Christian König Reviewed-by: Matthew Auld Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-8-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 9 +++++++++ include/drm/ttm/ttm_tt.h | 11 ++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 1c9930fb5e7d..69c4a20b95d0 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -58,6 +58,15 @@ TTM resource object reference .. kernel-doc:: drivers/gpu/drm/ttm/ttm_resource.c :export: +TTM TT object reference +----------------------- + +.. kernel-doc:: include/drm/ttm/ttm_tt.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/ttm/ttm_tt.c + :export: + The Graphics Execution Manager (GEM) ==================================== diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index e402dab1d0f6..b3963ab12e1f 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -54,7 +54,7 @@ struct ttm_operation_ctx; * @dma_address: The DMA (bus) addresses of the pages * @swap_storage: Pointer to shmem struct file for swap storage. * @pages_list: used by some page allocation backend - * @caching: The current caching state of the pages. + * @caching: The current caching state of the pages, see enum ttm_caching. * * This is a structure holding the pages, caching- and aperture binding * status for a buffer object that isn't backed by fixed (VRAM / AGP) @@ -126,8 +126,9 @@ int ttm_sg_tt_init(struct ttm_tt *ttm_dma, struct ttm_buffer_object *bo, void ttm_tt_fini(struct ttm_tt *ttm); /** - * ttm_ttm_destroy: + * ttm_tt_destroy: * + * @bdev: the ttm_device this object belongs to * @ttm: The struct ttm_tt. * * Unbind, unpopulate and destroy common struct ttm_tt. @@ -148,15 +149,19 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm, /** * ttm_tt_populate - allocate pages for a ttm * + * @bdev: the ttm_device this object belongs to * @ttm: Pointer to the ttm_tt structure + * @ctx: operation context for populating the tt object. * * Calls the driver method to allocate pages for a ttm */ -int ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); +int ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm, + struct ttm_operation_ctx *ctx); /** * ttm_tt_unpopulate - free pages from a ttm * + * @bdev: the ttm_device this object belongs to * @ttm: Pointer to the ttm_tt structure * * Calls the driver method to free all pages from a ttm -- cgit v1.2.3 From 361da7c34216382b7329521c397db0e3e8f6e02b Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 7 Sep 2021 09:42:42 +0200 Subject: drm/ttm: enable TTM page pool kerneldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the remaining warnings and finally enable this. Signed-off-by: Christian König Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210908132933.3269-9-christian.koenig@amd.com --- Documentation/gpu/drm-mm.rst | 9 +++++++++ include/drm/ttm/ttm_pool.h | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 69c4a20b95d0..e0538083a2c0 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -67,6 +67,15 @@ TTM TT object reference .. kernel-doc:: drivers/gpu/drm/ttm/ttm_tt.c :export: +TTM page pool reference +----------------------- + +.. kernel-doc:: include/drm/ttm/ttm_pool.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/ttm/ttm_pool.c + :export: + The Graphics Execution Manager (GEM) ==================================== diff --git a/include/drm/ttm/ttm_pool.h b/include/drm/ttm/ttm_pool.h index 4321728bdd11..ef09b23d29e3 100644 --- a/include/drm/ttm/ttm_pool.h +++ b/include/drm/ttm/ttm_pool.h @@ -37,7 +37,7 @@ struct ttm_pool; struct ttm_operation_ctx; /** - * ttm_pool_type - Pool for a certain memory type + * struct ttm_pool_type - Pool for a certain memory type * * @pool: the pool we belong to, might be NULL for the global ones * @order: the allocation order our pages have @@ -58,8 +58,9 @@ struct ttm_pool_type { }; /** - * ttm_pool - Pool for all caching and orders + * struct ttm_pool - Pool for all caching and orders * + * @dev: the device we allocate pages for * @use_dma_alloc: if coherent DMA allocations should be used * @use_dma32: if GFP_DMA32 should be used * @caching: pools for each caching/order -- cgit v1.2.3 From 353be7c2328ccba0add424d015ef51ddf423e202 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Sep 2021 13:00:16 +0000 Subject: drm: document drm_mode_create_lease object requirements validate_lease expects one CRTC, one connector and one plane. Signed-off-by: Simon Ser Cc: Daniel Vetter Cc: Pekka Paalanen Cc: Keith Packard Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210903130000.1590-1-contact@emersion.fr --- include/uapi/drm/drm_mode.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 90c55383f1ee..e4a2570a6058 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -1110,6 +1110,9 @@ struct drm_mode_destroy_blob { * struct drm_mode_create_lease - Create lease * * Lease mode resources, creating another drm_master. + * + * The @object_ids array must reference at least one CRTC, one connector and + * one plane if &DRM_CLIENT_CAP_UNIVERSAL_PLANES is enabled. */ struct drm_mode_create_lease { /** @object_ids: Pointer to array of object ids (__u32) */ -- cgit v1.2.3 From 617d5b34f22c66fe9fc9f150be27f5de1b87ca15 Mon Sep 17 00:00:00 2001 From: xinhui pan Date: Mon, 13 Sep 2021 16:09:50 +0800 Subject: drm/ttm: Try to check if new ttm man out of bounds during compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow TTM know if vendor set new ttm mananger out of bounds by adding build_bug_on. Signed-off-by: xinhui pan Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210913080950.180752-1-xinhui.pan@amd.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_range_manager.c | 8 ++++---- include/drm/ttm/ttm_device.h | 3 +++ include/drm/ttm/ttm_range_manager.h | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c index f4b08a8705b3..67d68a4a8640 100644 --- a/drivers/gpu/drm/ttm/ttm_range_manager.c +++ b/drivers/gpu/drm/ttm/ttm_range_manager.c @@ -138,7 +138,7 @@ static const struct ttm_resource_manager_func ttm_range_manager_func = { * Initialise a generic range manager for the selected memory type. * The range manager is installed for this device in the type slot. */ -int ttm_range_man_init(struct ttm_device *bdev, +int ttm_range_man_init_nocheck(struct ttm_device *bdev, unsigned type, bool use_tt, unsigned long p_size) { @@ -163,7 +163,7 @@ int ttm_range_man_init(struct ttm_device *bdev, ttm_resource_manager_set_used(man, true); return 0; } -EXPORT_SYMBOL(ttm_range_man_init); +EXPORT_SYMBOL(ttm_range_man_init_nocheck); /** * ttm_range_man_fini @@ -173,7 +173,7 @@ EXPORT_SYMBOL(ttm_range_man_init); * * Remove the generic range manager from a slot and tear it down. */ -int ttm_range_man_fini(struct ttm_device *bdev, +int ttm_range_man_fini_nocheck(struct ttm_device *bdev, unsigned type) { struct ttm_resource_manager *man = ttm_manager_type(bdev, type); @@ -200,4 +200,4 @@ int ttm_range_man_fini(struct ttm_device *bdev, kfree(rman); return 0; } -EXPORT_SYMBOL(ttm_range_man_fini); +EXPORT_SYMBOL(ttm_range_man_fini_nocheck); diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h index 3cc1d9b76131..cbe03d45e883 100644 --- a/include/drm/ttm/ttm_device.h +++ b/include/drm/ttm/ttm_device.h @@ -291,12 +291,15 @@ int ttm_device_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx, static inline struct ttm_resource_manager * ttm_manager_type(struct ttm_device *bdev, int mem_type) { + BUILD_BUG_ON(__builtin_constant_p(mem_type) + && mem_type >= TTM_NUM_MEM_TYPES); return bdev->man_drv[mem_type]; } static inline void ttm_set_driver_manager(struct ttm_device *bdev, int type, struct ttm_resource_manager *manager) { + BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES); bdev->man_drv[type] = manager; } diff --git a/include/drm/ttm/ttm_range_manager.h b/include/drm/ttm/ttm_range_manager.h index 22b6fa42ac20..7963b957e9ef 100644 --- a/include/drm/ttm/ttm_range_manager.h +++ b/include/drm/ttm/ttm_range_manager.h @@ -4,6 +4,7 @@ #define _TTM_RANGE_MANAGER_H_ #include +#include #include /** @@ -33,10 +34,23 @@ to_ttm_range_mgr_node(struct ttm_resource *res) return container_of(res, struct ttm_range_mgr_node, base); } -int ttm_range_man_init(struct ttm_device *bdev, +int ttm_range_man_init_nocheck(struct ttm_device *bdev, unsigned type, bool use_tt, unsigned long p_size); -int ttm_range_man_fini(struct ttm_device *bdev, +int ttm_range_man_fini_nocheck(struct ttm_device *bdev, unsigned type); +static __always_inline int ttm_range_man_init(struct ttm_device *bdev, + unsigned int type, bool use_tt, + unsigned long p_size) +{ + BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES); + return ttm_range_man_init_nocheck(bdev, type, use_tt, p_size); +} +static __always_inline int ttm_range_man_fini(struct ttm_device *bdev, + unsigned int type) +{ + BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES); + return ttm_range_man_fini_nocheck(bdev, type); +} #endif -- cgit v1.2.3 From 87ea95808d53e56b03e620e8f8f3add48899a88d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 10 Sep 2021 15:09:39 +0200 Subject: drm/bridge: Add a function to abstract away panels Display drivers so far need to have a lot of boilerplate to first retrieve either the panel or bridge that they are connected to using drm_of_find_panel_or_bridge(), and then either deal with each with ad-hoc functions or create a drm panel bridge through drm_panel_bridge_add. In order to reduce the boilerplate and hopefully create a path of least resistance towards using the DRM panel bridge layer, let's create the function devm_drm_of_get_bridge() to reduce that boilerplate. Signed-off-by: Maxime Ripard Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210910130941.1740182-2-maxime@cerno.tech --- drivers/gpu/drm/drm_bridge.c | 41 +++++++++++++++++++++++++++++++++++++---- drivers/gpu/drm/drm_of.c | 3 +++ include/drm/drm_bridge.h | 2 ++ 3 files changed, 42 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index a8ed66751c2d..4c68733fa660 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "drm_crtc_internal.h" @@ -51,10 +52,8 @@ * * Display drivers are responsible for linking encoders with the first bridge * in the chains. This is done by acquiring the appropriate bridge with - * of_drm_find_bridge() or drm_of_find_panel_or_bridge(), or creating it for a - * panel with drm_panel_bridge_add_typed() (or the managed version - * devm_drm_panel_bridge_add_typed()). Once acquired, the bridge shall be - * attached to the encoder with a call to drm_bridge_attach(). + * devm_drm_of_get_bridge(). Once acquired, the bridge shall be attached to the + * encoder with a call to drm_bridge_attach(). * * Bridges are responsible for linking themselves with the next bridge in the * chain, if any. This is done the same way as for encoders, with the call to @@ -1233,6 +1232,40 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_drm_find_bridge); + +/** + * devm_drm_of_get_bridge - Return next bridge in the chain + * @dev: device to tie the bridge lifetime to + * @np: device tree node containing encoder output ports + * @port: port in the device tree node + * @endpoint: endpoint in the device tree node + * + * Given a DT node's port and endpoint number, finds the connected node + * and returns the associated bridge if any, or creates and returns a + * drm panel bridge instance if a panel is connected. + * + * Returns a pointer to the bridge if successful, or an error pointer + * otherwise. + */ +struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, + struct device_node *np, + u32 port, u32 endpoint) +{ + struct drm_bridge *bridge; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(np, port, endpoint, + &panel, &bridge); + if (ret) + return ERR_PTR(ret); + + if (panel) + bridge = devm_drm_panel_bridge_add(dev, panel); + + return bridge; +} +EXPORT_SYMBOL(devm_drm_of_get_bridge); #endif MODULE_AUTHOR("Ajay Kumar "); diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 997b8827fed2..37c34146eea8 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -231,6 +231,9 @@ EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); * return either the associated struct drm_panel or drm_bridge device. Either * @panel or @bridge must not be NULL. * + * This function is deprecated and should not be used in new drivers. Use + * devm_drm_of_get_bridge() instead. + * * Returns zero if successful, or one of the standard error codes if it fails. */ int drm_of_find_panel_or_bridge(const struct device_node *np, diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 46bdfa48c413..9cdbd209388e 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -911,6 +911,8 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, struct drm_panel *panel, u32 connector_type); +struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, struct device_node *node, + u32 port, u32 endpoint); struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge); #endif -- cgit v1.2.3