···11+/*22+ * Copyright (C) 2017 Etnaviv Project33+ *44+ * This program is free software; you can redistribute it and/or modify it55+ * under the terms of the GNU General Public License version 2 as published by66+ * the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful, but WITHOUT99+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1010+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1111+ * more details.1212+ *1313+ * You should have received a copy of the GNU General Public License along with1414+ * this program. If not, see <http://www.gnu.org/licenses/>.1515+ */1616+1717+#include <drm/drm_mm.h>1818+1919+#include "etnaviv_cmdbuf.h"2020+#include "etnaviv_gpu.h"2121+#include "etnaviv_mmu.h"2222+2323+#define SUBALLOC_SIZE SZ_256K2424+#define SUBALLOC_GRANULE SZ_4K2525+#define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE)2626+2727+struct etnaviv_cmdbuf_suballoc {2828+ /* suballocated dma buffer properties */2929+ struct etnaviv_gpu *gpu;3030+ void *vaddr;3131+ dma_addr_t paddr;3232+3333+ /* GPU mapping */3434+ u32 iova;3535+ struct drm_mm_node vram_node; /* only used on MMUv2 */3636+3737+ /* allocation management */3838+ struct mutex lock;3939+ DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES);4040+ int free_space;4141+ wait_queue_head_t free_event;4242+};4343+4444+struct etnaviv_cmdbuf_suballoc *4545+etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu)4646+{4747+ struct etnaviv_cmdbuf_suballoc *suballoc;4848+ int ret;4949+5050+ suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL);5151+ if (!suballoc)5252+ return ERR_PTR(-ENOMEM);5353+5454+ suballoc->gpu = gpu;5555+ mutex_init(&suballoc->lock);5656+ init_waitqueue_head(&suballoc->free_event);5757+5858+ suballoc->vaddr = dma_alloc_wc(gpu->dev, SUBALLOC_SIZE,5959+ &suballoc->paddr, GFP_KERNEL);6060+ if (!suballoc->vaddr)6161+ goto free_suballoc;6262+6363+ ret = etnaviv_iommu_get_suballoc_va(gpu, suballoc->paddr,6464+ &suballoc->vram_node, SUBALLOC_SIZE,6565+ &suballoc->iova);6666+ if (ret)6767+ goto free_dma;6868+6969+ return suballoc;7070+7171+free_dma:7272+ dma_free_wc(gpu->dev, SUBALLOC_SIZE, suballoc->vaddr, suballoc->paddr);7373+free_suballoc:7474+ kfree(suballoc);7575+7676+ return NULL;7777+}7878+7979+void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc)8080+{8181+ etnaviv_iommu_put_suballoc_va(suballoc->gpu, &suballoc->vram_node,8282+ SUBALLOC_SIZE, suballoc->iova);8383+ dma_free_wc(suballoc->gpu->dev, SUBALLOC_SIZE, suballoc->vaddr,8484+ suballoc->paddr);8585+ kfree(suballoc);8686+}8787+8888+struct etnaviv_cmdbuf *8989+etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,9090+ size_t nr_bos)9191+{9292+ struct etnaviv_cmdbuf *cmdbuf;9393+ size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),9494+ sizeof(*cmdbuf));9595+ int granule_offs, order, ret;9696+9797+ cmdbuf = kzalloc(sz, GFP_KERNEL);9898+ if (!cmdbuf)9999+ return NULL;100100+101101+ cmdbuf->suballoc = suballoc;102102+ cmdbuf->size = size;103103+104104+ order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE);105105+retry:106106+ mutex_lock(&suballoc->lock);107107+ granule_offs = bitmap_find_free_region(suballoc->granule_map,108108+ SUBALLOC_GRANULES, order);109109+ if (granule_offs < 0) {110110+ suballoc->free_space = 0;111111+ mutex_unlock(&suballoc->lock);112112+ ret = wait_event_interruptible_timeout(suballoc->free_event,113113+ suballoc->free_space,114114+ msecs_to_jiffies(10 * 1000));115115+ if (!ret) {116116+ dev_err(suballoc->gpu->dev,117117+ "Timeout waiting for cmdbuf space\n");118118+ return NULL;119119+ }120120+ goto retry;121121+ }122122+ mutex_unlock(&suballoc->lock);123123+ cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE;124124+ cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;125125+126126+ return cmdbuf;127127+}128128+129129+void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)130130+{131131+ struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc;132132+ int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) /133133+ SUBALLOC_GRANULE);134134+135135+ mutex_lock(&suballoc->lock);136136+ bitmap_release_region(suballoc->granule_map,137137+ cmdbuf->suballoc_offset / SUBALLOC_GRANULE,138138+ order);139139+ suballoc->free_space = 1;140140+ mutex_unlock(&suballoc->lock);141141+ wake_up_all(&suballoc->free_event);142142+ kfree(cmdbuf);143143+}144144+145145+u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf)146146+{147147+ return buf->suballoc->iova + buf->suballoc_offset;148148+}149149+150150+dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf)151151+{152152+ return buf->suballoc->paddr + buf->suballoc_offset;153153+}
+58
drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h
···11+/*22+ * Copyright (C) 2017 Etnaviv Project33+ *44+ * This program is free software; you can redistribute it and/or modify it55+ * under the terms of the GNU General Public License version 2 as published by66+ * the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful, but WITHOUT99+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1010+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1111+ * more details.1212+ *1313+ * You should have received a copy of the GNU General Public License along with1414+ * this program. If not, see <http://www.gnu.org/licenses/>.1515+ */1616+1717+#ifndef __ETNAVIV_CMDBUF_H__1818+#define __ETNAVIV_CMDBUF_H__1919+2020+#include <linux/types.h>2121+2222+struct etnaviv_gpu;2323+struct etnaviv_cmdbuf_suballoc;2424+2525+struct etnaviv_cmdbuf {2626+ /* suballocator this cmdbuf is allocated from */2727+ struct etnaviv_cmdbuf_suballoc *suballoc;2828+ /* user context key, must be unique between all active users */2929+ struct etnaviv_file_private *ctx;3030+ /* cmdbuf properties */3131+ int suballoc_offset;3232+ void *vaddr;3333+ u32 size;3434+ u32 user_size;3535+ /* fence after which this buffer is to be disposed */3636+ struct dma_fence *fence;3737+ /* target exec state */3838+ u32 exec_state;3939+ /* per GPU in-flight list */4040+ struct list_head node;4141+ /* BOs attached to this command buffer */4242+ unsigned int nr_bos;4343+ struct etnaviv_vram_mapping *bo_map[0];4444+};4545+4646+struct etnaviv_cmdbuf_suballoc *4747+etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu);4848+void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc);4949+5050+struct etnaviv_cmdbuf *5151+etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,5252+ size_t nr_bos);5353+void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);5454+5555+u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf);5656+dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf);5757+5858+#endif /* __ETNAVIV_CMDBUF_H__ */
+3-2
drivers/gpu/drm/etnaviv/etnaviv_drv.c
···1818#include <linux/of_platform.h>1919#include <drm/drm_of.h>20202121+#include "etnaviv_cmdbuf.h"2122#include "etnaviv_drv.h"2223#include "etnaviv_gpu.h"2324#include "etnaviv_gem.h"2425#include "etnaviv_mmu.h"2525-#include "etnaviv_gem.h"26262727#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING2828static bool reglog;···177177 u32 i;178178179179 seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",180180- buf->vaddr, (u64)buf->paddr, size - buf->user_size);180180+ buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),181181+ size - buf->user_size);181182182183 for (i = 0; i < size / 4; i++) {183184 if (i && !(i % 4))
+3-3
drivers/gpu/drm/etnaviv/etnaviv_dump.c
···1515 */16161717#include <linux/devcoredump.h>1818+#include "etnaviv_cmdbuf.h"1819#include "etnaviv_dump.h"1920#include "etnaviv_gem.h"2021#include "etnaviv_gpu.h"···178177 etnaviv_core_dump_mmu(&iter, gpu, mmu_size);179178 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,180179 gpu->buffer->size,181181- etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer));180180+ etnaviv_cmdbuf_get_va(gpu->buffer));182181183182 list_for_each_entry(cmd, &gpu->active_cmd_list, node)184183 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,185185- cmd->size,186186- etnaviv_iommu_get_cmdbuf_va(gpu, cmd));184184+ cmd->size, etnaviv_cmdbuf_get_va(cmd));187185188186 /* Reserve space for the bomap */189187 if (n_bomap_pages) {
+5-3
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
···1515 */16161717#include <linux/reservation.h>1818+#include "etnaviv_cmdbuf.h"1819#include "etnaviv_drv.h"1920#include "etnaviv_gpu.h"2021#include "etnaviv_gem.h"···333332 bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));334333 relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));335334 stream = drm_malloc_ab(1, args->stream_size);336336- cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8,337337- args->nr_bos);335335+ cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc,336336+ ALIGN(args->stream_size, 8) + 8,337337+ args->nr_bos);338338 if (!bos || !relocs || !stream || !cmdbuf) {339339 ret = -ENOMEM;340340 goto err_submit_cmds;···424422err_submit_cmds:425423 /* if we still own the cmdbuf */426424 if (cmdbuf)427427- etnaviv_gpu_cmdbuf_free(cmdbuf);425425+ etnaviv_cmdbuf_free(cmdbuf);428426 if (stream)429427 drm_free_large(stream);430428 if (bos)