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 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 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 42 void *alloc_io_mem(int size, int flags) 43 { 44 int order = get_order(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 63 void free_io_mem(void *p, int size) 64 { 65 int order = get_order(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