Received: by 2002:ab2:7a09:0:b0:1f8:46dc:890e with SMTP id k9csp29352lqo; Wed, 15 May 2024 06:58:13 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCUg4WMAV5iWOgHoMzZzm+smGmYAXhVlQuQmuFiociNBIIymK3PCaYrH2PS/TUmx8p/A+3K5HJQJ8ndketjcgRep7pI6NoDjCwe9AWny+A== X-Google-Smtp-Source: AGHT+IFz8SDjDgZFhXd8kF+sDZjIvr585cIFrS+6vrpt7hSZMUrsUWZjiCpr0F3I0cO4EVHwoBU/ X-Received: by 2002:a05:6512:4003:b0:522:221:d19d with SMTP id 2adb3069b0e04-5220fd7bfccmr15612856e87.15.1715781493224; Wed, 15 May 2024 06:58:13 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1715781493; cv=pass; d=google.com; s=arc-20160816; b=ZvZWEq9oaLkn/urF6XweLh5/F1HmlKkP4k9TaestnLjRm8zHji2vYMRttHhaHXUMgp G3VH0Moz88D+W1NhU3g6RPgKwd9/6OI/ikzIRrRfJq5oCgSVVEpHc78PsD8NIFPhbOlw HSAfUj3MF3x9SEonpvLVciLXp8nN+szEhvr/Z1VTqmdz7qzBv/hhz2dAXZ67e1EvW7rb n+/V3KHglm6iLiV3ohXHS2JxpkTQOs2E8q4ECiXulDPYGEWABL1SN46id2S4R+GteR/S +3e+f8nxYlwb3hO2JbOIZnjunQEvvWRiUczngIp4hZoNhJPtkJeUIfIA5rtmXoUahKAD 0uSg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=mqwXoFsEVvh/XBRgYHF22VJlZkY1QmvxzNDLv1KcDcU=; fh=oKXp7eYw+ueF/PASYm8o1QMj1RprGGi2Ykngp1NB+LU=; b=oqCiHKnc6TDGbN39xtzUW7d9NZk1MI0SADwDWiAsxzcJr0+E9eyeAC6jP59+irlxFu JgrxwzFg3kHfzSLfqX3s1Zi/JIYpj88CetFM70OHR9ZSQue+eaJh79gVtWFzCCz2C1lf vYs4O2fcb2Sa141VAfzKcxEK2ijUTEw6ZX5RJQdpi3PQ7DwELzwmTtOguu06IPzmdg3U F9KpMRuzTwVKYh067VaG7usksJOMBNQQpdhgTepOPP2P0hkCcojdim8yW2yVVBo215lZ 2DYKclnuJQzLbW3GTy2AsZfr6lVb7T7W9bmEsRIVjGwKe+5Dz59D00urtvnlh3Dhzyay lxrA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WxSnfSTm; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-179953-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-179953-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id a640c23a62f3a-a5a17ba3a08si747691766b.587.2024.05.15.06.58.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 May 2024 06:58:13 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-179953-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WxSnfSTm; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-179953-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-179953-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id C77841F23F69 for ; Wed, 15 May 2024 13:58:12 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 79A0113FD65; Wed, 15 May 2024 13:57:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WxSnfSTm" Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4BCBF64CFC; Wed, 15 May 2024 13:57:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1715781465; cv=none; b=L+msbWDSBlz8xEeWVu8RN0eYz71M7x6SPp3KWb+XLDfk7zjhGp9CewMYlLO1KOC9XE2X1HJaEZcz6h/zuRTdvnNM3Jhmet0xrPLE9lI9+wUrpmoHJxzUbS5ruCZqTwxmfaubJWmkOLLXKAK5OLz+0rIn1BoS118iVFGRMj1PU/4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1715781465; c=relaxed/simple; bh=y4c5Ovhy94byqgEWHicSc3d/PAkjnLlMSsPZmPA2CY4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ktYxxCT6Rdaz/izq/hTDWibQTmNqHAuQuPglpZQIHcvPARgysIfclO68s1nIxtseAOVsXNZ9OSOldkAYKVWZOUnaFl1Ct7FNJrebot1uAW1/WxIqZkpAbkzZk5+60xmlproYeqDzyGlDwB5stlKHZWh6XOuO3OSR+E5j+HR6MqU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WxSnfSTm; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5FAD3C4AF19; Wed, 15 May 2024 13:57:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1715781464; bh=y4c5Ovhy94byqgEWHicSc3d/PAkjnLlMSsPZmPA2CY4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=WxSnfSTmQ/csjEC2fejH+PymBQ7/2Gv2FU3ve4/QA2kxCOURBe1IcIN3l7T56t2uo m0dglIusTz5Ckpsvo0Rawk7iFM8OAo9r7czY2FuhmGIwYDWUpT/KauDYo355CHhV9Z igQJoWElO4xiLoUIQ/DzdfS3+kgD7l5VVR89N0b/5ckoAUz39/6AO3bu1I/3b/WuHa KORhwnw0kV8jAfZuqnqzj02bt85XjEdZp8N7snX6wUgbfdk1m+tcaCGGA2zEBxBvq/ BYqFU9tddtWMy9s28lvy8+AjgUpK9NEQqPNnPG0XX78WlWnvpSRVGTR7t+klSSeiAU XwD1+9VdLQT1w== From: Maxime Ripard Date: Wed, 15 May 2024 15:56:56 +0200 Subject: [PATCH 1/8] dma-buf: heaps: Introduce a new heap for reserved memory Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20240515-dma-buf-ecc-heap-v1-1-54cbbd049511@kernel.org> References: <20240515-dma-buf-ecc-heap-v1-0-54cbbd049511@kernel.org> In-Reply-To: <20240515-dma-buf-ecc-heap-v1-0-54cbbd049511@kernel.org> To: Rob Herring , Saravana Kannan , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Mattijs Korpershoek , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Maxime Ripard X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9483; i=mripard@kernel.org; h=from:subject:message-id; bh=y4c5Ovhy94byqgEWHicSc3d/PAkjnLlMSsPZmPA2CY4=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGku+30tkivZGtj+2vRlvdih5t2+sUmOa28rw7qJs/4/b mTJ9zvZMZWFQZiTQVZMkeWJTNjp5e2LqxzsV/6AmcPKBDKEgYtTACaS5cBYn3Fzof6U71OkEm4s XePqtdGj8sCHmS9fFS23yHdbtP5D/T3F37vSzB43HYg9LZZ71vGFF2PDBLPK1M6/gokbFULVbHa byT7/G6TGYTg7XX7uH9uQKRMDt900VbkeslZxtf9TFedz/8oB X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Some reserved memory regions might have particular memory setup or attributes that make them good candidates for heaps. Let's provide a heap type that will create a new heap for each reserved memory region flagged as such. Signed-off-by: Maxime Ripard --- drivers/dma-buf/heaps/Kconfig | 8 + drivers/dma-buf/heaps/Makefile | 1 + drivers/dma-buf/heaps/carveout_heap.c | 314 ++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+) diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig index a5eef06c4226..c6981d696733 100644 --- a/drivers/dma-buf/heaps/Kconfig +++ b/drivers/dma-buf/heaps/Kconfig @@ -1,5 +1,13 @@ +config DMABUF_HEAPS_CARVEOUT + bool "Carveout Heaps" + depends on DMABUF_HEAPS + help + Choose this option to enable the carveout dmabuf heap. The carveout + heap is backed by pages from reserved memory regions flagged as + exportable. If in doubt, say Y. + config DMABUF_HEAPS_SYSTEM bool "DMA-BUF System Heap" depends on DMABUF_HEAPS help Choose this option to enable the system dmabuf heap. The system heap diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile index 974467791032..b734647ad5c8 100644 --- a/drivers/dma-buf/heaps/Makefile +++ b/drivers/dma-buf/heaps/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_DMABUF_HEAPS_CARVEOUT) += carveout_heap.o obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o diff --git a/drivers/dma-buf/heaps/carveout_heap.c b/drivers/dma-buf/heaps/carveout_heap.c new file mode 100644 index 000000000000..896ca67e6bd9 --- /dev/null +++ b/drivers/dma-buf/heaps/carveout_heap.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +struct carveout_heap_priv { + struct dma_heap *heap; + struct gen_pool *pool; +}; + +struct carveout_heap_buffer_priv { + struct mutex lock; + struct list_head attachments; + + unsigned long len; + unsigned long num_pages; + struct carveout_heap_priv *heap; + void *buffer; +}; + +struct carveout_heap_attachment { + struct list_head head; + struct sg_table table; + + struct device *dev; + bool mapped; +}; + +static int carveout_heap_attach(struct dma_buf *buf, + struct dma_buf_attachment *attachment) +{ + struct carveout_heap_buffer_priv *priv = buf->priv; + struct carveout_heap_attachment *a; + int ret; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + INIT_LIST_HEAD(&a->head); + a->dev = attachment->dev; + attachment->priv = a; + + ret = sg_alloc_table(&a->table, priv->num_pages, GFP_KERNEL); + if (ret) + goto err_cleanup_attach; + + mutex_lock(&priv->lock); + list_add(&a->head, &priv->attachments); + mutex_unlock(&priv->lock); + + return 0; + +err_cleanup_attach: + kfree(a); + return ret; +} + +static void carveout_heap_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct carveout_heap_buffer_priv *priv = dmabuf->priv; + struct carveout_heap_attachment *a = attachment->priv; + + mutex_lock(&priv->lock); + list_del(&a->head); + mutex_unlock(&priv->lock); + + sg_free_table(&a->table); + kfree(a); +} + +static struct sg_table * +carveout_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct carveout_heap_attachment *a = attachment->priv; + struct sg_table *table = &a->table; + int ret; + + ret = dma_map_sgtable(a->dev, table, direction, 0); + if (ret) + return ERR_PTR(-ENOMEM); + + a->mapped = true; + + return table; +} + +static void carveout_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + struct carveout_heap_attachment *a = attachment->priv; + + a->mapped = false; + dma_unmap_sgtable(a->dev, table, direction, 0); +} + +static int +carveout_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct carveout_heap_buffer_priv *priv = dmabuf->priv; + struct carveout_heap_attachment *a; + + mutex_lock(&priv->lock); + + list_for_each_entry(a, &priv->attachments, head) { + if (!a->mapped) + continue; + + dma_sync_sgtable_for_cpu(a->dev, &a->table, direction); + } + + mutex_unlock(&priv->lock); + + return 0; +} + +static int +carveout_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct carveout_heap_buffer_priv *priv = dmabuf->priv; + struct carveout_heap_attachment *a; + + mutex_lock(&priv->lock); + + list_for_each_entry(a, &priv->attachments, head) { + if (!a->mapped) + continue; + + dma_sync_sgtable_for_device(a->dev, &a->table, direction); + } + + mutex_unlock(&priv->lock); + + return 0; +} + +static int carveout_heap_mmap(struct dma_buf *dmabuf, + struct vm_area_struct *vma) +{ + struct carveout_heap_buffer_priv *priv = dmabuf->priv; + struct page *page = virt_to_page(priv->buffer); + + return remap_pfn_range(vma, vma->vm_start, page_to_pfn(page), + priv->num_pages * PAGE_SIZE, vma->vm_page_prot); +} + +static void carveout_heap_dma_buf_release(struct dma_buf *buf) +{ + struct carveout_heap_buffer_priv *buffer_priv = buf->priv; + struct carveout_heap_priv *heap_priv = buffer_priv->heap; + + gen_pool_free(heap_priv->pool, (unsigned long)buffer_priv->buffer, + buffer_priv->len); + kfree(buffer_priv); +} + +static const struct dma_buf_ops carveout_heap_buf_ops = { + .attach = carveout_heap_attach, + .detach = carveout_heap_detach, + .map_dma_buf = carveout_heap_map_dma_buf, + .unmap_dma_buf = carveout_heap_unmap_dma_buf, + .begin_cpu_access = carveout_heap_dma_buf_begin_cpu_access, + .end_cpu_access = carveout_heap_dma_buf_end_cpu_access, + .mmap = carveout_heap_mmap, + .release = carveout_heap_dma_buf_release, +}; + +static struct dma_buf *carveout_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct carveout_heap_priv *heap_priv = dma_heap_get_drvdata(heap); + struct carveout_heap_buffer_priv *buffer_priv; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *buf; + dma_addr_t daddr; + void *buffer; + int ret; + + buffer_priv = kzalloc(sizeof(*buffer_priv), GFP_KERNEL); + if (!buffer_priv) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&buffer_priv->attachments); + mutex_init(&buffer_priv->lock); + + buffer = gen_pool_dma_zalloc(heap_priv->pool, len, &daddr); + if (!buffer) { + ret = -ENOMEM; + goto err_free_buffer_priv; + } + + buffer_priv->buffer = buffer; + buffer_priv->heap = heap_priv; + buffer_priv->len = len; + buffer_priv->num_pages = len / PAGE_SIZE; + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &carveout_heap_buf_ops; + exp_info.size = buffer_priv->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer_priv; + + buf = dma_buf_export(&exp_info); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto err_free_buffer; + } + + return buf; + +err_free_buffer: + gen_pool_free(heap_priv->pool, (unsigned long)buffer, len); +err_free_buffer_priv: + kfree(buffer_priv); + + return ERR_PTR(ret); +} + +static const struct dma_heap_ops carveout_heap_ops = { + .allocate = carveout_heap_allocate, +}; + +static int __init carveout_heap_setup(struct device_node *node) +{ + struct dma_heap_export_info exp_info = {}; + const struct reserved_mem *rmem; + struct carveout_heap_priv *priv; + struct dma_heap *heap; + struct gen_pool *pool; + void *base; + int ret; + + rmem = of_reserved_mem_lookup(node); + if (!rmem) + return -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pool = gen_pool_create(PAGE_SHIFT, NUMA_NO_NODE); + if (!pool) { + ret = -ENOMEM; + goto err_cleanup_heap; + } + priv->pool = pool; + + base = memremap(rmem->base, rmem->size, MEMREMAP_WB); + if (!base) { + ret = -ENOMEM; + goto err_release_mem_region; + } + + ret = gen_pool_add_virt(pool, (unsigned long)base, rmem->base, + rmem->size, NUMA_NO_NODE); + if (ret) + goto err_unmap; + + exp_info.name = node->full_name; + exp_info.ops = &carveout_heap_ops; + exp_info.priv = priv; + + heap = dma_heap_add(&exp_info); + if (IS_ERR(heap)) { + ret = PTR_ERR(heap); + goto err_cleanup_pool_region; + } + priv->heap = heap; + + return 0; + +err_cleanup_pool_region: + gen_pool_free(pool, (unsigned long)base, rmem->size); +err_unmap: + memunmap(base); +err_release_mem_region: + gen_pool_destroy(pool); +err_cleanup_heap: + kfree(priv); + return ret; +} + +static int __init carveout_heap_init(void) +{ + struct device_node *rmem_node; + struct device_node *node; + int ret; + + rmem_node = of_find_node_by_path("/reserved-memory"); + if (!rmem_node) + return 0; + + for_each_child_of_node(rmem_node, node) { + if (!of_property_read_bool(node, "export")) + continue; + + ret = carveout_heap_setup(node); + if (ret) + return ret; + } + + return 0; +} + +module_init(carveout_heap_init); -- 2.44.0