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> 22*533bbdb3SJanosch Frank #include <uv.h> 23b0fe3988SPierre Morel 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 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 42b0fe3988SPierre Morel void *alloc_io_mem(int size, int flags) 43b0fe3988SPierre Morel { 44b0fe3988SPierre Morel int order = get_order(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); 51*533bbdb3SJanosch 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 63b0fe3988SPierre Morel void free_io_mem(void *p, int size) 64b0fe3988SPierre Morel { 65b0fe3988SPierre Morel int order = get_order(size >> PAGE_SHIFT); 66b0fe3988SPierre Morel 67b0fe3988SPierre Morel assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE)); 68b0fe3988SPierre Morel 69*533bbdb3SJanosch Frank if (uv_os_is_guest()) 70b0fe3988SPierre Morel unshare_pages(p, 1 << order); 71b0fe3988SPierre Morel free_pages(p); 72b0fe3988SPierre Morel } 73