| 1 | |
| 2 | |
| 3 | * Copyright © 2023 Intel Corporation
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/fault-inject.h>
|
| 7 |
|
| 8 | #include <drm/drm_managed.h>
|
| 9 | #include <drm/drm_pagemap_util.h>
|
| 10 |
|
| 11 | #include "xe_bo.h"
|
| 12 | #include "xe_device_types.h"
|
| 13 | #include "xe_ggtt.h"
|
| 14 | #include "xe_memirq.h"
|
| 15 | #include "xe_migrate.h"
|
| 16 | #include "xe_pcode.h"
|
| 17 | #include "xe_sa.h"
|
| 18 | #include "xe_svm.h"
|
| 19 | #include "xe_tile.h"
|
| 20 | #include "xe_tile_sysfs.h"
|
| 21 | #include "xe_ttm_vram_mgr.h"
|
| 22 | #include "xe_vram.h"
|
| 23 | #include "xe_vram_types.h"
|
| 24 | #include "xe_wa.h"
|
| 25 |
|
| 26 | |
| 27 | * DOC: Multi-tile Design
|
| 28 | *
|
| 29 | * Different vendors use the term "tile" a bit differently, but in the Intel
|
| 30 | * world, a 'tile' is pretty close to what most people would think of as being
|
| 31 | * a complete GPU. When multiple GPUs are placed behind a single PCI device,
|
| 32 | * that's what is referred to as a "multi-tile device." In such cases, pretty
|
| 33 | * much all hardware is replicated per-tile, although certain responsibilities
|
| 34 | * like PCI communication, reporting of interrupts to the OS, etc. are handled
|
| 35 | * solely by the "root tile." A multi-tile platform takes care of tying the
|
| 36 | * tiles together in a way such that interrupt notifications from remote tiles
|
| 37 | * are forwarded to the root tile, the per-tile vram is combined into a single
|
| 38 | * address space, etc.
|
| 39 | *
|
| 40 | * In contrast, a "GT" (which officially stands for "Graphics Technology") is
|
| 41 | * the subset of a GPU/tile that is responsible for implementing graphics
|
| 42 | * and/or media operations. The GT is where a lot of the driver implementation
|
| 43 | * happens since it's where the hardware engines, the execution units, and the
|
| 44 | * GuC all reside.
|
| 45 | *
|
| 46 | * Historically most Intel devices were single-tile devices that contained a
|
| 47 | * single GT. PVC is an example of an Intel platform built on a multi-tile
|
| 48 | * design (i.e., multiple GPUs behind a single PCI device); each PVC tile only
|
| 49 | * has a single GT. In contrast, platforms like MTL that have separate chips
|
| 50 | * for render and media IP are still only a single logical GPU, but the
|
| 51 | * graphics and media IP blocks are each exposed as a separate GT within that
|
| 52 | * single GPU. This is important from a software perspective because multi-GT
|
| 53 | * platforms like MTL only replicate a subset of the GPU hardware and behave
|
| 54 | * differently than multi-tile platforms like PVC where nearly everything is
|
| 55 | * replicated.
|
| 56 | *
|
| 57 | * Per-tile functionality (shared by all GTs within the tile):
|
| 58 | * - Complete 4MB MMIO space (containing SGunit/SoC registers, GT
|
| 59 | * registers, display registers, etc.)
|
| 60 | * - Global GTT
|
| 61 | * - VRAM (if discrete)
|
| 62 | * - Interrupt flows
|
| 63 | * - Migration context
|
| 64 | * - kernel batchbuffer pool
|
| 65 | * - Primary GT
|
| 66 | * - Media GT (if media version >= 13)
|
| 67 | *
|
| 68 | * Per-GT functionality:
|
| 69 | * - GuC
|
| 70 | * - Hardware engines
|
| 71 | * - Programmable hardware units (subslices, EUs)
|
| 72 | * - GSI subset of registers (multiple copies of these registers reside
|
| 73 | * within the complete MMIO space provided by the tile, but at different
|
| 74 | * offsets --- 0 for render, 0x380000 for media)
|
| 75 | * - Multicast register steering
|
| 76 | * - TLBs to cache page table translations
|
| 77 | * - Reset capability
|
| 78 | * - Low-level power management (e.g., C6)
|
| 79 | * - Clock frequency
|
| 80 | * - MOCS and PAT programming
|
| 81 |
|
| 82 |
|
| 83 | |
| 84 | * xe_tile_alloc - Perform per-tile memory allocation
|
| 85 | * @tile: Tile to perform allocations for
|
| 86 | *
|
| 87 | * Allocates various per-tile data structures using DRM-managed allocations.
|
| 88 | * Does not touch the hardware.
|
| 89 | *
|
| 90 | * Returns -ENOMEM if allocations fail, otherwise 0.
|
| 91 |
|
| 92 | static int xe_tile_alloc(struct xe_tile *tile)
|
| 93 | {
|
| 94 | tile->mem.ggtt = xe_ggtt_alloc(tile);
|
| 95 | if (!tile->mem.ggtt)
|
| 96 | return -ENOMEM;
|
| 97 |
|
| 98 | tile->migrate = xe_migrate_alloc(tile);
|
| 99 | if (!tile->migrate)
|
| 100 | return -ENOMEM;
|
| 101 |
|
| 102 | return 0;
|
| 103 | }
|
| 104 |
|
| 105 | |
| 106 | * xe_tile_alloc_vram - Perform per-tile VRAM structs allocation
|
| 107 | * @tile: Tile to perform allocations for
|
| 108 | *
|
| 109 | * Allocates VRAM per-tile data structures using DRM-managed allocations.
|
| 110 | * Does not touch the hardware.
|
| 111 | *
|
| 112 | * Returns -ENOMEM if allocations fail, otherwise 0.
|
| 113 |
|
| 114 | int xe_tile_alloc_vram(struct xe_tile *tile)
|
| 115 | {
|
| 116 | struct xe_device *xe = tile_to_xe(tile);
|
| 117 | struct xe_vram_region *vram;
|
| 118 |
|
| 119 | if (!IS_DGFX(xe))
|
| 120 | return 0;
|
| 121 |
|
| 122 | vram = xe_vram_region_alloc(xe, tile->id, XE_PL_VRAM0 + tile->id);
|
| 123 | if (!vram)
|
| 124 | return -ENOMEM;
|
| 125 | tile->mem.vram = vram;
|
| 126 |
|
| 127 | |
| 128 | * If the kernel_vram is not already allocated,
|
| 129 | * it means that tile has common VRAM region for
|
| 130 | * kernel and user space.
|
| 131 |
|
| 132 | if (!tile->mem.kernel_vram)
|
| 133 | tile->mem.kernel_vram = tile->mem.vram;
|
| 134 |
|
| 135 | return 0;
|
| 136 | }
|
| 137 |
|
| 138 | |
| 139 | * xe_tile_init_early - Initialize the tile and primary GT
|
| 140 | * @tile: Tile to initialize
|
| 141 | * @xe: Parent Xe device
|
| 142 | * @id: Tile ID
|
| 143 | *
|
| 144 | * Initializes per-tile resources that don't require any interactions with the
|
| 145 | * hardware or any knowledge about the Graphics/Media IP version.
|
| 146 | *
|
| 147 | * Returns: 0 on success, negative error code on error.
|
| 148 |
|
| 149 | int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id)
|
| 150 | {
|
| 151 | int err;
|
| 152 |
|
| 153 | tile->xe = xe;
|
| 154 | tile->id = id;
|
| 155 |
|
| 156 | err = xe_tile_alloc(tile);
|
| 157 | if (err)
|
| 158 | return err;
|
| 159 |
|
| 160 | err = xe_pcode_init_early(tile);
|
| 161 | if (err)
|
| 162 | return err;
|
| 163 |
|
| 164 | return 0;
|
| 165 | }
|
| 166 | ALLOW_ERROR_INJECTION(xe_tile_init_early, ERRNO);
|
| 167 |
|
| 168 | |
| 169 | * xe_tile_init_noalloc - Init tile up to the point where allocations can happen.
|
| 170 | * @tile: The tile to initialize.
|
| 171 | *
|
| 172 | * This function prepares the tile to allow memory allocations to VRAM, but is
|
| 173 | * not allowed to allocate memory itself. This state is useful for display
|
| 174 | * readout, because the inherited display framebuffer will otherwise be
|
| 175 | * overwritten as it is usually put at the start of VRAM.
|
| 176 | *
|
| 177 | * Note that since this is tile initialization, it should not perform any
|
| 178 | * GT-specific operations, and thus does not need to hold GT forcewake.
|
| 179 | *
|
| 180 | * Returns: 0 on success, negative error code on error.
|
| 181 |
|
| 182 | int xe_tile_init_noalloc(struct xe_tile *tile)
|
| 183 | {
|
| 184 | struct xe_device *xe = tile_to_xe(tile);
|
| 185 | int err;
|
| 186 |
|
| 187 | xe_wa_apply_tile_workarounds(tile);
|
| 188 |
|
| 189 | err = xe_pagemap_cache_create(tile);
|
| 190 | if (err)
|
| 191 | return err;
|
| 192 |
|
| 193 | if (IS_DGFX(xe) && !ttm_resource_manager_used(&tile->mem.vram->ttm.manager)) {
|
| 194 | err = xe_ttm_vram_mgr_init(xe, tile->mem.vram);
|
| 195 | if (err)
|
| 196 | return err;
|
| 197 |
|
| 198 | xe->info.mem_region_mask |= BIT(tile->mem.vram->id) << 1;
|
| 199 | }
|
| 200 |
|
| 201 | return xe_tile_sysfs_init(tile);
|
| 202 | }
|
| 203 |
|
| 204 | int xe_tile_init(struct xe_tile *tile)
|
| 205 | {
|
| 206 | int err;
|
| 207 |
|
| 208 | err = xe_memirq_init(&tile->memirq);
|
| 209 | if (err)
|
| 210 | return err;
|
| 211 |
|
| 212 | tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16);
|
| 213 | if (IS_ERR(tile->mem.kernel_bb_pool))
|
| 214 | return PTR_ERR(tile->mem.kernel_bb_pool);
|
| 215 |
|
| 216 |
|
| 217 | tile->mem.reclaim_pool = xe_sa_bo_manager_init(tile, SZ_1M, XE_PAGE_RECLAIM_LIST_MAX_SIZE);
|
| 218 | if (IS_ERR(tile->mem.reclaim_pool))
|
| 219 | return PTR_ERR(tile->mem.reclaim_pool);
|
| 220 |
|
| 221 | return 0;
|
| 222 | }
|
| 223 | void xe_tile_migrate_wait(struct xe_tile *tile)
|
| 224 | {
|
| 225 | xe_migrate_wait(tile->migrate);
|
| 226 | }
|
| 227 |
|
| 228 | #if IS_ENABLED(CONFIG_DRM_XE_PAGEMAP)
|
| 229 | |
| 230 | * xe_tile_local_pagemap() - Return a pointer to the tile's local drm_pagemap if any
|
| 231 | * @tile: The tile.
|
| 232 | *
|
| 233 | * Return: A pointer to the tile's local drm_pagemap, or NULL if local pagemap
|
| 234 | * support has been compiled out.
|
| 235 |
|
| 236 | struct drm_pagemap *xe_tile_local_pagemap(struct xe_tile *tile)
|
| 237 | {
|
| 238 | struct drm_pagemap *dpagemap =
|
| 239 | drm_pagemap_get_from_cache_if_active(xe_tile_to_vr(tile)->dpagemap_cache);
|
| 240 |
|
| 241 | if (dpagemap) {
|
| 242 | xe_assert(tile_to_xe(tile), kref_read(&dpagemap->ref) >= 2);
|
| 243 | drm_pagemap_put(dpagemap);
|
| 244 | }
|
| 245 |
|
| 246 | return dpagemap;
|
| 247 | }
|
| 248 | #endif
|
| 249 |
|