mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-11 15:49:56 +00:00
drm/nouveau: exec: report max pushs through getparam
Report the maximum number of IBs that can be pushed with a single DRM_IOCTL_NOUVEAU_EXEC through DRM_IOCTL_NOUVEAU_GETPARAM. While the maximum number of IBs per ring might vary between chipsets, the kernel will make sure that userspace can only push a fraction of the maximum number of IBs per ring per job, such that we avoid a situation where there's only a single job occupying the ring, which could potentially lead to the ring run dry. Using DRM_IOCTL_NOUVEAU_GETPARAM to report the maximum number of IBs that can be pushed with a single DRM_IOCTL_NOUVEAU_EXEC implies that all channels of a given device have the same ring size. Reviewed-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com> Acked-by: Faith Ekstrand <faith.ekstrand@collabora.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231002135008.10651-3-dakr@redhat.com
This commit is contained in:
parent
bbe08a0e11
commit
d59e75eef5
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "nouveau_drv.h"
|
#include "nouveau_drv.h"
|
||||||
#include "nouveau_dma.h"
|
#include "nouveau_dma.h"
|
||||||
|
#include "nouveau_exec.h"
|
||||||
#include "nouveau_gem.h"
|
#include "nouveau_gem.h"
|
||||||
#include "nouveau_chan.h"
|
#include "nouveau_chan.h"
|
||||||
#include "nouveau_abi16.h"
|
#include "nouveau_abi16.h"
|
||||||
@ -183,6 +184,20 @@ nouveau_abi16_fini(struct nouveau_abi16 *abi16)
|
|||||||
cli->abi16 = NULL;
|
cli->abi16 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
getparam_dma_ib_max(struct nvif_device *device)
|
||||||
|
{
|
||||||
|
const struct nvif_mclass dmas[] = {
|
||||||
|
{ NV03_CHANNEL_DMA, 0 },
|
||||||
|
{ NV10_CHANNEL_DMA, 0 },
|
||||||
|
{ NV17_CHANNEL_DMA, 0 },
|
||||||
|
{ NV40_CHANNEL_DMA, 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
return nvif_mclass(&device->object, dmas) < 0 ? NV50_DMA_IB_MAX : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
|
nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
|
||||||
{
|
{
|
||||||
@ -247,6 +262,12 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
|
|||||||
case NOUVEAU_GETPARAM_GRAPH_UNITS:
|
case NOUVEAU_GETPARAM_GRAPH_UNITS:
|
||||||
getparam->value = nvkm_gr_units(gr);
|
getparam->value = nvkm_gr_units(gr);
|
||||||
break;
|
break;
|
||||||
|
case NOUVEAU_GETPARAM_EXEC_PUSH_MAX: {
|
||||||
|
int ib_max = getparam_dma_ib_max(device);
|
||||||
|
|
||||||
|
getparam->value = nouveau_exec_push_max_from_ib_max(ib_max);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
|
NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -454,7 +454,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
|
|||||||
chan->user_get = 0x44;
|
chan->user_get = 0x44;
|
||||||
chan->user_get_hi = 0x60;
|
chan->user_get_hi = 0x60;
|
||||||
chan->dma.ib_base = 0x10000 / 4;
|
chan->dma.ib_base = 0x10000 / 4;
|
||||||
chan->dma.ib_max = (0x02000 / 8) - 1;
|
chan->dma.ib_max = NV50_DMA_IB_MAX;
|
||||||
chan->dma.ib_put = 0;
|
chan->dma.ib_put = 0;
|
||||||
chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
|
chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
|
||||||
chan->dma.max = chan->dma.ib_base;
|
chan->dma.max = chan->dma.ib_base;
|
||||||
|
@ -49,6 +49,9 @@ void nv50_dma_push(struct nouveau_channel *, u64 addr, u32 length,
|
|||||||
/* Maximum push buffer size. */
|
/* Maximum push buffer size. */
|
||||||
#define NV50_DMA_PUSH_MAX_LENGTH 0x7fffff
|
#define NV50_DMA_PUSH_MAX_LENGTH 0x7fffff
|
||||||
|
|
||||||
|
/* Maximum IBs per ring. */
|
||||||
|
#define NV50_DMA_IB_MAX ((0x02000 / 8) - 1)
|
||||||
|
|
||||||
/* Object handles - for stuff that's doesn't use handle == oclass. */
|
/* Object handles - for stuff that's doesn't use handle == oclass. */
|
||||||
enum {
|
enum {
|
||||||
NvDmaFB = 0x80000002,
|
NvDmaFB = 0x80000002,
|
||||||
|
@ -379,7 +379,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
|
|||||||
struct nouveau_channel *chan = NULL;
|
struct nouveau_channel *chan = NULL;
|
||||||
struct nouveau_exec_job_args args = {};
|
struct nouveau_exec_job_args args = {};
|
||||||
struct drm_nouveau_exec *req = data;
|
struct drm_nouveau_exec *req = data;
|
||||||
int ret = 0;
|
int push_max, ret = 0;
|
||||||
|
|
||||||
if (unlikely(!abi16))
|
if (unlikely(!abi16))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -404,9 +404,10 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
|
|||||||
if (!chan->dma.ib_max)
|
if (!chan->dma.ib_max)
|
||||||
return nouveau_abi16_put(abi16, -ENOSYS);
|
return nouveau_abi16_put(abi16, -ENOSYS);
|
||||||
|
|
||||||
if (unlikely(req->push_count > NOUVEAU_GEM_MAX_PUSH)) {
|
push_max = nouveau_exec_push_max_from_ib_max(chan->dma.ib_max);
|
||||||
|
if (unlikely(req->push_count > push_max)) {
|
||||||
NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
|
NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
|
||||||
req->push_count, NOUVEAU_GEM_MAX_PUSH);
|
req->push_count, push_max);
|
||||||
return nouveau_abi16_put(abi16, -EINVAL);
|
return nouveau_abi16_put(abi16, -EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,4 +51,14 @@ int nouveau_exec_job_init(struct nouveau_exec_job **job,
|
|||||||
int nouveau_exec_ioctl_exec(struct drm_device *dev, void *data,
|
int nouveau_exec_ioctl_exec(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
|
static inline unsigned int
|
||||||
|
nouveau_exec_push_max_from_ib_max(int ib_max)
|
||||||
|
{
|
||||||
|
/* Limit the number of IBs per job to half the size of the ring in order
|
||||||
|
* to avoid the ring running dry between submissions and preserve one
|
||||||
|
* more slot for the job's HW fence.
|
||||||
|
*/
|
||||||
|
return ib_max > 1 ? ib_max / 2 - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -44,6 +44,16 @@ extern "C" {
|
|||||||
#define NOUVEAU_GETPARAM_PTIMER_TIME 14
|
#define NOUVEAU_GETPARAM_PTIMER_TIME 14
|
||||||
#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15
|
#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15
|
||||||
#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16
|
#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @NOUVEAU_GETPARAM_EXEC_PUSH_MAX
|
||||||
|
*
|
||||||
|
* Query the maximum amount of IBs that can be pushed through a single
|
||||||
|
* &drm_nouveau_exec structure and hence a single &DRM_IOCTL_NOUVEAU_EXEC
|
||||||
|
* ioctl().
|
||||||
|
*/
|
||||||
|
#define NOUVEAU_GETPARAM_EXEC_PUSH_MAX 17
|
||||||
|
|
||||||
struct drm_nouveau_getparam {
|
struct drm_nouveau_getparam {
|
||||||
__u64 param;
|
__u64 param;
|
||||||
__u64 value;
|
__u64 value;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user