File: | dev/pci/drm/i915/gem/i915_gem_pages.c |
Warning: | line 61, column 37 The result of the left shift is undefined due to shifting by '32', which is greater or equal to the width of type 'unsigned int' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * SPDX-License-Identifier: MIT | |||
3 | * | |||
4 | * Copyright © 2014-2016 Intel Corporation | |||
5 | */ | |||
6 | ||||
7 | #include <drm/drm_cache.h> | |||
8 | ||||
9 | #include "gt/intel_gt.h" | |||
10 | #include "gt/intel_gt_pm.h" | |||
11 | ||||
12 | #include "i915_drv.h" | |||
13 | #include "i915_gem_object.h" | |||
14 | #include "i915_scatterlist.h" | |||
15 | #include "i915_gem_lmem.h" | |||
16 | #include "i915_gem_mman.h" | |||
17 | ||||
18 | void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, | |||
19 | struct sg_table *pages, | |||
20 | unsigned int sg_page_sizes) | |||
21 | { | |||
22 | struct drm_i915_privateinteldrm_softc *i915 = to_i915(obj->base.dev); | |||
23 | unsigned long supported = RUNTIME_INFO(i915)(&(i915)->__runtime)->page_sizes; | |||
24 | bool_Bool shrinkable; | |||
25 | int i; | |||
26 | ||||
27 | assert_object_held_shared(obj); | |||
28 | ||||
29 | if (i915_gem_object_is_volatile(obj)) | |||
| ||||
30 | obj->mm.madv = I915_MADV_DONTNEED1; | |||
31 | ||||
32 | /* Make the pages coherent with the GPU (flushing any swapin). */ | |||
33 | if (obj->cache_dirty) { | |||
34 | WARN_ON_ONCE(IS_DGFX(i915))({ static int __warned; int __ret = !!(((&(i915)->__info )->is_dgfx)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "((&(i915)->__info)->is_dgfx)", "/usr/src/sys/dev/pci/drm/i915/gem/i915_gem_pages.c" , 34); __warned = 1; } __builtin_expect(!!(__ret), 0); }); | |||
35 | obj->write_domain = 0; | |||
36 | if (i915_gem_object_has_struct_page(obj)) | |||
37 | drm_clflush_sg(pages); | |||
38 | obj->cache_dirty = false0; | |||
39 | } | |||
40 | ||||
41 | obj->mm.get_page.sg_pos = pages->sgl; | |||
42 | obj->mm.get_page.sg_idx = 0; | |||
43 | obj->mm.get_dma_page.sg_pos = pages->sgl; | |||
44 | obj->mm.get_dma_page.sg_idx = 0; | |||
45 | ||||
46 | obj->mm.pages = pages; | |||
47 | ||||
48 | GEM_BUG_ON(!sg_page_sizes)((void)0); | |||
49 | obj->mm.page_sizes.phys = sg_page_sizes; | |||
50 | ||||
51 | /* | |||
52 | * Calculate the supported page-sizes which fit into the given | |||
53 | * sg_page_sizes. This will give us the page-sizes which we may be able | |||
54 | * to use opportunistically when later inserting into the GTT. For | |||
55 | * example if phys=2G, then in theory we should be able to use 1G, 2M, | |||
56 | * 64K or 4K pages, although in practice this will depend on a number of | |||
57 | * other factors. | |||
58 | */ | |||
59 | obj->mm.page_sizes.sg = 0; | |||
60 | for_each_set_bit(i, &supported, ilog2(I915_GTT_MAX_PAGE_SIZE) + 1)for ((i) = find_first_bit((&supported), (((sizeof((1ULL << (21))) <= 4) ? (fls((1ULL << (21))) - 1) : (flsl((1ULL << (21))) - 1)) + 1)); (i) < (((sizeof((1ULL << (21))) <= 4) ? (fls((1ULL << (21))) - 1) : (flsl((1ULL << (21))) - 1)) + 1); (i) = find_next_bit((&supported ), (((sizeof((1ULL << (21))) <= 4) ? (fls((1ULL << (21))) - 1) : (flsl((1ULL << (21))) - 1)) + 1), (i) + 1 )) { | |||
61 | if (obj->mm.page_sizes.phys & ~0u << i) | |||
| ||||
62 | obj->mm.page_sizes.sg |= BIT(i)(1UL << (i)); | |||
63 | } | |||
64 | GEM_BUG_ON(!HAS_PAGE_SIZES(i915, obj->mm.page_sizes.sg))((void)0); | |||
65 | ||||
66 | shrinkable = i915_gem_object_is_shrinkable(obj); | |||
67 | ||||
68 | if (i915_gem_object_is_tiled(obj) && | |||
69 | i915->gem_quirks & GEM_QUIRK_PIN_SWIZZLED_PAGES(1UL << (0))) { | |||
70 | GEM_BUG_ON(i915_gem_object_has_tiling_quirk(obj))((void)0); | |||
71 | i915_gem_object_set_tiling_quirk(obj); | |||
72 | GEM_BUG_ON(!list_empty(&obj->mm.link))((void)0); | |||
73 | atomic_inc(&obj->mm.shrink_pin)__sync_fetch_and_add(&obj->mm.shrink_pin, 1); | |||
74 | shrinkable = false0; | |||
75 | } | |||
76 | ||||
77 | if (shrinkable && !i915_gem_object_has_self_managed_shrink_list(obj)) { | |||
78 | struct list_head *list; | |||
79 | unsigned long flags; | |||
80 | ||||
81 | assert_object_held(obj)do { (void)(&((obj)->base.resv)->lock.base); } while (0); | |||
82 | spin_lock_irqsave(&i915->mm.obj_lock, flags)do { flags = 0; mtx_enter(&i915->mm.obj_lock); } while (0); | |||
83 | ||||
84 | i915->mm.shrink_count++; | |||
85 | i915->mm.shrink_memory += obj->base.size; | |||
86 | ||||
87 | if (obj->mm.madv != I915_MADV_WILLNEED0) | |||
88 | list = &i915->mm.purge_list; | |||
89 | else | |||
90 | list = &i915->mm.shrink_list; | |||
91 | list_add_tail(&obj->mm.link, list); | |||
92 | ||||
93 | atomic_set(&obj->mm.shrink_pin, 0)({ typeof(*(&obj->mm.shrink_pin)) __tmp = ((0)); *(volatile typeof(*(&obj->mm.shrink_pin)) *)&(*(&obj-> mm.shrink_pin)) = __tmp; __tmp; }); | |||
94 | spin_unlock_irqrestore(&i915->mm.obj_lock, flags)do { (void)(flags); mtx_leave(&i915->mm.obj_lock); } while (0); | |||
95 | } | |||
96 | } | |||
97 | ||||
98 | int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj) | |||
99 | { | |||
100 | struct drm_i915_privateinteldrm_softc *i915 = to_i915(obj->base.dev); | |||
101 | int err; | |||
102 | ||||
103 | assert_object_held_shared(obj); | |||
104 | ||||
105 | if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)__builtin_expect(!!(obj->mm.madv != 0), 0)) { | |||
106 | drm_dbg(&i915->drm,__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_DRIVER, "Attempting to obtain a purgeable object\n" ) | |||
107 | "Attempting to obtain a purgeable object\n")__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_DRIVER, "Attempting to obtain a purgeable object\n" ); | |||
108 | return -EFAULT14; | |||
109 | } | |||
110 | ||||
111 | err = obj->ops->get_pages(obj); | |||
112 | GEM_BUG_ON(!err && !i915_gem_object_has_pages(obj))((void)0); | |||
113 | ||||
114 | return err; | |||
115 | } | |||
116 | ||||
117 | /* Ensure that the associated pages are gathered from the backing storage | |||
118 | * and pinned into our object. i915_gem_object_pin_pages() may be called | |||
119 | * multiple times before they are released by a single call to | |||
120 | * i915_gem_object_unpin_pages() - once the pages are no longer referenced | |||
121 | * either as a result of memory pressure (reaping pages under the shrinker) | |||
122 | * or as the object is itself released. | |||
123 | */ | |||
124 | int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj) | |||
125 | { | |||
126 | int err; | |||
127 | ||||
128 | assert_object_held(obj)do { (void)(&((obj)->base.resv)->lock.base); } while (0); | |||
129 | ||||
130 | assert_object_held_shared(obj); | |||
131 | ||||
132 | if (unlikely(!i915_gem_object_has_pages(obj))__builtin_expect(!!(!i915_gem_object_has_pages(obj)), 0)) { | |||
133 | GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj))((void)0); | |||
134 | ||||
135 | err = ____i915_gem_object_get_pages(obj); | |||
136 | if (err) | |||
137 | return err; | |||
138 | ||||
139 | smp_mb__before_atomic()do { } while (0); | |||
140 | } | |||
141 | atomic_inc(&obj->mm.pages_pin_count)__sync_fetch_and_add(&obj->mm.pages_pin_count, 1); | |||
142 | ||||
143 | return 0; | |||
144 | } | |||
145 | ||||
146 | int i915_gem_object_pin_pages_unlocked(struct drm_i915_gem_object *obj) | |||
147 | { | |||
148 | struct i915_gem_ww_ctx ww; | |||
149 | int err; | |||
150 | ||||
151 | i915_gem_ww_ctx_init(&ww, true1); | |||
152 | retry: | |||
153 | err = i915_gem_object_lock(obj, &ww); | |||
154 | if (!err) | |||
155 | err = i915_gem_object_pin_pages(obj); | |||
156 | ||||
157 | if (err == -EDEADLK11) { | |||
158 | err = i915_gem_ww_ctx_backoff(&ww); | |||
159 | if (!err) | |||
160 | goto retry; | |||
161 | } | |||
162 | i915_gem_ww_ctx_fini(&ww); | |||
163 | return err; | |||
164 | } | |||
165 | ||||
166 | /* Immediately discard the backing storage */ | |||
167 | int i915_gem_object_truncate(struct drm_i915_gem_object *obj) | |||
168 | { | |||
169 | if (obj->ops->truncate) | |||
170 | return obj->ops->truncate(obj); | |||
171 | ||||
172 | return 0; | |||
173 | } | |||
174 | ||||
175 | static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) | |||
176 | { | |||
177 | struct radix_tree_iter iter; | |||
178 | void __rcu **slot; | |||
179 | ||||
180 | rcu_read_lock(); | |||
181 | radix_tree_for_each_slot(slot, &obj->mm.get_page.radix, &iter, 0)for ((&iter)->index = (0); radix_tree_iter_find(&obj ->mm.get_page.radix, &iter, &(slot)); (&iter)-> index++) | |||
182 | radix_tree_delete(&obj->mm.get_page.radix, iter.index); | |||
183 | radix_tree_for_each_slot(slot, &obj->mm.get_dma_page.radix, &iter, 0)for ((&iter)->index = (0); radix_tree_iter_find(&obj ->mm.get_dma_page.radix, &iter, &(slot)); (&iter )->index++) | |||
184 | radix_tree_delete(&obj->mm.get_dma_page.radix, iter.index); | |||
185 | rcu_read_unlock(); | |||
186 | } | |||
187 | ||||
188 | static void unmap_object(struct drm_i915_gem_object *obj, void *ptr) | |||
189 | { | |||
190 | if (is_vmalloc_addr(ptr)) | |||
191 | vunmap(ptr, obj->base.size); | |||
192 | } | |||
193 | ||||
194 | static void flush_tlb_invalidate(struct drm_i915_gem_object *obj) | |||
195 | { | |||
196 | struct drm_i915_privateinteldrm_softc *i915 = to_i915(obj->base.dev); | |||
197 | struct intel_gt *gt = to_gt(i915); | |||
198 | ||||
199 | if (!obj->mm.tlb) | |||
200 | return; | |||
201 | ||||
202 | intel_gt_invalidate_tlb(gt, obj->mm.tlb); | |||
203 | obj->mm.tlb = 0; | |||
204 | } | |||
205 | ||||
206 | struct sg_table * | |||
207 | __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj) | |||
208 | { | |||
209 | struct sg_table *pages; | |||
210 | ||||
211 | assert_object_held_shared(obj); | |||
212 | ||||
213 | pages = fetch_and_zero(&obj->mm.pages)({ typeof(*&obj->mm.pages) __T = *(&obj->mm.pages ); *(&obj->mm.pages) = (typeof(*&obj->mm.pages) )0; __T; }); | |||
214 | if (IS_ERR_OR_NULL(pages)) | |||
215 | return pages; | |||
216 | ||||
217 | if (i915_gem_object_is_volatile(obj)) | |||
218 | obj->mm.madv = I915_MADV_WILLNEED0; | |||
219 | ||||
220 | if (!i915_gem_object_has_self_managed_shrink_list(obj)) | |||
221 | i915_gem_object_make_unshrinkable(obj); | |||
222 | ||||
223 | if (obj->mm.mapping) { | |||
224 | unmap_object(obj, page_mask_bits(obj->mm.mapping)({ unsigned long __v = (unsigned long)(obj->mm.mapping); ( typeof(obj->mm.mapping))(__v & -(1UL << (12))); } )); | |||
225 | obj->mm.mapping = NULL((void *)0); | |||
226 | } | |||
227 | ||||
228 | __i915_gem_object_reset_page_iter(obj); | |||
229 | obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0; | |||
230 | ||||
231 | flush_tlb_invalidate(obj); | |||
232 | ||||
233 | return pages; | |||
234 | } | |||
235 | ||||
236 | int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj) | |||
237 | { | |||
238 | struct sg_table *pages; | |||
239 | ||||
240 | if (i915_gem_object_has_pinned_pages(obj)) | |||
241 | return -EBUSY16; | |||
242 | ||||
243 | /* May be called by shrinker from within get_pages() (on another bo) */ | |||
244 | assert_object_held_shared(obj); | |||
245 | ||||
246 | i915_gem_object_release_mmap_offset(obj); | |||
247 | ||||
248 | /* | |||
249 | * ->put_pages might need to allocate memory for the bit17 swizzle | |||
250 | * array, hence protect them from being reaped by removing them from gtt | |||
251 | * lists early. | |||
252 | */ | |||
253 | pages = __i915_gem_object_unset_pages(obj); | |||
254 | ||||
255 | /* | |||
256 | * XXX Temporary hijinx to avoid updating all backends to handle | |||
257 | * NULL pages. In the future, when we have more asynchronous | |||
258 | * get_pages backends we should be better able to handle the | |||
259 | * cancellation of the async task in a more uniform manner. | |||
260 | */ | |||
261 | if (!IS_ERR_OR_NULL(pages)) | |||
262 | obj->ops->put_pages(obj, pages); | |||
263 | ||||
264 | return 0; | |||
265 | } | |||
266 | ||||
267 | /* The 'mapping' part of i915_gem_object_pin_map() below */ | |||
268 | static void *i915_gem_object_map_page(struct drm_i915_gem_object *obj, | |||
269 | enum i915_map_type type) | |||
270 | { | |||
271 | unsigned long n_pages = obj->base.size >> PAGE_SHIFT12, i; | |||
272 | struct vm_page *stack[32], **pages = stack, *page; | |||
273 | struct sgt_iter iter; | |||
274 | pgprot_t pgprot; | |||
275 | void *vaddr; | |||
276 | ||||
277 | switch (type) { | |||
278 | default: | |||
279 | MISSING_CASE(type)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "type", (long)(type)); __builtin_expect(!!(__ret), 0); }); | |||
280 | fallthroughdo {} while (0); /* to use PAGE_KERNEL anyway */ | |||
281 | case I915_MAP_WB: | |||
282 | /* | |||
283 | * On 32b, highmem using a finite set of indirect PTE (i.e. | |||
284 | * vmap) to provide virtual mappings of the high pages. | |||
285 | * As these are finite, map_new_virtual() must wait for some | |||
286 | * other kmap() to finish when it runs out. If we map a large | |||
287 | * number of objects, there is no method for it to tell us | |||
288 | * to release the mappings, and we deadlock. | |||
289 | * | |||
290 | * However, if we make an explicit vmap of the page, that | |||
291 | * uses a larger vmalloc arena, and also has the ability | |||
292 | * to tell us to release unwanted mappings. Most importantly, | |||
293 | * it will fail and propagate an error instead of waiting | |||
294 | * forever. | |||
295 | * | |||
296 | * So if the page is beyond the 32b boundary, make an explicit | |||
297 | * vmap. | |||
298 | */ | |||
299 | #ifdef notyet | |||
300 | if (n_pages == 1 && !PageHighMem(sg_page(obj->mm.pages->sgl))0) | |||
301 | return page_address(sg_page(obj->mm.pages->sgl)); | |||
302 | #endif | |||
303 | pgprot = PAGE_KERNEL0; | |||
304 | break; | |||
305 | case I915_MAP_WC: | |||
306 | pgprot = pgprot_writecombine(PAGE_KERNEL_IO0); | |||
307 | break; | |||
308 | } | |||
309 | ||||
310 | if (n_pages > ARRAY_SIZE(stack)(sizeof((stack)) / sizeof((stack)[0]))) { | |||
311 | /* Too big for stack -- allocate temporary array instead */ | |||
312 | pages = kvmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL(0x0001 | 0x0004)); | |||
313 | if (!pages) | |||
314 | return ERR_PTR(-ENOMEM12); | |||
315 | } | |||
316 | ||||
317 | i = 0; | |||
318 | for_each_sgt_page(page, iter, obj->mm.pages)for ((iter) = __sgt_iter((obj->mm.pages)->sgl, 0); ((page ) = (iter).pfn == 0 ? ((void *)0) : (PHYS_TO_VM_PAGE(((paddr_t )((iter).pfn + ((iter).curr >> 12)) << 12)))); (( (iter).curr += (1 << 12)) >= (iter).max) ? (iter) = __sgt_iter (__sg_next((iter).sgp), 0), 0 : 0) | |||
319 | pages[i++] = page; | |||
320 | vaddr = vmap(pages, n_pages, 0, pgprot); | |||
321 | if (pages != stack) | |||
322 | kvfree(pages); | |||
323 | ||||
324 | return vaddr ?: ERR_PTR(-ENOMEM12); | |||
325 | } | |||
326 | ||||
327 | static void *i915_gem_object_map_pfn(struct drm_i915_gem_object *obj, | |||
328 | enum i915_map_type type) | |||
329 | { | |||
330 | STUB()do { printf("%s: stub\n", __func__); } while(0); | |||
331 | return NULL((void *)0); | |||
332 | #ifdef notyet | |||
333 | resource_size_t iomap = obj->mm.region->iomap.base - | |||
334 | obj->mm.region->region.start; | |||
335 | unsigned long n_pfn = obj->base.size >> PAGE_SHIFT12; | |||
336 | unsigned long stack[32], *pfns = stack, i; | |||
337 | struct sgt_iter iter; | |||
338 | dma_addr_t addr; | |||
339 | void *vaddr; | |||
340 | ||||
341 | GEM_BUG_ON(type != I915_MAP_WC)((void)0); | |||
342 | ||||
343 | if (n_pfn > ARRAY_SIZE(stack)(sizeof((stack)) / sizeof((stack)[0]))) { | |||
344 | /* Too big for stack -- allocate temporary array instead */ | |||
345 | pfns = kvmalloc_array(n_pfn, sizeof(*pfns), GFP_KERNEL(0x0001 | 0x0004)); | |||
346 | if (!pfns) | |||
347 | return ERR_PTR(-ENOMEM12); | |||
348 | } | |||
349 | ||||
350 | i = 0; | |||
351 | for_each_sgt_daddr(addr, iter, obj->mm.pages)for ((iter) = __sgt_iter((obj->mm.pages)->sgl, 1); ((addr ) = (iter).dma + (iter).curr), (iter).sgp; (((iter).curr += ( (1ULL << (12)))) >= (iter).max) ? (iter) = __sgt_iter (__sg_next((iter).sgp), 1), 0 : 0) | |||
352 | pfns[i++] = (iomap + addr) >> PAGE_SHIFT12; | |||
353 | vaddr = vmap_pfn(pfns, n_pfn, pgprot_writecombine(PAGE_KERNEL_IO0)); | |||
354 | if (pfns != stack) | |||
355 | kvfree(pfns); | |||
356 | ||||
357 | return vaddr ?: ERR_PTR(-ENOMEM12); | |||
358 | #endif | |||
359 | } | |||
360 | ||||
361 | static void *i915_gem_object_map(struct drm_i915_gem_object *obj, | |||
362 | enum i915_map_type type) | |||
363 | { | |||
364 | unsigned long n_pages = obj->base.size >> PAGE_SHIFT12; | |||
365 | struct sg_table *sgt = obj->mm.pages; | |||
366 | struct vm_page *stack_pages[32]; | |||
367 | struct vm_page **pages = stack_pages; | |||
368 | struct vm_struct *area; | |||
369 | pgprot_t pgprot; | |||
370 | void *addr; | |||
371 | ||||
372 | if (!i915_gem_object_has_struct_page(obj) && type != I915_MAP_WC) | |||
373 | return NULL((void *)0); | |||
374 | ||||
375 | #if 0 | |||
376 | /* A single page can always be kmapped */ | |||
377 | if (n_pages == 1 && type == I915_MAP_WB) | |||
378 | return kmap(sg_page(sgt->sgl)); | |||
379 | #endif | |||
380 | ||||
381 | if (n_pages > ARRAY_SIZE(stack_pages)(sizeof((stack_pages)) / sizeof((stack_pages)[0]))) { | |||
382 | /* Too big for stack -- allocate temporary array instead */ | |||
383 | pages = kvmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL(0x0001 | 0x0004)); | |||
384 | if (!pages) | |||
385 | return NULL((void *)0); | |||
386 | } | |||
387 | ||||
388 | switch (type) { | |||
389 | default: | |||
390 | MISSING_CASE(type)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "type", (long)(type)); __builtin_expect(!!(__ret), 0); }); | |||
391 | /* fallthrough - to use PAGE_KERNEL anyway */ | |||
392 | case I915_MAP_WB: | |||
393 | pgprot = PAGE_KERNEL0; | |||
394 | break; | |||
395 | case I915_MAP_WC: | |||
396 | pgprot = pgprot_writecombine(PAGE_KERNEL_IO0); | |||
397 | break; | |||
398 | } | |||
399 | ||||
400 | if (i915_gem_object_has_struct_page(obj)) { | |||
401 | struct sgt_iter iter; | |||
402 | struct vm_page *page; | |||
403 | unsigned long i = 0; | |||
404 | ||||
405 | for_each_sgt_page(page, iter, sgt)for ((iter) = __sgt_iter((sgt)->sgl, 0); ((page) = (iter). pfn == 0 ? ((void *)0) : (PHYS_TO_VM_PAGE(((paddr_t)((iter).pfn + ((iter).curr >> 12)) << 12)))); (((iter).curr += (1 << 12)) >= (iter).max) ? (iter) = __sgt_iter(__sg_next ((iter).sgp), 0), 0 : 0) | |||
406 | pages[i++] = page; | |||
407 | } else { | |||
408 | STUB()do { printf("%s: stub\n", __func__); } while(0); | |||
409 | #ifdef notyet | |||
410 | resource_size_t iomap; | |||
411 | struct sgt_iter iter; | |||
412 | pte_t **ptes = mem; | |||
413 | dma_addr_t addr; | |||
414 | ||||
415 | iomap = obj->mm.region->iomap.base; | |||
416 | iomap -= obj->mm.region->region.start; | |||
417 | ||||
418 | for_each_sgt_daddr(addr, iter, sgt)for ((iter) = __sgt_iter((sgt)->sgl, 1); ((addr) = (iter). dma + (iter).curr), (iter).sgp; (((iter).curr += ((1ULL << (12)))) >= (iter).max) ? (iter) = __sgt_iter(__sg_next((iter ).sgp), 1), 0 : 0) | |||
419 | **ptes++ = iomap_pte(iomap, addr, pgprot); | |||
420 | #endif | |||
421 | } | |||
422 | addr = vmap(pages, n_pages, 0, pgprot); | |||
423 | ||||
424 | if (pages != stack_pages) | |||
425 | kvfree(pages); | |||
426 | ||||
427 | return addr; | |||
428 | } | |||
429 | ||||
430 | /* get, pin, and map the pages of the object into kernel space */ | |||
431 | void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, | |||
432 | enum i915_map_type type) | |||
433 | { | |||
434 | enum i915_map_type has_type; | |||
435 | bool_Bool pinned; | |||
436 | void *ptr; | |||
437 | int err; | |||
438 | ||||
439 | if (!i915_gem_object_has_struct_page(obj) && | |||
440 | !i915_gem_object_has_iomem(obj)) | |||
441 | return ERR_PTR(-ENXIO6); | |||
442 | ||||
443 | if (WARN_ON_ONCE(obj->flags & I915_BO_ALLOC_GPU_ONLY)({ static int __warned; int __ret = !!(obj->flags & (1UL << (6))); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "obj->flags & (1UL << (6))", "/usr/src/sys/dev/pci/drm/i915/gem/i915_gem_pages.c" , 443); __warned = 1; } __builtin_expect(!!(__ret), 0); })) | |||
444 | return ERR_PTR(-EINVAL22); | |||
445 | ||||
446 | assert_object_held(obj)do { (void)(&((obj)->base.resv)->lock.base); } while (0); | |||
447 | ||||
448 | pinned = !(type & I915_MAP_OVERRIDE(1UL << (31))); | |||
449 | type &= ~I915_MAP_OVERRIDE(1UL << (31)); | |||
450 | ||||
451 | if (!atomic_inc_not_zero(&obj->mm.pages_pin_count)atomic_add_unless((&obj->mm.pages_pin_count), 1, 0)) { | |||
452 | if (unlikely(!i915_gem_object_has_pages(obj))__builtin_expect(!!(!i915_gem_object_has_pages(obj)), 0)) { | |||
453 | GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj))((void)0); | |||
454 | ||||
455 | err = ____i915_gem_object_get_pages(obj); | |||
456 | if (err) | |||
457 | return ERR_PTR(err); | |||
458 | ||||
459 | smp_mb__before_atomic()do { } while (0); | |||
460 | } | |||
461 | atomic_inc(&obj->mm.pages_pin_count)__sync_fetch_and_add(&obj->mm.pages_pin_count, 1); | |||
462 | pinned = false0; | |||
463 | } | |||
464 | GEM_BUG_ON(!i915_gem_object_has_pages(obj))((void)0); | |||
465 | ||||
466 | /* | |||
467 | * For discrete our CPU mappings needs to be consistent in order to | |||
468 | * function correctly on !x86. When mapping things through TTM, we use | |||
469 | * the same rules to determine the caching type. | |||
470 | * | |||
471 | * The caching rules, starting from DG1: | |||
472 | * | |||
473 | * - If the object can be placed in device local-memory, then the | |||
474 | * pages should be allocated and mapped as write-combined only. | |||
475 | * | |||
476 | * - Everything else is always allocated and mapped as write-back, | |||
477 | * with the guarantee that everything is also coherent with the | |||
478 | * GPU. | |||
479 | * | |||
480 | * Internal users of lmem are already expected to get this right, so no | |||
481 | * fudging needed there. | |||
482 | */ | |||
483 | if (i915_gem_object_placement_possible(obj, INTEL_MEMORY_LOCAL)) { | |||
484 | if (type != I915_MAP_WC && !obj->mm.n_placements) { | |||
485 | ptr = ERR_PTR(-ENODEV19); | |||
486 | goto err_unpin; | |||
487 | } | |||
488 | ||||
489 | type = I915_MAP_WC; | |||
490 | } else if (IS_DGFX(to_i915(obj->base.dev))((&(to_i915(obj->base.dev))->__info)->is_dgfx)) { | |||
491 | type = I915_MAP_WB; | |||
492 | } | |||
493 | ||||
494 | ptr = page_unpack_bits(obj->mm.mapping, &has_type)({ unsigned long __v = (unsigned long)(obj->mm.mapping); * (&has_type) = __v & ((1UL << (12)) - 1); (typeof (obj->mm.mapping))(__v & -(1UL << (12))); }); | |||
495 | if (ptr && has_type != type) { | |||
496 | if (pinned) { | |||
497 | ptr = ERR_PTR(-EBUSY16); | |||
498 | goto err_unpin; | |||
499 | } | |||
500 | ||||
501 | unmap_object(obj, ptr); | |||
502 | ||||
503 | ptr = obj->mm.mapping = NULL((void *)0); | |||
504 | } | |||
505 | ||||
506 | if (!ptr) { | |||
507 | err = i915_gem_object_wait_moving_fence(obj, true1); | |||
508 | if (err) { | |||
509 | ptr = ERR_PTR(err); | |||
510 | goto err_unpin; | |||
511 | } | |||
512 | ||||
513 | if (GEM_WARN_ON(type == I915_MAP_WC && !pat_enabled())({ __builtin_expect(!!(!!(type == I915_MAP_WC && !pat_enabled ())), 0); })) | |||
514 | ptr = ERR_PTR(-ENODEV19); | |||
515 | else if (i915_gem_object_has_struct_page(obj)) | |||
516 | ptr = i915_gem_object_map_page(obj, type); | |||
517 | else | |||
518 | ptr = i915_gem_object_map_pfn(obj, type); | |||
519 | if (IS_ERR(ptr)) | |||
520 | goto err_unpin; | |||
521 | ||||
522 | obj->mm.mapping = page_pack_bits(ptr, type)({ unsigned long __bits = (type); ((void)0); ((typeof(ptr))(( unsigned long)(ptr) | __bits)); }); | |||
523 | } | |||
524 | ||||
525 | return ptr; | |||
526 | ||||
527 | err_unpin: | |||
528 | atomic_dec(&obj->mm.pages_pin_count)__sync_fetch_and_sub(&obj->mm.pages_pin_count, 1); | |||
529 | return ptr; | |||
530 | } | |||
531 | ||||
532 | void *i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj, | |||
533 | enum i915_map_type type) | |||
534 | { | |||
535 | void *ret; | |||
536 | ||||
537 | i915_gem_object_lock(obj, NULL((void *)0)); | |||
538 | ret = i915_gem_object_pin_map(obj, type); | |||
539 | i915_gem_object_unlock(obj); | |||
540 | ||||
541 | return ret; | |||
542 | } | |||
543 | ||||
544 | void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj, | |||
545 | unsigned long offset, | |||
546 | unsigned long size) | |||
547 | { | |||
548 | enum i915_map_type has_type; | |||
549 | void *ptr; | |||
550 | ||||
551 | GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj))((void)0); | |||
552 | GEM_BUG_ON(range_overflows_t(typeof(obj->base.size),((void)0) | |||
553 | offset, size, obj->base.size))((void)0); | |||
554 | ||||
555 | wmb()do { __asm volatile("sfence" ::: "memory"); } while (0); /* let all previous writes be visible to coherent partners */ | |||
556 | obj->mm.dirty = true1; | |||
557 | ||||
558 | if (obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE(1UL << (1))) | |||
559 | return; | |||
560 | ||||
561 | ptr = page_unpack_bits(obj->mm.mapping, &has_type)({ unsigned long __v = (unsigned long)(obj->mm.mapping); * (&has_type) = __v & ((1UL << (12)) - 1); (typeof (obj->mm.mapping))(__v & -(1UL << (12))); }); | |||
562 | if (has_type == I915_MAP_WC) | |||
563 | return; | |||
564 | ||||
565 | drm_clflush_virt_range(ptr + offset, size); | |||
566 | if (size == obj->base.size) { | |||
567 | obj->write_domain &= ~I915_GEM_DOMAIN_CPU0x00000001; | |||
568 | obj->cache_dirty = false0; | |||
569 | } | |||
570 | } | |||
571 | ||||
572 | void __i915_gem_object_release_map(struct drm_i915_gem_object *obj) | |||
573 | { | |||
574 | GEM_BUG_ON(!obj->mm.mapping)((void)0); | |||
575 | ||||
576 | /* | |||
577 | * We allow removing the mapping from underneath pinned pages! | |||
578 | * | |||
579 | * Furthermore, since this is an unsafe operation reserved only | |||
580 | * for construction time manipulation, we ignore locking prudence. | |||
581 | */ | |||
582 | unmap_object(obj, page_mask_bits(fetch_and_zero(&obj->mm.mapping))({ unsigned long __v = (unsigned long)(({ typeof(*&obj-> mm.mapping) __T = *(&obj->mm.mapping); *(&obj-> mm.mapping) = (typeof(*&obj->mm.mapping))0; __T; })); ( typeof(({ typeof(*&obj->mm.mapping) __T = *(&obj-> mm.mapping); *(&obj->mm.mapping) = (typeof(*&obj-> mm.mapping))0; __T; })))(__v & -(1UL << (12))); })); | |||
583 | ||||
584 | i915_gem_object_unpin_map(obj); | |||
585 | } | |||
586 | ||||
587 | struct scatterlist * | |||
588 | __i915_gem_object_get_sg(struct drm_i915_gem_object *obj, | |||
589 | struct i915_gem_object_page_iter *iter, | |||
590 | unsigned int n, | |||
591 | unsigned int *offset, | |||
592 | bool_Bool dma) | |||
593 | { | |||
594 | struct scatterlist *sg; | |||
595 | unsigned int idx, count; | |||
596 | ||||
597 | might_sleep()assertwaitok(); | |||
598 | GEM_BUG_ON(n >= obj->base.size >> PAGE_SHIFT)((void)0); | |||
599 | if (!i915_gem_object_has_pinned_pages(obj)) | |||
600 | assert_object_held(obj)do { (void)(&((obj)->base.resv)->lock.base); } while (0); | |||
601 | ||||
602 | /* As we iterate forward through the sg, we record each entry in a | |||
603 | * radixtree for quick repeated (backwards) lookups. If we have seen | |||
604 | * this index previously, we will have an entry for it. | |||
605 | * | |||
606 | * Initial lookup is O(N), but this is amortized to O(1) for | |||
607 | * sequential page access (where each new request is consecutive | |||
608 | * to the previous one). Repeated lookups are O(lg(obj->base.size)), | |||
609 | * i.e. O(1) with a large constant! | |||
610 | */ | |||
611 | if (n < READ_ONCE(iter->sg_idx)({ typeof(iter->sg_idx) __tmp = *(volatile typeof(iter-> sg_idx) *)&(iter->sg_idx); membar_datadep_consumer(); __tmp ; })) | |||
612 | goto lookup; | |||
613 | ||||
614 | mutex_lock(&iter->lock)rw_enter_write(&iter->lock); | |||
615 | ||||
616 | /* We prefer to reuse the last sg so that repeated lookup of this | |||
617 | * (or the subsequent) sg are fast - comparing against the last | |||
618 | * sg is faster than going through the radixtree. | |||
619 | */ | |||
620 | ||||
621 | sg = iter->sg_pos; | |||
622 | idx = iter->sg_idx; | |||
623 | count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); | |||
624 | ||||
625 | while (idx + count <= n) { | |||
626 | void *entry; | |||
627 | unsigned long i; | |||
628 | int ret; | |||
629 | ||||
630 | /* If we cannot allocate and insert this entry, or the | |||
631 | * individual pages from this range, cancel updating the | |||
632 | * sg_idx so that on this lookup we are forced to linearly | |||
633 | * scan onwards, but on future lookups we will try the | |||
634 | * insertion again (in which case we need to be careful of | |||
635 | * the error return reporting that we have already inserted | |||
636 | * this index). | |||
637 | */ | |||
638 | ret = radix_tree_insert(&iter->radix, idx, sg); | |||
639 | if (ret && ret != -EEXIST17) | |||
640 | goto scan; | |||
641 | ||||
642 | entry = xa_mk_value(idx); | |||
643 | for (i = 1; i < count; i++) { | |||
644 | ret = radix_tree_insert(&iter->radix, idx + i, entry); | |||
645 | if (ret && ret != -EEXIST17) | |||
646 | goto scan; | |||
647 | } | |||
648 | ||||
649 | idx += count; | |||
650 | sg = ____sg_next(sg); | |||
651 | count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); | |||
652 | } | |||
653 | ||||
654 | scan: | |||
655 | iter->sg_pos = sg; | |||
656 | iter->sg_idx = idx; | |||
657 | ||||
658 | mutex_unlock(&iter->lock)rw_exit_write(&iter->lock); | |||
659 | ||||
660 | if (unlikely(n < idx)__builtin_expect(!!(n < idx), 0)) /* insertion completed by another thread */ | |||
661 | goto lookup; | |||
662 | ||||
663 | /* In case we failed to insert the entry into the radixtree, we need | |||
664 | * to look beyond the current sg. | |||
665 | */ | |||
666 | while (idx + count <= n) { | |||
667 | idx += count; | |||
668 | sg = ____sg_next(sg); | |||
669 | count = dma ? __sg_dma_page_count(sg) : __sg_page_count(sg); | |||
670 | } | |||
671 | ||||
672 | *offset = n - idx; | |||
673 | return sg; | |||
674 | ||||
675 | lookup: | |||
676 | rcu_read_lock(); | |||
677 | ||||
678 | sg = radix_tree_lookup(&iter->radix, n); | |||
679 | GEM_BUG_ON(!sg)((void)0); | |||
680 | ||||
681 | /* If this index is in the middle of multi-page sg entry, | |||
682 | * the radix tree will contain a value entry that points | |||
683 | * to the start of that range. We will return the pointer to | |||
684 | * the base page and the offset of this page within the | |||
685 | * sg entry's range. | |||
686 | */ | |||
687 | *offset = 0; | |||
688 | if (unlikely(xa_is_value(sg))__builtin_expect(!!(xa_is_value(sg)), 0)) { | |||
689 | unsigned long base = xa_to_value(sg); | |||
690 | ||||
691 | sg = radix_tree_lookup(&iter->radix, base); | |||
692 | GEM_BUG_ON(!sg)((void)0); | |||
693 | ||||
694 | *offset = n - base; | |||
695 | } | |||
696 | ||||
697 | rcu_read_unlock(); | |||
698 | ||||
699 | return sg; | |||
700 | } | |||
701 | ||||
702 | struct vm_page * | |||
703 | i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n) | |||
704 | { | |||
705 | struct scatterlist *sg; | |||
706 | unsigned int offset; | |||
707 | ||||
708 | GEM_BUG_ON(!i915_gem_object_has_struct_page(obj))((void)0); | |||
709 | ||||
710 | sg = i915_gem_object_get_sg(obj, n, &offset); | |||
711 | return nth_page(sg_page(sg), offset)(&(sg_page(sg))[(offset)]); | |||
712 | } | |||
713 | ||||
714 | /* Like i915_gem_object_get_page(), but mark the returned page dirty */ | |||
715 | struct vm_page * | |||
716 | i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, | |||
717 | unsigned int n) | |||
718 | { | |||
719 | struct vm_page *page; | |||
720 | ||||
721 | page = i915_gem_object_get_page(obj, n); | |||
722 | if (!obj->mm.dirty) | |||
723 | set_page_dirty(page)x86_atomic_clearbits_u32(&page->pg_flags, 0x00000008); | |||
724 | ||||
725 | return page; | |||
726 | } | |||
727 | ||||
728 | dma_addr_t | |||
729 | i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, | |||
730 | unsigned long n, | |||
731 | unsigned int *len) | |||
732 | { | |||
733 | struct scatterlist *sg; | |||
734 | unsigned int offset; | |||
735 | ||||
736 | sg = i915_gem_object_get_sg_dma(obj, n, &offset); | |||
737 | ||||
738 | if (len) | |||
739 | *len = sg_dma_len(sg)((sg)->length) - (offset << PAGE_SHIFT12); | |||
740 | ||||
741 | return sg_dma_address(sg)((sg)->dma_address) + (offset << PAGE_SHIFT12); | |||
742 | } | |||
743 | ||||
744 | dma_addr_t | |||
745 | i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, | |||
746 | unsigned long n) | |||
747 | { | |||
748 | return i915_gem_object_get_dma_address_len(obj, n, NULL((void *)0)); | |||
749 | } |
1 | /* $OpenBSD: atomic.h,v 1.22 2024/01/06 12:52:20 jsg Exp $ */ |
2 | /** |
3 | * \file drm_atomic.h |
4 | * Atomic operations used in the DRM which may or may not be provided by the OS. |
5 | * |
6 | * \author Eric Anholt <anholt@FreeBSD.org> |
7 | */ |
8 | |
9 | /*- |
10 | * Copyright 2004 Eric Anholt |
11 | * All Rights Reserved. |
12 | * |
13 | * Permission is hereby granted, free of charge, to any person obtaining a |
14 | * copy of this software and associated documentation files (the "Software"), |
15 | * to deal in the Software without restriction, including without limitation |
16 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
17 | * and/or sell copies of the Software, and to permit persons to whom the |
18 | * Software is furnished to do so, subject to the following conditions: |
19 | * |
20 | * The above copyright notice and this permission notice (including the next |
21 | * paragraph) shall be included in all copies or substantial portions of the |
22 | * Software. |
23 | * |
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
27 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
28 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
29 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
30 | * OTHER DEALINGS IN THE SOFTWARE. |
31 | */ |
32 | |
33 | #ifndef _DRM_LINUX_ATOMIC_H_ |
34 | #define _DRM_LINUX_ATOMIC_H_ |
35 | |
36 | #include <sys/types.h> |
37 | #include <sys/mutex.h> |
38 | #include <machine/intr.h> |
39 | #include <linux/types.h> |
40 | #include <linux/compiler.h> /* via x86/include/asm/atomic.h */ |
41 | |
42 | #define ATOMIC_INIT(x)(x) (x) |
43 | |
44 | #define atomic_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) WRITE_ONCE(*(p), (v))({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) |
45 | #define atomic_read(p)({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) READ_ONCE(*(p))({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) |
46 | #define atomic_inc(p)__sync_fetch_and_add(p, 1) __sync_fetch_and_add(p, 1) |
47 | #define atomic_dec(p)__sync_fetch_and_sub(p, 1) __sync_fetch_and_sub(p, 1) |
48 | #define atomic_add(n, p)__sync_fetch_and_add(p, n) __sync_fetch_and_add(p, n) |
49 | #define atomic_sub(n, p)__sync_fetch_and_sub(p, n) __sync_fetch_and_sub(p, n) |
50 | #define atomic_and(n, p)__sync_fetch_and_and(p, n) __sync_fetch_and_and(p, n) |
51 | #define atomic_or(n, p)x86_atomic_setbits_u32(p, n) atomic_setbits_intx86_atomic_setbits_u32(p, n) |
52 | #define atomic_add_return(n, p)__sync_add_and_fetch(p, n) __sync_add_and_fetch(p, n) |
53 | #define atomic_sub_return(n, p)__sync_sub_and_fetch(p, n) __sync_sub_and_fetch(p, n) |
54 | #define atomic_sub_and_test(n, p)(__sync_sub_and_fetch(p, n) == 0) (atomic_sub_return(n, p)__sync_sub_and_fetch(p, n) == 0) |
55 | #define atomic_inc_return(v)__sync_add_and_fetch((v), 1) atomic_add_return(1, (v))__sync_add_and_fetch((v), 1) |
56 | #define atomic_dec_return(v)__sync_sub_and_fetch((v), 1) atomic_sub_return(1, (v))__sync_sub_and_fetch((v), 1) |
57 | #define atomic_dec_and_test(v)(__sync_sub_and_fetch((v), 1) == 0) (atomic_dec_return(v)__sync_sub_and_fetch((v), 1) == 0) |
58 | #define atomic_inc_and_test(v)(__sync_add_and_fetch((v), 1) == 0) (atomic_inc_return(v)__sync_add_and_fetch((v), 1) == 0) |
59 | #define atomic_cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) __sync_val_compare_and_swap(p, o, n) |
60 | #define cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) __sync_val_compare_and_swap(p, o, n) |
61 | #define cmpxchg64(p, o, n)__sync_val_compare_and_swap(p, o, n) __sync_val_compare_and_swap(p, o, n) |
62 | #define atomic_set_release(p, v)({ typeof(*((p))) __tmp = (((v))); *(volatile typeof(*((p))) * )&(*((p))) = __tmp; __tmp; }) atomic_set((p), (v))({ typeof(*((p))) __tmp = (((v))); *(volatile typeof(*((p))) * )&(*((p))) = __tmp; __tmp; }) |
63 | #define atomic_andnot(bits, p)x86_atomic_clearbits_u32(p,bits) atomic_clearbits_intx86_atomic_clearbits_u32(p,bits) |
64 | #define atomic_fetch_inc(p)__sync_fetch_and_add(p, 1) __sync_fetch_and_add(p, 1) |
65 | #define atomic_fetch_xor(n, p)__sync_fetch_and_xor(p, n) __sync_fetch_and_xor(p, n) |
66 | |
67 | #define try_cmpxchg(p, op, n)({ __typeof(p) __op = (__typeof((p)))(op); __typeof(*(p)) __o = *__op; __typeof(*(p)) __p = __sync_val_compare_and_swap((p ), (__o), (n)); if (__p != __o) *__op = __p; (__p == __o); }) \ |
68 | ({ \ |
69 | __typeof(p) __op = (__typeof((p)))(op); \ |
70 | __typeof(*(p)) __o = *__op; \ |
71 | __typeof(*(p)) __p = __sync_val_compare_and_swap((p), (__o), (n)); \ |
72 | if (__p != __o) \ |
73 | *__op = __p; \ |
74 | (__p == __o); \ |
75 | }) |
76 | |
77 | static inline bool_Bool |
78 | atomic_try_cmpxchg(volatile int *p, int *op, int n) |
79 | { |
80 | return try_cmpxchg(p, op, n)({ __typeof(p) __op = (__typeof((p)))(op); __typeof(*(p)) __o = *__op; __typeof(*(p)) __p = __sync_val_compare_and_swap((p ), (__o), (n)); if (__p != __o) *__op = __p; (__p == __o); }); |
81 | } |
82 | |
83 | static inline int |
84 | atomic_xchg(volatile int *v, int n) |
85 | { |
86 | __sync_synchronize(); |
87 | return __sync_lock_test_and_set(v, n); |
88 | } |
89 | |
90 | #define xchg(v, n)__sync_lock_test_and_set(v, n) __sync_lock_test_and_set(v, n) |
91 | |
92 | static inline int |
93 | atomic_add_unless(volatile int *v, int n, int u) |
94 | { |
95 | int o; |
96 | |
97 | do { |
98 | o = *v; |
99 | if (o == u) |
100 | return 0; |
101 | } while (__sync_val_compare_and_swap(v, o, o +n) != o); |
102 | |
103 | return 1; |
104 | } |
105 | |
106 | #define atomic_inc_not_zero(v)atomic_add_unless((v), 1, 0) atomic_add_unless((v), 1, 0) |
107 | |
108 | static inline int |
109 | atomic_dec_if_positive(volatile int *v) |
110 | { |
111 | int r, o; |
112 | |
113 | do { |
114 | o = *v; |
115 | r = o - 1; |
116 | if (r < 0) |
117 | break; |
118 | } while (__sync_val_compare_and_swap(v, o, r) != o); |
119 | |
120 | return r; |
121 | } |
122 | |
123 | #define atomic_long_read(p)({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) READ_ONCE(*(p))({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) |
124 | |
125 | /* 32 bit powerpc lacks 64 bit atomics */ |
126 | #if !defined(__powerpc__) || defined(__powerpc64__) |
127 | |
128 | typedef int64_t atomic64_t; |
129 | |
130 | #define ATOMIC64_INIT(x)(x) (x) |
131 | |
132 | #define atomic64_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) WRITE_ONCE(*(p), (v))({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) |
133 | #define atomic64_read(p)({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) READ_ONCE(*(p))({ typeof(*(p)) __tmp = *(volatile typeof(*(p)) *)&(*(p)) ; membar_datadep_consumer(); __tmp; }) |
134 | |
135 | static inline int64_t |
136 | atomic64_xchg(volatile int64_t *v, int64_t n) |
137 | { |
138 | __sync_synchronize(); |
139 | return __sync_lock_test_and_set(v, n); |
140 | } |
141 | |
142 | static inline int64_t |
143 | atomic64_cmpxchg(volatile int64_t *v, int64_t o, int64_t n) |
144 | { |
145 | return __sync_val_compare_and_swap(v, o, n); |
146 | } |
147 | |
148 | #define atomic64_add(n, p)__sync_fetch_and_add_8(p, n) __sync_fetch_and_add_8(p, n) |
149 | #define atomic64_sub(n, p)__sync_fetch_and_sub_8(p, n) __sync_fetch_and_sub_8(p, n) |
150 | #define atomic64_inc(p)__sync_fetch_and_add_8(p, 1) __sync_fetch_and_add_8(p, 1) |
151 | #define atomic64_add_return(n, p)__sync_add_and_fetch_8(p, n) __sync_add_and_fetch_8(p, n) |
152 | #define atomic64_inc_return(p)__sync_add_and_fetch_8(p, 1) __sync_add_and_fetch_8(p, 1) |
153 | |
154 | #else |
155 | |
156 | extern struct mutex atomic64_mtx; |
157 | |
158 | typedef struct { |
159 | volatile int64_t val; |
160 | } atomic64_t; |
161 | |
162 | #define ATOMIC64_INIT(x)(x) { (x) } |
163 | |
164 | static inline void |
165 | atomic64_set(atomic64_t *v, int64_t i)({ typeof(*(atomic64_t *v)) __tmp = ((int64_t i)); *(volatile typeof(*(atomic64_t *v)) *)&(*(atomic64_t *v)) = __tmp; __tmp ; }) |
166 | { |
167 | mtx_enter(&atomic64_mtx); |
168 | v->val = i; |
169 | mtx_leave(&atomic64_mtx); |
170 | } |
171 | |
172 | static inline int64_t |
173 | atomic64_read(atomic64_t *v)({ typeof(*(atomic64_t *v)) __tmp = *(volatile typeof(*(atomic64_t *v)) *)&(*(atomic64_t *v)); membar_datadep_consumer(); __tmp ; }) |
174 | { |
175 | int64_t val; |
176 | |
177 | mtx_enter(&atomic64_mtx); |
178 | val = v->val; |
179 | mtx_leave(&atomic64_mtx); |
180 | |
181 | return val; |
182 | } |
183 | |
184 | static inline int64_t |
185 | atomic64_xchg(atomic64_t *v, int64_t n) |
186 | { |
187 | int64_t val; |
188 | |
189 | mtx_enter(&atomic64_mtx); |
190 | val = v->val; |
191 | v->val = n; |
192 | mtx_leave(&atomic64_mtx); |
193 | |
194 | return val; |
195 | } |
196 | |
197 | static inline void |
198 | atomic64_add(int i, atomic64_t *v)__sync_fetch_and_add_8(atomic64_t *v, int i) |
199 | { |
200 | mtx_enter(&atomic64_mtx); |
201 | v->val += i; |
202 | mtx_leave(&atomic64_mtx); |
203 | } |
204 | |
205 | #define atomic64_inc(p)__sync_fetch_and_add_8(p, 1) atomic64_add(p, 1)__sync_fetch_and_add_8(1, p) |
206 | |
207 | static inline int64_t |
208 | atomic64_add_return(int i, atomic64_t *v)__sync_add_and_fetch_8(atomic64_t *v, int i) |
209 | { |
210 | int64_t val; |
211 | |
212 | mtx_enter(&atomic64_mtx); |
213 | val = v->val + i; |
214 | v->val = val; |
215 | mtx_leave(&atomic64_mtx); |
216 | |
217 | return val; |
218 | } |
219 | |
220 | #define atomic64_inc_return(p)__sync_add_and_fetch_8(p, 1) atomic64_add_return(p, 1)__sync_add_and_fetch_8(1, p) |
221 | |
222 | static inline void |
223 | atomic64_sub(int i, atomic64_t *v)__sync_fetch_and_sub_8(atomic64_t *v, int i) |
224 | { |
225 | mtx_enter(&atomic64_mtx); |
226 | v->val -= i; |
227 | mtx_leave(&atomic64_mtx); |
228 | } |
229 | #endif |
230 | |
231 | #ifdef __LP64__1 |
232 | typedef int64_t atomic_long_t; |
233 | #define atomic_long_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) atomic64_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) |
234 | #define atomic_long_xchg(v, n)atomic64_xchg(v, n) atomic64_xchg(v, n) |
235 | #define atomic_long_cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) atomic_cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) |
236 | #define atomic_long_add(i, v)__sync_fetch_and_add_8(v, i) atomic64_add(i, v)__sync_fetch_and_add_8(v, i) |
237 | #define atomic_long_sub(i, v)__sync_fetch_and_sub_8(v, i) atomic64_sub(i, v)__sync_fetch_and_sub_8(v, i) |
238 | #else |
239 | typedef int32_t atomic_long_t; |
240 | #define atomic_long_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) atomic_set(p, v)({ typeof(*(p)) __tmp = ((v)); *(volatile typeof(*(p)) *)& (*(p)) = __tmp; __tmp; }) |
241 | #define atomic_long_xchg(v, n)atomic64_xchg(v, n) atomic_xchg(v, n) |
242 | #define atomic_long_cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) atomic_cmpxchg(p, o, n)__sync_val_compare_and_swap(p, o, n) |
243 | #define atomic_long_add(i, v)__sync_fetch_and_add_8(v, i) atomic_add(i, v)__sync_fetch_and_add(v, i) |
244 | #define atomic_long_sub(i, v)__sync_fetch_and_sub_8(v, i) atomic_sub(i, v)__sync_fetch_and_sub(v, i) |
245 | #endif |
246 | |
247 | static inline atomic_t |
248 | test_and_set_bit(u_int b, volatile void *p) |
249 | { |
250 | unsigned int m = 1 << (b & 0x1f); |
251 | unsigned int prev = __sync_fetch_and_or((volatile u_int *)p + (b >> 5), m); |
252 | return (prev & m) != 0; |
253 | } |
254 | |
255 | static inline void |
256 | clear_bit(u_int b, volatile void *p) |
257 | { |
258 | atomic_clearbits_intx86_atomic_clearbits_u32(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f)); |
259 | } |
260 | |
261 | static inline void |
262 | clear_bit_unlock(u_int b, volatile void *p) |
263 | { |
264 | membar_enter()do { __asm volatile("mfence" ::: "memory"); } while (0); |
265 | clear_bit(b, p); |
266 | } |
267 | |
268 | static inline void |
269 | set_bit(u_int b, volatile void *p) |
270 | { |
271 | atomic_setbits_intx86_atomic_setbits_u32(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f)); |
272 | } |
273 | |
274 | static inline void |
275 | __clear_bit(u_int b, volatile void *p) |
276 | { |
277 | volatile u_int *ptr = (volatile u_int *)p; |
278 | ptr[b >> 5] &= ~(1 << (b & 0x1f)); |
279 | } |
280 | |
281 | static inline void |
282 | __set_bit(u_int b, volatile void *p) |
283 | { |
284 | volatile u_int *ptr = (volatile u_int *)p; |
285 | ptr[b >> 5] |= (1 << (b & 0x1f)); |
286 | } |
287 | |
288 | static inline int |
289 | test_bit(u_int b, const volatile void *p) |
290 | { |
291 | return !!(((volatile u_int *)p)[b >> 5] & (1 << (b & 0x1f))); |
292 | } |
293 | |
294 | static inline int |
295 | __test_and_set_bit(u_int b, volatile void *p) |
296 | { |
297 | unsigned int m = 1 << (b & 0x1f); |
298 | volatile u_int *ptr = (volatile u_int *)p; |
299 | unsigned int prev = ptr[b >> 5]; |
300 | ptr[b >> 5] |= m; |
301 | |
302 | return (prev & m) != 0; |
303 | } |
304 | |
305 | static inline int |
306 | test_and_clear_bit(u_int b, volatile void *p) |
307 | { |
308 | unsigned int m = 1 << (b & 0x1f); |
309 | unsigned int prev = __sync_fetch_and_and((volatile u_int *)p + (b >> 5), ~m); |
310 | return (prev & m) != 0; |
311 | } |
312 | |
313 | static inline int |
314 | __test_and_clear_bit(u_int b, volatile void *p) |
315 | { |
316 | volatile u_int *ptr = (volatile u_int *)p; |
317 | int rv = !!(ptr[b >> 5] & (1 << (b & 0x1f))); |
318 | ptr[b >> 5] &= ~(1 << (b & 0x1f)); |
319 | return rv; |
320 | } |
321 | |
322 | static inline int |
323 | find_first_zero_bit(volatile void *p, int max) |
324 | { |
325 | int b; |
326 | volatile u_int *ptr = (volatile u_int *)p; |
327 | |
328 | for (b = 0; b < max; b += 32) { |
329 | if (ptr[b >> 5] != ~0) { |
330 | for (;;) { |
331 | if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0) |
332 | return b; |
333 | b++; |
334 | } |
335 | } |
336 | } |
337 | return max; |
338 | } |
339 | |
340 | static inline int |
341 | find_next_zero_bit(volatile void *p, int max, int b) |
342 | { |
343 | volatile u_int *ptr = (volatile u_int *)p; |
344 | |
345 | for (; b < max; b += 32) { |
346 | if (ptr[b >> 5] != ~0) { |
347 | for (;;) { |
348 | if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0) |
349 | return b; |
350 | b++; |
351 | } |
352 | } |
353 | } |
354 | return max; |
355 | } |
356 | |
357 | static inline int |
358 | find_first_bit(volatile void *p, int max) |
359 | { |
360 | int b; |
361 | volatile u_int *ptr = (volatile u_int *)p; |
362 | |
363 | for (b = 0; b < max; b += 32) { |
364 | if (ptr[b >> 5] != 0) { |
365 | for (;;) { |
366 | if (ptr[b >> 5] & (1 << (b & 0x1f))) |
367 | return b; |
368 | b++; |
369 | } |
370 | } |
371 | } |
372 | return max; |
373 | } |
374 | |
375 | static inline int |
376 | find_next_bit(const volatile void *p, int max, int b) |
377 | { |
378 | volatile u_int *ptr = (volatile u_int *)p; |
379 | |
380 | for (; b < max; b+= 32) { |
381 | if (ptr[b >> 5] != 0) { |
382 | for (;;) { |
383 | if (ptr[b >> 5] & (1 << (b & 0x1f))) |
384 | return b; |
385 | b++; |
386 | } |
387 | } |
388 | } |
389 | return max; |
390 | } |
391 | |
392 | #define for_each_set_bit(b, p, max)for ((b) = find_first_bit((p), (max)); (b) < (max); (b) = find_next_bit ((p), (max), (b) + 1)) \ |
393 | for ((b) = find_first_bit((p), (max)); \ |
394 | (b) < (max); \ |
395 | (b) = find_next_bit((p), (max), (b) + 1)) |
396 | |
397 | #define for_each_clear_bit(b, p, max)for ((b) = find_first_zero_bit((p), (max)); (b) < (max); ( b) = find_next_zero_bit((p), (max), (b) + 1)) \ |
398 | for ((b) = find_first_zero_bit((p), (max)); \ |
399 | (b) < (max); \ |
400 | (b) = find_next_zero_bit((p), (max), (b) + 1)) |
401 | |
402 | #if defined(__i386__) |
403 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __asm volatile("lock; addl $0,-4(%%esp)" : : : "memory", "cc") |
404 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __asm volatile("lock; addl $0,-4(%%esp)" : : : "memory", "cc") |
405 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __asm volatile("lock; addl $0,-4(%%esp)" : : : "memory", "cc") |
406 | #define smp_mb()__asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc" ) __asm volatile("lock; addl $0,-4(%%esp)" : : : "memory", "cc") |
407 | #define smp_rmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("")do { __asm volatile("" ::: "memory"); } while (0) |
408 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("")do { __asm volatile("" ::: "memory"); } while (0) |
409 | #define __smp_store_mb(var, value)do { (void)__sync_lock_test_and_set(&var, value); } while (0) do { (void)xchg(&var, value)__sync_lock_test_and_set(&var, value); } while (0) |
410 | #define smp_mb__after_atomic()do { } while (0) do { } while (0) |
411 | #define smp_mb__before_atomic()do { } while (0) do { } while (0) |
412 | #elif defined(__amd64__1) |
413 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("lfence")do { __asm volatile("lfence" ::: "memory"); } while (0) |
414 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("sfence")do { __asm volatile("sfence" ::: "memory"); } while (0) |
415 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("mfence")do { __asm volatile("mfence" ::: "memory"); } while (0) |
416 | #define smp_mb()__asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc" ) __asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc") |
417 | #define smp_rmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("")do { __asm volatile("" ::: "memory"); } while (0) |
418 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("")do { __asm volatile("" ::: "memory"); } while (0) |
419 | #define __smp_store_mb(var, value)do { (void)__sync_lock_test_and_set(&var, value); } while (0) do { (void)xchg(&var, value)__sync_lock_test_and_set(&var, value); } while (0) |
420 | #define smp_mb__after_atomic()do { } while (0) do { } while (0) |
421 | #define smp_mb__before_atomic()do { } while (0) do { } while (0) |
422 | #elif defined(__aarch64__) |
423 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("dsb ld")do { __asm volatile("dsb ld" ::: "memory"); } while (0) |
424 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("dsb st")do { __asm volatile("dsb st" ::: "memory"); } while (0) |
425 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("dsb sy")do { __asm volatile("dsb sy" ::: "memory"); } while (0) |
426 | #define dma_rmb() __membar("dmb oshld")do { __asm volatile("dmb oshld" ::: "memory"); } while (0) |
427 | #define dma_wmb() __membar("dmb oshst")do { __asm volatile("dmb oshst" ::: "memory"); } while (0) |
428 | #define dma_mb() __membar("dmb osh")do { __asm volatile("dmb osh" ::: "memory"); } while (0) |
429 | #elif defined(__arm__) |
430 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("dsb sy")do { __asm volatile("dsb sy" ::: "memory"); } while (0) |
431 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("dsb sy")do { __asm volatile("dsb sy" ::: "memory"); } while (0) |
432 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("dsb sy")do { __asm volatile("dsb sy" ::: "memory"); } while (0) |
433 | #elif defined(__mips64__) |
434 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) mips_sync() |
435 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) mips_sync() |
436 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) mips_sync() |
437 | #elif defined(__powerpc64__) |
438 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
439 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
440 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
441 | #define smp_rmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("lwsync")do { __asm volatile("lwsync" ::: "memory"); } while (0) |
442 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("lwsync")do { __asm volatile("lwsync" ::: "memory"); } while (0) |
443 | #elif defined(__powerpc__) |
444 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
445 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
446 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("sync")do { __asm volatile("sync" ::: "memory"); } while (0) |
447 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("eieio")do { __asm volatile("eieio" ::: "memory"); } while (0) |
448 | #elif defined(__riscv) |
449 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) __membar("fence ir,ir")do { __asm volatile("fence ir,ir" ::: "memory"); } while (0) |
450 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) __membar("fence ow,ow")do { __asm volatile("fence ow,ow" ::: "memory"); } while (0) |
451 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) __membar("fence iorw,iorw")do { __asm volatile("fence iorw,iorw" ::: "memory"); } while ( 0) |
452 | #define smp_rmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("fence r,r")do { __asm volatile("fence r,r" ::: "memory"); } while (0) |
453 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) __membar("fence w,w")do { __asm volatile("fence w,w" ::: "memory"); } while (0) |
454 | #define smp_mb()__asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc" ) __membar("fence rw,rw")do { __asm volatile("fence rw,rw" ::: "memory"); } while (0) |
455 | #elif defined(__sparc64__) |
456 | #define rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) membar_sync()do { __asm volatile("mfence" ::: "memory"); } while (0) |
457 | #define wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) membar_sync()do { __asm volatile("mfence" ::: "memory"); } while (0) |
458 | #define mb()do { __asm volatile("mfence" ::: "memory"); } while (0) membar_sync()do { __asm volatile("mfence" ::: "memory"); } while (0) |
459 | #endif |
460 | |
461 | #ifndef smp_rmb |
462 | #define smp_rmb()do { __asm volatile("" ::: "memory"); } while (0) rmb()do { __asm volatile("lfence" ::: "memory"); } while (0) |
463 | #endif |
464 | |
465 | #ifndef smp_wmb |
466 | #define smp_wmb()do { __asm volatile("" ::: "memory"); } while (0) wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) |
467 | #endif |
468 | |
469 | #ifndef mmiowb |
470 | #define mmiowb()do { __asm volatile("sfence" ::: "memory"); } while (0) wmb()do { __asm volatile("sfence" ::: "memory"); } while (0) |
471 | #endif |
472 | |
473 | #ifndef smp_mb__before_atomic |
474 | #define smp_mb__before_atomic()do { } while (0) mb()do { __asm volatile("mfence" ::: "memory"); } while (0) |
475 | #endif |
476 | |
477 | #ifndef smp_mb__after_atomic |
478 | #define smp_mb__after_atomic()do { } while (0) mb()do { __asm volatile("mfence" ::: "memory"); } while (0) |
479 | #endif |
480 | |
481 | #ifndef smp_store_mb |
482 | #define smp_store_mb(x, v)do { x = v; do { __asm volatile("mfence" ::: "memory"); } while (0); } while (0) do { x = v; mb()do { __asm volatile("mfence" ::: "memory"); } while (0); } while (0) |
483 | #endif |
484 | |
485 | #endif |