1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * I/O page allocation
4 *
5 * Copyright (c) 2021 IBM Corp
6 *
7 * Authors:
8 * Pierre Morel <pmorel@linux.ibm.com>
9 *
10 * Using this interface provide host access to the allocated pages in
11 * case the guest is a protected guest.
12 * This is needed for I/O buffers.
13 *
14 */
15 #include <libcflat.h>
16 #include <asm/page.h>
17 #include <asm/uv.h>
18 #include <malloc_io.h>
19 #include <alloc_page.h>
20 #include <asm/facility.h>
21 #include <bitops.h>
22 #include <uv.h>
23
share_pages(void * p,int count)24 static int share_pages(void *p, int count)
25 {
26 int i = 0;
27
28 for (i = 0; i < count; i++, p += PAGE_SIZE)
29 if (uv_set_shared((unsigned long)p))
30 break;
31 return i;
32 }
33
unshare_pages(void * p,int count)34 static void unshare_pages(void *p, int count)
35 {
36 int i;
37
38 for (i = count; i > 0; i--, p += PAGE_SIZE)
39 uv_remove_shared((unsigned long)p);
40 }
41
alloc_io_mem(int size,int flags)42 void *alloc_io_mem(int size, int flags)
43 {
44 int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
45 void *p;
46 int n;
47
48 assert(size);
49
50 p = alloc_pages_flags(order, AREA_DMA31 | flags);
51 if (!p || !uv_os_is_guest())
52 return p;
53
54 n = share_pages(p, 1 << order);
55 if (n == 1 << order)
56 return p;
57
58 unshare_pages(p, n);
59 free_pages(p);
60 return NULL;
61 }
62
free_io_mem(void * p,int size)63 void free_io_mem(void *p, int size)
64 {
65 int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
66
67 assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE));
68
69 if (uv_os_is_guest())
70 unshare_pages(p, 1 << order);
71 free_pages(p);
72 }
73