blob: 57e980d1a84bcbff173aa2737682b76593af8360 [file] [log] [blame]
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright 2016-2019 HabanaLabs, Ltd.
5 * All Rights Reserved.
6 */
7
Omer Shpigelman0feaf862019-02-16 00:39:22 +02008#include <uapi/misc/habanalabs.h>
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02009#include "habanalabs.h"
Greg Kroah-Hartman7b16a152020-07-28 19:18:51 +020010#include "../include/hw_ip/mmu/mmu_general.h"
Oded Gabbayeff6f4a2019-02-16 00:39:21 +020011
12#include <linux/uaccess.h>
13#include <linux/slab.h>
Omer Shpigelman0feaf862019-02-16 00:39:22 +020014
Omer Shpigelman0feaf862019-02-16 00:39:22 +020015#define HL_MMU_DEBUG 0
16
Moti Haimovskib19dc672020-11-18 20:15:29 +020017/* use small pages for supporting non-pow2 (32M/40M/48M) DRAM phys page sizes */
18#define DRAM_POOL_PAGE_SIZE SZ_8M
19
Omer Shpigelman0feaf862019-02-16 00:39:22 +020020/*
21 * The va ranges in context object contain a list with the available chunks of
22 * device virtual memory.
23 * There is one range for host allocations and one for DRAM allocations.
24 *
25 * On initialization each range contains one chunk of all of its available
26 * virtual range which is a half of the total device virtual range.
27 *
28 * On each mapping of physical pages, a suitable virtual range chunk (with a
29 * minimum size) is selected from the list. If the chunk size equals the
30 * requested size, the chunk is returned. Otherwise, the chunk is split into
31 * two chunks - one to return as result and a remainder to stay in the list.
32 *
33 * On each Unmapping of a virtual address, the relevant virtual chunk is
34 * returned to the list. The chunk is added to the list and if its edges match
35 * the edges of the adjacent chunks (means a contiguous chunk can be created),
36 * the chunks are merged.
37 *
38 * On finish, the list is checked to have only one chunk of all the relevant
39 * virtual range (which is a half of the device total virtual range).
40 * If not (means not all mappings were unmapped), a warning is printed.
41 */
42
43/*
Omer Shpigelman3b762f52020-12-09 13:28:46 +020044 * alloc_device_memory() - allocate device memory.
45 * @ctx: pointer to the context structure.
46 * @args: host parameters containing the requested size.
47 * @ret_handle: result handle.
Omer Shpigelman0feaf862019-02-16 00:39:22 +020048 *
49 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +020050 * - Allocate the requested size rounded up to 'dram_page_size' pages.
51 * - Return unique handle for later map/unmap/free.
Omer Shpigelman0feaf862019-02-16 00:39:22 +020052 */
53static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
54 u32 *ret_handle)
55{
56 struct hl_device *hdev = ctx->hdev;
57 struct hl_vm *vm = &hdev->vm;
58 struct hl_vm_phys_pg_pack *phys_pg_pack;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +020059 u64 paddr = 0, total_size, num_pgs, i;
Moti Haimovskib19dc672020-11-18 20:15:29 +020060 u32 num_curr_pgs, page_size;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +020061 int handle, rc;
Omer Shpigelman0feaf862019-02-16 00:39:22 +020062 bool contiguous;
63
64 num_curr_pgs = 0;
65 page_size = hdev->asic_prop.dram_page_size;
Moti Haimovskib19dc672020-11-18 20:15:29 +020066 num_pgs = DIV_ROUND_UP_ULL(args->alloc.mem_size, page_size);
67 total_size = num_pgs * page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +020068
Ofir Bitton08391522020-08-11 08:57:45 +030069 if (!total_size) {
70 dev_err(hdev->dev, "Cannot allocate 0 bytes\n");
71 return -EINVAL;
72 }
73
Omer Shpigelman0feaf862019-02-16 00:39:22 +020074 contiguous = args->flags & HL_MEM_CONTIGUOUS;
75
76 if (contiguous) {
77 paddr = (u64) gen_pool_alloc(vm->dram_pg_pool, total_size);
78 if (!paddr) {
79 dev_err(hdev->dev,
Oded Gabbayfc6121e2020-09-23 14:07:32 +030080 "failed to allocate %llu contiguous pages with total size of %llu\n",
81 num_pgs, total_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +020082 return -ENOMEM;
83 }
84 }
85
86 phys_pg_pack = kzalloc(sizeof(*phys_pg_pack), GFP_KERNEL);
87 if (!phys_pg_pack) {
88 rc = -ENOMEM;
89 goto pages_pack_err;
90 }
91
92 phys_pg_pack->vm_type = VM_TYPE_PHYS_PACK;
93 phys_pg_pack->asid = ctx->asid;
94 phys_pg_pack->npages = num_pgs;
95 phys_pg_pack->page_size = page_size;
96 phys_pg_pack->total_size = total_size;
97 phys_pg_pack->flags = args->flags;
98 phys_pg_pack->contiguous = contiguous;
99
Omer Shpigelman4eb1d122019-03-07 15:47:19 +0200100 phys_pg_pack->pages = kvmalloc_array(num_pgs, sizeof(u64), GFP_KERNEL);
Ofir Bitton08391522020-08-11 08:57:45 +0300101 if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200102 rc = -ENOMEM;
103 goto pages_arr_err;
104 }
105
106 if (phys_pg_pack->contiguous) {
107 for (i = 0 ; i < num_pgs ; i++)
108 phys_pg_pack->pages[i] = paddr + i * page_size;
109 } else {
110 for (i = 0 ; i < num_pgs ; i++) {
111 phys_pg_pack->pages[i] = (u64) gen_pool_alloc(
112 vm->dram_pg_pool,
113 page_size);
114 if (!phys_pg_pack->pages[i]) {
115 dev_err(hdev->dev,
Oded Gabbaycab8e3e2019-03-27 09:44:28 +0200116 "Failed to allocate device memory (out of memory)\n");
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200117 rc = -ENOMEM;
118 goto page_err;
119 }
120
121 num_curr_pgs++;
122 }
123 }
124
125 spin_lock(&vm->idr_lock);
126 handle = idr_alloc(&vm->phys_pg_pack_handles, phys_pg_pack, 1, 0,
Ofir Bittond5eb8372021-02-14 15:35:56 +0200127 GFP_KERNEL);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200128 spin_unlock(&vm->idr_lock);
129
130 if (handle < 0) {
131 dev_err(hdev->dev, "Failed to get handle for page\n");
132 rc = -EFAULT;
133 goto idr_err;
134 }
135
136 for (i = 0 ; i < num_pgs ; i++)
137 kref_get(&vm->dram_pg_pool_refcount);
138
139 phys_pg_pack->handle = handle;
140
141 atomic64_add(phys_pg_pack->total_size, &ctx->dram_phys_mem);
142 atomic64_add(phys_pg_pack->total_size, &hdev->dram_used_mem);
143
144 *ret_handle = handle;
145
146 return 0;
147
148idr_err:
149page_err:
150 if (!phys_pg_pack->contiguous)
151 for (i = 0 ; i < num_curr_pgs ; i++)
152 gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[i],
153 page_size);
154
Omer Shpigelman4eb1d122019-03-07 15:47:19 +0200155 kvfree(phys_pg_pack->pages);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200156pages_arr_err:
157 kfree(phys_pg_pack);
158pages_pack_err:
159 if (contiguous)
160 gen_pool_free(vm->dram_pg_pool, paddr, total_size);
161
162 return rc;
163}
164
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200165/**
166 * dma_map_host_va() - DMA mapping of the given host virtual address.
167 * @hdev: habanalabs device structure.
168 * @addr: the host virtual address of the memory area.
169 * @size: the size of the memory area.
170 * @p_userptr: pointer to result userptr structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200171 *
172 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200173 * - Allocate userptr structure.
174 * - Pin the given host memory using the userptr structure.
175 * - Perform DMA mapping to have the DMA addresses of the pages.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200176 */
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300177static int dma_map_host_va(struct hl_device *hdev, u64 addr, u64 size,
178 struct hl_userptr **p_userptr)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200179{
180 struct hl_userptr *userptr;
181 int rc;
182
183 userptr = kzalloc(sizeof(*userptr), GFP_KERNEL);
184 if (!userptr) {
185 rc = -ENOMEM;
186 goto userptr_err;
187 }
188
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300189 rc = hl_pin_host_memory(hdev, addr, size, userptr);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200190 if (rc) {
191 dev_err(hdev->dev, "Failed to pin host memory\n");
192 goto pin_err;
193 }
194
195 rc = hdev->asic_funcs->asic_dma_map_sg(hdev, userptr->sgt->sgl,
196 userptr->sgt->nents, DMA_BIDIRECTIONAL);
197 if (rc) {
198 dev_err(hdev->dev, "failed to map sgt with DMA region\n");
199 goto dma_map_err;
200 }
201
202 userptr->dma_mapped = true;
203 userptr->dir = DMA_BIDIRECTIONAL;
204 userptr->vm_type = VM_TYPE_USERPTR;
205
206 *p_userptr = userptr;
207
208 return 0;
209
210dma_map_err:
211 hl_unpin_host_memory(hdev, userptr);
212pin_err:
213 kfree(userptr);
214userptr_err:
215
216 return rc;
217}
218
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200219/**
220 * dma_unmap_host_va() - DMA unmapping of the given host virtual address.
221 * @hdev: habanalabs device structure.
222 * @userptr: userptr to free.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200223 *
224 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200225 * - Unpins the physical pages.
226 * - Frees the userptr structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200227 */
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300228static void dma_unmap_host_va(struct hl_device *hdev,
229 struct hl_userptr *userptr)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200230{
231 hl_unpin_host_memory(hdev, userptr);
232 kfree(userptr);
233}
234
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200235/**
236 * dram_pg_pool_do_release() - free DRAM pages pool
237 * @ref: pointer to reference object.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200238 *
239 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200240 * - Frees the idr structure of physical pages handles.
241 * - Frees the generic pool of DRAM physical pages.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200242 */
243static void dram_pg_pool_do_release(struct kref *ref)
244{
245 struct hl_vm *vm = container_of(ref, struct hl_vm,
246 dram_pg_pool_refcount);
247
248 /*
249 * free the idr here as only here we know for sure that there are no
250 * allocated physical pages and hence there are no handles in use
251 */
252 idr_destroy(&vm->phys_pg_pack_handles);
253 gen_pool_destroy(vm->dram_pg_pool);
254}
255
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200256/**
257 * free_phys_pg_pack() - free physical page pack.
258 * @hdev: habanalabs device structure.
259 * @phys_pg_pack: physical page pack to free.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200260 *
261 * This function does the following:
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200262 * - For DRAM memory only
263 * - iterate over the pack, scrub and free each physical block structure by
264 * returning it to the general pool.
265 * In case of error during scrubbing, initiate hard reset.
266 * Once hard reset is triggered, scrubbing is bypassed while freeing the
267 * memory continues.
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200268 * - Free the hl_vm_phys_pg_pack structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200269 */
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200270static int free_phys_pg_pack(struct hl_device *hdev,
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300271 struct hl_vm_phys_pg_pack *phys_pg_pack)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200272{
273 struct hl_vm *vm = &hdev->vm;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200274 u64 i;
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200275 int rc = 0;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200276
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200277 if (phys_pg_pack->created_from_userptr)
278 goto end;
279
280 if (phys_pg_pack->contiguous) {
281 if (hdev->memory_scrub && !hdev->disabled) {
282 rc = hdev->asic_funcs->scrub_device_mem(hdev,
283 phys_pg_pack->pages[0],
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200284 phys_pg_pack->total_size);
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200285 if (rc)
286 dev_err(hdev->dev,
287 "Failed to scrub contiguous device memory\n");
288 }
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200289
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200290 gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[0],
291 phys_pg_pack->total_size);
292
293 for (i = 0; i < phys_pg_pack->npages ; i++)
294 kref_put(&vm->dram_pg_pool_refcount,
295 dram_pg_pool_do_release);
296 } else {
297 for (i = 0 ; i < phys_pg_pack->npages ; i++) {
298 if (hdev->memory_scrub && !hdev->disabled && rc == 0) {
299 rc = hdev->asic_funcs->scrub_device_mem(
300 hdev,
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200301 phys_pg_pack->pages[i],
302 phys_pg_pack->page_size);
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200303 if (rc)
304 dev_err(hdev->dev,
305 "Failed to scrub device memory\n");
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200306 }
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200307 gen_pool_free(vm->dram_pg_pool,
308 phys_pg_pack->pages[i],
309 phys_pg_pack->page_size);
310 kref_put(&vm->dram_pg_pool_refcount,
311 dram_pg_pool_do_release);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200312 }
313 }
314
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200315 if (rc && !hdev->disabled)
316 hl_device_reset(hdev, HL_RESET_HARD);
317
318end:
Omer Shpigelman4eb1d122019-03-07 15:47:19 +0200319 kvfree(phys_pg_pack->pages);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200320 kfree(phys_pg_pack);
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200321
322 return rc;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200323}
324
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200325/**
326 * free_device_memory() - free device memory.
327 * @ctx: pointer to the context structure.
Omer Shpigelmanf19040c2020-12-09 13:34:11 +0200328 * @args: host parameters containing the requested size.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200329 *
330 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200331 * - Free the device memory related to the given handle.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200332 */
Omer Shpigelmanf19040c2020-12-09 13:34:11 +0200333static int free_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200334{
335 struct hl_device *hdev = ctx->hdev;
336 struct hl_vm *vm = &hdev->vm;
337 struct hl_vm_phys_pg_pack *phys_pg_pack;
Omer Shpigelmanf19040c2020-12-09 13:34:11 +0200338 u32 handle = args->free.handle;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200339
340 spin_lock(&vm->idr_lock);
341 phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, handle);
342 if (phys_pg_pack) {
343 if (atomic_read(&phys_pg_pack->mapping_cnt) > 0) {
344 dev_err(hdev->dev, "handle %u is mapped, cannot free\n",
345 handle);
346 spin_unlock(&vm->idr_lock);
347 return -EINVAL;
348 }
349
350 /*
351 * must remove from idr before the freeing of the physical
352 * pages as the refcount of the pool is also the trigger of the
353 * idr destroy
354 */
355 idr_remove(&vm->phys_pg_pack_handles, handle);
356 spin_unlock(&vm->idr_lock);
357
358 atomic64_sub(phys_pg_pack->total_size, &ctx->dram_phys_mem);
359 atomic64_sub(phys_pg_pack->total_size, &hdev->dram_used_mem);
360
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +0200361 return free_phys_pg_pack(hdev, phys_pg_pack);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200362 } else {
363 spin_unlock(&vm->idr_lock);
364 dev_err(hdev->dev,
365 "free device memory failed, no match for handle %u\n",
366 handle);
367 return -EINVAL;
368 }
369
370 return 0;
371}
372
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200373/**
374 * clear_va_list_locked() - free virtual addresses list.
375 * @hdev: habanalabs device structure.
376 * @va_list: list of virtual addresses to free.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200377 *
378 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200379 * - Iterate over the list and free each virtual addresses block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200380 *
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200381 * This function should be called only when va_list lock is taken.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200382 */
383static void clear_va_list_locked(struct hl_device *hdev,
384 struct list_head *va_list)
385{
386 struct hl_vm_va_block *va_block, *tmp;
387
388 list_for_each_entry_safe(va_block, tmp, va_list, node) {
389 list_del(&va_block->node);
390 kfree(va_block);
391 }
392}
393
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200394/**
395 * print_va_list_locked() - print virtual addresses list.
396 * @hdev: habanalabs device structure.
397 * @va_list: list of virtual addresses to print.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200398 *
399 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200400 * - Iterate over the list and print each virtual addresses block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200401 *
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200402 * This function should be called only when va_list lock is taken.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200403 */
404static void print_va_list_locked(struct hl_device *hdev,
405 struct list_head *va_list)
406{
407#if HL_MMU_DEBUG
408 struct hl_vm_va_block *va_block;
409
410 dev_dbg(hdev->dev, "print va list:\n");
411
412 list_for_each_entry(va_block, va_list, node)
413 dev_dbg(hdev->dev,
414 "va block, start: 0x%llx, end: 0x%llx, size: %llu\n",
415 va_block->start, va_block->end, va_block->size);
416#endif
417}
418
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200419/**
420 * merge_va_blocks_locked() - merge a virtual block if possible.
421 * @hdev: pointer to the habanalabs device structure.
422 * @va_list: pointer to the virtual addresses block list.
423 * @va_block: virtual block to merge with adjacent blocks.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200424 *
425 * This function does the following:
426 * - Merge the given blocks with the adjacent blocks if their virtual ranges
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200427 * create a contiguous virtual range.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200428 *
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200429 * This Function should be called only when va_list lock is taken.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200430 */
431static void merge_va_blocks_locked(struct hl_device *hdev,
432 struct list_head *va_list, struct hl_vm_va_block *va_block)
433{
434 struct hl_vm_va_block *prev, *next;
435
436 prev = list_prev_entry(va_block, node);
437 if (&prev->node != va_list && prev->end + 1 == va_block->start) {
438 prev->end = va_block->end;
439 prev->size = prev->end - prev->start;
440 list_del(&va_block->node);
441 kfree(va_block);
442 va_block = prev;
443 }
444
445 next = list_next_entry(va_block, node);
446 if (&next->node != va_list && va_block->end + 1 == next->start) {
447 next->start = va_block->start;
448 next->size = next->end - next->start;
449 list_del(&va_block->node);
450 kfree(va_block);
451 }
452}
453
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200454/**
455 * add_va_block_locked() - add a virtual block to the virtual addresses list.
456 * @hdev: pointer to the habanalabs device structure.
457 * @va_list: pointer to the virtual addresses block list.
458 * @start: start virtual address.
459 * @end: end virtual address.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200460 *
461 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200462 * - Add the given block to the virtual blocks list and merge with other blocks
463 * if a contiguous virtual block can be created.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200464 *
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200465 * This Function should be called only when va_list lock is taken.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200466 */
467static int add_va_block_locked(struct hl_device *hdev,
468 struct list_head *va_list, u64 start, u64 end)
469{
470 struct hl_vm_va_block *va_block, *res = NULL;
471 u64 size = end - start;
472
473 print_va_list_locked(hdev, va_list);
474
475 list_for_each_entry(va_block, va_list, node) {
476 /* TODO: remove upon matureness */
477 if (hl_mem_area_crosses_range(start, size, va_block->start,
478 va_block->end)) {
479 dev_err(hdev->dev,
480 "block crossing ranges at start 0x%llx, end 0x%llx\n",
481 va_block->start, va_block->end);
482 return -EINVAL;
483 }
484
485 if (va_block->end < start)
486 res = va_block;
487 }
488
489 va_block = kmalloc(sizeof(*va_block), GFP_KERNEL);
490 if (!va_block)
491 return -ENOMEM;
492
493 va_block->start = start;
494 va_block->end = end;
495 va_block->size = size;
496
497 if (!res)
498 list_add(&va_block->node, va_list);
499 else
500 list_add(&va_block->node, &res->node);
501
502 merge_va_blocks_locked(hdev, va_list, va_block);
503
504 print_va_list_locked(hdev, va_list);
505
506 return 0;
507}
508
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200509/**
510 * add_va_block() - wrapper for add_va_block_locked.
511 * @hdev: pointer to the habanalabs device structure.
512 * @va_list: pointer to the virtual addresses block list.
513 * @start: start virtual address.
514 * @end: end virtual address.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200515 *
516 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200517 * - Takes the list lock and calls add_va_block_locked.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200518 */
519static inline int add_va_block(struct hl_device *hdev,
520 struct hl_va_range *va_range, u64 start, u64 end)
521{
522 int rc;
523
524 mutex_lock(&va_range->lock);
525 rc = add_va_block_locked(hdev, &va_range->list, start, end);
526 mutex_unlock(&va_range->lock);
527
528 return rc;
529}
530
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200531/**
farah kassabri1ae32b92021-01-31 18:56:03 +0200532 * is_hint_crossing_range() - check if hint address crossing specified reserved
533 * range.
534 */
535static inline bool is_hint_crossing_range(enum hl_va_range_type range_type,
536 u64 start_addr, u32 size, struct asic_fixed_properties *prop) {
537 bool range_cross;
538
539 if (range_type == HL_VA_RANGE_TYPE_DRAM)
540 range_cross =
541 hl_mem_area_crosses_range(start_addr, size,
542 prop->hints_dram_reserved_va_range.start_addr,
543 prop->hints_dram_reserved_va_range.end_addr);
544 else if (range_type == HL_VA_RANGE_TYPE_HOST)
545 range_cross =
546 hl_mem_area_crosses_range(start_addr, size,
547 prop->hints_host_reserved_va_range.start_addr,
548 prop->hints_host_reserved_va_range.end_addr);
549 else
550 range_cross =
551 hl_mem_area_crosses_range(start_addr, size,
552 prop->hints_host_hpage_reserved_va_range.start_addr,
553 prop->hints_host_hpage_reserved_va_range.end_addr);
554
555 return range_cross;
556}
557
558/**
Omer Shpigelman7c52fb02020-06-28 21:15:53 +0300559 * get_va_block() - get a virtual block for the given size and alignment.
farah kassabri8d79ce12021-01-11 10:10:00 +0200560 *
Omer Shpigelman7c52fb02020-06-28 21:15:53 +0300561 * @hdev: pointer to the habanalabs device structure.
562 * @va_range: pointer to the virtual addresses range.
563 * @size: requested block size.
564 * @hint_addr: hint for requested address by the user.
565 * @va_block_align: required alignment of the virtual block start address.
farah kassabri1ae32b92021-01-31 18:56:03 +0200566 * @range_type: va range type (host, dram)
Yuri Nudelman486e1972021-06-03 17:51:58 +0300567 * @flags: additional memory flags, currently only uses HL_MEM_FORCE_HINT
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200568 *
569 * This function does the following:
570 * - Iterate on the virtual block list to find a suitable virtual block for the
farah kassabri8d79ce12021-01-11 10:10:00 +0200571 * given size, hint address and alignment.
Omer Shpigelman7c52fb02020-06-28 21:15:53 +0300572 * - Reserve the requested block and update the list.
573 * - Return the start address of the virtual block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200574 */
farah kassabri8d79ce12021-01-11 10:10:00 +0200575static u64 get_va_block(struct hl_device *hdev,
Moti Haimovskib19dc672020-11-18 20:15:29 +0200576 struct hl_va_range *va_range,
farah kassabri1ae32b92021-01-31 18:56:03 +0200577 u64 size, u64 hint_addr, u32 va_block_align,
Yuri Nudelman486e1972021-06-03 17:51:58 +0300578 enum hl_va_range_type range_type,
579 u32 flags)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200580{
581 struct hl_vm_va_block *va_block, *new_va_block = NULL;
farah kassabri1ae32b92021-01-31 18:56:03 +0200582 struct asic_fixed_properties *prop = &hdev->asic_prop;
farah kassabri8d79ce12021-01-11 10:10:00 +0200583 u64 tmp_hint_addr, valid_start, valid_size, prev_start, prev_end,
farah kassabri1ae32b92021-01-31 18:56:03 +0200584 align_mask, reserved_valid_start = 0, reserved_valid_size = 0,
585 dram_hint_mask = prop->dram_hints_align_mask;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200586 bool add_prev = false;
farah kassabri8d79ce12021-01-11 10:10:00 +0200587 bool is_align_pow_2 = is_power_of_2(va_range->page_size);
farah kassabri1ae32b92021-01-31 18:56:03 +0200588 bool is_hint_dram_addr = hl_is_dram_va(hdev, hint_addr);
Yuri Nudelman486e1972021-06-03 17:51:58 +0300589 bool force_hint = flags & HL_MEM_FORCE_HINT;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200590
farah kassabri8d79ce12021-01-11 10:10:00 +0200591 if (is_align_pow_2)
592 align_mask = ~((u64)va_block_align - 1);
593 else
594 /*
595 * with non-power-of-2 range we work only with page granularity
596 * and the start address is page aligned,
597 * so no need for alignment checking.
598 */
599 size = DIV_ROUND_UP_ULL(size, va_range->page_size) *
600 va_range->page_size;
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000601
farah kassabri1ae32b92021-01-31 18:56:03 +0200602 tmp_hint_addr = hint_addr & ~dram_hint_mask;
farah kassabri8d79ce12021-01-11 10:10:00 +0200603
604 /* Check if we need to ignore hint address */
605 if ((is_align_pow_2 && (hint_addr & (va_block_align - 1))) ||
farah kassabri1ae32b92021-01-31 18:56:03 +0200606 (!is_align_pow_2 && is_hint_dram_addr &&
607 do_div(tmp_hint_addr, va_range->page_size))) {
Oded Gabbayb8e785c2021-04-26 18:32:25 +0300608
Yuri Nudelman486e1972021-06-03 17:51:58 +0300609 if (force_hint) {
Oded Gabbay82629c72021-06-29 18:08:05 +0300610 /* Hint must be respected, so here we just fail */
Yuri Nudelman486e1972021-06-03 17:51:58 +0300611 dev_err(hdev->dev,
612 "Hint address 0x%llx is not page aligned - cannot be respected\n",
613 hint_addr);
614 return 0;
615 }
616
Oded Gabbayb8e785c2021-04-26 18:32:25 +0300617 dev_dbg(hdev->dev,
618 "Hint address 0x%llx will be ignored because it is not aligned\n",
619 hint_addr);
Omer Shpigelman7c52fb02020-06-28 21:15:53 +0300620 hint_addr = 0;
farah kassabri8d79ce12021-01-11 10:10:00 +0200621 }
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200622
623 mutex_lock(&va_range->lock);
624
625 print_va_list_locked(hdev, &va_range->list);
626
627 list_for_each_entry(va_block, &va_range->list, node) {
farah kassabri8d79ce12021-01-11 10:10:00 +0200628 /* Calc the first possible aligned addr */
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200629 valid_start = va_block->start;
630
farah kassabri8d79ce12021-01-11 10:10:00 +0200631 if (is_align_pow_2 && (valid_start & (va_block_align - 1))) {
Omer Shpigelman7c52fb02020-06-28 21:15:53 +0300632 valid_start &= align_mask;
633 valid_start += va_block_align;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200634 if (valid_start > va_block->end)
635 continue;
636 }
637
638 valid_size = va_block->end - valid_start;
farah kassabri8d79ce12021-01-11 10:10:00 +0200639 if (valid_size < size)
640 continue;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200641
farah kassabri1ae32b92021-01-31 18:56:03 +0200642 /*
643 * In case hint address is 0, and arc_hints_range_reservation
644 * property enabled, then avoid allocating va blocks from the
645 * range reserved for hint addresses
646 */
647 if (prop->hints_range_reservation && !hint_addr)
648 if (is_hint_crossing_range(range_type, valid_start,
649 size, prop))
650 continue;
651
farah kassabri8d79ce12021-01-11 10:10:00 +0200652 /* Pick the minimal length block which has the required size */
653 if (!new_va_block || (valid_size < reserved_valid_size)) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200654 new_va_block = va_block;
Moti Haimovskib19dc672020-11-18 20:15:29 +0200655 reserved_valid_start = valid_start;
656 reserved_valid_size = valid_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200657 }
658
659 if (hint_addr && hint_addr >= valid_start &&
Moti Haimovskib19dc672020-11-18 20:15:29 +0200660 (hint_addr + size) <= va_block->end) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200661 new_va_block = va_block;
Moti Haimovskib19dc672020-11-18 20:15:29 +0200662 reserved_valid_start = hint_addr;
663 reserved_valid_size = valid_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200664 break;
665 }
666 }
667
668 if (!new_va_block) {
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200669 dev_err(hdev->dev, "no available va block for size %llu\n",
farah kassabri8d79ce12021-01-11 10:10:00 +0200670 size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200671 goto out;
672 }
673
Yuri Nudelman486e1972021-06-03 17:51:58 +0300674 if (force_hint && reserved_valid_start != hint_addr) {
675 /* Hint address must be respected. If we are here - this means
676 * we could not respect it.
677 */
678 dev_err(hdev->dev,
679 "Hint address 0x%llx could not be respected\n",
680 hint_addr);
681 reserved_valid_start = 0;
682 goto out;
683 }
684
farah kassabri8d79ce12021-01-11 10:10:00 +0200685 /*
686 * Check if there is some leftover range due to reserving the new
687 * va block, then return it to the main virtual addresses list.
688 */
Moti Haimovskib19dc672020-11-18 20:15:29 +0200689 if (reserved_valid_start > new_va_block->start) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200690 prev_start = new_va_block->start;
Moti Haimovskib19dc672020-11-18 20:15:29 +0200691 prev_end = reserved_valid_start - 1;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200692
Moti Haimovskib19dc672020-11-18 20:15:29 +0200693 new_va_block->start = reserved_valid_start;
694 new_va_block->size = reserved_valid_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200695
696 add_prev = true;
697 }
698
699 if (new_va_block->size > size) {
700 new_va_block->start += size;
701 new_va_block->size = new_va_block->end - new_va_block->start;
702 } else {
703 list_del(&new_va_block->node);
704 kfree(new_va_block);
705 }
706
707 if (add_prev)
708 add_va_block_locked(hdev, &va_range->list, prev_start,
709 prev_end);
710
711 print_va_list_locked(hdev, &va_range->list);
712out:
713 mutex_unlock(&va_range->lock);
714
Moti Haimovskib19dc672020-11-18 20:15:29 +0200715 return reserved_valid_start;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200716}
717
718/*
Ofir Bittonbe91b912020-10-22 15:04:10 +0300719 * hl_reserve_va_block() - reserve a virtual block of a given size.
720 * @hdev: pointer to the habanalabs device structure.
721 * @ctx: current context
722 * @type: virtual addresses range type.
723 * @size: requested block size.
Ofir Bitton412c41f2020-11-04 15:18:55 +0200724 * @alignment: required alignment in bytes of the virtual block start address,
725 * 0 means no alignment.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300726 *
727 * This function does the following:
728 * - Iterate on the virtual block list to find a suitable virtual block for the
Ofir Bitton412c41f2020-11-04 15:18:55 +0200729 * given size and alignment.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300730 * - Reserve the requested block and update the list.
731 * - Return the start address of the virtual block.
732 */
733u64 hl_reserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx,
Ofir Bitton412c41f2020-11-04 15:18:55 +0200734 enum hl_va_range_type type, u32 size, u32 alignment)
Ofir Bittonbe91b912020-10-22 15:04:10 +0300735{
736 return get_va_block(hdev, ctx->va_range[type], size, 0,
Yuri Nudelman486e1972021-06-03 17:51:58 +0300737 max(alignment, ctx->va_range[type]->page_size),
738 type, 0);
Ofir Bittonbe91b912020-10-22 15:04:10 +0300739}
740
741/**
742 * hl_get_va_range_type() - get va_range type for the given address and size.
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200743 * @address: the start address of the area we want to validate.
744 * @size: the size in bytes of the area we want to validate.
745 * @type: returned va_range type.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300746 *
747 * Return: true if the area is inside a valid range, false otherwise.
748 */
749static int hl_get_va_range_type(struct hl_ctx *ctx, u64 address, u64 size,
750 enum hl_va_range_type *type)
751{
752 int i;
753
754 for (i = 0 ; i < HL_VA_RANGE_TYPE_MAX; i++) {
755 if (hl_mem_area_inside_range(address, size,
756 ctx->va_range[i]->start_addr,
757 ctx->va_range[i]->end_addr)) {
758 *type = i;
759 return 0;
760 }
761 }
762
763 return -EINVAL;
764}
765
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200766/**
767 * hl_unreserve_va_block() - wrapper for add_va_block to unreserve a va block.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300768 * @hdev: pointer to the habanalabs device structure
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200769 * @ctx: pointer to the context structure.
770 * @start: start virtual address.
771 * @end: end virtual address.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300772 *
773 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200774 * - Takes the list lock and calls add_va_block_locked.
Ofir Bittonbe91b912020-10-22 15:04:10 +0300775 */
776int hl_unreserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx,
777 u64 start_addr, u64 size)
778{
779 enum hl_va_range_type type;
780 int rc;
781
782 rc = hl_get_va_range_type(ctx, start_addr, size, &type);
783 if (rc) {
784 dev_err(hdev->dev,
785 "cannot find va_range for va %#llx size %llu",
786 start_addr, size);
787 return rc;
788 }
789
790 rc = add_va_block(hdev, ctx->va_range[type], start_addr,
791 start_addr + size - 1);
792 if (rc)
793 dev_warn(hdev->dev,
794 "add va block failed for vaddr: 0x%llx\n", start_addr);
795
796 return rc;
797}
798
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200799/**
800 * get_sg_info() - get number of pages and the DMA address from SG list.
801 * @sg: the SG list.
802 * @dma_addr: pointer to DMA address to return.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200803 *
804 * Calculate the number of consecutive pages described by the SG list. Take the
805 * offset of the address in the first page, add to it the length and round it up
806 * to the number of needed pages.
807 */
808static u32 get_sg_info(struct scatterlist *sg, dma_addr_t *dma_addr)
809{
810 *dma_addr = sg_dma_address(sg);
811
812 return ((((*dma_addr) & (PAGE_SIZE - 1)) + sg_dma_len(sg)) +
813 (PAGE_SIZE - 1)) >> PAGE_SHIFT;
814}
815
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200816/**
817 * init_phys_pg_pack_from_userptr() - initialize physical page pack from host
818 * memory
819 * @ctx: pointer to the context structure.
820 * @userptr: userptr to initialize from.
821 * @pphys_pg_pack: result pointer.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200822 *
823 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200824 * - Pin the physical pages related to the given virtual block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200825 * - Create a physical page pack from the physical pages related to the given
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200826 * virtual block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200827 */
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000828static int init_phys_pg_pack_from_userptr(struct hl_ctx *ctx,
829 struct hl_userptr *userptr,
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300830 struct hl_vm_phys_pg_pack **pphys_pg_pack)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200831{
832 struct hl_vm_phys_pg_pack *phys_pg_pack;
833 struct scatterlist *sg;
834 dma_addr_t dma_addr;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200835 u64 page_mask, total_npages;
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000836 u32 npages, page_size = PAGE_SIZE,
Omer Shpigelman64a7e292020-01-05 09:05:45 +0000837 huge_page_size = ctx->hdev->asic_prop.pmmu_huge.page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200838 bool first = true, is_huge_page_opt = true;
839 int rc, i, j;
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000840 u32 pgs_in_huge_page = huge_page_size >> __ffs(page_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200841
842 phys_pg_pack = kzalloc(sizeof(*phys_pg_pack), GFP_KERNEL);
843 if (!phys_pg_pack)
844 return -ENOMEM;
845
846 phys_pg_pack->vm_type = userptr->vm_type;
847 phys_pg_pack->created_from_userptr = true;
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000848 phys_pg_pack->asid = ctx->asid;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200849 atomic_set(&phys_pg_pack->mapping_cnt, 1);
850
851 /* Only if all dma_addrs are aligned to 2MB and their
852 * sizes is at least 2MB, we can use huge page mapping.
853 * We limit the 2MB optimization to this condition,
854 * since later on we acquire the related VA range as one
855 * consecutive block.
856 */
857 total_npages = 0;
858 for_each_sg(userptr->sgt->sgl, sg, userptr->sgt->nents, i) {
859 npages = get_sg_info(sg, &dma_addr);
860
861 total_npages += npages;
862
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000863 if ((npages % pgs_in_huge_page) ||
864 (dma_addr & (huge_page_size - 1)))
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200865 is_huge_page_opt = false;
866 }
867
868 if (is_huge_page_opt) {
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000869 page_size = huge_page_size;
870 do_div(total_npages, pgs_in_huge_page);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200871 }
872
873 page_mask = ~(((u64) page_size) - 1);
874
Omer Shpigelman4eb1d122019-03-07 15:47:19 +0200875 phys_pg_pack->pages = kvmalloc_array(total_npages, sizeof(u64),
876 GFP_KERNEL);
Ofir Bitton08391522020-08-11 08:57:45 +0300877 if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200878 rc = -ENOMEM;
879 goto page_pack_arr_mem_err;
880 }
881
882 phys_pg_pack->npages = total_npages;
883 phys_pg_pack->page_size = page_size;
884 phys_pg_pack->total_size = total_npages * page_size;
885
886 j = 0;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200887 for_each_sg(userptr->sgt->sgl, sg, userptr->sgt->nents, i) {
888 npages = get_sg_info(sg, &dma_addr);
889
890 /* align down to physical page size and save the offset */
891 if (first) {
892 first = false;
893 phys_pg_pack->offset = dma_addr & (page_size - 1);
894 dma_addr &= page_mask;
895 }
896
897 while (npages) {
898 phys_pg_pack->pages[j++] = dma_addr;
899 dma_addr += page_size;
900
901 if (is_huge_page_opt)
Omer Shpigelman54bb6742019-11-14 18:23:55 +0000902 npages -= pgs_in_huge_page;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200903 else
904 npages--;
905 }
906 }
907
908 *pphys_pg_pack = phys_pg_pack;
909
910 return 0;
911
912page_pack_arr_mem_err:
913 kfree(phys_pg_pack);
914
915 return rc;
916}
917
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200918/**
919 * map_phys_pg_pack() - maps the physical page pack..
920 * @ctx: pointer to the context structure.
921 * @vaddr: start address of the virtual area to map from.
922 * @phys_pg_pack: the pack of physical pages to map to.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200923 *
924 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200925 * - Maps each chunk of virtual memory to matching physical chunk.
926 * - Stores number of successful mappings in the given argument.
927 * - Returns 0 on success, error code otherwise.
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200928 */
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300929static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr,
930 struct hl_vm_phys_pg_pack *phys_pg_pack)
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200931{
932 struct hl_device *hdev = ctx->hdev;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200933 u64 next_vaddr = vaddr, paddr, mapped_pg_cnt = 0, i;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200934 u32 page_size = phys_pg_pack->page_size;
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200935 int rc = 0;
farah kassabri2f6274e2021-03-11 11:24:57 +0200936 bool is_host_addr;
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200937
938 for (i = 0 ; i < phys_pg_pack->npages ; i++) {
939 paddr = phys_pg_pack->pages[i];
940
Ofir Bitton5c054872020-10-22 15:13:10 +0300941 rc = hl_mmu_map_page(ctx, next_vaddr, paddr, page_size,
Pawel Piskorski7fc40bc2019-12-06 17:32:38 +0200942 (i + 1) == phys_pg_pack->npages);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200943 if (rc) {
944 dev_err(hdev->dev,
Omer Shpigelmanbfb1ce12019-03-05 10:59:16 +0200945 "map failed for handle %u, npages: %llu, mapped: %llu",
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200946 phys_pg_pack->handle, phys_pg_pack->npages,
947 mapped_pg_cnt);
948 goto err;
949 }
950
951 mapped_pg_cnt++;
952 next_vaddr += page_size;
953 }
954
955 return 0;
956
957err:
farah kassabri2f6274e2021-03-11 11:24:57 +0200958 is_host_addr = !hl_is_dram_va(hdev, vaddr);
959
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200960 next_vaddr = vaddr;
961 for (i = 0 ; i < mapped_pg_cnt ; i++) {
Ofir Bitton5c054872020-10-22 15:13:10 +0300962 if (hl_mmu_unmap_page(ctx, next_vaddr, page_size,
Pawel Piskorski7fc40bc2019-12-06 17:32:38 +0200963 (i + 1) == mapped_pg_cnt))
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200964 dev_warn_ratelimited(hdev->dev,
965 "failed to unmap handle %u, va: 0x%llx, pa: 0x%llx, page size: %u\n",
966 phys_pg_pack->handle, next_vaddr,
967 phys_pg_pack->pages[i], page_size);
968
969 next_vaddr += page_size;
farah kassabri2f6274e2021-03-11 11:24:57 +0200970
971 /*
972 * unmapping on Palladium can be really long, so avoid a CPU
973 * soft lockup bug by sleeping a little between unmapping pages
974 *
975 * In addition, on host num of pages could be huge,
976 * because page size could be 4KB, so when unmapping host
977 * pages sleep every 32K pages to avoid soft lockup
978 */
979 if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0))
980 usleep_range(50, 200);
Omer Shpigelman0feaf862019-02-16 00:39:22 +0200981 }
982
983 return rc;
984}
985
Omer Shpigelman3b762f52020-12-09 13:28:46 +0200986/**
987 * unmap_phys_pg_pack() - unmaps the physical page pack.
988 * @ctx: pointer to the context structure.
989 * @vaddr: start address of the virtual area to unmap.
990 * @phys_pg_pack: the pack of physical pages to unmap.
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300991 */
992static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr,
993 struct hl_vm_phys_pg_pack *phys_pg_pack)
994{
995 struct hl_device *hdev = ctx->hdev;
996 u64 next_vaddr, i;
Oded Gabbay94883072021-01-11 17:49:30 +0200997 bool is_host_addr;
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +0300998 u32 page_size;
999
Oded Gabbay94883072021-01-11 17:49:30 +02001000 is_host_addr = !hl_is_dram_va(hdev, vaddr);
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001001 page_size = phys_pg_pack->page_size;
1002 next_vaddr = vaddr;
1003
1004 for (i = 0 ; i < phys_pg_pack->npages ; i++, next_vaddr += page_size) {
Ofir Bitton5c054872020-10-22 15:13:10 +03001005 if (hl_mmu_unmap_page(ctx, next_vaddr, page_size,
Pawel Piskorski7fc40bc2019-12-06 17:32:38 +02001006 (i + 1) == phys_pg_pack->npages))
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001007 dev_warn_ratelimited(hdev->dev,
1008 "unmap failed for vaddr: 0x%llx\n", next_vaddr);
1009
1010 /*
1011 * unmapping on Palladium can be really long, so avoid a CPU
1012 * soft lockup bug by sleeping a little between unmapping pages
Oded Gabbay94883072021-01-11 17:49:30 +02001013 *
farah kassabri2f6274e2021-03-11 11:24:57 +02001014 * In addition, on host num of pages could be huge,
1015 * because page size could be 4KB, so when unmapping host
1016 * pages sleep every 32K pages to avoid soft lockup
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001017 */
Oded Gabbay94883072021-01-11 17:49:30 +02001018 if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0))
1019 usleep_range(50, 200);
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001020 }
1021}
1022
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001023static int get_paddr_from_handle(struct hl_ctx *ctx, struct hl_mem_in *args,
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001024 u64 *paddr)
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001025{
1026 struct hl_device *hdev = ctx->hdev;
1027 struct hl_vm *vm = &hdev->vm;
1028 struct hl_vm_phys_pg_pack *phys_pg_pack;
1029 u32 handle;
1030
1031 handle = lower_32_bits(args->map_device.handle);
1032 spin_lock(&vm->idr_lock);
1033 phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, handle);
1034 if (!phys_pg_pack) {
1035 spin_unlock(&vm->idr_lock);
1036 dev_err(hdev->dev, "no match for handle %u\n", handle);
1037 return -EINVAL;
1038 }
1039
1040 *paddr = phys_pg_pack->pages[0];
1041
1042 spin_unlock(&vm->idr_lock);
1043
1044 return 0;
1045}
1046
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001047/**
1048 * map_device_va() - map the given memory.
1049 * @ctx: pointer to the context structure.
1050 * @args: host parameters with handle/host virtual address.
1051 * @device_addr: pointer to result device virtual address.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001052 *
1053 * This function does the following:
1054 * - If given a physical device memory handle, map to a device virtual block
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001055 * and return the start address of this block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001056 * - If given a host virtual address and size, find the related physical pages,
1057 * map a device virtual block to this pages and return the start address of
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001058 * this block.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001059 */
1060static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args,
1061 u64 *device_addr)
1062{
1063 struct hl_device *hdev = ctx->hdev;
1064 struct hl_vm *vm = &hdev->vm;
1065 struct hl_vm_phys_pg_pack *phys_pg_pack;
1066 struct hl_userptr *userptr = NULL;
1067 struct hl_vm_hash_node *hnode;
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001068 struct hl_va_range *va_range;
Oded Gabbay82629c72021-06-29 18:08:05 +03001069 enum vm_type *vm_type;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001070 u64 ret_vaddr, hint_addr;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001071 u32 handle = 0, va_block_align;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001072 int rc;
1073 bool is_userptr = args->flags & HL_MEM_USERPTR;
farah kassabri1ae32b92021-01-31 18:56:03 +02001074 enum hl_va_range_type va_range_type = 0;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001075
1076 /* Assume failure */
1077 *device_addr = 0;
1078
1079 if (is_userptr) {
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001080 u64 addr = args->map_host.host_virt_addr,
1081 size = args->map_host.mem_size;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001082 u32 page_size = hdev->asic_prop.pmmu.page_size,
1083 huge_page_size = hdev->asic_prop.pmmu_huge.page_size;
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001084
1085 rc = dma_map_host_va(hdev, addr, size, &userptr);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001086 if (rc) {
1087 dev_err(hdev->dev, "failed to get userptr from va\n");
1088 return rc;
1089 }
1090
Omer Shpigelman54bb6742019-11-14 18:23:55 +00001091 rc = init_phys_pg_pack_from_userptr(ctx, userptr,
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001092 &phys_pg_pack);
1093 if (rc) {
1094 dev_err(hdev->dev,
1095 "unable to init page pack for vaddr 0x%llx\n",
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001096 addr);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001097 goto init_page_pack_err;
1098 }
1099
Oded Gabbay82629c72021-06-29 18:08:05 +03001100 vm_type = (enum vm_type *) userptr;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001101 hint_addr = args->map_host.hint_addr;
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001102 handle = phys_pg_pack->handle;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001103
1104 /* get required alignment */
1105 if (phys_pg_pack->page_size == page_size) {
Ofir Bitton784b9162020-10-22 11:05:55 +03001106 va_range = ctx->va_range[HL_VA_RANGE_TYPE_HOST];
farah kassabri1ae32b92021-01-31 18:56:03 +02001107 va_range_type = HL_VA_RANGE_TYPE_HOST;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001108 /*
1109 * huge page alignment may be needed in case of regular
1110 * page mapping, depending on the host VA alignment
1111 */
1112 if (addr & (huge_page_size - 1))
1113 va_block_align = page_size;
1114 else
1115 va_block_align = huge_page_size;
1116 } else {
1117 /*
1118 * huge page alignment is needed in case of huge page
1119 * mapping
1120 */
Ofir Bitton784b9162020-10-22 11:05:55 +03001121 va_range = ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE];
farah kassabri1ae32b92021-01-31 18:56:03 +02001122 va_range_type = HL_VA_RANGE_TYPE_HOST_HUGE;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001123 va_block_align = huge_page_size;
1124 }
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001125 } else {
1126 handle = lower_32_bits(args->map_device.handle);
1127
1128 spin_lock(&vm->idr_lock);
1129 phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, handle);
1130 if (!phys_pg_pack) {
1131 spin_unlock(&vm->idr_lock);
1132 dev_err(hdev->dev,
1133 "no match for handle %u\n", handle);
1134 return -EINVAL;
1135 }
1136
1137 /* increment now to avoid freeing device memory while mapping */
1138 atomic_inc(&phys_pg_pack->mapping_cnt);
1139
1140 spin_unlock(&vm->idr_lock);
1141
Oded Gabbay82629c72021-06-29 18:08:05 +03001142 vm_type = (enum vm_type *) phys_pg_pack;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001143
1144 hint_addr = args->map_device.hint_addr;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001145
Moti Haimovskib19dc672020-11-18 20:15:29 +02001146 /* DRAM VA alignment is the same as the MMU page size */
Ofir Bitton784b9162020-10-22 11:05:55 +03001147 va_range = ctx->va_range[HL_VA_RANGE_TYPE_DRAM];
farah kassabri1ae32b92021-01-31 18:56:03 +02001148 va_range_type = HL_VA_RANGE_TYPE_DRAM;
Omer Shpigelman7c52fb02020-06-28 21:15:53 +03001149 va_block_align = hdev->asic_prop.dmmu.page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001150 }
1151
1152 /*
1153 * relevant for mapping device physical memory only, as host memory is
1154 * implicitly shared
1155 */
1156 if (!is_userptr && !(phys_pg_pack->flags & HL_MEM_SHARED) &&
1157 phys_pg_pack->asid != ctx->asid) {
1158 dev_err(hdev->dev,
1159 "Failed to map memory, handle %u is not shared\n",
1160 handle);
1161 rc = -EPERM;
1162 goto shared_err;
1163 }
1164
1165 hnode = kzalloc(sizeof(*hnode), GFP_KERNEL);
1166 if (!hnode) {
1167 rc = -ENOMEM;
1168 goto hnode_err;
1169 }
1170
Yuri Nudelman486e1972021-06-03 17:51:58 +03001171 if (hint_addr && phys_pg_pack->offset) {
1172 if (args->flags & HL_MEM_FORCE_HINT) {
Oded Gabbay82629c72021-06-29 18:08:05 +03001173 /* Fail if hint must be respected but it can't be */
Yuri Nudelman486e1972021-06-03 17:51:58 +03001174 dev_err(hdev->dev,
1175 "Hint address 0x%llx cannot be respected because source memory is not aligned 0x%x\n",
1176 hint_addr, phys_pg_pack->offset);
1177 rc = -EINVAL;
1178 goto va_block_err;
1179 }
1180 dev_dbg(hdev->dev,
1181 "Hint address 0x%llx will be ignored because source memory is not aligned 0x%x\n",
1182 hint_addr, phys_pg_pack->offset);
1183 }
1184
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001185 ret_vaddr = get_va_block(hdev, va_range, phys_pg_pack->total_size,
farah kassabri1ae32b92021-01-31 18:56:03 +02001186 hint_addr, va_block_align,
Yuri Nudelman486e1972021-06-03 17:51:58 +03001187 va_range_type, args->flags);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001188 if (!ret_vaddr) {
1189 dev_err(hdev->dev, "no available va block for handle %u\n",
1190 handle);
1191 rc = -ENOMEM;
1192 goto va_block_err;
1193 }
1194
1195 mutex_lock(&ctx->mmu_lock);
1196
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001197 rc = map_phys_pg_pack(ctx, ret_vaddr, phys_pg_pack);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001198 if (rc) {
1199 mutex_unlock(&ctx->mmu_lock);
1200 dev_err(hdev->dev, "mapping page pack failed for handle %u\n",
1201 handle);
1202 goto map_err;
1203 }
1204
Alon Mizrahi08c03a12021-04-08 15:30:59 +03001205 rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, false,
1206 *vm_type, ctx->asid, ret_vaddr, phys_pg_pack->total_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001207
1208 mutex_unlock(&ctx->mmu_lock);
1209
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001210 if (rc) {
1211 dev_err(hdev->dev,
1212 "mapping handle %u failed due to MMU cache invalidation\n",
1213 handle);
1214 goto map_err;
1215 }
1216
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001217 ret_vaddr += phys_pg_pack->offset;
1218
1219 hnode->ptr = vm_type;
1220 hnode->vaddr = ret_vaddr;
1221
1222 mutex_lock(&ctx->mem_hash_lock);
1223 hash_add(ctx->mem_hash, &hnode->node, ret_vaddr);
1224 mutex_unlock(&ctx->mem_hash_lock);
1225
1226 *device_addr = ret_vaddr;
1227
1228 if (is_userptr)
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +02001229 rc = free_phys_pg_pack(hdev, phys_pg_pack);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001230
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +02001231 return rc;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001232
1233map_err:
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001234 if (add_va_block(hdev, va_range, ret_vaddr,
1235 ret_vaddr + phys_pg_pack->total_size - 1))
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001236 dev_warn(hdev->dev,
1237 "release va block failed for handle 0x%x, vaddr: 0x%llx\n",
1238 handle, ret_vaddr);
1239
1240va_block_err:
1241 kfree(hnode);
1242hnode_err:
1243shared_err:
1244 atomic_dec(&phys_pg_pack->mapping_cnt);
1245 if (is_userptr)
1246 free_phys_pg_pack(hdev, phys_pg_pack);
1247init_page_pack_err:
1248 if (is_userptr)
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001249 dma_unmap_host_va(hdev, userptr);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001250
1251 return rc;
1252}
1253
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001254/**
1255 * unmap_device_va() - unmap the given device virtual address.
1256 * @ctx: pointer to the context structure.
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001257 * @args: host parameters with device virtual address to unmap.
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001258 * @ctx_free: true if in context free flow, false otherwise.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001259 *
1260 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001261 * - unmap the physical pages related to the given virtual address.
1262 * - return the device virtual block to the virtual block list.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001263 */
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001264static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args,
1265 bool ctx_free)
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001266{
1267 struct hl_device *hdev = ctx->hdev;
Moti Haimovskib19dc672020-11-18 20:15:29 +02001268 struct asic_fixed_properties *prop = &hdev->asic_prop;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001269 struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
1270 struct hl_vm_hash_node *hnode = NULL;
1271 struct hl_userptr *userptr = NULL;
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001272 struct hl_va_range *va_range;
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001273 u64 vaddr = args->unmap.device_virt_addr;
Oded Gabbay82629c72021-06-29 18:08:05 +03001274 enum vm_type *vm_type;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001275 bool is_userptr;
Tomer Tayarc68f1ba2020-06-01 09:56:47 +03001276 int rc = 0;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001277
1278 /* protect from double entrance */
1279 mutex_lock(&ctx->mem_hash_lock);
1280 hash_for_each_possible(ctx->mem_hash, hnode, node, (unsigned long)vaddr)
1281 if (vaddr == hnode->vaddr)
1282 break;
1283
1284 if (!hnode) {
1285 mutex_unlock(&ctx->mem_hash_lock);
1286 dev_err(hdev->dev,
1287 "unmap failed, no mem hnode for vaddr 0x%llx\n",
1288 vaddr);
1289 return -EINVAL;
1290 }
1291
1292 hash_del(&hnode->node);
1293 mutex_unlock(&ctx->mem_hash_lock);
1294
1295 vm_type = hnode->ptr;
1296
1297 if (*vm_type == VM_TYPE_USERPTR) {
1298 is_userptr = true;
1299 userptr = hnode->ptr;
Omer Shpigelman54bb6742019-11-14 18:23:55 +00001300 rc = init_phys_pg_pack_from_userptr(ctx, userptr,
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001301 &phys_pg_pack);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001302 if (rc) {
1303 dev_err(hdev->dev,
1304 "unable to init page pack for vaddr 0x%llx\n",
1305 vaddr);
1306 goto vm_type_err;
1307 }
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001308
1309 if (phys_pg_pack->page_size ==
1310 hdev->asic_prop.pmmu.page_size)
Ofir Bitton784b9162020-10-22 11:05:55 +03001311 va_range = ctx->va_range[HL_VA_RANGE_TYPE_HOST];
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001312 else
Ofir Bitton784b9162020-10-22 11:05:55 +03001313 va_range = ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE];
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001314 } else if (*vm_type == VM_TYPE_PHYS_PACK) {
1315 is_userptr = false;
Ofir Bitton784b9162020-10-22 11:05:55 +03001316 va_range = ctx->va_range[HL_VA_RANGE_TYPE_DRAM];
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001317 phys_pg_pack = hnode->ptr;
1318 } else {
1319 dev_warn(hdev->dev,
1320 "unmap failed, unknown vm desc for vaddr 0x%llx\n",
1321 vaddr);
1322 rc = -EFAULT;
1323 goto vm_type_err;
1324 }
1325
1326 if (atomic_read(&phys_pg_pack->mapping_cnt) == 0) {
1327 dev_err(hdev->dev, "vaddr 0x%llx is not mapped\n", vaddr);
1328 rc = -EINVAL;
1329 goto mapping_cnt_err;
1330 }
1331
Moti Haimovskib19dc672020-11-18 20:15:29 +02001332 if (!is_userptr && !is_power_of_2(phys_pg_pack->page_size))
1333 vaddr = prop->dram_base_address +
1334 DIV_ROUND_DOWN_ULL(vaddr - prop->dram_base_address,
1335 phys_pg_pack->page_size) *
1336 phys_pg_pack->page_size;
1337 else
1338 vaddr &= ~(((u64) phys_pg_pack->page_size) - 1);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001339
1340 mutex_lock(&ctx->mmu_lock);
1341
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001342 unmap_phys_pg_pack(ctx, vaddr, phys_pg_pack);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001343
Omer Shpigelmanbea84c42019-11-14 18:23:58 +00001344 /*
1345 * During context free this function is called in a loop to clean all
1346 * the context mappings. Hence the cache invalidation can be called once
1347 * at the loop end rather than for each iteration
1348 */
1349 if (!ctx_free)
Alon Mizrahi08c03a12021-04-08 15:30:59 +03001350 rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, true,
1351 *vm_type, ctx->asid, vaddr,
1352 phys_pg_pack->total_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001353
1354 mutex_unlock(&ctx->mmu_lock);
1355
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001356 /*
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001357 * If the context is closing we don't need to check for the MMU cache
1358 * invalidation return code and update the VA free list as in this flow
1359 * we invalidate the MMU cache outside of this unmap function and the VA
1360 * free list will be freed anyway.
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001361 */
1362 if (!ctx_free) {
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001363 int tmp_rc;
1364
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001365 if (rc)
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001366 dev_err(hdev->dev,
1367 "unmapping vaddr 0x%llx failed due to MMU cache invalidation\n",
1368 vaddr);
1369
1370 tmp_rc = add_va_block(hdev, va_range, vaddr,
1371 vaddr + phys_pg_pack->total_size - 1);
1372 if (tmp_rc) {
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001373 dev_warn(hdev->dev,
1374 "add va block failed for vaddr: 0x%llx\n",
1375 vaddr);
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001376 if (!rc)
1377 rc = tmp_rc;
1378 }
Omer Shpigelman71c5e552019-11-14 18:23:57 +00001379 }
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001380
1381 atomic_dec(&phys_pg_pack->mapping_cnt);
1382 kfree(hnode);
1383
1384 if (is_userptr) {
Bharat Jauharid4b1e5d2021-03-18 12:11:19 +02001385 rc = free_phys_pg_pack(hdev, phys_pg_pack);
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001386 dma_unmap_host_va(hdev, userptr);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001387 }
1388
Omer Shpigelman8ff5f4f2020-05-24 23:06:59 +03001389 return rc;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001390
1391mapping_cnt_err:
1392 if (is_userptr)
1393 free_phys_pg_pack(hdev, phys_pg_pack);
1394vm_type_err:
1395 mutex_lock(&ctx->mem_hash_lock);
1396 hash_add(ctx->mem_hash, &hnode->node, vaddr);
1397 mutex_unlock(&ctx->mem_hash_lock);
1398
1399 return rc;
1400}
1401
Oded Gabbay6df50d22021-02-05 16:04:34 +02001402static int map_block(struct hl_device *hdev, u64 address, u64 *handle,
1403 u32 *size)
Ofir Bittond00697f2021-01-05 12:55:06 +02001404{
1405 u32 block_id = 0;
1406 int rc;
1407
Oded Gabbay6df50d22021-02-05 16:04:34 +02001408 rc = hdev->asic_funcs->get_hw_block_id(hdev, address, size, &block_id);
Ofir Bittond00697f2021-01-05 12:55:06 +02001409
1410 *handle = block_id | HL_MMAP_TYPE_BLOCK;
1411 *handle <<= PAGE_SHIFT;
1412
1413 return rc;
1414}
1415
1416static void hw_block_vm_close(struct vm_area_struct *vma)
1417{
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001418 struct hl_vm_hw_block_list_node *lnode =
1419 (struct hl_vm_hw_block_list_node *) vma->vm_private_data;
1420 struct hl_ctx *ctx = lnode->ctx;
Ofir Bittond00697f2021-01-05 12:55:06 +02001421
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001422 mutex_lock(&ctx->hw_block_list_lock);
1423 list_del(&lnode->node);
1424 mutex_unlock(&ctx->hw_block_list_lock);
Ofir Bittond00697f2021-01-05 12:55:06 +02001425 hl_ctx_put(ctx);
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001426 kfree(lnode);
Ofir Bittond00697f2021-01-05 12:55:06 +02001427 vma->vm_private_data = NULL;
1428}
1429
1430static const struct vm_operations_struct hw_block_vm_ops = {
1431 .close = hw_block_vm_close
1432};
1433
1434/**
1435 * hl_hw_block_mmap() - mmap a hw block to user.
1436 * @hpriv: pointer to the private data of the fd
1437 * @vma: pointer to vm_area_struct of the process
1438 *
1439 * Driver increments context reference for every HW block mapped in order
1440 * to prevent user from closing FD without unmapping first
1441 */
1442int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
1443{
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001444 struct hl_vm_hw_block_list_node *lnode;
Ofir Bittond00697f2021-01-05 12:55:06 +02001445 struct hl_device *hdev = hpriv->hdev;
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001446 struct hl_ctx *ctx = hpriv->ctx;
Ofir Bittond00697f2021-01-05 12:55:06 +02001447 u32 block_id, block_size;
1448 int rc;
1449
1450 /* We use the page offset to hold the block id and thus we need to clear
1451 * it before doing the mmap itself
1452 */
1453 block_id = vma->vm_pgoff;
1454 vma->vm_pgoff = 0;
1455
1456 /* Driver only allows mapping of a complete HW block */
1457 block_size = vma->vm_end - vma->vm_start;
1458
Ofir Bittond00697f2021-01-05 12:55:06 +02001459 if (!access_ok((void __user *) (uintptr_t) vma->vm_start, block_size)) {
Ofir Bittond00697f2021-01-05 12:55:06 +02001460 dev_err(hdev->dev,
1461 "user pointer is invalid - 0x%lx\n",
1462 vma->vm_start);
1463
1464 return -EINVAL;
1465 }
1466
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001467 lnode = kzalloc(sizeof(*lnode), GFP_KERNEL);
1468 if (!lnode)
1469 return -ENOMEM;
Ofir Bittond00697f2021-01-05 12:55:06 +02001470
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001471 vma->vm_ops = &hw_block_vm_ops;
1472 vma->vm_private_data = lnode;
1473
1474 hl_ctx_get(hdev, ctx);
Ofir Bittond00697f2021-01-05 12:55:06 +02001475
1476 rc = hdev->asic_funcs->hw_block_mmap(hdev, vma, block_id, block_size);
1477 if (rc) {
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001478 hl_ctx_put(ctx);
1479 kfree(lnode);
Ofir Bittond00697f2021-01-05 12:55:06 +02001480 return rc;
1481 }
1482
Sagiv Ozeria4371c12021-02-23 11:01:08 +02001483 lnode->ctx = ctx;
1484 lnode->vaddr = vma->vm_start;
1485 lnode->size = block_size;
1486 lnode->id = block_id;
1487
1488 mutex_lock(&ctx->hw_block_list_lock);
1489 list_add_tail(&lnode->node, &ctx->hw_block_mem_list);
1490 mutex_unlock(&ctx->hw_block_list_lock);
1491
Ofir Bittond00697f2021-01-05 12:55:06 +02001492 vma->vm_pgoff = block_id;
1493
1494 return 0;
1495}
1496
Oded Gabbay54303a12019-04-04 14:42:26 +03001497static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args)
1498{
1499 struct hl_device *hdev = hpriv->hdev;
1500 struct hl_ctx *ctx = hpriv->ctx;
Ofir Bittond00697f2021-01-05 12:55:06 +02001501 u64 block_handle, device_addr = 0;
Oded Gabbay6df50d22021-02-05 16:04:34 +02001502 u32 handle = 0, block_size;
Oded Gabbay54303a12019-04-04 14:42:26 +03001503 int rc;
1504
1505 switch (args->in.op) {
1506 case HL_MEM_OP_ALLOC:
1507 if (args->in.alloc.mem_size == 0) {
1508 dev_err(hdev->dev,
1509 "alloc size must be larger than 0\n");
1510 rc = -EINVAL;
1511 goto out;
1512 }
1513
1514 /* Force contiguous as there are no real MMU
1515 * translations to overcome physical memory gaps
1516 */
1517 args->in.flags |= HL_MEM_CONTIGUOUS;
1518 rc = alloc_device_memory(ctx, &args->in, &handle);
1519
1520 memset(args, 0, sizeof(*args));
1521 args->out.handle = (__u64) handle;
1522 break;
1523
1524 case HL_MEM_OP_FREE:
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001525 rc = free_device_memory(ctx, &args->in);
Oded Gabbay54303a12019-04-04 14:42:26 +03001526 break;
1527
1528 case HL_MEM_OP_MAP:
1529 if (args->in.flags & HL_MEM_USERPTR) {
1530 device_addr = args->in.map_host.host_virt_addr;
1531 rc = 0;
1532 } else {
1533 rc = get_paddr_from_handle(ctx, &args->in,
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001534 &device_addr);
Oded Gabbay54303a12019-04-04 14:42:26 +03001535 }
1536
1537 memset(args, 0, sizeof(*args));
1538 args->out.device_virt_addr = device_addr;
1539 break;
1540
1541 case HL_MEM_OP_UNMAP:
1542 rc = 0;
1543 break;
1544
Ofir Bittond00697f2021-01-05 12:55:06 +02001545 case HL_MEM_OP_MAP_BLOCK:
1546 rc = map_block(hdev, args->in.map_block.block_addr,
Oded Gabbay6df50d22021-02-05 16:04:34 +02001547 &block_handle, &block_size);
1548 args->out.block_handle = block_handle;
1549 args->out.block_size = block_size;
Ofir Bittond00697f2021-01-05 12:55:06 +02001550 break;
1551
Oded Gabbay54303a12019-04-04 14:42:26 +03001552 default:
1553 dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n");
1554 rc = -ENOTTY;
1555 break;
1556 }
1557
1558out:
1559 return rc;
1560}
1561
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001562int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data)
1563{
Ofir Bitton66a76402020-10-05 14:40:10 +03001564 enum hl_device_status status;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001565 union hl_mem_args *args = data;
1566 struct hl_device *hdev = hpriv->hdev;
1567 struct hl_ctx *ctx = hpriv->ctx;
Ofir Bittond00697f2021-01-05 12:55:06 +02001568 u64 block_handle, device_addr = 0;
Oded Gabbay6df50d22021-02-05 16:04:34 +02001569 u32 handle = 0, block_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001570 int rc;
1571
Ofir Bitton66a76402020-10-05 14:40:10 +03001572 if (!hl_device_operational(hdev, &status)) {
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001573 dev_warn_ratelimited(hdev->dev,
Oded Gabbay3f5398c2019-04-06 15:41:35 +03001574 "Device is %s. Can't execute MEMORY IOCTL\n",
Ofir Bitton66a76402020-10-05 14:40:10 +03001575 hdev->status[status]);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001576 return -EBUSY;
1577 }
1578
Oded Gabbay54303a12019-04-04 14:42:26 +03001579 if (!hdev->mmu_enable)
1580 return mem_ioctl_no_mmu(hpriv, args);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001581
Oded Gabbay54303a12019-04-04 14:42:26 +03001582 switch (args->in.op) {
1583 case HL_MEM_OP_ALLOC:
Oded Gabbay54303a12019-04-04 14:42:26 +03001584 if (args->in.alloc.mem_size == 0) {
1585 dev_err(hdev->dev,
1586 "alloc size must be larger than 0\n");
1587 rc = -EINVAL;
1588 goto out;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001589 }
Oded Gabbay3e622992020-10-18 15:32:23 +03001590
1591 /* If DRAM does not support virtual memory the driver won't
1592 * handle the allocation/freeing of that memory. However, for
1593 * system administration/monitoring purposes, the driver will
1594 * keep track of the amount of DRAM memory that is allocated
1595 * and freed by the user. Because this code totally relies on
1596 * the user's input, the driver can't ensure the validity
1597 * of this accounting.
1598 */
Oded Gabbay7f070c92020-11-09 09:48:31 +02001599 if (!hdev->asic_prop.dram_supports_virtual_memory) {
Oded Gabbay3e622992020-10-18 15:32:23 +03001600 atomic64_add(args->in.alloc.mem_size,
1601 &ctx->dram_phys_mem);
1602 atomic64_add(args->in.alloc.mem_size,
1603 &hdev->dram_used_mem);
1604
1605 dev_dbg(hdev->dev, "DRAM alloc is not supported\n");
1606 rc = 0;
1607
1608 memset(args, 0, sizeof(*args));
1609 args->out.handle = 0;
1610 goto out;
1611 }
1612
Oded Gabbay54303a12019-04-04 14:42:26 +03001613 rc = alloc_device_memory(ctx, &args->in, &handle);
1614
1615 memset(args, 0, sizeof(*args));
1616 args->out.handle = (__u64) handle;
1617 break;
1618
1619 case HL_MEM_OP_FREE:
Oded Gabbay3e622992020-10-18 15:32:23 +03001620 /* If DRAM does not support virtual memory the driver won't
1621 * handle the allocation/freeing of that memory. However, for
1622 * system administration/monitoring purposes, the driver will
1623 * keep track of the amount of DRAM memory that is allocated
1624 * and freed by the user. Because this code totally relies on
1625 * the user's input, the driver can't ensure the validity
1626 * of this accounting.
1627 */
Oded Gabbay7f070c92020-11-09 09:48:31 +02001628 if (!hdev->asic_prop.dram_supports_virtual_memory) {
Oded Gabbay3e622992020-10-18 15:32:23 +03001629 atomic64_sub(args->in.alloc.mem_size,
1630 &ctx->dram_phys_mem);
1631 atomic64_sub(args->in.alloc.mem_size,
1632 &hdev->dram_used_mem);
1633
1634 dev_dbg(hdev->dev, "DRAM alloc is not supported\n");
1635 rc = 0;
1636
1637 goto out;
1638 }
1639
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001640 rc = free_device_memory(ctx, &args->in);
Oded Gabbay54303a12019-04-04 14:42:26 +03001641 break;
1642
1643 case HL_MEM_OP_MAP:
1644 rc = map_device_va(ctx, &args->in, &device_addr);
1645
1646 memset(args, 0, sizeof(*args));
1647 args->out.device_virt_addr = device_addr;
1648 break;
1649
1650 case HL_MEM_OP_UNMAP:
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02001651 rc = unmap_device_va(ctx, &args->in, false);
Oded Gabbay54303a12019-04-04 14:42:26 +03001652 break;
1653
Ofir Bittond00697f2021-01-05 12:55:06 +02001654 case HL_MEM_OP_MAP_BLOCK:
1655 rc = map_block(hdev, args->in.map_block.block_addr,
Oded Gabbay6df50d22021-02-05 16:04:34 +02001656 &block_handle, &block_size);
1657 args->out.block_handle = block_handle;
1658 args->out.block_size = block_size;
Oded Gabbay54303a12019-04-04 14:42:26 +03001659 break;
1660
1661 default:
1662 dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n");
1663 rc = -ENOTTY;
1664 break;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001665 }
1666
1667out:
1668 return rc;
1669}
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001670
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001671static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size,
1672 u32 npages, u64 start, u32 offset,
1673 struct hl_userptr *userptr)
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001674{
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001675 int rc;
1676
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001677 if (!access_ok((void __user *) (uintptr_t) addr, size)) {
Oded Gabbay230afe72019-02-27 00:19:18 +02001678 dev_err(hdev->dev, "user pointer is invalid - 0x%llx\n", addr);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001679 return -EFAULT;
1680 }
1681
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001682 userptr->pages = kvmalloc_array(npages, sizeof(*userptr->pages),
1683 GFP_KERNEL);
1684 if (!userptr->pages)
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001685 return -ENOMEM;
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001686
Daniel Vetterd88a0c12020-11-27 17:41:18 +01001687 rc = pin_user_pages_fast(start, npages,
1688 FOLL_FORCE | FOLL_WRITE | FOLL_LONGTERM,
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001689 userptr->pages);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001690
1691 if (rc != npages) {
1692 dev_err(hdev->dev,
Tomer Tayarf5d6e392021-06-10 20:48:39 +03001693 "Failed (%d) to pin host memory with user ptr 0x%llx, size 0x%llx, npages %d\n",
1694 rc, addr, size, npages);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001695 if (rc < 0)
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001696 goto destroy_pages;
1697 npages = rc;
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001698 rc = -EFAULT;
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001699 goto put_pages;
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001700 }
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001701 userptr->npages = npages;
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001702
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001703 rc = sg_alloc_table_from_pages(userptr->sgt,
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001704 userptr->pages,
Ofir Bittond5eb8372021-02-14 15:35:56 +02001705 npages, offset, size, GFP_KERNEL);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001706 if (rc < 0) {
1707 dev_err(hdev->dev, "failed to create SG table from pages\n");
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001708 goto put_pages;
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001709 }
1710
1711 return 0;
1712
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001713put_pages:
1714 unpin_user_pages(userptr->pages, npages);
1715destroy_pages:
1716 kvfree(userptr->pages);
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001717 return rc;
1718}
1719
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001720/**
1721 * hl_pin_host_memory() - pins a chunk of host memory.
1722 * @hdev: pointer to the habanalabs device structure.
1723 * @addr: the host virtual address of the memory area.
1724 * @size: the size of the memory area.
1725 * @userptr: pointer to hl_userptr structure.
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001726 *
1727 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001728 * - Pins the physical pages.
1729 * - Create an SG list from those pages.
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001730 */
1731int hl_pin_host_memory(struct hl_device *hdev, u64 addr, u64 size,
1732 struct hl_userptr *userptr)
1733{
1734 u64 start, end;
1735 u32 npages, offset;
1736 int rc;
1737
1738 if (!size) {
1739 dev_err(hdev->dev, "size to pin is invalid - %llu\n", size);
1740 return -EINVAL;
1741 }
1742
1743 /*
1744 * If the combination of the address and size requested for this memory
1745 * region causes an integer overflow, return error.
1746 */
1747 if (((addr + size) < addr) ||
1748 PAGE_ALIGN(addr + size) < (addr + size)) {
1749 dev_err(hdev->dev,
1750 "user pointer 0x%llx + %llu causes integer overflow\n",
1751 addr, size);
1752 return -EINVAL;
1753 }
1754
Ofir Bittond5eb8372021-02-14 15:35:56 +02001755 userptr->sgt = kzalloc(sizeof(*userptr->sgt), GFP_KERNEL);
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001756 if (!userptr->sgt)
1757 return -ENOMEM;
1758
1759 start = addr & PAGE_MASK;
1760 offset = addr & ~PAGE_MASK;
1761 end = PAGE_ALIGN(addr + size);
1762 npages = (end - start) >> PAGE_SHIFT;
1763
1764 userptr->size = size;
1765 userptr->addr = addr;
1766 userptr->dma_mapped = false;
1767 INIT_LIST_HEAD(&userptr->job_node);
1768
1769 rc = get_user_memory(hdev, addr, size, npages, start, offset,
1770 userptr);
1771 if (rc) {
1772 dev_err(hdev->dev,
1773 "failed to get user memory for address 0x%llx\n",
1774 addr);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001775 goto free_sgt;
1776 }
1777
Oded Gabbayc2164772019-02-16 00:39:24 +02001778 hl_debugfs_add_userptr(hdev, userptr);
1779
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001780 return 0;
1781
1782free_sgt:
1783 kfree(userptr->sgt);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001784 return rc;
1785}
1786
1787/*
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001788 * hl_unpin_host_memory - unpins a chunk of host memory.
1789 * @hdev: pointer to the habanalabs device structure
1790 * @userptr: pointer to hl_userptr structure
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001791 *
1792 * This function does the following:
1793 * - Unpins the physical pages related to the host memory
1794 * - Free the SG list
1795 */
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001796void hl_unpin_host_memory(struct hl_device *hdev, struct hl_userptr *userptr)
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001797{
Oded Gabbayc2164772019-02-16 00:39:24 +02001798 hl_debugfs_remove_userptr(hdev, userptr);
1799
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001800 if (userptr->dma_mapped)
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03001801 hdev->asic_funcs->hl_dma_unmap_sg(hdev, userptr->sgt->sgl,
1802 userptr->sgt->nents,
1803 userptr->dir);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001804
Daniel Vetterd4cb1922020-11-27 17:41:17 +01001805 unpin_user_pages_dirty_lock(userptr->pages, userptr->npages, true);
1806 kvfree(userptr->pages);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001807
1808 list_del(&userptr->job_node);
1809
1810 sg_free_table(userptr->sgt);
1811 kfree(userptr->sgt);
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001812}
1813
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001814/**
1815 * hl_userptr_delete_list() - clear userptr list.
1816 * @hdev: pointer to the habanalabs device structure.
1817 * @userptr_list: pointer to the list to clear.
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001818 *
1819 * This function does the following:
1820 * - Iterates over the list and unpins the host memory and frees the userptr
1821 * structure.
1822 */
1823void hl_userptr_delete_list(struct hl_device *hdev,
1824 struct list_head *userptr_list)
1825{
1826 struct hl_userptr *userptr, *tmp;
1827
1828 list_for_each_entry_safe(userptr, tmp, userptr_list, job_node) {
1829 hl_unpin_host_memory(hdev, userptr);
1830 kfree(userptr);
1831 }
1832
1833 INIT_LIST_HEAD(userptr_list);
1834}
1835
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001836/**
1837 * hl_userptr_is_pinned() - returns whether the given userptr is pinned.
1838 * @hdev: pointer to the habanalabs device structure.
1839 * @userptr_list: pointer to the list to clear.
1840 * @userptr: pointer to userptr to check.
Oded Gabbayeff6f4a2019-02-16 00:39:21 +02001841 *
1842 * This function does the following:
1843 * - Iterates over the list and checks if the given userptr is in it, means is
1844 * pinned. If so, returns true, otherwise returns false.
1845 */
1846bool hl_userptr_is_pinned(struct hl_device *hdev, u64 addr,
1847 u32 size, struct list_head *userptr_list,
1848 struct hl_userptr **userptr)
1849{
1850 list_for_each_entry((*userptr), userptr_list, job_node) {
1851 if ((addr == (*userptr)->addr) && (size == (*userptr)->size))
1852 return true;
1853 }
1854
1855 return false;
1856}
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001857
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001858/**
1859 * va_range_init() - initialize virtual addresses range.
1860 * @hdev: pointer to the habanalabs device structure.
1861 * @va_range: pointer to the range to initialize.
1862 * @start: range start address.
1863 * @end: range end address.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001864 *
1865 * This function does the following:
1866 * - Initializes the virtual addresses list of the given range with the given
1867 * addresses.
1868 */
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001869static int va_range_init(struct hl_device *hdev, struct hl_va_range *va_range,
Ofir Bitton784b9162020-10-22 11:05:55 +03001870 u64 start, u64 end, u32 page_size)
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001871{
1872 int rc;
1873
1874 INIT_LIST_HEAD(&va_range->list);
1875
Moti Haimovskib19dc672020-11-18 20:15:29 +02001876 /*
1877 * PAGE_SIZE alignment
1878 * it is the callers responsibility to align the addresses if the
1879 * page size is not a power of 2
1880 */
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001881
Moti Haimovskib19dc672020-11-18 20:15:29 +02001882 if (is_power_of_2(page_size)) {
1883 if (start & (PAGE_SIZE - 1)) {
1884 start &= PAGE_MASK;
1885 start += PAGE_SIZE;
1886 }
1887
1888 if (end & (PAGE_SIZE - 1))
1889 end &= PAGE_MASK;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001890 }
1891
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001892 if (start >= end) {
1893 dev_err(hdev->dev, "too small vm range for va list\n");
1894 return -EFAULT;
1895 }
1896
1897 rc = add_va_block(hdev, va_range, start, end);
1898
1899 if (rc) {
1900 dev_err(hdev->dev, "Failed to init host va list\n");
1901 return rc;
1902 }
1903
1904 va_range->start_addr = start;
1905 va_range->end_addr = end;
Ofir Bitton784b9162020-10-22 11:05:55 +03001906 va_range->page_size = page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001907
1908 return 0;
1909}
1910
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001911/**
1912 * va_range_fini() - clear a virtual addresses range.
1913 * @hdev: pointer to the habanalabs structure.
1914 * va_range: pointer to virtual addresses rang.e
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001915 *
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001916 * This function does the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001917 * - Frees the virtual addresses block list and its lock.
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001918 */
Ofir Bitton784b9162020-10-22 11:05:55 +03001919static void va_range_fini(struct hl_device *hdev, struct hl_va_range *va_range)
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001920{
1921 mutex_lock(&va_range->lock);
1922 clear_va_list_locked(hdev, &va_range->list);
1923 mutex_unlock(&va_range->lock);
1924
1925 mutex_destroy(&va_range->lock);
1926 kfree(va_range);
1927}
1928
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001929/**
1930 * vm_ctx_init_with_ranges() - initialize virtual memory for context.
1931 * @ctx: pointer to the habanalabs context structure.
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001932 * @host_range_start: host virtual addresses range start.
1933 * @host_range_end: host virtual addresses range end.
1934 * @host_huge_range_start: host virtual addresses range start for memory
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001935 * allocated with huge pages.
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001936 * @host_huge_range_end: host virtual addresses range end for memory allocated
1937 * with huge pages.
1938 * @dram_range_start: dram virtual addresses range start.
1939 * @dram_range_end: dram virtual addresses range end.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001940 *
1941 * This function initializes the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02001942 * - MMU for context.
1943 * - Virtual address to area descriptor hashtable.
1944 * - Virtual block list of available virtual memory.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001945 */
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001946static int vm_ctx_init_with_ranges(struct hl_ctx *ctx,
1947 u64 host_range_start,
1948 u64 host_range_end,
Ofir Bitton784b9162020-10-22 11:05:55 +03001949 u32 host_page_size,
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001950 u64 host_huge_range_start,
1951 u64 host_huge_range_end,
Ofir Bitton784b9162020-10-22 11:05:55 +03001952 u32 host_huge_page_size,
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001953 u64 dram_range_start,
Ofir Bitton784b9162020-10-22 11:05:55 +03001954 u64 dram_range_end,
1955 u32 dram_page_size)
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001956{
1957 struct hl_device *hdev = ctx->hdev;
Ofir Bitton784b9162020-10-22 11:05:55 +03001958 int i, rc;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001959
Ofir Bitton784b9162020-10-22 11:05:55 +03001960 for (i = 0 ; i < HL_VA_RANGE_TYPE_MAX ; i++) {
1961 ctx->va_range[i] =
1962 kzalloc(sizeof(struct hl_va_range), GFP_KERNEL);
1963 if (!ctx->va_range[i]) {
1964 rc = -ENOMEM;
1965 goto free_va_range;
1966 }
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001967 }
1968
Omer Shpigelman27ca384c2019-02-28 10:46:11 +02001969 rc = hl_mmu_ctx_init(ctx);
1970 if (rc) {
1971 dev_err(hdev->dev, "failed to init context %d\n", ctx->asid);
Ofir Bitton784b9162020-10-22 11:05:55 +03001972 goto free_va_range;
Omer Shpigelman27ca384c2019-02-28 10:46:11 +02001973 }
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001974
1975 mutex_init(&ctx->mem_hash_lock);
1976 hash_init(ctx->mem_hash);
1977
Ofir Bitton784b9162020-10-22 11:05:55 +03001978 mutex_init(&ctx->va_range[HL_VA_RANGE_TYPE_HOST]->lock);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001979
Ofir Bitton784b9162020-10-22 11:05:55 +03001980 rc = va_range_init(hdev, ctx->va_range[HL_VA_RANGE_TYPE_HOST],
1981 host_range_start, host_range_end, host_page_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001982 if (rc) {
1983 dev_err(hdev->dev, "failed to init host vm range\n");
Ofir Bitton784b9162020-10-22 11:05:55 +03001984 goto mmu_ctx_fini;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001985 }
1986
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001987 if (hdev->pmmu_huge_range) {
Ofir Bitton784b9162020-10-22 11:05:55 +03001988 mutex_init(&ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]->lock);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02001989
Ofir Bitton784b9162020-10-22 11:05:55 +03001990 rc = va_range_init(hdev,
1991 ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE],
1992 host_huge_range_start, host_huge_range_end,
1993 host_huge_page_size);
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001994 if (rc) {
1995 dev_err(hdev->dev,
1996 "failed to init host huge vm range\n");
Ofir Bitton784b9162020-10-22 11:05:55 +03001997 goto clear_host_va_range;
Omer Shpigelman64a7e292020-01-05 09:05:45 +00001998 }
1999 } else {
Ofir Bitton8e718f22020-11-26 13:01:11 +02002000 kfree(ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]);
Ofir Bitton784b9162020-10-22 11:05:55 +03002001 ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE] =
2002 ctx->va_range[HL_VA_RANGE_TYPE_HOST];
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002003 }
2004
Ofir Bitton784b9162020-10-22 11:05:55 +03002005 mutex_init(&ctx->va_range[HL_VA_RANGE_TYPE_DRAM]->lock);
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002006
Ofir Bitton784b9162020-10-22 11:05:55 +03002007 rc = va_range_init(hdev, ctx->va_range[HL_VA_RANGE_TYPE_DRAM],
2008 dram_range_start, dram_range_end, dram_page_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002009 if (rc) {
2010 dev_err(hdev->dev, "failed to init dram vm range\n");
Ofir Bitton784b9162020-10-22 11:05:55 +03002011 goto clear_host_huge_va_range;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002012 }
2013
Oded Gabbayc2164772019-02-16 00:39:24 +02002014 hl_debugfs_add_ctx_mem_hash(hdev, ctx);
2015
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002016 return 0;
2017
Ofir Bitton784b9162020-10-22 11:05:55 +03002018clear_host_huge_va_range:
2019 mutex_destroy(&ctx->va_range[HL_VA_RANGE_TYPE_DRAM]->lock);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002020
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002021 if (hdev->pmmu_huge_range) {
Ofir Bitton784b9162020-10-22 11:05:55 +03002022 mutex_lock(&ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]->lock);
2023 clear_va_list_locked(hdev,
2024 &ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]->list);
2025 mutex_unlock(&ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]->lock);
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002026 }
Ofir Bitton784b9162020-10-22 11:05:55 +03002027clear_host_va_range:
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002028 if (hdev->pmmu_huge_range)
Ofir Bitton784b9162020-10-22 11:05:55 +03002029 mutex_destroy(&ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]->lock);
2030 mutex_lock(&ctx->va_range[HL_VA_RANGE_TYPE_HOST]->lock);
2031 clear_va_list_locked(hdev, &ctx->va_range[HL_VA_RANGE_TYPE_HOST]->list);
2032 mutex_unlock(&ctx->va_range[HL_VA_RANGE_TYPE_HOST]->lock);
2033mmu_ctx_fini:
2034 mutex_destroy(&ctx->va_range[HL_VA_RANGE_TYPE_HOST]->lock);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002035 mutex_destroy(&ctx->mem_hash_lock);
2036 hl_mmu_ctx_fini(ctx);
Ofir Bitton784b9162020-10-22 11:05:55 +03002037free_va_range:
2038 for (i = 0 ; i < HL_VA_RANGE_TYPE_MAX ; i++)
2039 kfree(ctx->va_range[i]);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002040
2041 return rc;
2042}
2043
2044int hl_vm_ctx_init(struct hl_ctx *ctx)
2045{
2046 struct asic_fixed_properties *prop = &ctx->hdev->asic_prop;
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002047 u64 host_range_start, host_range_end, host_huge_range_start,
2048 host_huge_range_end, dram_range_start, dram_range_end;
Ofir Bitton784b9162020-10-22 11:05:55 +03002049 u32 host_page_size, host_huge_page_size, dram_page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002050
2051 atomic64_set(&ctx->dram_phys_mem, 0);
2052
2053 /*
2054 * - If MMU is enabled, init the ranges as usual.
2055 * - If MMU is disabled, in case of host mapping, the returned address
2056 * is the given one.
2057 * In case of DRAM mapping, the returned address is the physical
2058 * address of the memory related to the given handle.
2059 */
Oded Gabbayf3a965c2020-10-04 23:00:39 +03002060 if (!ctx->hdev->mmu_enable)
2061 return 0;
2062
2063 dram_range_start = prop->dmmu.start_addr;
2064 dram_range_end = prop->dmmu.end_addr;
Moti Haimovskib19dc672020-11-18 20:15:29 +02002065 dram_page_size = prop->dram_page_size ?
2066 prop->dram_page_size : prop->dmmu.page_size;
Oded Gabbayf3a965c2020-10-04 23:00:39 +03002067 host_range_start = prop->pmmu.start_addr;
2068 host_range_end = prop->pmmu.end_addr;
Ofir Bitton784b9162020-10-22 11:05:55 +03002069 host_page_size = prop->pmmu.page_size;
Oded Gabbayf3a965c2020-10-04 23:00:39 +03002070 host_huge_range_start = prop->pmmu_huge.start_addr;
2071 host_huge_range_end = prop->pmmu_huge.end_addr;
Ofir Bitton784b9162020-10-22 11:05:55 +03002072 host_huge_page_size = prop->pmmu_huge.page_size;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002073
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002074 return vm_ctx_init_with_ranges(ctx, host_range_start, host_range_end,
Ofir Bitton784b9162020-10-22 11:05:55 +03002075 host_page_size, host_huge_range_start,
2076 host_huge_range_end, host_huge_page_size,
2077 dram_range_start, dram_range_end, dram_page_size);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002078}
2079
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002080/**
2081 * hl_vm_ctx_fini() - virtual memory teardown of context.
2082 * @ctx: pointer to the habanalabs context structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002083 *
2084 * This function perform teardown the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002085 * - Virtual block list of available virtual memory.
2086 * - Virtual address to area descriptor hashtable.
2087 * - MMU for context.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002088 *
2089 * In addition this function does the following:
2090 * - Unmaps the existing hashtable nodes if the hashtable is not empty. The
2091 * hashtable should be empty as no valid mappings should exist at this
2092 * point.
2093 * - Frees any existing physical page list from the idr which relates to the
2094 * current context asid.
2095 * - This function checks the virtual block list for correctness. At this point
2096 * the list should contain one element which describes the whole virtual
2097 * memory range of the context. Otherwise, a warning is printed.
2098 */
2099void hl_vm_ctx_fini(struct hl_ctx *ctx)
2100{
2101 struct hl_device *hdev = ctx->hdev;
2102 struct hl_vm *vm = &hdev->vm;
2103 struct hl_vm_phys_pg_pack *phys_pg_list;
2104 struct hl_vm_hash_node *hnode;
2105 struct hlist_node *tmp_node;
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02002106 struct hl_mem_in args;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002107 int i;
2108
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002109 if (!hdev->mmu_enable)
Oded Gabbayf3a965c2020-10-04 23:00:39 +03002110 return;
2111
Oded Gabbayc2164772019-02-16 00:39:24 +02002112 hl_debugfs_remove_ctx_mem_hash(hdev, ctx);
2113
Omer Shpigelmane604f552019-11-14 18:23:59 +00002114 /*
2115 * Clearly something went wrong on hard reset so no point in printing
2116 * another side effect error
2117 */
2118 if (!hdev->hard_reset_pending && !hash_empty(ctx->mem_hash))
2119 dev_notice(hdev->dev,
Oded Gabbay0eab4f82020-06-22 09:52:22 +03002120 "user released device without removing its memory mappings\n");
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002121
2122 hash_for_each_safe(ctx->mem_hash, i, tmp_node, hnode, node) {
2123 dev_dbg(hdev->dev,
2124 "hl_mem_hash_node of vaddr 0x%llx of asid %d is still alive\n",
2125 hnode->vaddr, ctx->asid);
Omer Shpigelmanf19040c2020-12-09 13:34:11 +02002126 args.unmap.device_virt_addr = hnode->vaddr;
2127 unmap_device_va(ctx, &args, true);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002128 }
2129
Ohad Sharabicb6ef0e2020-11-26 09:39:26 +02002130 mutex_lock(&ctx->mmu_lock);
2131
Omer Shpigelmanbea84c42019-11-14 18:23:58 +00002132 /* invalidate the cache once after the unmapping loop */
2133 hdev->asic_funcs->mmu_invalidate_cache(hdev, true, VM_TYPE_USERPTR);
2134 hdev->asic_funcs->mmu_invalidate_cache(hdev, true, VM_TYPE_PHYS_PACK);
2135
Ohad Sharabicb6ef0e2020-11-26 09:39:26 +02002136 mutex_unlock(&ctx->mmu_lock);
2137
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002138 spin_lock(&vm->idr_lock);
2139 idr_for_each_entry(&vm->phys_pg_pack_handles, phys_pg_list, i)
2140 if (phys_pg_list->asid == ctx->asid) {
2141 dev_dbg(hdev->dev,
Omer Shpigelman7f74d4d2019-08-12 11:48:46 +03002142 "page list 0x%px of asid %d is still alive\n",
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002143 phys_pg_list, ctx->asid);
Tomer Tayarc8113752019-08-04 07:03:41 +00002144 atomic64_sub(phys_pg_list->total_size,
2145 &hdev->dram_used_mem);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002146 free_phys_pg_pack(hdev, phys_pg_list);
2147 idr_remove(&vm->phys_pg_pack_handles, i);
2148 }
2149 spin_unlock(&vm->idr_lock);
2150
Ofir Bitton784b9162020-10-22 11:05:55 +03002151 va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_DRAM]);
Ofir Bitton8e718f22020-11-26 13:01:11 +02002152 va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_HOST]);
2153
Omer Shpigelman64a7e292020-01-05 09:05:45 +00002154 if (hdev->pmmu_huge_range)
Ofir Bitton784b9162020-10-22 11:05:55 +03002155 va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_HOST_HUGE]);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002156
2157 mutex_destroy(&ctx->mem_hash_lock);
2158 hl_mmu_ctx_fini(ctx);
Oded Gabbay3e622992020-10-18 15:32:23 +03002159
2160 /* In this case we need to clear the global accounting of DRAM usage
2161 * because the user notifies us on allocations. If the user is no more,
2162 * all DRAM is available
2163 */
Ofir Bitton8e39e752020-11-12 11:03:32 +02002164 if (ctx->asid != HL_KERNEL_ASID_ID &&
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002165 !hdev->asic_prop.dram_supports_virtual_memory)
2166 atomic64_set(&hdev->dram_used_mem, 0);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002167}
2168
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002169/**
2170 * hl_vm_init() - initialize virtual memory module.
2171 * @hdev: pointer to the habanalabs device structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002172 *
2173 * This function initializes the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002174 * - MMU module.
2175 * - DRAM physical pages pool of 2MB.
2176 * - Idr for device memory allocation handles.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002177 */
2178int hl_vm_init(struct hl_device *hdev)
2179{
2180 struct asic_fixed_properties *prop = &hdev->asic_prop;
2181 struct hl_vm *vm = &hdev->vm;
2182 int rc;
2183
Moti Haimovskib19dc672020-11-18 20:15:29 +02002184 if (is_power_of_2(prop->dram_page_size))
2185 vm->dram_pg_pool =
2186 gen_pool_create(__ffs(prop->dram_page_size), -1);
2187 else
2188 vm->dram_pg_pool =
2189 gen_pool_create(__ffs(DRAM_POOL_PAGE_SIZE), -1);
2190
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002191 if (!vm->dram_pg_pool) {
2192 dev_err(hdev->dev, "Failed to create dram page pool\n");
Oded Gabbay37d68ce2019-05-29 14:43:04 +03002193 return -ENOMEM;
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002194 }
2195
2196 kref_init(&vm->dram_pg_pool_refcount);
2197
2198 rc = gen_pool_add(vm->dram_pg_pool, prop->dram_user_base_address,
2199 prop->dram_end_address - prop->dram_user_base_address,
2200 -1);
2201
2202 if (rc) {
2203 dev_err(hdev->dev,
2204 "Failed to add memory to dram page pool %d\n", rc);
2205 goto pool_add_err;
2206 }
2207
2208 spin_lock_init(&vm->idr_lock);
2209 idr_init(&vm->phys_pg_pack_handles);
2210
2211 atomic64_set(&hdev->dram_used_mem, 0);
2212
2213 vm->init_done = true;
2214
2215 return 0;
2216
2217pool_add_err:
2218 gen_pool_destroy(vm->dram_pg_pool);
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002219
2220 return rc;
2221}
2222
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002223/**
2224 * hl_vm_fini() - virtual memory module teardown.
2225 * @hdev: pointer to the habanalabs device structure.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002226 *
2227 * This function perform teardown to the following:
Omer Shpigelman3b762f52020-12-09 13:28:46 +02002228 * - Idr for device memory allocation handles.
2229 * - DRAM physical pages pool of 2MB.
2230 * - MMU module.
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002231 */
2232void hl_vm_fini(struct hl_device *hdev)
2233{
2234 struct hl_vm *vm = &hdev->vm;
2235
2236 if (!vm->init_done)
2237 return;
2238
2239 /*
2240 * At this point all the contexts should be freed and hence no DRAM
2241 * memory should be in use. Hence the DRAM pool should be freed here.
2242 */
2243 if (kref_put(&vm->dram_pg_pool_refcount, dram_pg_pool_do_release) != 1)
2244 dev_warn(hdev->dev, "dram_pg_pool was not destroyed on %s\n",
2245 __func__);
2246
Omer Shpigelman0feaf862019-02-16 00:39:22 +02002247 vm->init_done = false;
2248}
Sagiv Ozeria4371c12021-02-23 11:01:08 +02002249
2250/**
2251 * hl_hw_block_mem_init() - HW block memory initialization.
2252 * @ctx: pointer to the habanalabs context structure.
2253 *
2254 * This function initializes the HW block virtual mapped addresses list and
2255 * it's lock.
2256 */
2257void hl_hw_block_mem_init(struct hl_ctx *ctx)
2258{
2259 mutex_init(&ctx->hw_block_list_lock);
2260 INIT_LIST_HEAD(&ctx->hw_block_mem_list);
2261}
2262
2263/**
2264 * hl_hw_block_mem_fini() - HW block memory teardown.
2265 * @ctx: pointer to the habanalabs context structure.
2266 *
2267 * This function clears the HW block virtual mapped addresses list and destroys
2268 * it's lock.
2269 */
2270void hl_hw_block_mem_fini(struct hl_ctx *ctx)
2271{
2272 struct hl_vm_hw_block_list_node *lnode, *tmp;
2273
2274 if (!list_empty(&ctx->hw_block_mem_list))
2275 dev_crit(ctx->hdev->dev, "HW block mem list isn't empty\n");
2276
2277 list_for_each_entry_safe(lnode, tmp, &ctx->hw_block_mem_list, node) {
2278 list_del(&lnode->node);
2279 kfree(lnode);
2280 }
2281
2282 mutex_destroy(&ctx->hw_block_list_lock);
2283}