Contributors: 10
Author Tokens Token Proportion Commits Commit Proportion
Matthew Brost 424 62.72% 1 4.76%
Matt Roper 88 13.02% 8 38.10%
K V P, Satyanarayana 72 10.65% 2 9.52%
Francois Dugast 37 5.47% 2 9.52%
Matthew Auld 26 3.85% 2 9.52%
José Roberto de Souza 21 3.11% 1 4.76%
Michal Wajdeczko 4 0.59% 2 9.52%
Kees Cook 2 0.30% 1 4.76%
Nitin Gote 1 0.15% 1 4.76%
Lucas De Marchi 1 0.15% 1 4.76%
Total 676 21


// SPDX-License-Identifier: MIT
/*
 * Copyright © 2022 Intel Corporation
 */

#include "xe_bb.h"

#include "instructions/xe_mi_commands.h"
#include "xe_assert.h"
#include "xe_device_types.h"
#include "xe_exec_queue_types.h"
#include "xe_gt.h"
#include "xe_sa.h"
#include "xe_sched_job.h"
#include "xe_vm_types.h"

static int bb_prefetch(struct xe_gt *gt)
{
	struct xe_device *xe = gt_to_xe(gt);

	if (GRAPHICS_VERx100(xe) >= 1250 && xe_gt_is_main_type(gt))
		/*
		 * RCS and CCS require 1K, although other engines would be
		 * okay with 512.
		 */
		return SZ_1K;
	else
		return SZ_512;
}

struct xe_bb *xe_bb_new(struct xe_gt *gt, u32 dwords, bool usm)
{
	struct xe_tile *tile = gt_to_tile(gt);
	struct xe_bb *bb = kmalloc_obj(*bb);
	int err;

	if (!bb)
		return ERR_PTR(-ENOMEM);

	/*
	 * We need to allocate space for the requested number of dwords,
	 * one additional MI_BATCH_BUFFER_END dword, and additional buffer
	 * space to accommodate the platform-specific hardware prefetch
	 * requirements.
	 */
	bb->bo = xe_sa_bo_new(!usm ? tile->mem.kernel_bb_pool : gt->usm.bb_pool,
			      4 * (dwords + 1) + bb_prefetch(gt));
	if (IS_ERR(bb->bo)) {
		err = PTR_ERR(bb->bo);
		goto err;
	}

	bb->cs = xe_sa_bo_cpu_addr(bb->bo);
	bb->len = 0;

	return bb;
err:
	kfree(bb);
	return ERR_PTR(err);
}

/**
 * xe_bb_alloc() - Allocate a new batch buffer structure
 * @gt: the &xe_gt
 *
 * Allocates and initializes a new xe_bb structure with an associated
 * uninitialized suballoc object.
 *
 * Returns: Batch buffer structure or an ERR_PTR(-ENOMEM).
 */
struct xe_bb *xe_bb_alloc(struct xe_gt *gt)
{
	struct xe_bb *bb = kmalloc_obj(*bb);
	int err;

	if (!bb)
		return ERR_PTR(-ENOMEM);

	bb->bo = xe_sa_bo_alloc(GFP_KERNEL);
	if (IS_ERR(bb->bo)) {
		err = PTR_ERR(bb->bo);
		goto err;
	}

	return bb;

err:
	kfree(bb);
	return ERR_PTR(err);
}

/**
 * xe_bb_init() - Initialize a batch buffer with memory from a sub-allocator pool
 * @bb: Batch buffer structure to initialize
 * @bb_pool: Suballoc memory pool to allocate from
 * @dwords: Number of dwords to be allocated
 *
 * Initializes the batch buffer by allocating memory from the specified
 * suballoc pool.
 *
 * Return: 0 on success, negative error code on failure.
 */
int xe_bb_init(struct xe_bb *bb, struct xe_sa_manager *bb_pool, u32 dwords)
{
	int err;

	/*
	 * We need to allocate space for the requested number of dwords &
	 * one additional MI_BATCH_BUFFER_END dword. Since the whole SA
	 * is submitted to HW, we need to make sure that the last instruction
	 * is not over written when the last chunk of SA is allocated for BB.
	 * So, this extra DW acts as a guard here.
	 */
	err = xe_sa_bo_init(bb_pool, bb->bo, 4 * (dwords + 1));
	if (err)
		return err;

	bb->cs = xe_sa_bo_cpu_addr(bb->bo);
	bb->len = 0;

	return 0;
}

static struct xe_sched_job *
__xe_bb_create_job(struct xe_exec_queue *q, struct xe_bb *bb, u64 *addr)
{
	u32 size = drm_suballoc_size(bb->bo);

	if (bb->len == 0 || bb->cs[bb->len - 1] != MI_BATCH_BUFFER_END)
		bb->cs[bb->len++] = MI_BATCH_BUFFER_END;

	xe_gt_assert(q->gt, bb->len * 4 + bb_prefetch(q->gt) <= size);

	xe_sa_bo_flush_write(bb->bo);

	return xe_sched_job_create(q, addr);
}

struct xe_sched_job *xe_bb_create_migration_job(struct xe_exec_queue *q,
						struct xe_bb *bb,
						u64 batch_base_ofs,
						u32 second_idx)
{
	u64 addr[2] = {
		batch_base_ofs + drm_suballoc_soffset(bb->bo),
		batch_base_ofs + drm_suballoc_soffset(bb->bo) +
		4 * second_idx,
	};

	xe_gt_assert(q->gt, second_idx <= bb->len);
	xe_gt_assert(q->gt, xe_sched_job_is_migration(q));
	xe_gt_assert(q->gt, q->width == 1);

	return __xe_bb_create_job(q, bb, addr);
}

struct xe_sched_job *xe_bb_create_job(struct xe_exec_queue *q,
				      struct xe_bb *bb)
{
	u64 addr = xe_sa_bo_gpu_addr(bb->bo);

	xe_gt_assert(q->gt, !xe_sched_job_is_migration(q));
	xe_gt_assert(q->gt, q->width == 1);
	return __xe_bb_create_job(q, bb, &addr);
}

void xe_bb_free(struct xe_bb *bb, struct dma_fence *fence)
{
	if (!bb)
		return;

	xe_sa_bo_free(bb->bo, fence);
	kfree(bb);
}