Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: MIT
nvif-y := nvif/object.o
nvif-y += nvif/client.o
nvif-y += nvif/conn.o
nvif-y += nvif/device.o
nvif-y += nvif/disp.o
nvif-y += nvif/driver.o
nvif-y += nvif/event.o
nvif-y += nvif/fifo.o
nvif-y += nvif/head.o
nvif-y += nvif/mem.o
nvif-y += nvif/mmu.o
nvif-y += nvif/outp.o
nvif-y += nvif/timer.o
nvif-y += nvif/vmm.o
# Channel classes
nvif-y += nvif/chan.o
nvif-y += nvif/chan506f.o
nvif-y += nvif/chan906f.o
nvif-y += nvif/chanc36f.o
# Usermode classes
nvif-y += nvif/user.o
nvif-y += nvif/userc361.o
@@ -0,0 +1,159 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvif/chan.h>
static void
nvif_chan_gpfifo_push_kick(struct nvif_push *push)
{
struct nvif_chan *chan = container_of(push, typeof(*chan), push);
u32 put = push->bgn - (u32 *)chan->push.mem.object.map.ptr;
u32 cnt;
if (chan->func->gpfifo.post) {
if (push->end - push->cur < chan->func->gpfifo.post_size)
push->end = push->cur + chan->func->gpfifo.post_size;
WARN_ON(nvif_chan_gpfifo_post(chan));
}
cnt = push->cur - push->bgn;
chan->func->gpfifo.push(chan, true, chan->push.addr + (put << 2), cnt << 2, false);
chan->func->gpfifo.kick(chan);
}
static int
nvif_chan_gpfifo_push_wait(struct nvif_push *push, u32 push_nr)
{
struct nvif_chan *chan = container_of(push, typeof(*chan), push);
return nvif_chan_gpfifo_wait(chan, 1, push_nr);
}
int
nvif_chan_gpfifo_post(struct nvif_chan *chan)
{
const u32 *map = chan->push.mem.object.map.ptr;
const u32 pbptr = (chan->push.cur - map) + chan->func->gpfifo.post_size;
const u32 gpptr = (chan->gpfifo.cur + 1) & chan->gpfifo.max;
if (!chan->func->gpfifo.post)
return 0;
return chan->func->gpfifo.post(chan, gpptr, pbptr);
}
void
nvif_chan_gpfifo_push(struct nvif_chan *chan, u64 addr, u32 size, bool no_prefetch)
{
chan->func->gpfifo.push(chan, false, addr, size, no_prefetch);
}
int
nvif_chan_gpfifo_wait(struct nvif_chan *chan, u32 gpfifo_nr, u32 push_nr)
{
struct nvif_push *push = &chan->push;
int ret = 0, time = 1000000;
if (gpfifo_nr) {
/* Account for pushbuf space needed by nvif_chan_gpfifo_post(),
* if used after pushing userspace GPFIFO entries.
*/
if (chan->func->gpfifo.post)
push_nr += chan->func->gpfifo.post_size;
}
/* Account for the GPFIFO entry needed to submit pushbuf. */
if (push_nr)
gpfifo_nr++;
/* Wait for space in main push buffer. */
if (push->cur + push_nr > push->end) {
ret = nvif_chan_dma_wait(chan, push_nr);
if (ret)
return ret;
}
/* Wait for GPFIFO space. */
while (chan->gpfifo.free < gpfifo_nr) {
chan->gpfifo.free = chan->func->gpfifo.read_get(chan) - chan->gpfifo.cur - 1;
if (chan->gpfifo.free < 0)
chan->gpfifo.free += chan->gpfifo.max + 1;
if (chan->gpfifo.free < gpfifo_nr) {
if (!time--)
return -ETIMEDOUT;
udelay(1);
}
}
return 0;
}
void
nvif_chan_gpfifo_ctor(const struct nvif_chan_func *func, void *userd, void *gpfifo, u32 gpfifo_size,
void *push, u64 push_addr, u32 push_size, struct nvif_chan *chan)
{
chan->func = func;
chan->userd.map.ptr = userd;
chan->gpfifo.map.ptr = gpfifo;
chan->gpfifo.max = (gpfifo_size >> 3) - 1;
chan->gpfifo.free = chan->gpfifo.max;
chan->push.mem.object.map.ptr = push;
chan->push.wait = nvif_chan_gpfifo_push_wait;
chan->push.kick = nvif_chan_gpfifo_push_kick;
chan->push.addr = push_addr;
chan->push.hw.max = push_size >> 2;
chan->push.bgn = chan->push.cur = chan->push.end = push;
}
int
nvif_chan_dma_wait(struct nvif_chan *chan, u32 nr)
{
struct nvif_push *push = &chan->push;
u32 cur = push->cur - (u32 *)push->mem.object.map.ptr;
u32 free, time = 1000000;
nr += chan->func->gpfifo.post_size;
do {
u32 get = chan->func->push.read_get(chan);
if (get <= cur) {
free = push->hw.max - cur;
if (free >= nr)
break;
PUSH_KICK(push);
while (get == 0) {
get = chan->func->push.read_get(chan);
if (get == 0) {
if (!time--)
return -ETIMEDOUT;
udelay(1);
}
}
cur = 0;
}
free = get - cur - 1;
if (free < nr) {
if (!time--)
return -ETIMEDOUT;
udelay(1);
}
} while (free < nr);
push->bgn = (u32 *)push->mem.object.map.ptr + cur;
push->cur = push->bgn;
push->end = push->bgn + free - chan->func->gpfifo.post_size;
return 0;
}
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvif/chan.h>
void
nvif_chan506f_gpfifo_kick(struct nvif_chan *chan)
{
wmb();
nvif_wr32(&chan->userd, 0x8c, chan->gpfifo.cur);
}
void
nvif_chan506f_gpfifo_push(struct nvif_chan *chan, bool main, u64 addr, u32 size, bool no_prefetch)
{
u32 gpptr = chan->gpfifo.cur << 3;
if (WARN_ON(!chan->gpfifo.free))
return;
nvif_wr32(&chan->gpfifo, gpptr + 0, lower_32_bits(addr));
nvif_wr32(&chan->gpfifo, gpptr + 4, upper_32_bits(addr) |
(main ? 0 : BIT(9)) |
(size >> 2) << 10 |
(no_prefetch ? BIT(31) : 0));
chan->gpfifo.cur = (chan->gpfifo.cur + 1) & chan->gpfifo.max;
chan->gpfifo.free--;
if (!chan->gpfifo.free)
chan->push.end = chan->push.cur;
}
static u32
nvif_chan506f_gpfifo_read_get(struct nvif_chan *chan)
{
return nvif_rd32(&chan->userd, 0x88);
}
static u32
nvif_chan506f_read_get(struct nvif_chan *chan)
{
u32 tlgetlo = nvif_rd32(&chan->userd, 0x58);
u32 tlgethi = nvif_rd32(&chan->userd, 0x5c);
struct nvif_push *push = &chan->push;
/* Update cached GET pointer if TOP_LEVEL_GET is valid. */
if (tlgethi & BIT(31)) {
u64 tlget = ((u64)(tlgethi & 0xff) << 32) | tlgetlo;
push->hw.get = (tlget - push->addr) >> 2;
}
return push->hw.get;
}
static const struct nvif_chan_func
nvif_chan506f = {
.push.read_get = nvif_chan506f_read_get,
.gpfifo.read_get = nvif_chan506f_gpfifo_read_get,
.gpfifo.push = nvif_chan506f_gpfifo_push,
.gpfifo.kick = nvif_chan506f_gpfifo_kick,
};
int
nvif_chan506f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
void *push, u64 push_addr, u32 push_size)
{
nvif_chan_gpfifo_ctor(&nvif_chan506f, userd, gpfifo, gpfifo_size,
push, push_addr, push_size, chan);
return 0;
}
@@ -0,0 +1,93 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvif/chan.h>
#include <nvif/user.h>
#include <nvif/push906f.h>
#include <nvhw/class/cl906f.h>
/* Limits GPFIFO size to 1MiB, and "main" push buffer size to 64KiB. */
#define NVIF_CHAN906F_PBPTR_BITS 15
#define NVIF_CHAN906F_PBPTR_MASK ((1 << NVIF_CHAN906F_PBPTR_BITS) - 1)
#define NVIF_CHAN906F_GPPTR_SHIFT NVIF_CHAN906F_PBPTR_BITS
#define NVIF_CHAN906F_GPPTR_BITS (32 - NVIF_CHAN906F_PBPTR_BITS)
#define NVIF_CHAN906F_GPPTR_MASK ((1 << NVIF_CHAN906F_GPPTR_BITS) - 1)
#define NVIF_CHAN906F_SEM_RELEASE_SIZE 5
static int
nvif_chan906f_sem_release(struct nvif_chan *chan, u64 addr, u32 data)
{
struct nvif_push *push = &chan->push;
int ret;
ret = PUSH_WAIT(push, NVIF_CHAN906F_SEM_RELEASE_SIZE);
if (ret)
return ret;
PUSH_MTHD(push, NV906F, SEMAPHOREA,
NVVAL(NV906F, SEMAPHOREA, OFFSET_UPPER, upper_32_bits(addr)),
SEMAPHOREB, lower_32_bits(addr),
SEMAPHOREC, data,
SEMAPHORED,
NVDEF(NV906F, SEMAPHORED, OPERATION, RELEASE) |
NVDEF(NV906F, SEMAPHORED, RELEASE_WFI, DIS) |
NVDEF(NV906F, SEMAPHORED, RELEASE_SIZE, 16BYTE));
return 0;
}
int
nvif_chan906f_gpfifo_post(struct nvif_chan *chan, u32 gpptr, u32 pbptr)
{
return chan->func->sem.release(chan, chan->sema.addr,
(gpptr << NVIF_CHAN906F_GPPTR_SHIFT) | pbptr);
}
u32
nvif_chan906f_gpfifo_read_get(struct nvif_chan *chan)
{
return nvif_rd32(&chan->sema, 0) >> NVIF_CHAN906F_GPPTR_SHIFT;
}
u32
nvif_chan906f_read_get(struct nvif_chan *chan)
{
return nvif_rd32(&chan->sema, 0) & NVIF_CHAN906F_PBPTR_MASK;
}
static const struct nvif_chan_func
nvif_chan906f = {
.push.read_get = nvif_chan906f_read_get,
.gpfifo.read_get = nvif_chan906f_gpfifo_read_get,
.gpfifo.push = nvif_chan506f_gpfifo_push,
.gpfifo.kick = nvif_chan506f_gpfifo_kick,
.gpfifo.post = nvif_chan906f_gpfifo_post,
.gpfifo.post_size = NVIF_CHAN906F_SEM_RELEASE_SIZE,
.sem.release = nvif_chan906f_sem_release,
};
int
nvif_chan906f_ctor_(const struct nvif_chan_func *func, void *userd, void *gpfifo, u32 gpfifo_size,
void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr,
struct nvif_chan *chan)
{
nvif_chan_gpfifo_ctor(func, userd, gpfifo, gpfifo_size, push, push_addr, push_size, chan);
chan->sema.map.ptr = sema;
chan->sema.addr = sema_addr;
return 0;
}
int
nvif_chan906f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr)
{
return nvif_chan906f_ctor_(&nvif_chan906f, userd, gpfifo, gpfifo_size,
push, push_addr, push_size, sema, sema_addr, chan);
}
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvif/chan.h>
#include <nvif/user.h>
#include <nvif/push906f.h>
#include <nvhw/class/clc36f.h>
static void
nvif_chanc36f_gpfifo_kick(struct nvif_chan *chan)
{
struct nvif_user *usermode = chan->usermode;
nvif_wr32(&chan->userd, 0x8c, chan->gpfifo.cur);
wmb(); /* ensure CPU writes are flushed to BAR1 */
nvif_rd32(&chan->userd, 0); /* ensure BAR1 writes are flushed to vidmem */
usermode->func->doorbell(usermode, chan->doorbell_token);
}
#define NVIF_CHANC36F_SEM_RELEASE_SIZE 6
static int
nvif_chanc36f_sem_release(struct nvif_chan *chan, u64 addr, u32 data)
{
struct nvif_push *push = &chan->push;
int ret;
ret = PUSH_WAIT(push, NVIF_CHANC36F_SEM_RELEASE_SIZE);
if (ret)
return ret;
PUSH_MTHD(push, NVC36F, SEM_ADDR_LO, lower_32_bits(addr),
SEM_ADDR_HI, upper_32_bits(addr),
SEM_PAYLOAD_LO, data);
PUSH_MTHD(push, NVC36F, SEM_EXECUTE,
NVDEF(NVC36F, SEM_EXECUTE, OPERATION, RELEASE) |
NVDEF(NVC36F, SEM_EXECUTE, RELEASE_WFI, DIS) |
NVDEF(NVC36F, SEM_EXECUTE, PAYLOAD_SIZE, 32BIT) |
NVDEF(NVC36F, SEM_EXECUTE, RELEASE_TIMESTAMP, DIS));
return 0;
}
static const struct nvif_chan_func
nvif_chanc36f = {
.push.read_get = nvif_chan906f_read_get,
.gpfifo.read_get = nvif_chan906f_gpfifo_read_get,
.gpfifo.push = nvif_chan506f_gpfifo_push,
.gpfifo.kick = nvif_chanc36f_gpfifo_kick,
.gpfifo.post = nvif_chan906f_gpfifo_post,
.gpfifo.post_size = NVIF_CHANC36F_SEM_RELEASE_SIZE,
.sem.release = nvif_chanc36f_sem_release,
};
int
nvif_chanc36f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr,
struct nvif_user *usermode, u32 doorbell_token)
{
int ret;
ret = nvif_chan906f_ctor_(&nvif_chanc36f, userd, gpfifo, gpfifo_size,
push, push_addr, push_size, sema, sema_addr, chan);
if (ret)
return ret;
chan->usermode = usermode;
chan->doorbell_token = doorbell_token;
return 0;
}
@@ -0,0 +1,69 @@
/*
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <nvif/client.h>
#include <nvif/driver.h>
#include <nvif/ioctl.h>
#include <nvif/class.h>
#include <nvif/if0000.h>
int
nvif_client_suspend(struct nvif_client *client, bool runtime)
{
return client->driver->suspend(client->object.priv, runtime);
}
int
nvif_client_resume(struct nvif_client *client)
{
return client->driver->resume(client->object.priv);
}
void
nvif_client_dtor(struct nvif_client *client)
{
nvif_object_dtor(&client->object);
client->driver = NULL;
}
int
nvif_client_ctor(struct nvif_client *parent, const char *name, struct nvif_client *client)
{
struct nvif_client_v0 args = {};
int ret;
strscpy_pad(args.name, name, sizeof(args.name));
ret = nvif_object_ctor(parent != client ? &parent->object : NULL,
name ? name : "nvifClient", 0,
NVIF_CLASS_CLIENT, &args, sizeof(args),
&client->object);
if (ret)
return ret;
client->object.client = client;
client->object.handle = ~0;
client->driver = parent->driver;
return 0;
}
@@ -0,0 +1,87 @@
/*
* Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/conn.h>
#include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0011.h>
int
nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func func, u8 types,
struct nvif_event *event)
{
DEFINE_RAW_FLEX(struct nvif_event_v0, args, data,
sizeof(struct nvif_conn_event_v0));
struct nvif_conn_event_v0 *args_conn =
(struct nvif_conn_event_v0 *)args->data;
int ret;
args_conn->version = 0;
args_conn->types = types;
ret = nvif_event_ctor_(&conn->object, name ?: "nvifConnHpd", nvif_conn_id(conn),
func, true, args, __struct_size(args), false, event);
NVIF_DEBUG(&conn->object, "[NEW EVENT:HPD types:%02x]", types);
return ret;
}
void
nvif_conn_dtor(struct nvif_conn *conn)
{
nvif_object_dtor(&conn->object);
}
int
nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_conn *conn)
{
struct nvif_conn_v0 args;
int ret;
args.version = 0;
args.id = id;
ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN,
&args, sizeof(args), &conn->object);
NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id);
if (ret)
return ret;
conn->id = id;
switch (args.type) {
case NVIF_CONN_V0_VGA : conn->info.type = NVIF_CONN_VGA; break;
case NVIF_CONN_V0_TV : conn->info.type = NVIF_CONN_TV; break;
case NVIF_CONN_V0_DVI_I : conn->info.type = NVIF_CONN_DVI_I; break;
case NVIF_CONN_V0_DVI_D : conn->info.type = NVIF_CONN_DVI_D; break;
case NVIF_CONN_V0_LVDS : conn->info.type = NVIF_CONN_LVDS; break;
case NVIF_CONN_V0_LVDS_SPWG: conn->info.type = NVIF_CONN_LVDS_SPWG; break;
case NVIF_CONN_V0_HDMI : conn->info.type = NVIF_CONN_HDMI; break;
case NVIF_CONN_V0_DP : conn->info.type = NVIF_CONN_DP; break;
case NVIF_CONN_V0_EDP : conn->info.type = NVIF_CONN_EDP; break;
default:
break;
}
return 0;
}
@@ -0,0 +1,69 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <nvif/device.h>
#include <nvif/client.h>
u64
nvif_device_time(struct nvif_device *device)
{
if (!device->user.func) {
struct nv_device_time_v0 args = {};
int ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_TIME,
&args, sizeof(args));
WARN_ON_ONCE(ret != 0);
return args.time;
}
return device->user.func->time(&device->user);
}
int
nvif_device_map(struct nvif_device *device)
{
return nvif_object_map(&device->object, NULL, 0);
}
void
nvif_device_dtor(struct nvif_device *device)
{
nvif_user_dtor(device);
kfree(device->runlist);
device->runlist = NULL;
nvif_object_dtor(&device->object);
}
int
nvif_device_ctor(struct nvif_client *client, const char *name, struct nvif_device *device)
{
int ret = nvif_object_ctor(&client->object, name ? name : "nvifDevice", 0,
0x0080, NULL, 0, &device->object);
device->runlist = NULL;
device->user.func = NULL;
if (ret == 0) {
device->info.version = 0;
ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_INFO,
&device->info, sizeof(device->info));
}
return ret;
}
@@ -0,0 +1,83 @@
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/disp.h>
#include <nvif/device.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0010.h>
void
nvif_disp_dtor(struct nvif_disp *disp)
{
nvif_object_dtor(&disp->object);
}
int
nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct nvif_disp *disp)
{
static const struct nvif_mclass disps[] = {
{ GB202_DISP, 0 },
{ AD102_DISP, 0 },
{ GA102_DISP, 0 },
{ TU102_DISP, 0 },
{ GV100_DISP, 0 },
{ GP102_DISP, 0 },
{ GP100_DISP, 0 },
{ GM200_DISP, 0 },
{ GM107_DISP, 0 },
{ GK110_DISP, 0 },
{ GK104_DISP, 0 },
{ GF110_DISP, 0 },
{ GT214_DISP, 0 },
{ GT206_DISP, 0 },
{ GT200_DISP, 0 },
{ G82_DISP, 0 },
{ NV50_DISP, 0 },
{ NV04_DISP, 0 },
{}
};
struct nvif_disp_v0 args;
int cid, ret;
cid = nvif_sclass(&device->object, disps, oclass);
disp->object.client = NULL;
if (cid < 0) {
NVIF_DEBUG(&device->object, "[NEW disp%04x] not supported", oclass);
return cid;
}
args.version = 0;
ret = nvif_object_ctor(&device->object, name ?: "nvifDisp", 0,
disps[cid].oclass, &args, sizeof(args), &disp->object);
NVIF_ERRON(ret, &device->object, "[NEW disp%04x]", disps[cid].oclass);
if (ret)
return ret;
NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x head_mask:%08x",
args.conn_mask, args.outp_mask, args.head_mask);
disp->conn_mask = args.conn_mask;
disp->outp_mask = args.outp_mask;
disp->head_mask = args.head_mask;
return 0;
}
@@ -0,0 +1,40 @@
/*
* Copyright 2016 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <nvif/driver.h>
#include <nvif/client.h>
int
nvif_driver_init(const char *drv, const char *cfg, const char *dbg,
const char *name, u64 device, struct nvif_client *client)
{
int ret;
client->driver = &nvif_driver_nvkm;
ret = client->driver->init(name, device, cfg, dbg, &client->object.priv);
if (ret)
return ret;
return nvif_client_ctor(client, name, client);
}
@@ -0,0 +1,81 @@
/*
* Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/event.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if000e.h>
int
nvif_event_block(struct nvif_event *event)
{
if (nvif_event_constructed(event)) {
int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_BLOCK, NULL, 0);
NVIF_ERRON(ret, &event->object, "[BLOCK]");
return ret;
}
return 0;
}
int
nvif_event_allow(struct nvif_event *event)
{
if (nvif_event_constructed(event)) {
int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_ALLOW, NULL, 0);
NVIF_ERRON(ret, &event->object, "[ALLOW]");
return ret;
}
return 0;
}
void
nvif_event_dtor(struct nvif_event *event)
{
nvif_object_dtor(&event->object);
}
int
nvif_event_ctor_(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func,
bool wait, struct nvif_event_v0 *args, u32 argc, bool warn,
struct nvif_event *event)
{
struct nvif_event_v0 _args;
int ret;
if (!args) {
args = &_args;
argc = sizeof(_args);
}
args->version = 0;
args->wait = wait;
ret = nvif_object_ctor(parent, name ?: "nvifEvent", handle,
NVIF_CLASS_EVENT, args, argc, &event->object);
NVIF_ERRON(ret && warn, parent, "[NEW EVENT wait:%d size:%zd]",
args->wait, argc - sizeof(*args));
if (ret)
return ret;
event->func = func;
return 0;
}
@@ -0,0 +1,85 @@
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/fifo.h>
static int
nvif_fifo_runlists(struct nvif_device *device)
{
struct nvif_object *object = &device->object;
TRAILING_OVERLAP(struct nv_device_info_v1, m, data,
struct {
struct nv_device_info_v1_data runlists;
struct nv_device_info_v1_data runlist[64];
} v;
) *a;
int ret, i;
if (device->runlist)
return 0;
if (!(a = kmalloc_obj(*a)))
return -ENOMEM;
a->m.version = 1;
a->m.count = sizeof(a->v) / sizeof(a->v.runlists);
a->v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS;
for (i = 0; i < ARRAY_SIZE(a->v.runlist); i++) {
a->v.runlist[i].mthd = NV_DEVICE_HOST_RUNLIST_ENGINES;
a->v.runlist[i].data = i;
}
ret = nvif_object_mthd(object, NV_DEVICE_V0_INFO, a, sizeof(*a));
if (ret)
goto done;
device->runlists = fls64(a->v.runlists.data);
device->runlist = kzalloc_objs(*device->runlist, device->runlists);
if (!device->runlist) {
ret = -ENOMEM;
goto done;
}
for (i = 0; i < device->runlists; i++) {
if (a->v.runlist[i].mthd != NV_DEVICE_INFO_INVALID)
device->runlist[i].engines = a->v.runlist[i].data;
}
done:
kfree(a);
return ret;
}
u64
nvif_fifo_runlist(struct nvif_device *device, u64 engine)
{
u64 runm = 0;
int ret, i;
if ((ret = nvif_fifo_runlists(device)))
return runm;
for (i = 0; i < device->runlists; i++) {
if (device->runlist[i].engines & engine)
runm |= BIT_ULL(i);
}
return runm;
}
@@ -0,0 +1,58 @@
/*
* Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/head.h>
#include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0013.h>
int
nvif_head_vblank_event_ctor(struct nvif_head *head, const char *name, nvif_event_func func,
bool wait, struct nvif_event *event)
{
int ret = nvif_event_ctor(&head->object, name ?: "nvifHeadVBlank", nvif_head_id(head),
func, wait, NULL, 0, event);
NVIF_ERRON(ret, &head->object, "[NEW EVENT:VBLANK]");
return ret;
}
void
nvif_head_dtor(struct nvif_head *head)
{
nvif_object_dtor(&head->object);
}
int
nvif_head_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_head *head)
{
struct nvif_head_v0 args;
int ret;
args.version = 0;
args.id = id;
ret = nvif_object_ctor(&disp->object, name ? name : "nvifHead", id, NVIF_CLASS_HEAD,
&args, sizeof(args), &head->object);
NVIF_ERRON(ret, &disp->object, "[NEW head id:%d]", args.id);
return ret;
}
@@ -0,0 +1,103 @@
/*
* Copyright 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/mem.h>
#include <nvif/client.h>
#include <nvif/if000a.h>
int
nvif_mem_ctor_map(struct nvif_mmu *mmu, const char *name, u8 type, u64 size,
struct nvif_mem *mem)
{
int ret = nvif_mem_ctor(mmu, name, mmu->mem, NVIF_MEM_MAPPABLE | type,
0, size, NULL, 0, mem);
if (ret == 0) {
ret = nvif_object_map(&mem->object, NULL, 0);
if (ret)
nvif_mem_dtor(mem);
}
return ret;
}
void
nvif_mem_dtor(struct nvif_mem *mem)
{
nvif_object_dtor(&mem->object);
}
int
nvif_mem_ctor_type(struct nvif_mmu *mmu, const char *name, s32 oclass,
int type, u8 page, u64 size, void *argv, u32 argc,
struct nvif_mem *mem)
{
struct nvif_mem_v0 *args;
u8 stack[128];
int ret;
mem->object.client = NULL;
if (type < 0)
return -EINVAL;
if (sizeof(*args) + argc > sizeof(stack)) {
if (!(args = kmalloc(sizeof(*args) + argc, GFP_KERNEL)))
return -ENOMEM;
} else {
args = (void *)stack;
}
args->version = 0;
args->type = type;
args->page = page;
args->size = size;
memcpy(args->data, argv, argc);
ret = nvif_object_ctor(&mmu->object, name ? name : "nvifMem", 0, oclass,
args, sizeof(*args) + argc, &mem->object);
if (ret == 0) {
mem->type = mmu->type[type].type;
mem->page = args->page;
mem->addr = args->addr;
mem->size = args->size;
}
if (args != (void *)stack)
kfree(args);
return ret;
}
int
nvif_mem_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, u8 type,
u8 page, u64 size, void *argv, u32 argc, struct nvif_mem *mem)
{
int ret = -EINVAL, i;
mem->object.client = NULL;
for (i = 0; ret && i < mmu->type_nr; i++) {
if ((mmu->type[i].type & type) == type) {
ret = nvif_mem_ctor_type(mmu, name, oclass, i, page,
size, argv, argc, mem);
}
}
return ret;
}
@@ -0,0 +1,133 @@
/*
* Copyright 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/mmu.h>
#include <nvif/class.h>
#include <nvif/if0008.h>
void
nvif_mmu_dtor(struct nvif_mmu *mmu)
{
if (!nvif_object_constructed(&mmu->object))
return;
kfree(mmu->kind);
kfree(mmu->type);
kfree(mmu->heap);
nvif_object_dtor(&mmu->object);
}
int
nvif_mmu_ctor(struct nvif_object *parent, const char *name, s32 oclass,
struct nvif_mmu *mmu)
{
static const struct nvif_mclass mems[] = {
{ NVIF_CLASS_MEM_GF100, -1 },
{ NVIF_CLASS_MEM_NV50 , -1 },
{ NVIF_CLASS_MEM_NV04 , -1 },
{}
};
struct nvif_mmu_v0 args;
int ret, i;
args.version = 0;
mmu->heap = NULL;
mmu->type = NULL;
mmu->kind = NULL;
ret = nvif_object_ctor(parent, name ? name : "nvifMmu", 0, oclass,
&args, sizeof(args), &mmu->object);
if (ret)
goto done;
mmu->dmabits = args.dmabits;
mmu->heap_nr = args.heap_nr;
mmu->type_nr = args.type_nr;
mmu->kind_nr = args.kind_nr;
ret = nvif_mclass(&mmu->object, mems);
if (ret < 0)
goto done;
mmu->mem = mems[ret].oclass;
mmu->heap = kmalloc_objs(*mmu->heap, mmu->heap_nr);
mmu->type = kmalloc_objs(*mmu->type, mmu->type_nr);
if (ret = -ENOMEM, !mmu->heap || !mmu->type)
goto done;
mmu->kind = kmalloc_objs(*mmu->kind, mmu->kind_nr);
if (!mmu->kind && mmu->kind_nr)
goto done;
for (i = 0; i < mmu->heap_nr; i++) {
struct nvif_mmu_heap_v0 args = { .index = i };
ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_HEAP,
&args, sizeof(args));
if (ret)
goto done;
mmu->heap[i].size = args.size;
}
for (i = 0; i < mmu->type_nr; i++) {
struct nvif_mmu_type_v0 args = { .index = i };
ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_TYPE,
&args, sizeof(args));
if (ret)
goto done;
mmu->type[i].type = 0;
if (args.vram) mmu->type[i].type |= NVIF_MEM_VRAM;
if (args.host) mmu->type[i].type |= NVIF_MEM_HOST;
if (args.comp) mmu->type[i].type |= NVIF_MEM_COMP;
if (args.disp) mmu->type[i].type |= NVIF_MEM_DISP;
if (args.kind ) mmu->type[i].type |= NVIF_MEM_KIND;
if (args.mappable) mmu->type[i].type |= NVIF_MEM_MAPPABLE;
if (args.coherent) mmu->type[i].type |= NVIF_MEM_COHERENT;
if (args.uncached) mmu->type[i].type |= NVIF_MEM_UNCACHED;
mmu->type[i].heap = args.heap;
}
if (mmu->kind_nr) {
struct nvif_mmu_kind_v0 *kind;
size_t argc = struct_size(kind, data, mmu->kind_nr);
if (ret = -ENOMEM, !(kind = kmalloc(argc, GFP_KERNEL)))
goto done;
kind->version = 0;
kind->count = mmu->kind_nr;
ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_KIND,
kind, argc);
if (ret == 0)
memcpy(mmu->kind, kind->data, kind->count);
mmu->kind_inv = kind->kind_inv;
kfree(kind);
}
done:
if (ret)
nvif_mmu_dtor(mmu);
return ret;
}
@@ -0,0 +1,279 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <nvif/object.h>
#include <nvif/client.h>
#include <nvif/driver.h>
#include <nvif/ioctl.h>
int
nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
{
struct nvif_client *client = object->client;
union {
struct nvif_ioctl_v0 v0;
} *args = data;
if (size >= sizeof(*args) && args->v0.version == 0) {
if (object != &client->object)
args->v0.object = nvif_handle(object);
else
args->v0.object = 0;
} else
return -ENOSYS;
return client->driver->ioctl(client->object.priv, data, size, hack);
}
void
nvif_object_sclass_put(struct nvif_sclass **psclass)
{
kfree(*psclass);
*psclass = NULL;
}
int
nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_sclass_v0 sclass;
} *args = NULL;
int ret, cnt = 0, i;
u32 size;
while (1) {
size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
if (!(args = kmalloc(size, GFP_KERNEL)))
return -ENOMEM;
args->ioctl.version = 0;
args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
args->sclass.version = 0;
args->sclass.count = cnt;
ret = nvif_object_ioctl(object, args, size, NULL);
if (ret == 0 && args->sclass.count <= cnt)
break;
cnt = args->sclass.count;
kfree(args);
if (ret != 0)
return ret;
}
*psclass = kzalloc_objs(**psclass, args->sclass.count);
if (*psclass) {
for (i = 0; i < args->sclass.count; i++) {
(*psclass)[i].oclass = args->sclass.oclass[i].oclass;
(*psclass)[i].minver = args->sclass.oclass[i].minver;
(*psclass)[i].maxver = args->sclass.oclass[i].maxver;
}
ret = args->sclass.count;
} else {
ret = -ENOMEM;
}
kfree(args);
return ret;
}
int
nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_mthd_v0 mthd;
} *args;
u32 args_size;
u8 stack[128];
int ret;
if (check_add_overflow(sizeof(*args), size, &args_size))
return -ENOMEM;
if (args_size > sizeof(stack)) {
args = kmalloc(args_size, GFP_KERNEL);
if (!args)
return -ENOMEM;
} else {
args = (void *)stack;
}
args->ioctl.version = 0;
args->ioctl.type = NVIF_IOCTL_V0_MTHD;
args->mthd.version = 0;
args->mthd.method = mthd;
memcpy(args->mthd.data, data, size);
ret = nvif_object_ioctl(object, args, args_size, NULL);
memcpy(data, args->mthd.data, size);
if (args != (void *)stack)
kfree(args);
return ret;
}
void
nvif_object_unmap_handle(struct nvif_object *object)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_unmap unmap;
} args = {
.ioctl.type = NVIF_IOCTL_V0_UNMAP,
};
nvif_object_ioctl(object, &args, sizeof(args), NULL);
}
int
nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
u64 *handle, u64 *length)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_map_v0 map;
} *args;
u32 argn = sizeof(*args) + argc;
int ret, maptype;
if (!(args = kzalloc(argn, GFP_KERNEL)))
return -ENOMEM;
args->ioctl.type = NVIF_IOCTL_V0_MAP;
memcpy(args->map.data, argv, argc);
ret = nvif_object_ioctl(object, args, argn, NULL);
*handle = args->map.handle;
*length = args->map.length;
maptype = args->map.type;
kfree(args);
return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
}
void
nvif_object_unmap(struct nvif_object *object)
{
struct nvif_client *client = object->client;
if (object->map.ptr) {
if (object->map.size) {
client->driver->unmap(client, object->map.ptr,
object->map.size);
object->map.size = 0;
}
object->map.ptr = NULL;
nvif_object_unmap_handle(object);
}
}
int
nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
{
struct nvif_client *client = object->client;
u64 handle, length;
int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
if (ret >= 0) {
if (ret) {
object->map.ptr = client->driver->map(client,
handle,
length);
if (ret = -ENOMEM, object->map.ptr) {
object->map.size = length;
return 0;
}
} else {
object->map.ptr = (void *)(unsigned long)handle;
return 0;
}
nvif_object_unmap_handle(object);
}
return ret;
}
void
nvif_object_dtor(struct nvif_object *object)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_del del;
} args = {
.ioctl.type = NVIF_IOCTL_V0_DEL,
};
if (!nvif_object_constructed(object))
return;
nvif_object_unmap(object);
nvif_object_ioctl(object, &args, sizeof(args), NULL);
object->client = NULL;
}
int
nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle,
s32 oclass, void *data, u32 size, struct nvif_object *object)
{
struct {
struct nvif_ioctl_v0_hdr ioctl;
struct nvif_ioctl_new_v0 new;
} *args;
int ret = 0;
object->client = NULL;
object->name = name ? name : "nvifObject";
object->handle = handle;
object->oclass = oclass;
object->map.ptr = NULL;
object->map.size = 0;
if (parent) {
u32 args_size;
if (check_add_overflow(sizeof(*args), size, &args_size)) {
nvif_object_dtor(object);
return -ENOMEM;
}
args = kmalloc(args_size, GFP_KERNEL);
if (!args) {
nvif_object_dtor(object);
return -ENOMEM;
}
object->parent = parent->parent;
args->ioctl.version = 0;
args->ioctl.type = NVIF_IOCTL_V0_NEW;
args->new.version = 0;
args->new.object = nvif_handle(object);
args->new.handle = handle;
args->new.oclass = oclass;
memcpy(args->new.data, data, size);
ret = nvif_object_ioctl(parent, args, args_size, &object->priv);
memcpy(data, args->new.data, size);
kfree(args);
if (ret == 0)
object->client = parent->client;
}
if (ret)
nvif_object_dtor(object);
return ret;
}
@@ -0,0 +1,556 @@
/*
* Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/outp.h>
#include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h>
int
nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head,
u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn)
{
struct nvif_outp_dp_mst_vcpi_v0 args;
int ret;
args.version = 0;
args.head = head;
args.start_slot = start_slot;
args.num_slots = num_slots;
args.pbn = pbn;
args.aligned_pbn = aligned_pbn;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_VCPI, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
"[DP_MST_VCPI head:%d start_slot:%02x num_slots:%02x pbn:%04x aligned_pbn:%04x]",
args.head, args.start_slot, args.num_slots, args.pbn, args.aligned_pbn);
return ret;
}
int
nvif_outp_dp_mst_id_put(struct nvif_outp *outp, u32 id)
{
struct nvif_outp_dp_mst_id_get_v0 args;
int ret;
args.version = 0;
args.id = id;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_PUT, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_PUT id:%08x]", args.id);
return ret;
}
int
nvif_outp_dp_mst_id_get(struct nvif_outp *outp, u32 *id)
{
struct nvif_outp_dp_mst_id_get_v0 args;
int ret;
args.version = 0;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_GET, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_GET] id:%08x", args.id);
if (ret)
return ret;
*id = args.id;
return 0;
}
int
nvif_outp_dp_sst(struct nvif_outp *outp, int head, u32 watermark, u32 hblanksym, u32 vblanksym)
{
struct nvif_outp_dp_sst_v0 args;
int ret;
args.version = 0;
args.head = head;
args.watermark = watermark;
args.hblanksym = hblanksym;
args.vblanksym = vblanksym;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_SST, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
"[DP_SST head:%d watermark:%d hblanksym:%d vblanksym:%d]",
args.head, args.watermark, args.hblanksym, args.vblanksym);
return ret;
}
int
nvif_outp_dp_drive(struct nvif_outp *outp, u8 link_nr, u8 pe[4], u8 vs[4])
{
struct nvif_outp_dp_drive_v0 args;
int ret;
args.version = 0;
args.lanes = link_nr;
memcpy(args.pe, pe, sizeof(args.pe));
memcpy(args.vs, vs, sizeof(args.vs));
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_DRIVE, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DP_DRIVE lanes:%d]", args.lanes);
return ret;
}
int
nvif_outp_dp_train(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs,
u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain)
{
struct nvif_outp_dp_train_v0 args;
int ret;
args.version = 0;
args.retrain = retrain;
args.mst = mst;
args.lttprs = lttprs;
args.post_lt_adj = post_lt_adj;
args.link_nr = link_nr;
args.link_bw = link_bw;
memcpy(args.dpcd, dpcd, sizeof(args.dpcd));
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_TRAIN, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
"[DP_TRAIN retrain:%d mst:%d lttprs:%d post_lt_adj:%d nr:%d bw:%d]",
args.retrain, args.mst, args.lttprs, args.post_lt_adj, args.link_nr,
args.link_bw);
return ret;
}
int
nvif_outp_dp_rates(struct nvif_outp *outp, struct nvif_outp_dp_rate *rate, int rate_nr)
{
struct nvif_outp_dp_rates_v0 args;
int ret;
if (rate_nr > ARRAY_SIZE(args.rate))
return -EINVAL;
args.version = 0;
args.rates = rate_nr;
for (int i = 0; i < args.rates; i++, rate++) {
args.rate[i].dpcd = rate->dpcd;
args.rate[i].rate = rate->rate;
}
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RATES, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DP_RATES rates:%d]", args.rates);
return ret;
}
int
nvif_outp_dp_aux_xfer(struct nvif_outp *outp, u8 type, u8 *psize, u32 addr, u8 *data)
{
struct nvif_outp_dp_aux_xfer_v0 args;
u8 size = *psize;
int ret;
args.version = 0;
args.type = type;
args.size = size;
args.addr = addr;
memcpy(args.data, data, size);
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_XFER, &args, sizeof(args));
NVIF_DEBUG(&outp->object, "[DP_AUX_XFER type:%d size:%d addr:%05x] %d size:%d (ret: %d)",
args.type, size, args.addr, ret, args.size, ret);
if (ret < 0)
return ret;
*psize = args.size;
memcpy(data, args.data, size);
return ret;
}
int
nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable)
{
struct nvif_outp_dp_aux_pwr_v0 args;
int ret;
args.version = 0;
args.state = enable;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_PWR, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DP_AUX_PWR state:%d]", args.state);
return ret;
}
int
nvif_outp_hda_eld(struct nvif_outp *outp, int head, void *data, u32 size)
{
DEFINE_RAW_FLEX(struct nvif_outp_hda_eld_v0, mthd, data, 128);
int ret;
if (WARN_ON(size > __member_size(mthd->data)))
return -EINVAL;
mthd->version = 0;
mthd->head = head;
memcpy(mthd->data, data, size);
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, mthd, sizeof(*mthd) + size);
NVIF_ERRON(ret, &outp->object, "[HDA_ELD head:%d size:%d]", head, size);
return ret;
}
int
nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_v0 *args, u32 size)
{
int ret;
args->type = type;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INFOFRAME, args, sizeof(*args) + size);
NVIF_ERRON(ret, &outp->object, "[INFOFRAME type:%d size:%d]", type, size);
return ret;
}
int
nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey,
u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates)
{
struct nvif_outp_hdmi_v0 args;
int ret;
args.version = 0;
args.head = head;
args.enable = enable;
args.max_ac_packet = max_ac_packet;
args.rekey = rekey;
args.khz = khz;
args.scdc = scdc;
args.scdc_scrambling = scdc_scrambling;
args.scdc_low_rates = scdc_low_rates;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
"[HDMI head:%d enable:%d max_ac_packet:%d rekey:%d khz:%d scdc:%d "
"scdc_scrambling:%d scdc_low_rates:%d]",
args.head, args.enable, args.max_ac_packet, args.rekey, args.khz,
args.scdc, args.scdc_scrambling, args.scdc_low_rates);
return ret;
}
int
nvif_outp_lvds(struct nvif_outp *outp, bool dual, bool bpc8)
{
struct nvif_outp_lvds_v0 args;
int ret;
args.version = 0;
args.dual = dual;
args.bpc8 = bpc8;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LVDS, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[LVDS dual:%d 8bpc:%d]", args.dual, args.bpc8);
return ret;
}
int
nvif_outp_bl_set(struct nvif_outp *outp, int level)
{
struct nvif_outp_bl_set_v0 args;
int ret;
args.version = 0;
args.level = level;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_SET, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[BL_SET level:%d]", args.level);
return ret;
}
int
nvif_outp_bl_get(struct nvif_outp *outp)
{
struct nvif_outp_bl_get_v0 args;
int ret;
args.version = 0;
ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_GET, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[BL_GET level:%d]", args.level);
return ret ? ret : args.level;
}
void
nvif_outp_release(struct nvif_outp *outp)
{
int ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_RELEASE, NULL, 0);
NVIF_ERRON(ret, &outp->object, "[RELEASE]");
outp->or.id = -1;
}
static inline int
nvif_outp_acquire(struct nvif_outp *outp, u8 type, struct nvif_outp_acquire_v0 *args)
{
int ret;
args->version = 0;
args->type = type;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args));
if (ret)
return ret;
outp->or.id = args->or;
outp->or.link = args->link;
return 0;
}
int
nvif_outp_acquire_pior(struct nvif_outp *outp)
{
struct nvif_outp_acquire_v0 args;
int ret;
ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_PIOR, &args);
NVIF_ERRON(ret, &outp->object, "[ACQUIRE PIOR] or:%d", args.or);
return ret;
}
int
nvif_outp_acquire_sor(struct nvif_outp *outp, bool hda)
{
struct nvif_outp_acquire_v0 args;
int ret;
args.sor.hda = hda;
ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_SOR, &args);
NVIF_ERRON(ret, &outp->object, "[ACQUIRE SOR] or:%d link:%d", args.or, args.link);
return ret;
}
int
nvif_outp_acquire_dac(struct nvif_outp *outp)
{
struct nvif_outp_acquire_v0 args;
int ret;
ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DAC, &args);
NVIF_ERRON(ret, &outp->object, "[ACQUIRE DAC] or:%d", args.or);
return ret;
}
static int
nvif_outp_inherit(struct nvif_outp *outp,
u8 proto,
struct nvif_outp_inherit_v0 *args,
u8 *proto_out)
{
int ret;
args->version = 0;
args->proto = proto;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INHERIT, args, sizeof(*args));
if (ret)
return ret;
outp->or.id = args->or;
outp->or.link = args->link;
*proto_out = args->proto;
return 0;
}
int
nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out)
{
struct nvif_outp_inherit_v0 args;
int ret;
ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_LVDS, &args, proto_out);
NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:LVDS] ret:%d", ret);
return ret ?: args.head;
}
int
nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out)
{
struct nvif_outp_inherit_v0 args;
int ret;
ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_TMDS, &args, proto_out);
NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:TMDS] ret:%d", ret);
return ret ?: args.head;
}
int
nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out)
{
struct nvif_outp_inherit_v0 args;
int ret;
ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_DP, &args, proto_out);
NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:DP] ret:%d", ret);
// TODO: Get current link info
return ret ?: args.head;
}
int
nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out)
{
struct nvif_outp_inherit_v0 args;
int ret;
ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_RGB_CRT, &args, proto_out);
NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:RGB_CRT] ret:%d", ret);
return ret ?: args.head;
}
int
nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval)
{
struct nvif_outp_load_detect_v0 args;
int ret;
args.version = 0;
args.data = loadval;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LOAD_DETECT, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[LOAD_DETECT data:%08x] load:%02x", args.data, args.load);
return ret < 0 ? ret : args.load;
}
int
nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid)
{
struct nvif_outp_edid_get_v0 *args;
int ret;
args = kmalloc_obj(*args);
if (!args)
return -ENOMEM;
args->version = 0;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_EDID_GET, args, sizeof(*args));
NVIF_ERRON(ret, &outp->object, "[EDID_GET] size:%d", args->size);
if (ret)
goto done;
*pedid = kmemdup(args->data, args->size, GFP_KERNEL);
if (!*pedid) {
ret = -ENOMEM;
goto done;
}
ret = args->size;
done:
kfree(args);
return ret;
}
enum nvif_outp_detect_status
nvif_outp_detect(struct nvif_outp *outp)
{
struct nvif_outp_detect_v0 args;
int ret;
args.version = 0;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_DETECT, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[DETECT] status:%02x", args.status);
if (ret)
return UNKNOWN;
switch (args.status) {
case NVIF_OUTP_DETECT_V0_NOT_PRESENT: return NOT_PRESENT;
case NVIF_OUTP_DETECT_V0_PRESENT: return PRESENT;
case NVIF_OUTP_DETECT_V0_UNKNOWN: return UNKNOWN;
default:
WARN_ON(1);
break;
}
return UNKNOWN;
}
void
nvif_outp_dtor(struct nvif_outp *outp)
{
nvif_object_dtor(&outp->object);
}
int
nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_outp *outp)
{
struct nvif_outp_v0 args;
int ret;
args.version = 0;
args.id = id;
ret = nvif_object_ctor(&disp->object, name ?: "nvifOutp", id, NVIF_CLASS_OUTP,
&args, sizeof(args), &outp->object);
NVIF_ERRON(ret, &disp->object, "[NEW outp id:%d]", id);
if (ret)
return ret;
outp->id = args.id;
switch (args.type) {
case NVIF_OUTP_V0_TYPE_DAC : outp->info.type = NVIF_OUTP_DAC; break;
case NVIF_OUTP_V0_TYPE_SOR : outp->info.type = NVIF_OUTP_SOR; break;
case NVIF_OUTP_V0_TYPE_PIOR: outp->info.type = NVIF_OUTP_PIOR; break;
break;
default:
WARN_ON(1);
nvif_outp_dtor(outp);
return -EINVAL;
}
switch (args.proto) {
case NVIF_OUTP_V0_PROTO_RGB_CRT:
outp->info.proto = NVIF_OUTP_RGB_CRT;
outp->info.rgb_crt.freq_max = args.rgb_crt.freq_max;
break;
case NVIF_OUTP_V0_PROTO_TMDS:
outp->info.proto = NVIF_OUTP_TMDS;
outp->info.tmds.dual = args.tmds.dual;
break;
case NVIF_OUTP_V0_PROTO_LVDS:
outp->info.proto = NVIF_OUTP_LVDS;
outp->info.lvds.acpi_edid = args.lvds.acpi_edid;
break;
case NVIF_OUTP_V0_PROTO_DP:
outp->info.proto = NVIF_OUTP_DP;
outp->info.dp.aux = args.dp.aux;
outp->info.dp.mst = args.dp.mst;
outp->info.dp.increased_wm = args.dp.increased_wm;
outp->info.dp.link_nr = args.dp.link_nr;
outp->info.dp.link_bw = args.dp.link_bw;
break;
default:
WARN_ON(1);
nvif_outp_dtor(outp);
return -EINVAL;
}
outp->info.heads = args.heads;
outp->info.ddc = args.ddc;
outp->info.conn = args.conn;
outp->or.id = -1;
return 0;
}
@@ -0,0 +1,56 @@
/*
* Copyright 2020 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/timer.h>
#include <nvif/device.h>
s64
nvif_timer_wait_test(struct nvif_timer_wait *wait)
{
u64 time = nvif_device_time(wait->device);
if (wait->reads == 0) {
wait->time0 = time;
wait->time1 = time;
}
if (wait->time1 == time) {
if (WARN_ON(wait->reads++ == 16))
return -ETIMEDOUT;
} else {
wait->time1 = time;
wait->reads = 1;
}
if (wait->time1 - wait->time0 > wait->limit)
return -ETIMEDOUT;
return wait->time1 - wait->time0;
}
void
nvif_timer_wait_init(struct nvif_device *device, u64 nsec,
struct nvif_timer_wait *wait)
{
wait->device = device;
wait->limit = nsec;
wait->reads = 0;
}
@@ -0,0 +1,69 @@
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/user.h>
#include <nvif/device.h>
#include <nvif/class.h>
void
nvif_user_dtor(struct nvif_device *device)
{
if (device->user.func) {
nvif_object_dtor(&device->user.object);
device->user.func = NULL;
}
}
int
nvif_user_ctor(struct nvif_device *device, const char *name)
{
struct {
s32 oclass;
int version;
const struct nvif_user_func *func;
} users[] = {
{ BLACKWELL_USERMODE_A, -1, &nvif_userc361 },
{ HOPPER_USERMODE_A, -1, &nvif_userc361 },
{ AMPERE_USERMODE_A, -1, &nvif_userc361 },
{ TURING_USERMODE_A, -1, &nvif_userc361 },
{ VOLTA_USERMODE_A, -1, &nvif_userc361 },
{}
};
int cid, ret;
if (device->user.func)
return 0;
cid = nvif_mclass(&device->object, users);
if (cid < 0)
return cid;
ret = nvif_object_ctor(&device->object, name ? name : "nvifUsermode",
0, users[cid].oclass, NULL, 0,
&device->user.object);
if (ret)
return ret;
nvif_object_map(&device->user.object, NULL, 0);
device->user.func = users[cid].func;
return 0;
}
@@ -0,0 +1,47 @@
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/user.h>
static u64
nvif_userc361_time(struct nvif_user *user)
{
u32 hi, lo;
do {
hi = nvif_rd32(&user->object, 0x084);
lo = nvif_rd32(&user->object, 0x080);
} while (hi != nvif_rd32(&user->object, 0x084));
return ((u64)hi << 32 | lo);
}
static void
nvif_userc361_doorbell(struct nvif_user *user, u32 token)
{
nvif_wr32(&user->object, 0x90, token);
}
const struct nvif_user_func
nvif_userc361 = {
.doorbell = nvif_userc361_doorbell,
.time = nvif_userc361_time,
};
@@ -0,0 +1,263 @@
/*
* Copyright 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <nvif/vmm.h>
#include <nvif/mem.h>
#include <nvif/if000c.h>
int
nvif_vmm_unmap(struct nvif_vmm *vmm, u64 addr)
{
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_UNMAP,
&(struct nvif_vmm_unmap_v0) { .addr = addr },
sizeof(struct nvif_vmm_unmap_v0));
}
int
nvif_vmm_map(struct nvif_vmm *vmm, u64 addr, u64 size, void *argv, u32 argc,
struct nvif_mem *mem, u64 offset)
{
struct nvif_vmm_map_v0 *args;
u8 stack[48];
int ret;
if (sizeof(*args) + argc > sizeof(stack)) {
if (!(args = kmalloc(sizeof(*args) + argc, GFP_KERNEL)))
return -ENOMEM;
} else {
args = (void *)stack;
}
args->version = 0;
args->addr = addr;
args->size = size;
args->memory = nvif_handle(&mem->object);
args->offset = offset;
memcpy(args->data, argv, argc);
ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_MAP,
args, sizeof(*args) + argc);
if (args != (void *)stack)
kfree(args);
return ret;
}
void
nvif_vmm_put(struct nvif_vmm *vmm, struct nvif_vma *vma)
{
if (vma->size) {
WARN_ON(nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PUT,
&(struct nvif_vmm_put_v0) {
.addr = vma->addr,
}, sizeof(struct nvif_vmm_put_v0)));
vma->size = 0;
}
}
int
nvif_vmm_get(struct nvif_vmm *vmm, enum nvif_vmm_get type, bool sparse,
u8 page, u8 align, u64 size, struct nvif_vma *vma)
{
struct nvif_vmm_get_v0 args;
int ret;
args.version = vma->size = 0;
args.sparse = sparse;
args.page = page;
args.align = align;
args.size = size;
switch (type) {
case ADDR: args.type = NVIF_VMM_GET_V0_ADDR; break;
case PTES: args.type = NVIF_VMM_GET_V0_PTES; break;
case LAZY: args.type = NVIF_VMM_GET_V0_LAZY; break;
default:
WARN_ON(1);
return -EINVAL;
}
ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_GET,
&args, sizeof(args));
if (ret == 0) {
vma->addr = args.addr;
vma->size = args.size;
}
return ret;
}
int
nvif_vmm_raw_get(struct nvif_vmm *vmm, u64 addr, u64 size,
u8 shift)
{
struct nvif_vmm_raw_v0 args = {
.version = 0,
.op = NVIF_VMM_RAW_V0_GET,
.addr = addr,
.size = size,
.shift = shift,
};
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW,
&args, sizeof(args));
}
int
nvif_vmm_raw_put(struct nvif_vmm *vmm, u64 addr, u64 size, u8 shift)
{
struct nvif_vmm_raw_v0 args = {
.version = 0,
.op = NVIF_VMM_RAW_V0_PUT,
.addr = addr,
.size = size,
.shift = shift,
};
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW,
&args, sizeof(args));
}
int
nvif_vmm_raw_map(struct nvif_vmm *vmm, u64 addr, u64 size, u8 shift,
void *argv, u32 argc, struct nvif_mem *mem, u64 offset)
{
struct nvif_vmm_raw_v0 args = {
.version = 0,
.op = NVIF_VMM_RAW_V0_MAP,
.addr = addr,
.size = size,
.shift = shift,
.memory = nvif_handle(&mem->object),
.offset = offset,
.argv = (u64)(uintptr_t)argv,
.argc = argc,
};
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW,
&args, sizeof(args));
}
int
nvif_vmm_raw_unmap(struct nvif_vmm *vmm, u64 addr, u64 size,
u8 shift, bool sparse)
{
struct nvif_vmm_raw_v0 args = {
.version = 0,
.op = NVIF_VMM_RAW_V0_UNMAP,
.addr = addr,
.size = size,
.shift = shift,
.sparse = sparse,
};
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW,
&args, sizeof(args));
}
int
nvif_vmm_raw_sparse(struct nvif_vmm *vmm, u64 addr, u64 size, bool ref)
{
struct nvif_vmm_raw_v0 args = {
.version = 0,
.op = NVIF_VMM_RAW_V0_SPARSE,
.addr = addr,
.size = size,
.ref = ref,
};
return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_RAW,
&args, sizeof(args));
}
void
nvif_vmm_dtor(struct nvif_vmm *vmm)
{
kfree(vmm->page);
nvif_object_dtor(&vmm->object);
}
int
nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass,
enum nvif_vmm_type type, u64 addr, u64 size, void *argv, u32 argc,
struct nvif_vmm *vmm)
{
struct nvif_vmm_v0 *args;
u32 argn = sizeof(*args) + argc;
int ret = -ENOSYS, i;
vmm->object.client = NULL;
vmm->page = NULL;
if (!(args = kmalloc(argn, GFP_KERNEL)))
return -ENOMEM;
args->version = 0;
args->addr = addr;
args->size = size;
switch (type) {
case UNMANAGED: args->type = NVIF_VMM_V0_TYPE_UNMANAGED; break;
case MANAGED: args->type = NVIF_VMM_V0_TYPE_MANAGED; break;
case RAW: args->type = NVIF_VMM_V0_TYPE_RAW; break;
default:
WARN_ON(1);
ret = -EINVAL;
goto done;
}
memcpy(args->data, argv, argc);
ret = nvif_object_ctor(&mmu->object, name ? name : "nvifVmm", 0,
oclass, args, argn, &vmm->object);
if (ret)
goto done;
vmm->start = args->addr;
vmm->limit = args->size;
vmm->page_nr = args->page_nr;
vmm->page = kmalloc_objs(*vmm->page, vmm->page_nr);
if (!vmm->page) {
ret = -ENOMEM;
goto done;
}
for (i = 0; i < vmm->page_nr; i++) {
struct nvif_vmm_page_v0 args = { .index = i };
ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PAGE,
&args, sizeof(args));
if (ret)
break;
vmm->page[i].shift = args.shift;
vmm->page[i].sparse = args.sparse;
vmm->page[i].vram = args.vram;
vmm->page[i].host = args.host;
vmm->page[i].comp = args.comp;
}
done:
if (ret)
nvif_vmm_dtor(vmm);
kfree(args);
return ret;
}