/** * struct drm_mode_object - base structure for modeset objects * @id: userspace visible identifier * @type: type of the object, one of DRM_MODE_OBJECT\_\* * @properties: properties attached to this object, including values * @refcount: reference count for objects which with dynamic lifetime * @free_cb: free function callback, only set for objects with dynamic lifetime * * Base structure for modeset objects visible to userspace. Objects can be * looked up using drm_mode_object_find(). Besides basic uapi interface * properties like @id and @type it provides two services: * * - It tracks attached properties and their values. This is used by &drm_crtc, * &drm_plane and &drm_connector. Properties are attached by calling * drm_object_attach_property() before the object is visible to userspace. * * - For objects with dynamic lifetimes (as indicated by a non-NULL @free_cb) it * provides reference counting through drm_mode_object_get() and * drm_mode_object_put(). This is used by &drm_framebuffer, &drm_connector * and &drm_property_blob. These objects provide specialized reference * counting wrappers. */ structdrm_mode_object { uint32_t id; uint32_t type; structdrm_object_properties *properties; structkrefrefcount; void (*free_cb)(struct kref *kref); };
/** * struct drm_object_properties - property tracking for &drm_mode_object */ structdrm_object_properties { /** * @count: number of valid properties, must be less than or equal to * DRM_OBJECT_MAX_PROPERTY. */
int count; /** * @properties: Array of pointers to &drm_property. * * NOTE: if we ever start dynamically destroying properties (ie. * not at drm_mode_config_cleanup() time), then we'd have to do * a better job of detaching property from mode objects to avoid * dangling property pointers: */ structdrm_property *properties[DRM_OBJECT_MAX_PROPERTY];
/** * @values: Array to store the property values, matching @properties. Do * not read/write values directly, but use * drm_object_property_get_value() and drm_object_property_set_value(). * * Note that atomic drivers do not store mutable properties in this * array, but only the decoded values in the corresponding state * structure. The decoding is done using the &drm_crtc.atomic_get_property and * &drm_crtc.atomic_set_property hooks for &struct drm_crtc. For * &struct drm_plane the hooks are &drm_plane_funcs.atomic_get_property and * &drm_plane_funcs.atomic_set_property. And for &struct drm_connector * the hooks are &drm_connector_funcs.atomic_get_property and * &drm_connector_funcs.atomic_set_property . * * Hence atomic drivers should not use drm_object_property_set_value() * and drm_object_property_get_value() on mutable objects, i.e. those * without the DRM_MODE_PROP_IMMUTABLE flag set. * * For atomic drivers the default value of properties is stored in this * array, so drm_object_property_get_default_value can be used to * retrieve it. */ uint64_t values[DRM_OBJECT_MAX_PROPERTY]; };
/** * struct drm_property - modeset object property * * This structure represent a modeset object property. It combines both the name * of the property with the set of permissible values. This means that when a * driver wants to use a property with the same name on different objects, but * with different value ranges, then it must create property for each one. An * example would be rotation of &drm_plane, when e.g. the primary plane cannot * be rotated. But if both the name and the value range match, then the same * property structure can be instantiated multiple times for the same object. * Userspace must be able to cope with this and cannot assume that the same * symbolic property will have the same modeset object ID on all modeset * objects. * * Properties are created by one of the special functions, as explained in * detail in the @flags structure member. * * To actually expose a property it must be attached to each object using * drm_object_attach_property(). Currently properties can only be attached to * &drm_connector, &drm_crtc and &drm_plane. * * Properties are also used as the generic metadatatransport for the atomic * IOCTL. Everything that was set directly in structures in the legacy modeset * IOCTLs (like the plane source or destination windows, or e.g. the links to * the CRTC) is exposed as a property with the DRM_MODE_PROP_ATOMIC flag set. */ structdrm_property { /** * @head: per-device list of properties, for cleanup. */ structlist_headhead;
/** * @base: base KMS object */ structdrm_mode_objectbase; /** * @flags: * * Property flags and type. A property needs to be one of the following * types: * * DRM_MODE_PROP_RANGE * Range properties report their minimum and maximum admissible unsigned values. * The KMS core verifies that values set by application fit in that * range. The range is unsigned. Range properties are created using * drm_property_create_range(). * * DRM_MODE_PROP_SIGNED_RANGE * Range properties report their minimum and maximum admissible unsigned values. * The KMS core verifies that values set by application fit in that * range. The range is signed. Range properties are created using * drm_property_create_signed_range(). * * DRM_MODE_PROP_ENUM * Enumerated properties take a numerical value that ranges from 0 to * the number of enumerated values defined by the property minus one, * and associate a free-formed string name to each value. Applications * can retrieve the list of defined value-name pairs and use the * numerical value to get and set property instance values. Enum * properties are created using drm_property_create_enum(). * * DRM_MODE_PROP_BITMASK * Bitmask properties are enumeration properties that additionally * restrict all enumerated values to the 0..63 range. Bitmask property * instance values combine one or more of the enumerated bits defined * by the property. Bitmask properties are created using * drm_property_create_bitmask(). * * DRM_MODE_PROP_OBJECT * Object properties are used to link modeset objects. This is used * extensively in the atomic support to create the display pipeline, * by linking &drm_framebuffer to &drm_plane, &drm_plane to * &drm_crtc and &drm_connector to &drm_crtc. An object property can * only link to a specific type of &drm_mode_object, this limit is * enforced by the core. Object properties are created using * drm_property_create_object(). * * Object properties work like blob properties, but in a more * general fashion. They are limited to atomic drivers and must have * the DRM_MODE_PROP_ATOMIC flag set. * DRM_MODE_PROP_BLOB * Blob properties store a binary blob without any format restriction. * The binary blobs are created as KMS standalone objects, and blob * property instance values store the ID of their associated blob * object. Blob properties are created by calling * drm_property_create() with DRM_MODE_PROP_BLOB as the type. * * Actual blob objects to contain blob data are created using * drm_property_create_blob(), or through the corresponding IOCTL. * * Besides the built-in limit to only accept blob objects blob * properties work exactly like object properties. The only reasons * blob properties exist is backwards compatibility with existing * userspace. * * In addition a property can have any combination of the below flags: * * DRM_MODE_PROP_ATOMIC * Set for properties which encode atomic modeset state. Such * properties are not exposed to legacy userspace. * * DRM_MODE_PROP_IMMUTABLE * Set for properties whose values cannot be changed by * userspace. The kernel is allowed to update the value of these * properties. This is generally used to expose probe state to * userspace, e.g. the EDID, or the connector path property on DP * MST sinks. Kernel can update the value of an immutable property * by calling drm_object_property_set_value(). */ uint32_t flags; /** * @name: symbolic name of the properties */ char name[DRM_PROP_NAME_LEN]; /** * @num_values: size of the @values array. */ uint32_t num_values; /** * @values: * * Array with limits and values for the property. The * interpretation of these limits is dependent upon the type per @flags. */ uint64_t *values; /** * @dev: DRM device */ structdrm_device *dev; /** * @enum_list: * * List of &drm_prop_enum_list structures with the symbolic names for * enum and bitmask values. */ structlist_headenum_list; };
/** * struct drm_device - DRM device structure * * This structure represent a complete card that * may contain multiple heads. */ structdrm_device { /** @if_version: Highest interface version set */ int if_version;
/** @ref: Object ref-count */ structkrefref; /** @dev: Device structure of bus-device */ structdevice *dev; /** * @managed: * * Managed resources linked to the lifetime of this &drm_device as * tracked by @ref. */ struct { /** @managed.resources: managed resources list */ structlist_headresources; /** @managed.final_kfree: pointer for final kfree() call */ void *final_kfree; /** @managed.lock: protects @managed.resources */ spinlock_t lock; } managed; /** @driver: DRM driver managing the device */ conststructdrm_driver *driver; /** * @dev_private: * * DRM driver private data. This is deprecated and should be left set to * NULL. * * Instead of using this pointer it is recommended that drivers use * devm_drm_dev_alloc() and embed struct &drm_device in their larger * per-device structure. */ void *dev_private; /** * @primary: * * Primary node. Drivers should not interact with this * directly. debugfs interfaces can be registered with * drm_debugfs_add_file(), and sysfs should be directly added on the * hardware (and not character device node) struct device @dev. */ structdrm_minor *primary; /** * @render: * * Render node. Drivers should not interact with this directly ever. * Drivers should not expose any additional interfaces in debugfs or * sysfs on this node. */ structdrm_minor *render; /** @accel: Compute Acceleration node */ structdrm_minor *accel; /** * @registered: * * Internally used by drm_dev_register() and drm_connector_register(). */ bool registered; /** * @master: * * Currently active master for this device. * Protected by &master_mutex */ structdrm_master *master; /** * @driver_features: per-device driver features * * Drivers can clear specific flags here to disallow * certain features on a per-device basis while still * sharing a single &struct drm_driver instance across * all devices. */ u32 driver_features; /** * @unplugged: * * Flag to tell if the device has been unplugged. * See drm_dev_enter() and drm_dev_is_unplugged(). */ bool unplugged; /** @anon_inode: inode for private address-space */ structinode *anon_inode; /** @unique: Unique name of the device */ char *unique; /** * @struct_mutex: * * Lock for others (not &drm_minor.master and &drm_file.is_master) * * WARNING: * Only drivers annotated with DRIVER_LEGACY should be using this. */ structmutexstruct_mutex; /** * @master_mutex: * * Lock for &drm_minor.master and &drm_file.is_master */ structmutexmaster_mutex; /** * @open_count: * * Usage counter for outstanding files open, * protected by drm_global_mutex */ atomic_t open_count; /** @filelist_mutex: Protects @filelist. */ structmutexfilelist_mutex; /** * @filelist: * * List of userspace clients, linked through &drm_file.lhead. */ structlist_headfilelist; /** * @filelist_internal: * * List of open DRM files for in-kernel clients. * Protected by &filelist_mutex. */ structlist_headfilelist_internal; /** * @clientlist_mutex: * * Protects &clientlist access. */ structmutexclientlist_mutex; /** * @clientlist: * * List of in-kernel clients. Protected by &clientlist_mutex. */ structlist_headclientlist; /** * @vblank_disable_immediate: * * If true, vblank interrupt will be disabled immediately when the * refcount drops to zero, as opposed to via the vblank disable * timer. * * This can be set to true it the hardware has a working vblank counter * with high-precision timestamping (otherwise there are races) and the * driver uses drm_crtc_vblank_on() and drm_crtc_vblank_off() * appropriately. See also @max_vblank_count and * &drm_crtc_funcs.get_vblank_counter. */ bool vblank_disable_immediate; /** * @vblank: * * Array of vblank tracking structures, one per &struct drm_crtc. For * historical reasons (vblank support predates kernel modesetting) this * is free-standing and not part of &struct drm_crtc itself. It must be * initialized explicitly by calling drm_vblank_init(). */ structdrm_vblank_crtc *vblank; /** * @vblank_time_lock: * * Protects vblank count and time updates during vblank enable/disable */ spinlock_t vblank_time_lock; /** * @vbl_lock: Top-level vblank references lock, wraps the low-level * @vblank_time_lock. */ spinlock_t vbl_lock; /** * @max_vblank_count: * * Maximum value of the vblank registers. This value +1 will result in a * wrap-around of the vblank register. It is used by the vblank core to * handle wrap-arounds. * * If set to zero the vblank core will try to guess the elapsed vblanks * between times when the vblank interrupt is disabled through * high-precision timestamps. That approach is suffering from small * races and imprecision over longer time periods, hence exposing a * hardware vblank counter is always recommended. * * This is the statically configured device wide maximum. The driver * can instead choose to use a runtime configurable per-crtc value * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count * must be left at zero. See drm_crtc_set_max_vblank_count() on how * to use the per-crtc value. * * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. */ u32 max_vblank_count; /** @vblank_event_list: List of vblank events */ structlist_headvblank_event_list; /** * @event_lock: * * Protects @vblank_event_list and event delivery in * general. See drm_send_event() and drm_send_event_locked(). */ spinlock_t event_lock; /** @num_crtcs: Number of CRTCs on this device */ unsignedint num_crtcs; /** @mode_config: Current mode config */ structdrm_mode_configmode_config; /** @object_name_lock: GEM information */ structmutexobject_name_lock; /** @object_name_idr: GEM information */ structidrobject_name_idr; /** @vma_offset_manager: GEM information */ structdrm_vma_offset_manager *vma_offset_manager; /** @vram_mm: VRAM MM memory manager */ structdrm_vram_mm *vram_mm; /** * @switch_power_state: * * Power state of the client. * Used by drivers supporting the switcheroo driver. * The state is maintained in the * &vga_switcheroo_client_ops.set_gpu_state callback */ enum switch_power_state switch_power_state; /** * @fb_helper: * * Pointer to the fbdev emulation structure. * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini(). */ structdrm_fb_helper *fb_helper; /** * @debugfs_mutex: * * Protects &debugfs_list access. */ structmutexdebugfs_mutex; /** * @debugfs_list: * * List of debugfs files to be created by the DRM device. The files * must be added during drm_dev_register(). */ structlist_headdebugfs_list; /* Everything below here is for legacy driver, never use! */ /* private: */ #if IS_ENABLED(CONFIG_DRM_LEGACY) /* List of devices per driver for stealth attach cleanup */ structlist_headlegacy_dev_list;
#ifdef __alpha__ /** @hose: PCI hose, only used on ALPHA platforms. */ structpci_controller *hose; #endif
/* AGP data */ structdrm_agp_head *agp; /* Context handle management - linked list of context handles */ structlist_headctxlist; /* Context handle management - mutex for &ctxlist */ structmutexctxlist_mutex; /* Context handle management */ structidrctx_idr; /* Memory management - linked list of regions */ structlist_headmaplist; /* Memory management - user token hash table for maps */ structdrm_open_hashmap_hash; /* Context handle management - list of vmas (for debugging) */ structlist_headvmalist; /* Optional pointer for DMA support */ structdrm_device_dma *dma; /* Context swapping flag */ __volatile__ long context_flag; /* Last current context */ int last_context; /* Lock for &buf_use and a few other things. */ spinlock_t buf_lock; /* Usage counter for buffers in use -- cannot alloc */ int buf_use; /* Buffer allocation in progress */ atomic_t buf_alloc; struct { int context; structdrm_hw_lock *lock; } sigdata; structdrm_local_map *agp_buffer_map; unsignedint agp_buffer_token; /* Scatter gather memory */ structdrm_sg_mem *sg; /* IRQs */ bool irq_enabled; int irq; #endif };
/* * FIXME: Not sure we want to have drm_minor here in the end, but to avoid * header include loops we need it here for now. */
/* Note that the order of this enum is ABI (it determines * /dev/dri/renderD* numbers). * * Setting DRM_MINOR_ACCEL to 32 gives enough space for more drm minors to * be implemented before we hit any future */ enum drm_minor_type { DRM_MINOR_PRIMARY, DRM_MINOR_CONTROL, DRM_MINOR_RENDER, DRM_MINOR_ACCEL = 32, };
/** * struct drm_minor - DRM device minor structure * * This structure represents a DRM minor number for device nodes in /dev. * Entirely opaque to drivers and should never be inspected directly by drivers. * Drivers instead should only interact with &struct drm_file and of course * &struct drm_device, which is also where driver-private data and resources can * be attached to. */ structdrm_minor { /* private: */ int index; /* Minor device number */ int type; /* Control or render or accel */ structdevice *kdev;/* Linux device */ structdrm_device *dev;
/** * struct drm_debugfs_info - debugfs info list entry * * This structure represents a debugfs file to be created by the drm * core. 描述debugfs文件信息 */ structdrm_debugfs_info { /** @name: File name */ constchar *name;
/** * @show: * * Show callback. &seq_file->private will be set to the &struct * drm_debugfs_entry corresponding to the instance of this info * on a given &struct drm_device. */ int (*show)(struct seq_file*, void*);
/** @driver_features: Required driver features for this entry. */ u32 driver_features;
/** @data: Driver-private data, should not be device-specific. */ void *data; };
/** * struct drm_debugfs_entry - Per-device debugfs node structure * * This structure represents a debugfs file, as an instantiation of a &struct * drm_debugfs_info on a &struct drm_device. */ structdrm_debugfs_entry { /** @dev: &struct drm_device for this node. */ structdrm_device *dev;
/** @file: Template for this node. */ structdrm_debugfs_infofile;
/** @list: Linked list of all device nodes. */ structlist_headlist;// 链表节点,用于将当节点添加到drm设备的debugfs_list链表中 };
/** * struct drm_mode_config - Mode configuration control structure * @min_width: minimum fb pixel width on this device * @min_height: minimum fb pixel height on this device * @max_width: maximum fb pixel width on this device * @max_height: maximum fb pixel height on this device * @funcs: core driver provided mode setting functions * @poll_enabled: track polling support for this device * @poll_running: track polling status for this device * @delayed_event: track delayed poll uevent deliver for this device * @output_poll_work: delayed work for polling in process context * @preferred_depth: preferred RBG pixel depth, used by fb helpers * @prefer_shadow: hint to userspace to prefer shadow-fb rendering * @cursor_width: hint to userspace for max cursor width * @cursor_height: hint to userspace for max cursor height * @helper_private: mid-layer private data * * Core mode resource tracking structure. All CRTC, encoders, and connectors * enumerated by the driver are added here, as are global properties. Some * global restrictions are also here, e.g. dimension restrictions. * * Framebuffer sizes refer to the virtual screen that can be displayed by * the CRTC. This can be different from the physical resolution programmed. * The minimum width and height, stored in @min_width and @min_height, * describe the smallest size of the framebuffer. It correlates to the * minimum programmable resolution. * The maximum width, stored in @max_width, is typically limited by the * maximum pitch between two adjacent scanlines. The maximum height, stored * in @max_height, is usually only limited by the amount of addressable video * memory. For hardware that has no real maximum, drivers should pick a * reasonable default. * * See also @DRM_SHADOW_PLANE_MAX_WIDTH and @DRM_SHADOW_PLANE_MAX_HEIGHT. */ structdrm_mode_config { /** * @mutex: * * This is the big scary modeset BKL which protects everything that * isn't protect otherwise. Scope is unclear and fuzzy, try to remove * anything from under its protection and move it into more well-scoped * locks. * * The one important thing this protects is the use of @acquire_ctx. */ structmutexmutex;
/** * @connection_mutex: * * This protects connector state and the connector to encoder to CRTC * routing chain. * * For atomic drivers specifically this protects &drm_connector.state. */ structdrm_modeset_lockconnection_mutex;
/** * @acquire_ctx: * * Global implicit acquire context used by atomic drivers for legacy * IOCTLs. Deprecated, since implicit locking contexts make it * impossible to use driver-private &struct drm_modeset_lock. Users of * this must hold @mutex. */ structdrm_modeset_acquire_ctx *acquire_ctx;
/** * @idr_mutex: * * Mutex for KMS ID allocation and management. Protects both @object_idr * and @tile_idr. */ structmutexidr_mutex;
/** * @object_idr: * * Main KMS ID tracking object. Use this idr for all IDs, fb, crtc, * connector, modes - just makes life easier to have only one. */ structidrobject_idr; /** * @tile_idr: * * Use this idr for allocating new IDs for tiled sinks like use in some * high-res DP MST screens. */ structidrtile_idr;
/** @fb_lock: Mutex to protect fb the global @fb_list and @num_fb. */ structmutexfb_lock; /** @num_fb: Number of entries on @fb_list. */ int num_fb; /** @fb_list: List of all &struct drm_framebuffer. */ structlist_headfb_list;
/** * @connector_list_lock: Protects @num_connector and * @connector_list and @connector_free_list. */ spinlock_t connector_list_lock; /** * @num_connector: Number of connectors on this device. Protected by * @connector_list_lock. */ int num_connector; /** * @connector_ida: ID allocator for connector indices. */ structidaconnector_ida; /** * @connector_list: * * List of connector objects linked with &drm_connector.head. Protected * by @connector_list_lock. Only use drm_for_each_connector_iter() and * &struct drm_connector_list_iter to walk this list. */ structlist_headconnector_list; /** * @connector_free_list: * * List of connector objects linked with &drm_connector.free_head. * Protected by @connector_list_lock. Used by * drm_for_each_connector_iter() and * &struct drm_connector_list_iter to savely free connectors using * @connector_free_work. */ structllist_headconnector_free_list; /** * @connector_free_work: Work to clean up @connector_free_list. */ structwork_structconnector_free_work; /** * @num_encoder: * * Number of encoders on this device. This is invariant over the * lifetime of a device and hence doesn't need any locks. */ int num_encoder; /** * @encoder_list: * * List of encoder objects linked with &drm_encoder.head. This is * invariant over the lifetime of a device and hence doesn't need any * locks. */ structlist_headencoder_list;
/** * @num_total_plane: * * Number of universal (i.e. with primary/curso) planes on this device. * This is invariant over the lifetime of a device and hence doesn't * need any locks. */ int num_total_plane; /** * @plane_list: * * List of plane objects linked with &drm_plane.head. This is invariant * over the lifetime of a device and hence doesn't need any locks. */ structlist_headplane_list;
/** * @num_crtc: * * Number of CRTCs on this device linked with &drm_crtc.head. This is invariant over the lifetime * of a device and hence doesn't need any locks. */ int num_crtc; /** * @crtc_list: * * List of CRTC objects linked with &drm_crtc.head. This is invariant * over the lifetime of a device and hence doesn't need any locks. */ structlist_headcrtc_list;
/** * @property_list: * * List of property type objects linked with &drm_property.head. This is * invariant over the lifetime of a device and hence doesn't need any * locks. */ structlist_headproperty_list; /** * @privobj_list: * * List of private objects linked with &drm_private_obj.head. This is * invariant over the lifetime of a device and hence doesn't need any * locks. */ structlist_headprivobj_list;
int min_width, min_height; int max_width, max_height; conststructdrm_mode_config_funcs *funcs;
/** * @blob_lock: * * Mutex for blob property allocation and management, protects * @property_blob_list and &drm_file.blobs. */ structmutexblob_lock;
/** * @property_blob_list: * * List of all the blob property objects linked with * &drm_property_blob.head. Protected by @blob_lock. */ structlist_headproperty_blob_list;
/* pointers to standard properties */
/** * @edid_property: Default connector property to hold the EDID of the * currently connected sink, if any. */ structdrm_property *edid_property; /** * @dpms_property: Default connector property to control the * connector's DPMS state. */ structdrm_property *dpms_property; /** * @path_property: Default connector property to hold the DP MST path * for the port. */ structdrm_property *path_property; .... 大量的structdrm_property /** * @hdcp_content_type_property: DRM ENUM property for type of * Protected Content. */ structdrm_property *hdcp_content_type_property;
/** * @prefer_shadow_fbdev: * * Hint to framebuffer emulation to prefer shadow-fb rendering. */ bool prefer_shadow_fbdev;
/** * @quirk_addfb_prefer_xbgr_30bpp: * * Special hack for legacy ADDFB to keep nouveau userspace happy. Should * only ever be set by the nouveau kernel driver. */ bool quirk_addfb_prefer_xbgr_30bpp;
/** * @quirk_addfb_prefer_host_byte_order: * * When set to true drm_mode_addfb() will pick host byte order * pixel_format when calling drm_mode_addfb2(). This is how * drm_mode_addfb() should have worked from day one. It * didn't though, so we ended up with quirks in both kernel * and userspace drivers to deal with the broken behavior. * Simply fixing drm_mode_addfb() unconditionally would break * these drivers, so add a quirk bit here to allow drivers * opt-in. */ bool quirk_addfb_prefer_host_byte_order;
/** * @async_page_flip: Does this device support async flips on the primary * plane? */ bool async_page_flip;
/** * @fb_modifiers_not_supported: * * When this flag is set, the DRM device will not expose modifier * support to userspace. This is only used by legacy drivers that infer * the buffer layout through heuristics without using modifiers. New * drivers shall not set fhis flag. */ bool fb_modifiers_not_supported;
/** * @normalize_zpos: * * If true the drm core will call drm_atomic_normalize_zpos() as part of * atomic mode checking from drm_atomic_helper_check() */ bool normalize_zpos;
/** * @modifiers_property: Plane property to list support modifier/format * combination. */ structdrm_property *modifiers_property;
/** * @suspend_state: * * Atomic state when suspended. * Set by drm_mode_config_helper_suspend() and cleared by * drm_mode_config_helper_resume(). */ structdrm_atomic_state *suspend_state;
/** * struct drm_mode_config_funcs - basic driver provided mode setting functions * * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that * involve drivers. */ structdrm_mode_config_funcs { /** * @fb_create: * * Create a new framebuffer object. The core does basic checks on the * requested metadata, but most of that is left to the driver. See * &struct drm_mode_fb_cmd2 for details. * * To validate the pixel format and modifier drivers can use * drm_any_plane_has_format() to make sure at least one plane supports * the requested values. Note that the driver must first determine the * actual modifier used if the request doesn't have it specified, * ie. when (@mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0. * * IMPORTANT: These implied modifiers for legacy userspace must be * stored in struct &drm_framebuffer, including all relevant metadata * like &drm_framebuffer.pitches and &drm_framebuffer.offsets if the * modifier enables additional planes beyond the fourcc pixel format * code. This is required by the GETFB2 ioctl. * * If the parameters are deemed valid and the backing storage objects in * the underlying memory manager all exist, then the driver allocates * a new &drm_framebuffer structure, subclassed to contain * driver-specific information (like the internal native buffer object * references). It also needs to fill out all relevant metadata, which * should be done by calling drm_helper_mode_fill_fb_struct(). * * The initialization is finalized by calling drm_framebuffer_init(), * which registers the framebuffer and makes it accessible to other * threads. * * RETURNS: * * A new framebuffer with an initial reference count of 1 or a negative * error code encoded with ERR_PTR(). */ structdrm_framebuffer *(*fb_create)(structdrm_device *dev, structdrm_file *file_priv, conststructdrm_mode_fb_cmd2 *mode_cmd); /** * @get_format_info: * * Allows a driver to return custom format information for special * fb layouts (eg. ones with auxiliary compression control planes). * * RETURNS: * * The format information specific to the given fb metadata, or * NULL if none is found. */ conststructdrm_format_info *(*get_format_info)(conststructdrm_mode_fb_cmd2 *mode_cmd);
/** * @output_poll_changed: * * Callback used by helpers to inform the driver of output configuration * changes. * * Drivers implementing fbdev emulation use drm_kms_helper_hotplug_event() * to call this hook to inform the fbdev helper of output changes. * * 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);
/** * @mode_valid: * * Device specific validation of display modes. Can be used to reject * modes that can never be supported. Only device wide constraints can * be checked here. crtc/encoder/bridge/connector specific constraints * should be checked in the .mode_valid() hook for each specific object. */ enumdrm_mode_status(*mode_valid)(struct drm_device *dev, const struct drm_display_mode *mode); /** * @atomic_check: * * This is the only hook to validate an atomic modeset update. This * function must reject any modeset and state changes which the hardware * or driver doesn't support. This includes but is of course not limited * to: * * - Checking that the modes, framebuffers, scaling and placement * requirements and so on are within the limits of the hardware. * * - Checking that any hidden shared resources are not oversubscribed. * This can be shared PLLs, shared lanes, overall memory bandwidth, * display fifo space (where shared between planes or maybe even * CRTCs). * * - Checking that virtualized resources exported to userspace are not * oversubscribed. For various reasons it can make sense to expose * more planes, crtcs or encoders than which are physically there. One * example is dual-pipe operations (which generally should be hidden * from userspace if when lockstepped in hardware, exposed otherwise), * where a plane might need 1 hardware plane (if it's just on one * pipe), 2 hardware planes (when it spans both pipes) or maybe even * shared a hardware plane with a 2nd plane (if there's a compatible * plane requested on the area handled by the other pipe). * * - Check that any transitional state is possible and that if * requested, the update can indeed be done in the vblank period * without temporarily disabling some functions. * * - Check any other constraints the driver or hardware might have. * * - This callback also needs to correctly fill out the &drm_crtc_state * in this update to make sure that drm_atomic_crtc_needs_modeset() * reflects the nature of the possible update and returns true if and * only if the update cannot be applied without tearing within one * vblank on that CRTC. The core uses that information to reject * updates which require a full modeset (i.e. blanking the screen, or * at least pausing updates for a substantial amount of time) if * userspace has disallowed that in its request. * * - The driver also does not need to repeat basic input validation * like done for the corresponding legacy entry points. The core does * that before calling this hook. * * See the documentation of @atomic_commit for an exhaustive list of * error conditions which don't have to be checked at the in this * callback. * * See the documentation for &struct drm_atomic_state for how exactly * an atomic modeset update is described. * * Drivers using the atomic helpers can implement this hook using * drm_atomic_helper_check(), or one of the exported sub-functions of * it. * * RETURNS: * * 0 on success or one of the below negative error codes: * * - -EINVAL, if any of the above constraints are violated. * * - -EDEADLK, when returned from an attempt to acquire an additional * &drm_modeset_lock through drm_modeset_lock(). * * - -ENOMEM, if allocating additional state sub-structures failed due * to lack of memory. * * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. * This can either be due to a pending signal, or because the driver * needs to completely bail out to recover from an exceptional * situation like a GPU hang. From a userspace point all errors are * treated equally. */ int (*atomic_check)(struct drm_device *dev, struct drm_atomic_state *state);
/** * @atomic_commit: * * This is the only hook to commit an atomic modeset update. The core * guarantees that @atomic_check has been called successfully before * calling this function, and that nothing has been changed in the * interim. * * See the documentation for &struct drm_atomic_state for how exactly * an atomic modeset update is described. * * Drivers using the atomic helpers can implement this hook using * drm_atomic_helper_commit(), or one of the exported sub-functions of * it. * * Nonblocking commits (as indicated with the nonblock parameter) must * do any preparatory work which might result in an unsuccessful commit * in the context of this callback. The only exceptions are hardware * errors resulting in -EIO. But even in that case the driver must * ensure that the display pipe is at least running, to avoid * compositors crashing when pageflips don't work. Anything else, * specifically committing the update to the hardware, should be done * without blocking the caller. For updates which do not require a * modeset this must be guaranteed. * * The driver must wait for any pending rendering to the new * framebuffers to complete before executing the flip. It should also * wait for any pending rendering from other drivers if the underlying * buffer is a shared dma-buf. Nonblocking commits must not wait for * rendering in the context of this callback. * * An application can request to be notified when the atomic commit has * completed. These events are per-CRTC and can be distinguished by the * CRTC index supplied in &drm_event to userspace. * * The drm core will supply a &struct drm_event in each CRTC's * &drm_crtc_state.event. See the documentation for * &drm_crtc_state.event for more details about the precise semantics of * this event. * * NOTE: * * Drivers are not allowed to shut down any display pipe successfully * enabled through an atomic commit on their own. Doing so can result in * compositors crashing if a page flip is suddenly rejected because the * pipe is off. * * RETURNS: * * 0 on success or one of the below negative error codes: * * - -EBUSY, if a nonblocking updated is requested and there is * an earlier updated pending. Drivers are allowed to support a queue * of outstanding updates, but currently no driver supports that. * Note that drivers must wait for preceding updates to complete if a * synchronous update is requested, they are not allowed to fail the * commit in that case. * * - -ENOMEM, if the driver failed to allocate memory. Specifically * this can happen when trying to pin framebuffers, which must only * be done when committing the state. * * - -ENOSPC, as a refinement of the more generic -ENOMEM to indicate * that the driver has run out of vram, iommu space or similar GPU * address space needed for framebuffer. * * - -EIO, if the hardware completely died. * * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. * This can either be due to a pending signal, or because the driver * needs to completely bail out to recover from an exceptional * situation like a GPU hang. From a userspace point of view all errors are * treated equally. * * This list is exhaustive. Specifically this hook is not allowed to * return -EINVAL (any invalid requests should be caught in * @atomic_check) or -EDEADLK (this function must not acquire * additional modeset locks). */ int (*atomic_commit)(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock); /** * @atomic_state_alloc: * * This optional hook can be used by drivers that want to subclass struct * &drm_atomic_state to be able to track their own driver-private global * state easily. If this hook is implemented, drivers must also * implement @atomic_state_clear and @atomic_state_free. * * Subclassing of &drm_atomic_state is deprecated in favour of using * &drm_private_state and &drm_private_obj. * * RETURNS: * * A new &drm_atomic_state on success or NULL on failure. */ structdrm_atomic_state *(*atomic_state_alloc)(structdrm_device *dev);
/** * @atomic_state_clear: * * This hook must clear any driver private state duplicated into the * passed-in &drm_atomic_state. This hook is called when the caller * encountered a &drm_modeset_lock deadlock and needs to drop all * already acquired locks as part of the deadlock avoidance dance * implemented in drm_modeset_backoff(). * * Any duplicated state must be invalidated since a concurrent atomic * update might change it, and the drm atomic interfaces always apply * updates as relative changes to the current state. * * Drivers that implement this must call drm_atomic_state_default_clear() * to clear common state. * * Subclassing of &drm_atomic_state is deprecated in favour of using * &drm_private_state and &drm_private_obj. */ void (*atomic_state_clear)(struct drm_atomic_state *state);
/** * @atomic_state_free: * * This hook needs driver private resources and the &drm_atomic_state * itself. Note that the core first calls drm_atomic_state_clear() to * avoid code duplicate between the clear and free hooks. * * Drivers that implement this must call * drm_atomic_state_default_release() to release common resources. * * Subclassing of &drm_atomic_state is deprecated in favour of using * &drm_private_state and &drm_private_obj. */ void (*atomic_state_free)(struct drm_atomic_state *state); };
/** * struct drm_driver - DRM driver structure * * This structure represent the common code for a family of cards. There will be * one &struct drm_device for each card present in this family. It contains lots * of vfunc entries, and a pile of those probably should be moved to more * appropriate places like &drm_mode_config_funcs or into a new operations * structure for GEM drivers. */ structdrm_driver { /** * @load: * * Backward-compatible driver callback to complete initialization steps * after the driver is registered. For this reason, may suffer from * race conditions and its use is deprecated for new drivers. It is * therefore only supported for existing drivers not yet converted to * the new scheme. See devm_drm_dev_alloc() and drm_dev_register() for * proper and race-free way to set up a &struct drm_device. * * This is deprecated, do not use! * * Returns: * * Zero on success, non-zero value on failure. */ int (*load) (struct drm_device *, unsignedlong flags);
/** * @open: * * Driver callback when a new &struct drm_file is opened. Useful for * setting up driver-private data structures like buffer allocators, * execution contexts or similar things. Such driver-private resources * must be released again in @postclose. * * Since the display/modeset side of DRM can only be owned by exactly * one &struct drm_file (see &drm_file.is_master and &drm_device.master) * there should never be a need to set up any modeset related resources * in this callback. Doing so would be a driver design bug. * * Returns: * * 0 on success, a negative error code on failure, which will be * promoted to userspace as the result of the open() system call. */ int (*open) (struct drm_device *, struct drm_file *); /** * @postclose: * * One of the driver callbacks when a new &struct drm_file is closed. * Useful for tearing down driver-private data structures allocated in * @open like buffer allocators, execution contexts or similar things. * * Since the display/modeset side of DRM can only be owned by exactly * one &struct drm_file (see &drm_file.is_master and &drm_device.master) * there should never be a need to tear down any modeset related * resources in this callback. Doing so would be a driver design bug. */ void (*postclose) (struct drm_device *, struct drm_file *);
/** * @lastclose: * * Called when the last &struct drm_file has been closed and there's * currently no userspace client for the &struct drm_device. * * Modern drivers should only use this to force-restore the fbdev * framebuffer using drm_fb_helper_restore_fbdev_mode_unlocked(). * Anything else would indicate there's something seriously wrong. * Modern drivers can also use this to execute delayed power switching * state changes, e.g. in conjunction with the :ref:`vga_switcheroo` * infrastructure. * * This is called after @postclose hook has been called. * * NOTE: * * All legacy drivers use this callback to de-initialize the hardware. * This is purely because of the shadow-attach model, where the DRM * kernel driver does not really own the hardware. Instead ownershipe is * handled with the help of userspace through an inheritedly racy dance * to set/unset the VT into raw mode. * * Legacy drivers initialize the hardware in the @firstopen callback, * which isn't even called for modern drivers. */ void (*lastclose) (struct drm_device *);
/** * @unload: * * Reverse the effects of the driver load callback. Ideally, * the clean up performed by the driver should happen in the * reverse order of the initialization. Similarly to the load * hook, this handler is deprecated and its usage should be * dropped in favor of an open-coded teardown function at the * driver layer. See drm_dev_unregister() and drm_dev_put() * for the proper way to remove a &struct drm_device. * * The unload() hook is called right after unregistering * the device. * */ void (*unload) (struct drm_device *);
/** * @release: * * Optional callback for destroying device data after the final * reference is released, i.e. the device is being destroyed. * * This is deprecated, clean up all memory allocations associated with a * &drm_device using drmm_add_action(), drmm_kmalloc() and related * managed resources functions. */ void (*release) (struct drm_device *);
/** * @master_set: * * Called whenever the minor master is set. Only used by vmwgfx. */ void (*master_set)(struct drm_device *dev, struct drm_file *file_priv, bool from_open); /** * @master_drop: * * Called whenever the minor master is dropped. Only used by vmwgfx. */ void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
/** * @gem_create_object: constructor for gem objects * * Hook for allocating the GEM object struct, for use by the CMA * and SHMEM GEM helpers. Returns a GEM object on success, or an * ERR_PTR()-encoded error code otherwise. */ structdrm_gem_object *(*gem_create_object)(structdrm_device *dev, size_tsize);
/** * @prime_handle_to_fd: * * Main PRIME export function. Should be implemented with * drm_gem_prime_handle_to_fd() for GEM based drivers. * * For an in-depth discussion see :ref:`PRIME buffer sharing * documentation <prime_buffer_sharing>`. */ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); /** * @prime_fd_to_handle: * * Main PRIME import function. Should be implemented with * drm_gem_prime_fd_to_handle() for GEM based drivers. * * For an in-depth discussion see :ref:`PRIME buffer sharing * documentation <prime_buffer_sharing>`. */ int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle);
/** * @gem_prime_import: * * Import hook for GEM drivers. * * This defaults to drm_gem_prime_import() if not set. */ structdrm_gem_object * (*gem_prime_import)(structdrm_device *dev, structdma_buf *dma_buf); /** * @gem_prime_import_sg_table: * * Optional hook used by the PRIME helper functions * drm_gem_prime_import() respectively drm_gem_prime_import_dev(). */ structdrm_gem_object *(*gem_prime_import_sg_table)( structdrm_device *dev, structdma_buf_attachment *attach, structsg_table *sgt); /** * @gem_prime_mmap: * * mmap hook for GEM drivers, used to implement dma-buf mmap in the * PRIME helpers. * * This hook only exists for historical reasons. Drivers must use * drm_gem_prime_mmap() to implement it. * * FIXME: Convert all drivers to implement mmap in struct * &drm_gem_object_funcs and inline drm_gem_prime_mmap() into * its callers. This hook should be removed afterwards. */ int (*gem_prime_mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
/** * @dumb_create: * * This creates a new dumb buffer in the driver's backing storage manager (GEM, * TTM or something else entirely) and returns the resulting buffer handle. This * handle can then be wrapped up into a framebuffer modeset object. * * Note that userspace is not allowed to use such objects for render * acceleration - drivers must create their own private ioctls for such a use * case. * * Width, height and depth are specified in the &drm_mode_create_dumb * argument. The callback needs to fill the handle, pitch and size for * the created buffer. * * Called by the user via ioctl. * * Returns: * * Zero on success, negative errno on failure. */ int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); /** * @dumb_map_offset: * * Allocate an offset in the drm device node's address space to be able to * memory map a dumb buffer. * * The default implementation is drm_gem_create_mmap_offset(). GEM based * drivers must not overwrite this. * * Called by the user via ioctl. * * Returns: * * Zero on success, negative errno on failure. */ int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset); /** * @dumb_destroy: * * This destroys the userspace handle for the given dumb backing storage buffer. * Since buffer objects must be reference counted in the kernel a buffer object * won't be immediately freed if a framebuffer modeset object still uses it. * * Called by the user via ioctl. * * The default implementation is drm_gem_dumb_destroy(). GEM based drivers * must not overwrite this. * * Returns: * * Zero on success, negative errno on failure. */ int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle);
/** @major: driver major number */ int major; /** @minor: driver minor number */ int minor; /** @patchlevel: driver patch level */ int patchlevel; /** @name: driver name */ char *name; /** @desc: driver description */ char *desc; /** @date: driver date */ char *date;
/** * @driver_features: * Driver features, see &enum drm_driver_feature. Drivers can disable * some features on a per-instance basis using * &drm_device.driver_features. */ u32 driver_features;
/** * @ioctls: * * Array of driver-private IOCTL description entries. See the chapter on * :ref:`IOCTL support in the userland interfaces * chapter<drm_driver_ioctl>` for the full details. */
conststructdrm_ioctl_desc *ioctls; /** @num_ioctls: Number of entries in @ioctls. */ int num_ioctls;
/** * @fops: * * File operations for the DRM device node. See the discussion in * :ref:`file operations<drm_driver_fops>` for in-depth coverage and * some examples. */ conststructfile_operations *fops;
#ifdef CONFIG_DRM_LEGACY /* Everything below here is for legacy driver, never use! */ /* private: */
int (*firstopen) (struct drm_device *); void (*preclose) (struct drm_device *, struct drm_file *file_priv); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); int (*dma_quiescent) (struct drm_device *); int (*context_dtor) (struct drm_device *dev, int context); irqreturn_t (*irq_handler)(int irq, void *arg); void (*irq_preinstall)(struct drm_device *dev); int (*irq_postinstall)(struct drm_device *dev); void (*irq_uninstall)(struct drm_device *dev); u32 (*get_vblank_counter)(struct drm_device *dev, unsignedint pipe); int (*enable_vblank)(struct drm_device *dev, unsignedint pipe); void (*disable_vblank)(struct drm_device *dev, unsignedint pipe); int dev_priv_size; #endif };
DRIVER_RENDER:Driver supports dedicated render nodes. See also the section on render nodes for details.
DRIVER_ATOMIC:Driver supports the full atomic modesetting userspace API. Drivers which only use atomic internally, but do not support the full userspace API (e.g. not all properties converted to atomic, or multi-plane updates are not guaranteed to be tear-free) should not set this flag.
DRIVER_SYNCOB:Driver supports drm_syncobj for explicit synchronization of command submission.
DRIVER_SYNCOBJ_TIMELINE:Driver supports the timeline flavor of drm_syncobj for explicit synchronization of command submission.
DRIVER_COMPUTE_ACCEL:Driver supports compute acceleration devices. This flag is mutually exclusive with DRIVER_RENDER and DRIVER_MODESET. Devices that support both graphics and compute acceleration should be handled by two drivers that are connected using auxiliary bus.
DRIVER_USE_AGP:Set up DRM AGP support, see drm_agp_init(), the DRM core will manage AGP resources. New drivers don't need this.
DRIVER_LEGACY:Denote a legacy driver using shadow attach. Do not use.
DRIVER_PCI_DMA:Driver is capable of PCI DMA, mapping of PCI DMA buffers to userspace will be enabled. Only for legacy drivers. Do not use.
DRIVER_SG:Driver can perform scatter/gather DMA, allocation and mapping of scatter/gather buffers will be enabled. Only for legacy drivers. Do not use.
DRIVER_HAVE_DMA:Driver supports DMA, the userspace DMA API will be supported. Only for legacy drivers. Do not use.
DRIVER_HAVE_IRQ:Legacy irq support. Only for legacy drivers. Do not use.
/** * drm_sysfs_init - initialize sysfs helpers * * This is used to create the DRM class, which is the implicit parent of any * other top-level DRM sysfs objects. * * You must call drm_sysfs_destroy() to release the allocated resources. * * Return: 0 on success, negative error code on failure. */ intdrm_sysfs_init(void) { int err;
// 创建设备类,此函数的执行会在/sys/class/目录下创建一个新的文件夹drm drm_class = class_create(THIS_MODULE, "drm"); if (IS_ERR(drm_class)) return PTR_ERR(drm_class);
/* * DRM Core * The DRM core module initializes all global DRM objects and makes them * available to drivers. Once setup, drivers can probe their respective * devices. * Currently, core management includes: * - The "DRM-Global" key/value database * - Global ID management for connectors * - DRM major number allocation * - DRM minor management * - DRM sysfs class * - DRM debugfs root * * Furthermore, the DRM core provides dynamic char-dev lookups. For each * interface registered on a DRM device, you can request minor numbers from DRM * core. DRM core takes care of major-number management and char-dev * registration. A stub ->open() callback forwards any open() requests to the * registered minor. */
/* no per-device feature limits by default */ dev->driver_features = ~0u;
if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL) && (drm_core_check_feature(dev, DRIVER_RENDER) || drm_core_check_feature(dev, DRIVER_MODESET))) { DRM_ERROR("DRM driver can't be both a compute acceleration and graphics driver\n"); return -EINVAL; }
/* * DRM Minors * A DRM device can provide several char-dev interfaces on the DRM-Major. Each * of them is represented by a drm_minor object. Depending on the capabilities * of the device-driver, different interfaces are registered. * * Minors can be accessed via dev->$minor_name. This pointer is either * NULL or a valid drm_minor pointer and stays valid as long as the device is * valid. This means, DRM minors have the same life-time as the underlying * device. However, this doesn't mean that the minor is active. Minors are * registered and unregistered dynamically according to device-state. */
static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, unsignedint type) { switch (type) { case DRM_MINOR_PRIMARY: return &dev->primary; case DRM_MINOR_RENDER: return &dev->render; case DRM_MINOR_ACCEL: return &dev->accel; default: BUG(); } }
/** * drm_dev_register - Register DRM device * @dev: Device to register * @flags: Flags passed to the driver's .load() function * * Register the DRM device @dev with the system, advertise device to user-space * and start normal device operation. @dev must be initialized via drm_dev_init() * previously. * * Never call this twice on any device! * * NOTE: To ensure backward compatibility with existing drivers method this * function calls the &drm_driver.load method after registering the device * nodes, creating race conditions. Usage of the &drm_driver.load methods is * therefore deprecated, drivers must perform all initialization before calling * drm_dev_register(). * * RETURNS: * 0 on success, negative error code on failure. */ intdrm_dev_register(struct drm_device *dev, unsignedlong flags) { conststructdrm_driver *driver = dev->driver; int ret; // 如果没有配置load,则校验drm模式配置 if (!driver->load) drm_mode_config_validate(dev);
WARN_ON(!dev->managed.final_kfree);
// 如果需要全局互斥锁,则获取互斥锁 if (drm_dev_needs_global_mutex(dev)) mutex_lock(&drm_global_mutex);
// 直接返回 ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_minors;
// 重点 注册dev->primary这个minor ret = drm_minor_register(dev, DRM_MINOR_PRIMARY); if (ret) goto err_minors;
// 直接返回 ret = drm_minor_register(dev, DRM_MINOR_ACCEL); if (ret) goto err_minors;
ret = create_compat_control_link(dev); if (ret) goto err_minors;
// 设备注册标志设置为true dev->registered = true;
// 如果定义了load,会先执行load if (driver->load) { ret = driver->load(dev, flags); if (ret) goto err_minors; }
if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_register_all(dev);
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->dev ? dev_name(dev->dev) : "virtual device", dev->primary ? dev->primary->index : dev->accel->index);
WARN(crtc->cursor && crtc->funcs->cursor_set, "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set func", crtc->base.id, crtc->name); WARN(crtc->cursor && crtc->funcs->cursor_set2, "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set2 func", crtc->base.id, crtc->name); WARN(crtc->cursor && crtc->funcs->cursor_move, "[CRTC:%d:%s] must not have both a cursor plane and a cursor_move func", crtc->base.id, crtc->name);
if (crtc->primary) { WARN(!(crtc->primary->possible_crtcs & drm_crtc_mask(crtc)), "Bogus primary plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n", crtc->primary->base.id, crtc->primary->name, crtc->base.id, crtc->name); WARN(primary_with_crtc & drm_plane_mask(crtc->primary), "Primary plane [PLANE:%d:%s] used for multiple CRTCs", crtc->primary->base.id, crtc->primary->name); primary_with_crtc |= drm_plane_mask(crtc->primary); } if (crtc->cursor) { WARN(!(crtc->cursor->possible_crtcs & drm_crtc_mask(crtc)), "Bogus cursor plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n", crtc->cursor->base.id, crtc->cursor->name, crtc->base.id, crtc->name); WARN(cursor_with_crtc & drm_plane_mask(crtc->cursor), "Cursor plane [PLANE:%d:%s] used for multiple CRTCs", crtc->cursor->base.id, crtc->cursor->name); cursor_with_crtc |= drm_plane_mask(crtc->cursor); } }
drm_for_each_plane(plane, dev) { if (plane->type == DRM_PLANE_TYPE_PRIMARY) num_primary++; }
WARN(num_primary != dev->mode_config.num_crtc, "Must have as many primary planes as there are CRTCs, but have %u primary planes and %u CRTCs", num_primary, dev->mode_config.num_crtc); }
/* dev->filelist is sorted youngest first, but we want to present * oldest first (i.e. kernel, servers, clients), so walk backwardss. */ mutex_lock(&dev->filelist_mutex); list_for_each_entry_reverse(priv, &dev->filelist, lhead) { structtask_struct *task; bool is_current_master = drm_is_current_master(priv);
rk3399_ROCKPI4B_Android11:/ $ cat /sys/kernel/debug/dri/0/clients command pid dev master a uid magic composer@2.1-se 239 0 y y 1000 0 outputmanager@1 283 0 n n 1000 0 omx@1.0-service 387 0 n n 1046 0 omx@1.0-service 387 0 n n 1046 0 omx@1.0-service 387 0 n n 1046 0
rk3399_ROCKPI4B_Android11:/ $ cat /sys/kernel/debug/dri/0/gem_names name size handles refcount
/** * drm_mode_config_init - DRM mode_configuration structure initialization * @dev: DRM device * * This is the unmanaged version of drmm_mode_config_init() for drivers which * still explicitly call drm_mode_config_cleanup(). * * FIXME: This function is deprecated and drivers should be converted over to * drmm_mode_config_init(). */ staticinlineintdrm_mode_config_init(struct drm_device *dev) { return drmm_mode_config_init(dev); }
/** * drmm_mode_config_init - managed DRM mode_configuration structure * initialization * @dev: DRM device * * Initialize @dev's mode_config structure, used for tracking the graphics * configuration of @dev. * * Since this initializes the modeset locks, no locking is possible. Which is no * problem, since this should happen single threaded at init time. It is the * driver's problem to ensure this guarantee. * * Cleanup is automatically handled through registering drm_mode_config_cleanup * with drmm_add_action(). * * Returns: 0 on success, negative error value on failure. */ intdrmm_mode_config_init(struct drm_device *dev) { int ret;
ret = drm_mode_create_standard_properties(dev); if (ret) { drm_mode_config_cleanup(dev); return ret; }
/* Just to be sure */ dev->mode_config.num_fb = 0; dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; dev->mode_config.num_encoder = 0; dev->mode_config.num_total_plane = 0;
if (IS_ENABLED(CONFIG_LOCKDEP)) { structdrm_modeset_acquire_ctxmodeset_ctx; structww_acquire_ctxresv_ctx; structdma_resvresv; int ret;
dma_resv_init(&resv);
drm_modeset_acquire_init(&modeset_ctx, 0); ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &modeset_ctx); if (ret == -EDEADLK) ret = drm_modeset_backoff(&modeset_ctx);
ww_acquire_init(&resv_ctx, &reservation_ww_class); ret = dma_resv_lock(&resv, &resv_ctx); if (ret == -EDEADLK) dma_resv_lock_slow(&resv, &resv_ctx);