Commit 85d46533 authored by Thomas Hellström's avatar Thomas Hellström Committed by Matthew Brost
Browse files

drm/xe: Add dma_addr res cursor



Add dma_addr res cursor which walks an array of drm_pagemap_dma_addr.
Useful for SVM ranges and programing page tables.

v3:
 - Better commit message (Thomas)
 - Use new drm_pagemap.h location
v7:
 - Fix kernel doc (CI)

Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Signed-off-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: default avatarMatthew Brost <matthew.brost@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250306012657.3505757-11-matthew.brost@intel.com
parent 6fd979c2
Loading
Loading
Loading
Loading
+121 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

#include <linux/scatterlist.h>

#include <drm/drm_pagemap.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_resource.h>
@@ -34,17 +35,38 @@
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_macros.h"
#include "xe_svm.h"
#include "xe_ttm_vram_mgr.h"

/* state back for walking over vram_mgr, stolen_mgr, and gtt_mgr allocations */
/**
 * struct xe_res_cursor - state for walking over dma mapping, vram_mgr,
 * stolen_mgr, and gtt_mgr allocations
 */
struct xe_res_cursor {
	/** @start: Start of cursor */
	u64 start;
	/** @size: Size of the current segment. */
	u64 size;
	/** @remaining: Remaining bytes in cursor */
	u64 remaining;
	/** @node: Opaque point current node cursor */
	void *node;
	/** @mem_type: Memory type */
	u32 mem_type;
	/** @sgl: Scatterlist for cursor */
	struct scatterlist *sgl;
	/** @dma_addr: Current element in a struct drm_pagemap_device_addr array */
	const struct drm_pagemap_device_addr *dma_addr;
	/** @mm: Buddy allocator for VRAM cursor */
	struct drm_buddy *mm;
	/**
	 * @dma_start: DMA start address for the current segment.
	 * This may be different to @dma_addr.addr since elements in
	 * the array may be coalesced to a single segment.
	 */
	u64 dma_start;
	/** @dma_seg_size: Size of the current DMA segment. */
	u64 dma_seg_size;
};

static struct drm_buddy *xe_res_get_buddy(struct ttm_resource *res)
@@ -70,6 +92,7 @@ static inline void xe_res_first(struct ttm_resource *res,
				struct xe_res_cursor *cur)
{
	cur->sgl = NULL;
	cur->dma_addr = NULL;
	if (!res)
		goto fallback;

@@ -141,6 +164,36 @@ static inline void __xe_res_sg_next(struct xe_res_cursor *cur)
	cur->sgl = sgl;
}

/**
 * __xe_res_dma_next() - Advance the cursor when end-of-segment is reached
 * @cur: The cursor
 */
static inline void __xe_res_dma_next(struct xe_res_cursor *cur)
{
	const struct drm_pagemap_device_addr *addr = cur->dma_addr;
	u64 start = cur->start;

	while (start >= cur->dma_seg_size) {
		start -= cur->dma_seg_size;
		addr++;
		cur->dma_seg_size = PAGE_SIZE << addr->order;
	}
	cur->dma_start = addr->addr;

	/* Coalesce array_elements */
	while (cur->dma_seg_size - start < cur->remaining) {
		if (cur->dma_start + cur->dma_seg_size != addr[1].addr ||
		    addr->proto != addr[1].proto)
			break;
		addr++;
		cur->dma_seg_size += PAGE_SIZE << addr->order;
	}

	cur->dma_addr = addr;
	cur->start = start;
	cur->size = cur->dma_seg_size - start;
}

/**
 * xe_res_first_sg - initialize a xe_res_cursor with a scatter gather table
 *
@@ -160,11 +213,42 @@ static inline void xe_res_first_sg(const struct sg_table *sg,
	cur->start = start;
	cur->remaining = size;
	cur->size = 0;
	cur->dma_addr = NULL;
	cur->sgl = sg->sgl;
	cur->mem_type = XE_PL_TT;
	__xe_res_sg_next(cur);
}

/**
 * xe_res_first_dma - initialize a xe_res_cursor with dma_addr array
 *
 * @dma_addr: struct drm_pagemap_device_addr array to walk
 * @start: Start of the range
 * @size: Size of the range
 * @cur: cursor object to initialize
 *
 * Start walking over the range of allocations between @start and @size.
 */
static inline void xe_res_first_dma(const struct drm_pagemap_device_addr *dma_addr,
				    u64 start, u64 size,
				    struct xe_res_cursor *cur)
{
	XE_WARN_ON(!dma_addr);
	XE_WARN_ON(!IS_ALIGNED(start, PAGE_SIZE) ||
		   !IS_ALIGNED(size, PAGE_SIZE));

	cur->node = NULL;
	cur->start = start;
	cur->remaining = size;
	cur->dma_seg_size = PAGE_SIZE << dma_addr->order;
	cur->dma_start = 0;
	cur->size = 0;
	cur->dma_addr = dma_addr;
	__xe_res_dma_next(cur);
	cur->sgl = NULL;
	cur->mem_type = XE_PL_TT;
}

/**
 * xe_res_next - advance the cursor
 *
@@ -191,6 +275,12 @@ static inline void xe_res_next(struct xe_res_cursor *cur, u64 size)
		return;
	}

	if (cur->dma_addr) {
		cur->start += size;
		__xe_res_dma_next(cur);
		return;
	}

	if (cur->sgl) {
		cur->start += size;
		__xe_res_sg_next(cur);
@@ -232,6 +322,35 @@ static inline void xe_res_next(struct xe_res_cursor *cur, u64 size)
 */
static inline u64 xe_res_dma(const struct xe_res_cursor *cur)
{
	return cur->sgl ? sg_dma_address(cur->sgl) + cur->start : cur->start;
	if (cur->dma_addr)
		return cur->dma_start + cur->start;
	else if (cur->sgl)
		return sg_dma_address(cur->sgl) + cur->start;
	else
		return cur->start;
}

/**
 * xe_res_is_vram() - Whether the cursor current dma address points to
 * same-device VRAM
 * @cur: The cursor.
 *
 * Return: true iff the address returned by xe_res_dma() points to internal vram.
 */
static inline bool xe_res_is_vram(const struct xe_res_cursor *cur)
{
	if (cur->dma_addr)
		return cur->dma_addr->proto == XE_INTERCONNECT_VRAM;

	switch (cur->mem_type) {
	case XE_PL_STOLEN:
	case XE_PL_VRAM0:
	case XE_PL_VRAM1:
		return true;
	default:
		break;
	}

	return false;
}
#endif
+4 −0
Original line number Diff line number Diff line
@@ -6,6 +6,10 @@
#ifndef _XE_SVM_H_
#define _XE_SVM_H_

#include <drm/drm_pagemap.h>

#define XE_INTERCONNECT_VRAM DRM_INTERCONNECT_DRIVER

struct xe_vm;

#if IS_ENABLED(CONFIG_DRM_GPUSVM)