drm/nouveau/fifo: allow direct access to channel control registers where possible

The indirect method has been left in-place here as a fallback path, as
it may not be possible to map the non-PAGE_SIZE aligned control areas
across some chipset+interface combinations.

This isn't a problem for the primary use-case where the core and drm
are linked together in kernel-land, but across a VM or (in the case
where it applies now) between the core in the kernel and a userspace
test tool.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2014-08-10 04:10:25 +10:00
Родитель bbf8906b2c
Коммит 6c6ae061b6
11 изменённых файлов: 38 добавлений и 9 удалений

Просмотреть файл

@ -103,15 +103,10 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
return -ENOSPC;
}
/* map fifo control registers */
chan->user = ioremap(nv_device_resource_start(device, bar) + addr +
(chan->chid * size), size);
if (!chan->user)
return -EFAULT;
nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
chan->addr = nv_device_resource_start(device, bar) +
addr + size * chan->chid;
chan->size = size;
nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
return 0;
}
@ -121,7 +116,8 @@ nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
unsigned long flags;
iounmap(chan->user);
if (chan->user)
iounmap(chan->user);
spin_lock_irqsave(&priv->lock, flags);
priv->channel[chan->chid] = NULL;
@ -139,10 +135,24 @@ _nouveau_fifo_channel_dtor(struct nouveau_object *object)
nouveau_fifo_channel_destroy(chan);
}
int
_nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size)
{
struct nouveau_fifo_chan *chan = (void *)object;
*addr = chan->addr;
*size = chan->size;
return 0;
}
u32
_nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr)
{
struct nouveau_fifo_chan *chan = (void *)object;
if (unlikely(!chan->user)) {
chan->user = ioremap(chan->addr, chan->size);
if (WARN_ON_ONCE(chan->user == NULL))
return 0;
}
return ioread32_native(chan->user + addr);
}
@ -150,6 +160,11 @@ void
_nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
{
struct nouveau_fifo_chan *chan = (void *)object;
if (unlikely(!chan->user)) {
chan->user = ioremap(chan->addr, chan->size);
if (WARN_ON_ONCE(chan->user == NULL))
return;
}
iowrite32_native(data, chan->user + addr);
}

Просмотреть файл

@ -252,6 +252,7 @@ nv04_fifo_ofuncs = {
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -110,6 +110,7 @@ nv10_fifo_ofuncs = {
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -117,6 +117,7 @@ nv17_fifo_ofuncs = {
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -236,6 +236,7 @@ nv40_fifo_ofuncs = {
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -363,6 +363,7 @@ nv50_fifo_ofuncs_dma = {
.dtor = nv50_fifo_chan_dtor,
.init = nv50_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
@ -373,6 +374,7 @@ nv50_fifo_ofuncs_ind = {
.dtor = nv50_fifo_chan_dtor,
.init = nv50_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -324,6 +324,7 @@ nv84_fifo_ofuncs_dma = {
.dtor = nv50_fifo_chan_dtor,
.init = nv84_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
@ -334,6 +335,7 @@ nv84_fifo_ofuncs_ind = {
.dtor = nv50_fifo_chan_dtor,
.init = nv84_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -302,6 +302,7 @@ nvc0_fifo_ofuncs = {
.dtor = _nouveau_fifo_channel_dtor,
.init = nvc0_fifo_chan_init,
.fini = nvc0_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -336,6 +336,7 @@ nve0_fifo_ofuncs = {
.dtor = _nouveau_fifo_channel_dtor,
.init = nve0_fifo_chan_init,
.fini = nve0_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};

Просмотреть файл

@ -10,6 +10,7 @@ struct nouveau_fifo_chan {
struct nouveau_dmaobj *pushdma;
struct nouveau_gpuobj *pushgpu;
void __iomem *user;
u64 addr;
u32 size;
u16 chid;
atomic_t refcnt; /* NV04_NVSW_SET_REF */
@ -40,6 +41,7 @@ void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
void _nouveau_fifo_channel_dtor(struct nouveau_object *);
int _nouveau_fifo_channel_map(struct nouveau_object *, u64 *, u32 *);
u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u64);
void _nouveau_fifo_channel_wr32(struct nouveau_object *, u64, u32);

Просмотреть файл

@ -291,6 +291,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
struct nv_dma_v0 args = {};
int ret, i;
nvif_object_map(chan->object);
/* allocate dma objects to cover all allowed vram, and gart */
if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {