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