1116e217ebc29a73279849a21a08b9da903aa1ca
[linux-2.6-block.git] / drivers / gpu / drm / xe / xe_ttm_stolen_mgr.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2021-2022 Intel Corporation
4  * Copyright (C) 2021-2002 Red Hat
5  */
6
7 #include <drm/drm_managed.h>
8 #include <drm/drm_mm.h>
9
10 #include <drm/ttm/ttm_device.h>
11 #include <drm/ttm/ttm_placement.h>
12 #include <drm/ttm/ttm_range_manager.h>
13
14 #include "regs/xe_regs.h"
15 #include "xe_bo.h"
16 #include "xe_device.h"
17 #include "xe_gt.h"
18 #include "xe_mmio.h"
19 #include "xe_res_cursor.h"
20 #include "xe_ttm_stolen_mgr.h"
21 #include "xe_ttm_vram_mgr.h"
22
23 struct xe_ttm_stolen_mgr {
24         struct xe_ttm_vram_mgr base;
25
26         /* PCI base offset */
27         resource_size_t io_base;
28         /* GPU base offset */
29         resource_size_t stolen_base;
30
31         void *__iomem mapping;
32 };
33
34 static inline struct xe_ttm_stolen_mgr *
35 to_stolen_mgr(struct ttm_resource_manager *man)
36 {
37         return container_of(man, struct xe_ttm_stolen_mgr, base.manager);
38 }
39
40 /**
41  * xe_ttm_stolen_cpu_inaccessible - Can we directly CPU access stolen memory for
42  * this device.
43  * @xe: xe device
44  *
45  * On some integrated platforms we can't directly access stolen via the CPU
46  * (like some normal system memory).  Also on small-bar systems for discrete,
47  * since stolen is always as the end of normal VRAM, and the BAR likely doesn't
48  * stretch that far. However CPU access of stolen is generally rare, and at
49  * least on discrete should not be needed.
50  *
51  * If this is indeed inaccessible then we fallback to using the GGTT mappable
52  * aperture for CPU access. On discrete platforms we have no such thing, so when
53  * later attempting to CPU map the memory an error is instead thrown.
54  */
55 bool xe_ttm_stolen_cpu_inaccessible(struct xe_device *xe)
56 {
57         struct ttm_resource_manager *ttm_mgr =
58                 ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
59         struct xe_ttm_stolen_mgr *mgr;
60
61         if (!ttm_mgr)
62                 return true;
63
64         mgr = to_stolen_mgr(ttm_mgr);
65
66         return !mgr->io_base || GRAPHICS_VERx100(xe) < 1270;
67 }
68
69 static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
70 {
71         struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
72         struct xe_gt *gt = to_gt(xe);
73         u64 vram_size, stolen_size;
74         int err;
75
76         err = xe_mmio_total_vram_size(xe, &vram_size, NULL);
77         if (err) {
78                 drm_info(&xe->drm, "Querying total vram size failed\n");
79                 return 0;
80         }
81
82         /* Use DSM base address instead for stolen memory */
83         mgr->stolen_base = xe_mmio_read64(gt, GEN12_DSMBASE.reg) & GEN12_BDSM_MASK;
84         if (drm_WARN_ON(&xe->drm, vram_size < mgr->stolen_base))
85                 return 0;
86
87         stolen_size = vram_size - mgr->stolen_base;
88         if (mgr->stolen_base + stolen_size <= pci_resource_len(pdev, 2))
89                 mgr->io_base = pci_resource_start(pdev, 2) + mgr->stolen_base;
90
91         /*
92          * There may be few KB of platform dependent reserved memory at the end
93          * of lmem which is not part of the DSM. Such reserved memory portion is
94          * always less then DSM granularity so align down the stolen_size to DSM
95          * granularity to accommodate such reserve lmem portion.
96          */
97         return ALIGN_DOWN(stolen_size, SZ_1M);
98 }
99
100 static u32 detect_bar2_integrated(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
101 {
102         struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
103         u32 stolen_size;
104         u32 ggc, gms;
105
106         ggc = xe_mmio_read32(to_gt(xe), GGC.reg);
107
108         /* check GGMS, should be fixed 0x3 (8MB) */
109         if (drm_WARN_ON(&xe->drm, (ggc & GGMS_MASK) != GGMS_MASK))
110                 return 0;
111
112         mgr->stolen_base = mgr->io_base = pci_resource_start(pdev, 2) + SZ_8M;
113
114         /* return valid GMS value, -EIO if invalid */
115         gms = REG_FIELD_GET(GMS_MASK, ggc);
116         switch (gms) {
117         case 0x0 ... 0x04:
118                 stolen_size = gms * 32 * SZ_1M;
119                 break;
120         case 0xf0 ... 0xfe:
121                 stolen_size = (gms - 0xf0 + 1) * 4 * SZ_1M;
122                 break;
123         default:
124                 return 0;
125         }
126
127         if (drm_WARN_ON(&xe->drm, stolen_size + SZ_8M > pci_resource_len(pdev, 2)))
128                 return 0;
129
130         return stolen_size;
131 }
132
133 extern struct resource intel_graphics_stolen_res;
134
135 static u64 detect_stolen(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
136 {
137 #ifdef CONFIG_X86
138         /* Map into GGTT */
139         mgr->io_base = pci_resource_start(to_pci_dev(xe->drm.dev), 2);
140
141         /* Stolen memory is x86 only */
142         mgr->stolen_base = intel_graphics_stolen_res.start;
143         return resource_size(&intel_graphics_stolen_res);
144 #else
145         return 0;
146 #endif
147 }
148
149 void xe_ttm_stolen_mgr_init(struct xe_device *xe)
150 {
151         struct xe_ttm_stolen_mgr *mgr = drmm_kzalloc(&xe->drm, sizeof(*mgr), GFP_KERNEL);
152         struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
153         u64 stolen_size, pgsize;
154         int err;
155
156         if (IS_DGFX(xe))
157                 stolen_size = detect_bar2_dgfx(xe, mgr);
158         else if (GRAPHICS_VERx100(xe) >= 1270)
159                 stolen_size = detect_bar2_integrated(xe, mgr);
160         else
161                 stolen_size = detect_stolen(xe, mgr);
162
163         if (!stolen_size) {
164                 drm_dbg_kms(&xe->drm, "No stolen memory support\n");
165                 return;
166         }
167
168         pgsize = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
169         if (pgsize < PAGE_SIZE)
170                 pgsize = PAGE_SIZE;
171
172         err = __xe_ttm_vram_mgr_init(xe, &mgr->base, XE_PL_STOLEN, stolen_size, pgsize);
173         if (err) {
174                 drm_dbg_kms(&xe->drm, "Stolen mgr init failed: %i\n", err);
175                 return;
176         }
177
178         drm_dbg_kms(&xe->drm, "Initialized stolen memory support with %llu bytes\n",
179                     stolen_size);
180
181         if (!xe_ttm_stolen_cpu_inaccessible(xe))
182                 mgr->mapping = devm_ioremap_wc(&pdev->dev, mgr->io_base, stolen_size);
183 }
184
185 u64 xe_ttm_stolen_io_offset(struct xe_bo *bo, u32 offset)
186 {
187         struct xe_device *xe = xe_bo_device(bo);
188         struct ttm_resource_manager *ttm_mgr = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
189         struct xe_ttm_stolen_mgr *mgr = to_stolen_mgr(ttm_mgr);
190         struct xe_res_cursor cur;
191
192         XE_BUG_ON(!mgr->io_base);
193
194         if (!IS_DGFX(xe) && xe_ttm_stolen_cpu_inaccessible(xe))
195                 return mgr->io_base + xe_bo_ggtt_addr(bo) + offset;
196
197         xe_res_first(bo->ttm.resource, offset, 4096, &cur);
198         return mgr->io_base + cur.start;
199 }
200
201 static int __xe_ttm_stolen_io_mem_reserve_bar2(struct xe_device *xe,
202                                                struct xe_ttm_stolen_mgr *mgr,
203                                                struct ttm_resource *mem)
204 {
205         struct xe_res_cursor cur;
206
207         if (!mgr->io_base)
208                 return -EIO;
209
210         xe_res_first(mem, 0, 4096, &cur);
211         mem->bus.offset = cur.start;
212
213         drm_WARN_ON(&xe->drm, !(mem->placement & TTM_PL_FLAG_CONTIGUOUS));
214
215         if (mem->placement & TTM_PL_FLAG_CONTIGUOUS && mgr->mapping)
216                 mem->bus.addr = (u8 *)mgr->mapping + mem->bus.offset;
217
218         mem->bus.offset += mgr->io_base;
219         mem->bus.is_iomem = true;
220         mem->bus.caching = ttm_write_combined;
221
222         return 0;
223 }
224
225 static int __xe_ttm_stolen_io_mem_reserve_stolen(struct xe_device *xe,
226                                                  struct xe_ttm_stolen_mgr *mgr,
227                                                  struct ttm_resource *mem)
228 {
229 #ifdef CONFIG_X86
230         struct xe_bo *bo = ttm_to_xe_bo(mem->bo);
231
232         XE_BUG_ON(IS_DGFX(xe));
233
234         /* XXX: Require BO to be mapped to GGTT? */
235         if (drm_WARN_ON(&xe->drm, !(bo->flags & XE_BO_CREATE_GGTT_BIT)))
236                 return -EIO;
237
238         /* GGTT is always contiguously mapped */
239         mem->bus.offset = xe_bo_ggtt_addr(bo) + mgr->io_base;
240
241         mem->bus.is_iomem = true;
242         mem->bus.caching = ttm_write_combined;
243
244         return 0;
245 #else
246         /* How is it even possible to get here without gen12 stolen? */
247         drm_WARN_ON(&xe->drm, 1);
248         return -EIO;
249 #endif
250 }
251
252 int xe_ttm_stolen_io_mem_reserve(struct xe_device *xe, struct ttm_resource *mem)
253 {
254         struct ttm_resource_manager *ttm_mgr = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
255         struct xe_ttm_stolen_mgr *mgr = ttm_mgr ? to_stolen_mgr(ttm_mgr) : NULL;
256
257         if (!mgr || !mgr->io_base)
258                 return -EIO;
259
260         if (!xe_ttm_stolen_cpu_inaccessible(xe))
261                 return __xe_ttm_stolen_io_mem_reserve_bar2(xe, mgr, mem);
262         else
263                 return __xe_ttm_stolen_io_mem_reserve_stolen(xe, mgr, mem);
264 }
265
266 u64 xe_ttm_stolen_gpu_offset(struct xe_device *xe)
267 {
268         struct xe_ttm_stolen_mgr *mgr =
269                 to_stolen_mgr(ttm_manager_type(&xe->ttm, XE_PL_STOLEN));
270
271         return mgr->stolen_base;
272 }