diff options
author | Erik Staats <estaats@google.com> | 2021-11-23 07:03:28 -0800 |
---|---|---|
committer | Erik Staats <estaats@google.com> | 2021-11-30 22:46:52 +0000 |
commit | a204033deaaa98322b63e5f60927789d48092afa (patch) | |
tree | c094a2692550558654e8b67cd09df217d4b1ebe6 /mali_pixel | |
parent | e9ea9c8d4c8cffa826c55f283742e59fe3d81449 (diff) | |
download | gpu-a204033deaaa98322b63e5f60927789d48092afa.tar.gz |
Implement Mali Pixel protected memory allocation.
Bug: 194627754
Test: Verified that a GPU protected memory test can pass. It sometimes
fails with a GPU fault.
Test: See details in testing done comment in
https://partner-android-review.googlesource.com/2102797 .
Change-Id: I0723b94a68024c8977167a49b735d2ce1e3b11bc
Diffstat (limited to 'mali_pixel')
-rw-r--r-- | mali_pixel/Kbuild | 5 | ||||
-rw-r--r-- | mali_pixel/protected_memory_allocator.c | 283 |
2 files changed, 285 insertions, 3 deletions
diff --git a/mali_pixel/Kbuild b/mali_pixel/Kbuild index 14aa628..13c975e 100644 --- a/mali_pixel/Kbuild +++ b/mali_pixel/Kbuild @@ -47,7 +47,10 @@ ifeq ($(CONFIG_MALI_PROTECTED_MEMORY_ALLOCATOR),m) endif # Use our defines when compiling, and include mali platform module headers -ccflags-y += $(DEFINES) -I$(src)/../common/include +ccflags-y += \ + $(DEFINES) \ + -I$(src)/../common/include \ + -I$(srctree)/include/linux # Add kernel module target if any of our config options is enabled ifneq ($(mali_pixel-objs),) diff --git a/mali_pixel/protected_memory_allocator.c b/mali_pixel/protected_memory_allocator.c index f037891..cc50690 100644 --- a/mali_pixel/protected_memory_allocator.c +++ b/mali_pixel/protected_memory_allocator.c @@ -6,18 +6,297 @@ * protected memory for use by Mali GPU device drivers. */ +#include <linux/dma-buf.h> +#include <linux/dma-heap.h> #include <linux/of.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/protected_memory_allocator.h> +#include <linux/slab.h> +#include <soc/samsung/exynos-smc.h> +#define MALI_PMA_DMA_HEAP_NAME "vframe-secure" + +/** + * struct mali_pma_dev - Structure for managing a Mali protected memory + * allocator device. + * + * @pma_dev: The base protected memory allocator device. + * @dev: The device for which to allocate protected memory. + * @dma_heap: The DMA buffer heap from which to allocate protected memory. + */ +struct mali_pma_dev { + struct protected_memory_allocator_device pma_dev; + struct device *dev; + struct dma_heap *dma_heap; +}; + +/** + * struct mali_protected_memory_allocation - Structure for tracking a Mali + * protected memory allocation. + * + * @pma: The base protected memory allocation record. + * @dma_buf: The DMA buffer allocated for the protected memory. A reference to + * the DMA buffer is held by this pointer. + * @dma_attachment: The DMA buffer device attachment. + * @dma_sg_table: The DMA buffer scatter/gather table. + */ +struct mali_protected_memory_allocation { + struct protected_memory_allocation pma; + struct dma_buf* dma_buf; + struct dma_buf_attachment* dma_attachment; + struct sg_table* dma_sg_table; +}; + +static struct protected_memory_allocation *mali_pma_alloc_page( + struct protected_memory_allocator_device *pma_dev, + unsigned int order); + +static phys_addr_t mali_pma_get_phys_addr( + struct protected_memory_allocator_device *pma_dev, + struct protected_memory_allocation *pma); + +static void mali_pma_free_page( + struct protected_memory_allocator_device *pma_dev, + struct protected_memory_allocation *pma); + +static int protected_memory_allocator_probe(struct platform_device *pdev); + +static int protected_memory_allocator_remove(struct platform_device *pdev); + +/** + * mali_pma_alloc_page - Allocate protected memory pages + * + * @pma_dev: The protected memory allocator the request is being made + * through. + * @order: How many pages to allocate, as a base-2 logarithm. + * + * Return: Pointer to allocated memory, or NULL if allocation failed. + */ +static struct protected_memory_allocation *mali_pma_alloc_page( + struct protected_memory_allocator_device *pma_dev, + unsigned int order) { + struct mali_pma_dev *mali_pma_dev; + struct protected_memory_allocation* pma = NULL; + struct mali_protected_memory_allocation *mali_pma; + struct dma_buf* dma_buf; + struct dma_buf_attachment* dma_attachment; + struct sg_table* dma_sg_table; + size_t alloc_size; + bool success = false; + + /* Get the Mali protected memory allocator device record. */ + mali_pma_dev = container_of(pma_dev, struct mali_pma_dev, pma_dev); + + /* Allocate a Mali protected memory allocation record. */ + mali_pma = devm_kzalloc( + mali_pma_dev->dev, sizeof(*mali_pma), GFP_KERNEL); + if (!mali_pma) { + dev_err(mali_pma_dev->dev, + "Failed to allocate a Mali protected memory allocation " + "record\n"); + goto out; + } + pma = &(mali_pma->pma); + pma->order = order; + + /* Allocate a DMA buffer. */ + alloc_size = 1 << (PAGE_SHIFT + order); + dma_buf = dma_heap_buffer_alloc( + mali_pma_dev->dma_heap, alloc_size, O_RDWR, 0); + if (IS_ERR(dma_buf)) { + dev_err(mali_pma_dev->dev, + "Failed to allocate a DMA buffer of size %zu\n", + alloc_size); + goto out; + } + mali_pma->dma_buf = dma_buf; + + /* Attach the device to the DMA buffer. */ + dma_attachment = dma_buf_attach(dma_buf, mali_pma_dev->dev); + if (IS_ERR(dma_attachment)) { + dev_err(mali_pma_dev->dev, + "Failed to attach the device to the DMA buffer\n"); + goto out; + } + mali_pma->dma_attachment = dma_attachment; + + /* Map the DMA buffer into the attached device address space. */ + dma_sg_table = + dma_buf_map_attachment(dma_attachment, DMA_BIDIRECTIONAL); + if (IS_ERR(dma_sg_table)) { + dev_err(mali_pma_dev->dev, "Failed to map the DMA buffer\n"); + goto out; + } + mali_pma->dma_sg_table = dma_sg_table; + pma->pa = page_to_phys(sg_page(dma_sg_table->sgl)); + + /* Mark the allocation as successful. */ + success = true; + +out: + /* Clean up on error. */ + if (!success) { + if (pma) { + mali_pma_free_page(pma_dev, pma); + pma = NULL; + } + } + + return pma; +} + +/** + * mali_pma_get_phys_addr - Get the physical address of the protected memory + * allocation + * + * @pma_dev: The protected memory allocator the request is being made + * through. + * @pma: The protected memory allocation whose physical address + * shall be retrieved + * + * Return: The physical address of the given allocation. + */ +static phys_addr_t mali_pma_get_phys_addr( + struct protected_memory_allocator_device *pma_dev, + struct protected_memory_allocation *pma) { + return pma->pa; +} + +/** + * pma_free_page - Free a page of memory + * + * @pma_dev: The protected memory allocator the request is being made + * through. + * @pma: The protected memory allocation to free. + */ +static void mali_pma_free_page( + struct protected_memory_allocator_device *pma_dev, + struct protected_memory_allocation *pma) { + struct mali_pma_dev *mali_pma_dev; + struct mali_protected_memory_allocation *mali_pma; + + /* + * Get the Mali protected memory allocator device record and allocation + * record. + */ + mali_pma_dev = container_of(pma_dev, struct mali_pma_dev, pma_dev); + mali_pma = + container_of(pma, struct mali_protected_memory_allocation, pma); + + /* Free the Mali protected memory allocation. */ + if (mali_pma->dma_sg_table) { + dma_buf_unmap_attachment( + mali_pma->dma_attachment, + mali_pma->dma_sg_table, DMA_BIDIRECTIONAL); + } + if (mali_pma->dma_attachment) { + dma_buf_detach(mali_pma->dma_buf, mali_pma->dma_attachment); + } + if (mali_pma->dma_buf) { + dma_buf_put(mali_pma->dma_buf); + } + devm_kfree(mali_pma_dev->dev, mali_pma); +} + +/** + * protected_memory_allocator_probe - Probe the protected memory allocator + * device + * + * @pdev: The platform device to probe. + */ static int protected_memory_allocator_probe(struct platform_device *pdev) { - dev_info(&pdev->dev, "Protected memory allocator not implemented\n"); - return -ENODEV; + struct mali_pma_dev *mali_pma_dev; + struct protected_memory_allocator_device *pma_dev; + int ret = 0; + + /* Create a Mali protected memory allocator device record. */ + mali_pma_dev = kzalloc(sizeof(*mali_pma_dev), GFP_KERNEL); + if (!mali_pma_dev) { + dev_err(&(pdev->dev), + "Failed to create a Mali protected memory allocator " + "device record\n"); + ret = -ENOMEM; + goto out; + } + pma_dev = &(mali_pma_dev->pma_dev); + platform_set_drvdata(pdev, pma_dev); + + /* Configure the Mali protected memory allocator. */ + mali_pma_dev->dev = &(pdev->dev); + pma_dev->owner = THIS_MODULE; + pma_dev->ops.pma_alloc_page = mali_pma_alloc_page; + pma_dev->ops.pma_get_phys_addr = mali_pma_get_phys_addr; + pma_dev->ops.pma_free_page = mali_pma_free_page; + + /* Get the DMA buffer heap. */ + mali_pma_dev->dma_heap = dma_heap_find(MALI_PMA_DMA_HEAP_NAME); + if (!mali_pma_dev->dma_heap) { + dev_err(&(pdev->dev), + "Failed to find \"%s\" DMA buffer heap\n", + MALI_PMA_DMA_HEAP_NAME); + ret = -ENODEV; + goto out; + } + + /* Enable protected mode for the GPU. */ + ret = exynos_smc( + SMC_PROTECTION_SET, 0, PROT_G3D, SMC_PROTECTION_ENABLE); + if (ret) { + dev_err(&(pdev->dev), + "Failed to enable protected mode for the GPU\n"); + goto out; + } + + /* Log that the protected memory allocator was successfully probed. */ + dev_info(&(pdev->dev), + "Protected memory allocator probed successfully\n"); + +out: + /* Clean up on error. */ + if (ret) { + protected_memory_allocator_remove(pdev); + } + + return ret; } +/** + * protected_memory_allocator_remove - Remove the protected memory allocator + * device + * + * @pdev: The protected memory allocator platform device to remove. + */ static int protected_memory_allocator_remove(struct platform_device *pdev) { + struct protected_memory_allocator_device *pma_dev; + struct mali_pma_dev *mali_pma_dev; + int ret; + + /* Get the Mali protected memory allocator device record. */ + pma_dev = platform_get_drvdata(pdev); + if (!pma_dev) { + return 0; + } + mali_pma_dev = container_of(pma_dev, struct mali_pma_dev, pma_dev); + + /* Disable protected mode for the GPU. */ + ret = exynos_smc( + SMC_PROTECTION_SET, 0, PROT_G3D, SMC_PROTECTION_DISABLE); + if (ret) { + dev_warn(&(pdev->dev), + "Failed to disable protected mode for the GPU\n"); + } + + /* Release the DMA buffer heap. */ + if (mali_pma_dev->dma_heap) { + dma_heap_put(mali_pma_dev->dma_heap); + } + + /* Free the Mali protected memory allocator device record. */ + kfree(mali_pma_dev); + return 0; } |