drivers/gpu/drm/drm_managed.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/drm_managed.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/drm_managed.c
Extension
.c
Size
8213 bytes
Lines
322
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct drmres_node {
	struct list_head	entry;
	drmres_release_t	release;
	const char		*name;
	size_t			size;
};

struct drmres {
	struct drmres_node		node;
	/*
	 * Some archs want to perform DMA into kmalloc caches
	 * and need a guaranteed alignment larger than
	 * the alignment of a 64-bit integer.
	 * Thus we use ARCH_DMA_MINALIGN for data[] which will force the same
	 * alignment for struct drmres when allocated by kmalloc().
	 */
	u8 __aligned(ARCH_DMA_MINALIGN) data[];
};

static void free_dr(struct drmres *dr)
{
	kfree_const(dr->node.name);
	kfree(dr);
}

void drm_managed_release(struct drm_device *dev)
{
	struct drmres *dr, *tmp;

	drm_dbg_drmres(dev, "drmres release begin\n");
	list_for_each_entry_safe(dr, tmp, &dev->managed.resources, node.entry) {
		drm_dbg_drmres(dev, "REL %p %s (%zu bytes)\n",
			       dr, dr->node.name, dr->node.size);

		if (dr->node.release)
			dr->node.release(dev, dr->node.size ? *(void **)&dr->data : NULL);

		list_del(&dr->node.entry);
		free_dr(dr);
	}
	drm_dbg_drmres(dev, "drmres release end\n");
}

/*
 * Always inline so that kmalloc_track_caller tracks the actual interesting
 * caller outside of drm_managed.c.
 */
static __always_inline struct drmres * alloc_dr(drmres_release_t release,
						size_t size, gfp_t gfp, int nid)
{
	size_t tot_size;
	struct drmres *dr;

	/* We must catch any near-SIZE_MAX cases that could overflow. */
	if (unlikely(check_add_overflow(sizeof(*dr), size, &tot_size)))
		return NULL;

	dr = kmalloc_node_track_caller(tot_size, gfp, nid);
	if (unlikely(!dr))
		return NULL;

	memset(dr, 0, offsetof(struct drmres, data));

	INIT_LIST_HEAD(&dr->node.entry);
	dr->node.release = release;
	dr->node.size = size;

	return dr;
}

static void del_dr(struct drm_device *dev, struct drmres *dr)
{
	list_del_init(&dr->node.entry);

	drm_dbg_drmres(dev, "DEL %p %s (%lu bytes)\n",
		       dr, dr->node.name, (unsigned long) dr->node.size);
}

static void add_dr(struct drm_device *dev, struct drmres *dr)
{
	unsigned long flags;

	spin_lock_irqsave(&dev->managed.lock, flags);
	list_add(&dr->node.entry, &dev->managed.resources);
	spin_unlock_irqrestore(&dev->managed.lock, flags);

	drm_dbg_drmres(dev, "ADD %p %s (%lu bytes)\n",
		       dr, dr->node.name, (unsigned long) dr->node.size);
}

Annotation

Implementation Notes