// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com>
*/
/* * Wraps pm_runtime_get_sync() in a refcount, so that we can reliably * get the pm_runtime refcount to 0 in vc4_reset().
*/ int
vc4_v3d_pm_get(struct vc4_dev *vc4)
{ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) return -ENODEV;
mutex_lock(&vc4->power_lock); if (vc4->power_refcount++ == 0) { int ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
/* Take all the memory that would have been reserved for user * QPU programs, since we don't have an interface for running * them, anyway.
*/
V3D_WRITE(V3D_VPMBASE, 0);
}
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) return -ENODEV;
try_again:
spin_lock_irqsave(&vc4->job_lock, irqflags);
slot = ffs(~vc4->bin_alloc_used); if (slot != 0) { /* Switch from ffs() bit index to a 0-based index. */
slot--;
vc4->bin_alloc_used |= BIT(slot);
spin_unlock_irqrestore(&vc4->job_lock, irqflags); return slot;
}
/* Couldn't find an open slot. Wait for render to complete * and try again.
*/
exec = vc4_last_render_job(vc4); if (exec)
seqno = exec->seqno;
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
if (seqno) { int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
if (ret == 0) goto try_again;
return ret;
}
return -ENOMEM;
}
/* * bin_bo_alloc() - allocates the memory that will be used for * tile binning. * * The binner has a limitation that the addresses in the tile state * buffer that point into the tile alloc buffer or binner overflow * memory only have 28 bits (256MB), and the top 4 on the bus for * tile alloc references end up coming from the tile state buffer's * address. * * To work around this, we allocate a single large buffer while V3D is * in use, make sure that it has the top 4 bits constant across its * entire extent, and then put the tile state, tile alloc, and binner * overflow memory inside that buffer. * * This creates a limitation where we may not be able to execute a job * if it doesn't fit within the buffer that we allocated up front. * However, it turns out that 16MB is "enough for anybody", and * real-world applications run into allocation failures from the * overall DMA pool before they make scenes complicated enough to run * out of bin space.
*/ staticint bin_bo_alloc(struct vc4_dev *vc4)
{ struct vc4_v3d *v3d = vc4->v3d;
uint32_t size = 16 * 1024 * 1024; int ret = 0; struct list_head list;
if (!v3d) return -ENODEV;
/* We may need to try allocating more than once to get a BO * that doesn't cross 256MB. Track the ones we've allocated * that failed so far, so that we can free them when we've got * one that succeeded (if we freed them right away, our next * allocation would probably be the same chunk of memory).
*/
INIT_LIST_HEAD(&list);
dev_err(&v3d->pdev->dev, "Failed to allocate memory for tile binning: " "%d. You may need to enable DMA or give it " "more memory.",
ret); break;
}
/* Check if this BO won't trigger the addressing bug. */ if ((bo->base.dma_addr & 0xf0000000) ==
((bo->base.dma_addr + bo->base.base.size - 1) & 0xf0000000)) {
vc4->bin_bo = bo;
/* Set up for allocating 512KB chunks of * binner memory. The biggest allocation we * need to do is for the initial tile alloc + * tile state buffer. We can render to a * maximum of ((2048*2048) / (32*32) = 4096 * tiles in a frame (until we do floating * point rendering, at which point it would be * 8192). Tile state is 48b/tile (rounded to * a page), and tile alloc is 32b/tile * (rounded to a page), plus a page of extra, * for a total of 320kb for our worst-case. * We choose 512kb so that it divides evenly * into our 16MB, and the rest of the 512kb * will be used as storage for the overflow * from the initial 32b CL per bin.
*/
vc4->bin_alloc_size = 512 * 1024;
vc4->bin_alloc_used = 0;
vc4->bin_alloc_overflow = 0;
WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 !=
bo->base.base.size / vc4->bin_alloc_size);
kref_init(&vc4->bin_bo_kref);
/* Enable the out-of-memory interrupt to set our * newly-allocated binner BO, potentially from an * already-pending-but-masked interrupt.
*/
V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
break;
}
/* Put it on the list to free later, and try again. */
list_add(&bo->unref_head, &list);
}
/* Free all the BOs we allocated but didn't choose. */ while (!list_empty(&list)) { struct vc4_bo *bo = list_last_entry(&list, struct vc4_bo, unref_head);
/* Disable the binner's overflow memory address, so the next * driver probe (if any) doesn't try to reuse our old * allocation.
*/
V3D_WRITE(V3D_BPOA, 0);
V3D_WRITE(V3D_BPOS, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.