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