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