blob: 080fc694362a5fbc1973d5ec06f4c86e107e7236 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* I/O page allocation
*
* Copyright (c) 2021 IBM Corp
*
* Authors:
* Pierre Morel <pmorel@linux.ibm.com>
*
* Using this interface provide host access to the allocated pages in
* case the guest is a protected guest.
* This is needed for I/O buffers.
*
*/
#include <libcflat.h>
#include <asm/page.h>
#include <asm/uv.h>
#include <malloc_io.h>
#include <alloc_page.h>
#include <asm/facility.h>
#include <bitops.h>
#include <uv.h>
static int share_pages(void *p, int count)
{
int i = 0;
for (i = 0; i < count; i++, p += PAGE_SIZE)
if (uv_set_shared((unsigned long)p))
break;
return i;
}
static void unshare_pages(void *p, int count)
{
int i;
for (i = count; i > 0; i--, p += PAGE_SIZE)
uv_remove_shared((unsigned long)p);
}
void *alloc_io_mem(int size, int flags)
{
int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
void *p;
int n;
assert(size);
p = alloc_pages_flags(order, AREA_DMA31 | flags);
if (!p || !uv_os_is_guest())
return p;
n = share_pages(p, 1 << order);
if (n == 1 << order)
return p;
unshare_pages(p, n);
free_pages(p);
return NULL;
}
void free_io_mem(void *p, int size)
{
int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE));
if (uv_os_is_guest())
unshare_pages(p, 1 << order);
free_pages(p);
}