Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
6#include "xe_bb.h"
7
8#include "instructions/xe_mi_commands.h"
9#include "xe_assert.h"
10#include "xe_device_types.h"
11#include "xe_exec_queue_types.h"
12#include "xe_gt.h"
13#include "xe_sa.h"
14#include "xe_sched_job.h"
15#include "xe_vm_types.h"
16
17static int bb_prefetch(struct xe_gt *gt)
18{
19 struct xe_device *xe = gt_to_xe(gt);
20
21 if (GRAPHICS_VERx100(xe) >= 1250 && xe_gt_is_main_type(gt))
22 /*
23 * RCS and CCS require 1K, although other engines would be
24 * okay with 512.
25 */
26 return SZ_1K;
27 else
28 return SZ_512;
29}
30
31struct xe_bb *xe_bb_new(struct xe_gt *gt, u32 dwords, bool usm)
32{
33 struct xe_tile *tile = gt_to_tile(gt);
34 struct xe_bb *bb = kmalloc_obj(*bb);
35 int err;
36
37 if (!bb)
38 return ERR_PTR(-ENOMEM);
39
40 /*
41 * We need to allocate space for the requested number of dwords,
42 * one additional MI_BATCH_BUFFER_END dword, and additional buffer
43 * space to accommodate the platform-specific hardware prefetch
44 * requirements.
45 */
46 bb->bo = xe_sa_bo_new(!usm ? tile->mem.kernel_bb_pool : gt->usm.bb_pool,
47 4 * (dwords + 1) + bb_prefetch(gt));
48 if (IS_ERR(bb->bo)) {
49 err = PTR_ERR(bb->bo);
50 goto err;
51 }
52
53 bb->cs = xe_sa_bo_cpu_addr(bb->bo);
54 bb->len = 0;
55
56 return bb;
57err:
58 kfree(bb);
59 return ERR_PTR(err);
60}
61
62/**
63 * xe_bb_alloc() - Allocate a new batch buffer structure
64 * @gt: the &xe_gt
65 *
66 * Allocates and initializes a new xe_bb structure with an associated
67 * uninitialized suballoc object.
68 *
69 * Returns: Batch buffer structure or an ERR_PTR(-ENOMEM).
70 */
71struct xe_bb *xe_bb_alloc(struct xe_gt *gt)
72{
73 struct xe_bb *bb = kmalloc_obj(*bb);
74 int err;
75
76 if (!bb)
77 return ERR_PTR(-ENOMEM);
78
79 bb->bo = xe_sa_bo_alloc(GFP_KERNEL);
80 if (IS_ERR(bb->bo)) {
81 err = PTR_ERR(bb->bo);
82 goto err;
83 }
84
85 return bb;
86
87err:
88 kfree(bb);
89 return ERR_PTR(err);
90}
91
92/**
93 * xe_bb_init() - Initialize a batch buffer with memory from a sub-allocator pool
94 * @bb: Batch buffer structure to initialize
95 * @bb_pool: Suballoc memory pool to allocate from
96 * @dwords: Number of dwords to be allocated
97 *
98 * Initializes the batch buffer by allocating memory from the specified
99 * suballoc pool.
100 *
101 * Return: 0 on success, negative error code on failure.
102 */
103int xe_bb_init(struct xe_bb *bb, struct xe_sa_manager *bb_pool, u32 dwords)
104{
105 int err;
106
107 /*
108 * We need to allocate space for the requested number of dwords &
109 * one additional MI_BATCH_BUFFER_END dword. Since the whole SA
110 * is submitted to HW, we need to make sure that the last instruction
111 * is not over written when the last chunk of SA is allocated for BB.
112 * So, this extra DW acts as a guard here.
113 */
114 err = xe_sa_bo_init(bb_pool, bb->bo, 4 * (dwords + 1));
115 if (err)
116 return err;
117
118 bb->cs = xe_sa_bo_cpu_addr(bb->bo);
119 bb->len = 0;
120
121 return 0;
122}
123
124static struct xe_sched_job *
125__xe_bb_create_job(struct xe_exec_queue *q, struct xe_bb *bb, u64 *addr)
126{
127 u32 size = drm_suballoc_size(bb->bo);
128
129 if (bb->len == 0 || bb->cs[bb->len - 1] != MI_BATCH_BUFFER_END)
130 bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
131
132 xe_gt_assert(q->gt, bb->len * 4 + bb_prefetch(q->gt) <= size);
133
134 xe_sa_bo_flush_write(bb->bo);
135
136 return xe_sched_job_create(q, addr);
137}
138
139struct xe_sched_job *xe_bb_create_migration_job(struct xe_exec_queue *q,
140 struct xe_bb *bb,
141 u64 batch_base_ofs,
142 u32 second_idx)
143{
144 u64 addr[2] = {
145 batch_base_ofs + drm_suballoc_soffset(bb->bo),
146 batch_base_ofs + drm_suballoc_soffset(bb->bo) +
147 4 * second_idx,
148 };
149
150 xe_gt_assert(q->gt, second_idx <= bb->len);
151 xe_gt_assert(q->gt, xe_sched_job_is_migration(q));
152 xe_gt_assert(q->gt, q->width == 1);
153
154 return __xe_bb_create_job(q, bb, addr);
155}
156
157struct xe_sched_job *xe_bb_create_job(struct xe_exec_queue *q,
158 struct xe_bb *bb)
159{
160 u64 addr = xe_sa_bo_gpu_addr(bb->bo);
161
162 xe_gt_assert(q->gt, !xe_sched_job_is_migration(q));
163 xe_gt_assert(q->gt, q->width == 1);
164 return __xe_bb_create_job(q, bb, &addr);
165}
166
167void xe_bb_free(struct xe_bb *bb, struct dma_fence *fence)
168{
169 if (!bb)
170 return;
171
172 xe_sa_bo_free(bb->bo, fence);
173 kfree(bb);
174}