mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 04:56:13 +02:00
mem-buf: Define MEM_BUF_MEM_TYPE_BUDDY
Define a new remote alloc type which tries to allocate contiguous memory from cma. This memory will be transferred to a guest VM and added to the buddy allocator using memory hotplug. Change-Id: I04a4e734d24b6d8decac4e936d12d5e43b7f750b Signed-off-by: Patrick Daly <quic_pdaly@quicinc.com>
This commit is contained in:
parent
385221af95
commit
a375851b6a
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <soc/qcom/secure_buffer.h>
|
||||
|
||||
#include <linux/mem-buf.h>
|
||||
|
|
@ -102,6 +103,7 @@ static int mem_buf_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
u64 dma_mask = IS_ENABLED(CONFIG_ARM64) ? DMA_BIT_MASK(64) :
|
||||
DMA_BIT_MASK(32);
|
||||
int unused;
|
||||
|
||||
if (of_property_match_string(dev->of_node, "qcom,mem-buf-capabilities",
|
||||
"supplier") >= 0)
|
||||
|
|
@ -123,14 +125,26 @@ static int mem_buf_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (of_find_property(dev->of_node, "memory-region", &unused)) {
|
||||
ret = of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get memory-region property %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mem_buf_vm_init(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "mem_buf_vm_init failed %d\n", ret);
|
||||
return ret;
|
||||
goto err_vm_init;
|
||||
}
|
||||
|
||||
mem_buf_dev = dev;
|
||||
return 0;
|
||||
|
||||
err_vm_init:
|
||||
of_reserved_mem_device_release(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mem_buf_remove(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/qcom_dma_heap.h>
|
||||
#include <linux/qcom_tui_heap.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/cma.h>
|
||||
|
||||
#include "../../../../drivers/dma-buf/heaps/qcom_sg_ops.h"
|
||||
#include "mem-buf-gh.h"
|
||||
|
|
@ -202,12 +204,75 @@ static int mem_buf_rmt_alloc_dmaheap_mem(struct mem_buf_xfer_mem *xfer_mem)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* In future, try allocating from buddy if cma not available */
|
||||
static int mem_buf_rmt_alloc_buddy_mem(struct mem_buf_xfer_mem *xfer_mem)
|
||||
{
|
||||
struct cma *cma;
|
||||
struct sg_table *table;
|
||||
struct page *page;
|
||||
int ret;
|
||||
u32 align;
|
||||
size_t nr_pages;
|
||||
|
||||
pr_debug("%s: Starting DMAHEAP-BUDDY allocation\n", __func__);
|
||||
|
||||
/*
|
||||
* For the common case of 4Mb transfer, we want it to be nicely aligned
|
||||
* to allow for 2Mb block mappings in S2 pagetable.
|
||||
*/
|
||||
align = min(get_order(xfer_mem->size), get_order(SZ_2M));
|
||||
nr_pages = xfer_mem->size >> PAGE_SHIFT;
|
||||
|
||||
/*
|
||||
* Don't use dev_get_cma_area() as we don't want to fall back to
|
||||
* dma_contiguous_default_area.
|
||||
*/
|
||||
cma = mem_buf_dev->cma_area;
|
||||
if (!cma)
|
||||
return -ENOMEM;
|
||||
|
||||
table = kzalloc(sizeof(*table), GFP_KERNEL);
|
||||
if (!table) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_table;
|
||||
}
|
||||
|
||||
ret = sg_alloc_table(table, 1, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err_sg_init;
|
||||
|
||||
page = cma_alloc(cma, nr_pages, align, false);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
goto err_cma_alloc;
|
||||
}
|
||||
|
||||
sg_set_page(table->sgl, page, nr_pages << PAGE_SHIFT, 0);
|
||||
|
||||
/* Zero memory before transferring to Guest VM */
|
||||
memset(page_address(page), 0, nr_pages << PAGE_SHIFT);
|
||||
|
||||
xfer_mem->mem_sgt = table;
|
||||
xfer_mem->secure_alloc = false;
|
||||
pr_debug("%s: DMAHEAP-BUDDY allocation complete\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_cma_alloc:
|
||||
sg_free_table(table);
|
||||
err_sg_init:
|
||||
kfree(table);
|
||||
err_alloc_table:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mem_buf_rmt_alloc_mem(struct mem_buf_xfer_mem *xfer_mem)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (xfer_mem->mem_type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
ret = mem_buf_rmt_alloc_dmaheap_mem(xfer_mem);
|
||||
else if (xfer_mem->mem_type == MEM_BUF_BUDDY_MEM_TYPE)
|
||||
ret = mem_buf_rmt_alloc_buddy_mem(xfer_mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -233,10 +298,22 @@ static void mem_buf_rmt_free_dmaheap_mem(struct mem_buf_xfer_mem *xfer_mem)
|
|||
pr_debug("%s: DMAHEAP memory freed\n", __func__);
|
||||
}
|
||||
|
||||
static void mem_buf_rmt_free_buddy_mem(struct mem_buf_xfer_mem *xfer_mem)
|
||||
{
|
||||
struct sg_table *table = xfer_mem->mem_sgt;
|
||||
|
||||
pr_debug("%s: Freeing DMAHEAP-BUDDY memory\n", __func__);
|
||||
cma_release(dev_get_cma_area(mem_buf_dev), sg_page(table->sgl),
|
||||
table->sgl->length >> PAGE_SHIFT);
|
||||
pr_debug("%s: DMAHEAP-BUDDY memory freed\n", __func__);
|
||||
}
|
||||
|
||||
static void mem_buf_rmt_free_mem(struct mem_buf_xfer_mem *xfer_mem)
|
||||
{
|
||||
if (xfer_mem->mem_type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
mem_buf_rmt_free_dmaheap_mem(xfer_mem);
|
||||
else if (xfer_mem->mem_type == MEM_BUF_BUDDY_MEM_TYPE)
|
||||
mem_buf_rmt_free_buddy_mem(xfer_mem);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -263,6 +340,8 @@ static void *mem_buf_alloc_xfer_mem_type_data(enum mem_buf_mem_type type,
|
|||
|
||||
if (type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
data = mem_buf_alloc_dmaheap_xfer_mem_type_data(rmt_data);
|
||||
else if (type == MEM_BUF_BUDDY_MEM_TYPE)
|
||||
data = NULL;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -278,6 +357,7 @@ static void mem_buf_free_xfer_mem_type_data(enum mem_buf_mem_type type,
|
|||
{
|
||||
if (type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
mem_buf_free_dmaheap_xfer_mem_type_data(data);
|
||||
/* Do nothing for MEM_BUF_BUDDY_MEM_TYPE */
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -784,6 +864,8 @@ static void *mem_buf_retrieve_mem_type_data_user(enum mem_buf_mem_type mem_type,
|
|||
|
||||
if (mem_type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
data = mem_buf_retrieve_dmaheap_mem_type_data_user(mem_type_data);
|
||||
else if (mem_type == MEM_BUF_BUDDY_MEM_TYPE)
|
||||
data = NULL;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -800,6 +882,8 @@ static void *mem_buf_retrieve_mem_type_data(enum mem_buf_mem_type mem_type,
|
|||
|
||||
if (mem_type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
data = mem_buf_retrieve_dmaheap_mem_type_data(mem_type_data);
|
||||
else if (mem_type == MEM_BUF_BUDDY_MEM_TYPE)
|
||||
data = NULL;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -814,11 +898,18 @@ static void mem_buf_free_mem_type_data(enum mem_buf_mem_type mem_type,
|
|||
{
|
||||
if (mem_type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
mem_buf_free_dmaheap_mem_type_data(mem_type_data);
|
||||
/* Do nothing for MEM_BUF_BUDDY_MEM_TYPE */
|
||||
}
|
||||
|
||||
static bool is_valid_mem_type(enum mem_buf_mem_type mem_type)
|
||||
{
|
||||
return mem_type == MEM_BUF_DMAHEAP_MEM_TYPE;
|
||||
return (mem_type == MEM_BUF_DMAHEAP_MEM_TYPE) ||
|
||||
(mem_type == MEM_BUF_BUDDY_MEM_TYPE);
|
||||
}
|
||||
|
||||
static bool is_valid_ioctl_mem_type(enum mem_buf_mem_type mem_type)
|
||||
{
|
||||
return (mem_type == MEM_BUF_DMAHEAP_MEM_TYPE);
|
||||
}
|
||||
|
||||
void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data)
|
||||
|
|
@ -1098,8 +1189,8 @@ int mem_buf_alloc_fd(struct mem_buf_alloc_ioctl_arg *allocation_args)
|
|||
if (!allocation_args->size || !allocation_args->nr_acl_entries ||
|
||||
!allocation_args->acl_list ||
|
||||
(allocation_args->nr_acl_entries > MEM_BUF_MAX_NR_ACL_ENTS) ||
|
||||
!is_valid_mem_type(allocation_args->src_mem_type) ||
|
||||
!is_valid_mem_type(allocation_args->dst_mem_type) ||
|
||||
!is_valid_ioctl_mem_type(allocation_args->src_mem_type) ||
|
||||
!is_valid_ioctl_mem_type(allocation_args->dst_mem_type) ||
|
||||
allocation_args->reserved0 || allocation_args->reserved1 ||
|
||||
allocation_args->reserved2)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ static size_t mem_buf_get_mem_type_alloc_req_size(enum mem_buf_mem_type type)
|
|||
{
|
||||
if (type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
return MEM_BUF_MAX_DMAHEAP_NAME_LEN;
|
||||
/* Do nothing for MEM_BUF_BUDDY_MEM_TYPE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -78,6 +79,7 @@ static void mem_buf_populate_alloc_req_arb_payload(void *dst, void *src,
|
|||
{
|
||||
if (type == MEM_BUF_DMAHEAP_MEM_TYPE)
|
||||
strscpy(dst, src, MEM_BUF_MAX_DMAHEAP_NAME_LEN);
|
||||
/* Do nothing for MEM_BUF_BUDDY_MEM_TYPE */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
#include <linux/dma-buf.h>
|
||||
#include <uapi/linux/mem-buf.h>
|
||||
|
||||
/* For in-kernel use only, not allowed for userspace ioctl */
|
||||
#define MEM_BUF_BUDDY_MEM_TYPE (MEM_BUF_ION_MEM_TYPE + 2)
|
||||
|
||||
/* Used to obtain the underlying vmperm struct of a DMA-BUF */
|
||||
struct mem_buf_vmperm *to_mem_buf_vmperm(struct dma_buf *dmabuf);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_MEM_BUF_H
|
||||
|
|
@ -20,6 +21,7 @@ enum mem_buf_mem_type {
|
|||
MEM_BUF_MAX_MEM_TYPE,
|
||||
};
|
||||
#define MEM_BUF_DMAHEAP_MEM_TYPE (MEM_BUF_ION_MEM_TYPE + 1)
|
||||
/* RESERVED for MEM_BUF_BUDDY_MEM_TYPE: MEM_BUF_ION_MEM_TYPE + 2 */
|
||||
|
||||
/* The mem-buf values that represent VMIDs for an ACL. */
|
||||
#define MEM_BUF_VMID_PRIMARY_VM 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user