diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.c b/drivers/soc/qcom/mem_buf/mem-buf-dev.c index 30cb429adca3..2f8a769e211f 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -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) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index 119a54ffcd96..545d18bdf737 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #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; diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c index 3473be63465c..953c40d12add 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c @@ -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 */ } /* diff --git a/include/linux/mem-buf.h b/include/linux/mem-buf.h index ba62641ad8a4..8c08679abd52 100644 --- a/include/linux/mem-buf.h +++ b/include/linux/mem-buf.h @@ -14,6 +14,9 @@ #include #include +/* 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); diff --git a/include/uapi/linux/mem-buf.h b/include/uapi/linux/mem-buf.h index 3bfd4505d757..b3f0ae5a195e 100644 --- a/include/uapi/linux/mem-buf.h +++ b/include/uapi/linux/mem-buf.h @@ -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