drivers/gpu/drm/xe/xe_pt_walk.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/xe/xe_pt_walk.c
Extension
.c
Size
5278 bytes
Lines
162
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source 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

if (skip_to > next) {
			step += (skip_to - next) >> shift;
			next = skip_to;
		}
	}

	*addr = next;
	*offset += step;

	return next != end;
}

/**
 * xe_pt_walk_range() - Walk a range of a gpu page table tree with callbacks
 * for each page-table entry in all levels.
 * @parent: The root page table for walk start.
 * @level: The root page table level.
 * @addr: Virtual address start.
 * @end: Virtual address end + 1.
 * @walk: Walk info.
 *
 * Similar to the CPU page-table walker, this is a helper to walk
 * a gpu page table and call a provided callback function for each entry.
 *
 * Return: 0 on success, negative error code on error. The error is
 * propagated from the callback and on error the walk is terminated.
 */
int xe_pt_walk_range(struct xe_ptw *parent, unsigned int level,
		     u64 addr, u64 end, struct xe_pt_walk *walk)
{
	pgoff_t offset = xe_pt_offset(addr, level, walk);
	struct xe_ptw **entries = walk->staging ? (parent->staging ?: NULL) :
		(parent->children ?: NULL);
	const struct xe_pt_walk_ops *ops = walk->ops;
	enum page_walk_action action;
	struct xe_ptw *child;
	int err = 0;
	u64 next;

	do {
		next = xe_pt_addr_end(addr, end, level, walk);
		if (walk->shared_pt_mode && xe_pt_covers(addr, next, level,
							 walk))
			continue;
again:
		action = ACTION_SUBTREE;
		child = entries ? entries[offset] : NULL;
		err = ops->pt_entry(parent, offset, level, addr, next,
				    &child, &action, walk);
		if (err)
			break;

		/* Probably not needed yet for gpu pagetable walk. */
		if (unlikely(action == ACTION_AGAIN))
			goto again;

		if (likely(!level || !child || action == ACTION_CONTINUE))
			continue;

		err = xe_pt_walk_range(child, level - 1, addr, next, walk);

		if (!err && ops->pt_post_descend)
			err = ops->pt_post_descend(parent, offset, level, addr,
						   next, &child, &action, walk);
		if (err)
			break;

	} while (xe_pt_next(&offset, &addr, next, end, level, walk));

	return err;
}

/**
 * xe_pt_walk_shared() - Walk shared page tables of a page-table tree.
 * @parent: Root page table directory.
 * @level: Level of the root.
 * @addr: Start address.
 * @end: Last address + 1.
 * @walk: Walk info.
 *
 * This function is similar to xe_pt_walk_range() but it skips page tables
 * that are private to the range. Since the root (or @parent) page table is
 * typically also a shared page table this function is different in that it
 * calls the pt_entry callback and the post_descend callback also for the
 * root. The root can be detected in the callbacks by checking whether
 * parent == *child.
 * Walking only the shared page tables is common for unbind-type operations
 * where the page-table entries for an address range are cleared or detached
 * from the main page-table tree.
 *

Annotation

Implementation Notes