xref: /kvm-unit-tests/lib/s390x/malloc_io.c (revision b0fe398862052fc54ddb235d9ca2113901f6a56f)
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 
23 static int share_pages(void *p, int count)
24 {
25 	int i = 0;
26 
27 	for (i = 0; i < count; i++, p += PAGE_SIZE)
28 		if (uv_set_shared((unsigned long)p))
29 			break;
30 	return i;
31 }
32 
33 static void unshare_pages(void *p, int count)
34 {
35 	int i;
36 
37 	for (i = count; i > 0; i--, p += PAGE_SIZE)
38 		uv_remove_shared((unsigned long)p);
39 }
40 
41 void *alloc_io_mem(int size, int flags)
42 {
43 	int order = get_order(size >> PAGE_SHIFT);
44 	void *p;
45 	int n;
46 
47 	assert(size);
48 
49 	p = alloc_pages_flags(order, AREA_DMA31 | flags);
50 	if (!p || !test_facility(158))
51 		return p;
52 
53 	n = share_pages(p, 1 << order);
54 	if (n == 1 << order)
55 		return p;
56 
57 	unshare_pages(p, n);
58 	free_pages(p);
59 	return NULL;
60 }
61 
62 void free_io_mem(void *p, int size)
63 {
64 	int order = get_order(size >> PAGE_SHIFT);
65 
66 	assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE));
67 
68 	if (test_facility(158))
69 		unshare_pages(p, 1 << order);
70 	free_pages(p);
71 }
72