cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

etnaviv_cmdbuf.c (3615B)


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