1f6ffbd4fSLucas Stach // SPDX-License-Identifier: GPL-2.0 2ea1f5729SLucas Stach /* 3f6ffbd4fSLucas Stach * Copyright (C) 2017-2018 Etnaviv Project 4ea1f5729SLucas Stach */ 5ea1f5729SLucas Stach 66eae41feSSam Ravnborg #include <linux/dma-mapping.h> 76eae41feSSam Ravnborg 8e66774ddSLucas Stach #include <drm/drm_mm.h> 9e66774ddSLucas Stach 10ea1f5729SLucas Stach #include "etnaviv_cmdbuf.h" 11db82a043SLucas Stach #include "etnaviv_gem.h" 12ea1f5729SLucas Stach #include "etnaviv_gpu.h" 13ea1f5729SLucas Stach #include "etnaviv_mmu.h" 144fc3e66aSChristian Gmeiner #include "etnaviv_perfmon.h" 15ea1f5729SLucas Stach 16bffe5db8SLucas Stach #define SUBALLOC_SIZE SZ_512K 17e66774ddSLucas Stach #define SUBALLOC_GRANULE SZ_4K 18e66774ddSLucas Stach #define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE) 19e66774ddSLucas Stach 20e66774ddSLucas Stach struct etnaviv_cmdbuf_suballoc { 21e66774ddSLucas Stach /* suballocated dma buffer properties */ 22bffe5db8SLucas Stach struct device *dev; 23e66774ddSLucas Stach void *vaddr; 24e66774ddSLucas Stach dma_addr_t paddr; 25e66774ddSLucas Stach 26e66774ddSLucas Stach /* allocation management */ 27e66774ddSLucas Stach struct mutex lock; 28e66774ddSLucas Stach DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES); 29e66774ddSLucas Stach int free_space; 30e66774ddSLucas Stach wait_queue_head_t free_event; 31e66774ddSLucas Stach }; 32e66774ddSLucas Stach 33e66774ddSLucas Stach struct etnaviv_cmdbuf_suballoc * 34bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_new(struct device *dev) 35e66774ddSLucas Stach { 36e66774ddSLucas Stach struct etnaviv_cmdbuf_suballoc *suballoc; 37e66774ddSLucas Stach int ret; 38e66774ddSLucas Stach 39e66774ddSLucas Stach suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL); 40e66774ddSLucas Stach if (!suballoc) 41e66774ddSLucas Stach return ERR_PTR(-ENOMEM); 42e66774ddSLucas Stach 43bffe5db8SLucas Stach suballoc->dev = dev; 44e66774ddSLucas Stach mutex_init(&suballoc->lock); 45e66774ddSLucas Stach init_waitqueue_head(&suballoc->free_event); 46e66774ddSLucas Stach 47*088880ddSLucas Stach BUILD_BUG_ON(ETNAVIV_SOFTPIN_START_ADDRESS < SUBALLOC_SIZE); 48bffe5db8SLucas Stach suballoc->vaddr = dma_alloc_wc(dev, SUBALLOC_SIZE, 49e66774ddSLucas Stach &suballoc->paddr, GFP_KERNEL); 50c53ab613SLucas Stach if (!suballoc->vaddr) { 51c53ab613SLucas Stach ret = -ENOMEM; 52e66774ddSLucas Stach goto free_suballoc; 53c53ab613SLucas Stach } 54e66774ddSLucas Stach 55e66774ddSLucas Stach return suballoc; 56e66774ddSLucas Stach 57e66774ddSLucas Stach free_suballoc: 58e66774ddSLucas Stach kfree(suballoc); 59e66774ddSLucas Stach 60c53ab613SLucas Stach return ERR_PTR(ret); 61e66774ddSLucas Stach } 62e66774ddSLucas Stach 63db82a043SLucas Stach int etnaviv_cmdbuf_suballoc_map(struct etnaviv_cmdbuf_suballoc *suballoc, 6427b67278SLucas Stach struct etnaviv_iommu_context *context, 65db82a043SLucas Stach struct etnaviv_vram_mapping *mapping, 66db82a043SLucas Stach u32 memory_base) 67db82a043SLucas Stach { 6827b67278SLucas Stach return etnaviv_iommu_get_suballoc_va(context, mapping, memory_base, 69db82a043SLucas Stach suballoc->paddr, SUBALLOC_SIZE); 70db82a043SLucas Stach } 71db82a043SLucas Stach 7227b67278SLucas Stach void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu_context *context, 73db82a043SLucas Stach struct etnaviv_vram_mapping *mapping) 74db82a043SLucas Stach { 7527b67278SLucas Stach etnaviv_iommu_put_suballoc_va(context, mapping); 76db82a043SLucas Stach } 77db82a043SLucas Stach 78e66774ddSLucas Stach void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc) 79e66774ddSLucas Stach { 80bffe5db8SLucas Stach dma_free_wc(suballoc->dev, SUBALLOC_SIZE, suballoc->vaddr, 81e66774ddSLucas Stach suballoc->paddr); 82e66774ddSLucas Stach kfree(suballoc); 83e66774ddSLucas Stach } 84e66774ddSLucas Stach 852f9225dbSLucas Stach int etnaviv_cmdbuf_init(struct etnaviv_cmdbuf_suballoc *suballoc, 862f9225dbSLucas Stach struct etnaviv_cmdbuf *cmdbuf, u32 size) 87ea1f5729SLucas Stach { 88e66774ddSLucas Stach int granule_offs, order, ret; 89ea1f5729SLucas Stach 90e66774ddSLucas Stach cmdbuf->suballoc = suballoc; 91e66774ddSLucas Stach cmdbuf->size = size; 92ea1f5729SLucas Stach 93e66774ddSLucas Stach order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE); 94e66774ddSLucas Stach retry: 95e66774ddSLucas Stach mutex_lock(&suballoc->lock); 96e66774ddSLucas Stach granule_offs = bitmap_find_free_region(suballoc->granule_map, 97e66774ddSLucas Stach SUBALLOC_GRANULES, order); 98e66774ddSLucas Stach if (granule_offs < 0) { 99e66774ddSLucas Stach suballoc->free_space = 0; 100e66774ddSLucas Stach mutex_unlock(&suballoc->lock); 101e66774ddSLucas Stach ret = wait_event_interruptible_timeout(suballoc->free_event, 102e66774ddSLucas Stach suballoc->free_space, 103e66774ddSLucas Stach msecs_to_jiffies(10 * 1000)); 104e66774ddSLucas Stach if (!ret) { 105bffe5db8SLucas Stach dev_err(suballoc->dev, 106e66774ddSLucas Stach "Timeout waiting for cmdbuf space\n"); 1072f9225dbSLucas Stach return -ETIMEDOUT; 108ea1f5729SLucas Stach } 109e66774ddSLucas Stach goto retry; 110e66774ddSLucas Stach } 111e66774ddSLucas Stach mutex_unlock(&suballoc->lock); 112e66774ddSLucas Stach cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE; 113e66774ddSLucas Stach cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset; 114ea1f5729SLucas Stach 1152f9225dbSLucas Stach return 0; 116ea1f5729SLucas Stach } 117ea1f5729SLucas Stach 118ea1f5729SLucas Stach void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf) 119ea1f5729SLucas Stach { 120e66774ddSLucas Stach struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc; 121e66774ddSLucas Stach int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) / 122e66774ddSLucas Stach SUBALLOC_GRANULE); 123e66774ddSLucas Stach 124e66774ddSLucas Stach mutex_lock(&suballoc->lock); 125e66774ddSLucas Stach bitmap_release_region(suballoc->granule_map, 126e66774ddSLucas Stach cmdbuf->suballoc_offset / SUBALLOC_GRANULE, 127e66774ddSLucas Stach order); 128e66774ddSLucas Stach suballoc->free_space = 1; 129e66774ddSLucas Stach mutex_unlock(&suballoc->lock); 130e66774ddSLucas Stach wake_up_all(&suballoc->free_event); 131ea1f5729SLucas Stach } 132c3ef4b8cSLucas Stach 133db82a043SLucas Stach u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf, 134db82a043SLucas Stach struct etnaviv_vram_mapping *mapping) 135c3ef4b8cSLucas Stach { 136db82a043SLucas Stach return mapping->iova + buf->suballoc_offset; 137c3ef4b8cSLucas Stach } 1389912b4dbSLucas Stach 1399912b4dbSLucas Stach dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf) 1409912b4dbSLucas Stach { 141e66774ddSLucas Stach return buf->suballoc->paddr + buf->suballoc_offset; 1429912b4dbSLucas Stach } 143