1c39f472eSBen Skeggs /* 2c39f472eSBen Skeggs * Copyright 2012 Red Hat Inc. 3c39f472eSBen Skeggs * 4c39f472eSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 5c39f472eSBen Skeggs * copy of this software and associated documentation files (the "Software"), 6c39f472eSBen Skeggs * to deal in the Software without restriction, including without limitation 7c39f472eSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8c39f472eSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the 9c39f472eSBen Skeggs * Software is furnished to do so, subject to the following conditions: 10c39f472eSBen Skeggs * 11c39f472eSBen Skeggs * The above copyright notice and this permission notice shall be included in 12c39f472eSBen Skeggs * all copies or substantial portions of the Software. 13c39f472eSBen Skeggs * 14c39f472eSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15c39f472eSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16c39f472eSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17c39f472eSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18c39f472eSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19c39f472eSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20c39f472eSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE. 21c39f472eSBen Skeggs * 22c39f472eSBen Skeggs * Authors: Ben Skeggs 23c39f472eSBen Skeggs */ 24c39f472eSBen Skeggs 25c39f472eSBen Skeggs #include <core/client.h> 26c39f472eSBen Skeggs #include <core/object.h> 27c39f472eSBen Skeggs #include <core/handle.h> 28c39f472eSBen Skeggs #include <core/event.h> 29c39f472eSBen Skeggs #include <nvif/unpack.h> 30c39f472eSBen Skeggs #include <nvif/class.h> 31c39f472eSBen Skeggs #include <nvif/event.h> 32c39f472eSBen Skeggs 33c39f472eSBen Skeggs #include <engine/dmaobj.h> 34c39f472eSBen Skeggs #include <engine/fifo.h> 35c39f472eSBen Skeggs 36c39f472eSBen Skeggs static int 37c39f472eSBen Skeggs nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size, 38c39f472eSBen Skeggs struct nvkm_notify *notify) 39c39f472eSBen Skeggs { 40c39f472eSBen Skeggs if (size == 0) { 41c39f472eSBen Skeggs notify->size = 0; 42c39f472eSBen Skeggs notify->types = 1; 43c39f472eSBen Skeggs notify->index = 0; 44c39f472eSBen Skeggs return 0; 45c39f472eSBen Skeggs } 46c39f472eSBen Skeggs return -ENOSYS; 47c39f472eSBen Skeggs } 48c39f472eSBen Skeggs 49c39f472eSBen Skeggs static const struct nvkm_event_func 50c39f472eSBen Skeggs nouveau_fifo_event_func = { 51c39f472eSBen Skeggs .ctor = nouveau_fifo_event_ctor, 52c39f472eSBen Skeggs }; 53c39f472eSBen Skeggs 54c39f472eSBen Skeggs int 55c39f472eSBen Skeggs nouveau_fifo_channel_create_(struct nouveau_object *parent, 56c39f472eSBen Skeggs struct nouveau_object *engine, 57c39f472eSBen Skeggs struct nouveau_oclass *oclass, 58c39f472eSBen Skeggs int bar, u32 addr, u32 size, u32 pushbuf, 59c39f472eSBen Skeggs u64 engmask, int len, void **ptr) 60c39f472eSBen Skeggs { 61c39f472eSBen Skeggs struct nouveau_device *device = nv_device(engine); 62c39f472eSBen Skeggs struct nouveau_fifo *priv = (void *)engine; 63c39f472eSBen Skeggs struct nouveau_fifo_chan *chan; 64c39f472eSBen Skeggs struct nouveau_dmaeng *dmaeng; 65c39f472eSBen Skeggs unsigned long flags; 66c39f472eSBen Skeggs int ret; 67c39f472eSBen Skeggs 68c39f472eSBen Skeggs /* create base object class */ 69c39f472eSBen Skeggs ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, 70c39f472eSBen Skeggs engmask, len, ptr); 71c39f472eSBen Skeggs chan = *ptr; 72c39f472eSBen Skeggs if (ret) 73c39f472eSBen Skeggs return ret; 74c39f472eSBen Skeggs 75c39f472eSBen Skeggs /* validate dma object representing push buffer */ 76c39f472eSBen Skeggs chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf); 77c39f472eSBen Skeggs if (!chan->pushdma) 78c39f472eSBen Skeggs return -ENOENT; 79c39f472eSBen Skeggs 80c39f472eSBen Skeggs dmaeng = (void *)chan->pushdma->base.engine; 81c39f472eSBen Skeggs switch (chan->pushdma->base.oclass->handle) { 82c39f472eSBen Skeggs case NV_DMA_FROM_MEMORY: 83c39f472eSBen Skeggs case NV_DMA_IN_MEMORY: 84c39f472eSBen Skeggs break; 85c39f472eSBen Skeggs default: 86c39f472eSBen Skeggs return -EINVAL; 87c39f472eSBen Skeggs } 88c39f472eSBen Skeggs 89c39f472eSBen Skeggs ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu); 90c39f472eSBen Skeggs if (ret) 91c39f472eSBen Skeggs return ret; 92c39f472eSBen Skeggs 93c39f472eSBen Skeggs /* find a free fifo channel */ 94c39f472eSBen Skeggs spin_lock_irqsave(&priv->lock, flags); 95c39f472eSBen Skeggs for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { 96c39f472eSBen Skeggs if (!priv->channel[chan->chid]) { 97c39f472eSBen Skeggs priv->channel[chan->chid] = nv_object(chan); 98c39f472eSBen Skeggs break; 99c39f472eSBen Skeggs } 100c39f472eSBen Skeggs } 101c39f472eSBen Skeggs spin_unlock_irqrestore(&priv->lock, flags); 102c39f472eSBen Skeggs 103c39f472eSBen Skeggs if (chan->chid == priv->max) { 104c39f472eSBen Skeggs nv_error(priv, "no free channels\n"); 105c39f472eSBen Skeggs return -ENOSPC; 106c39f472eSBen Skeggs } 107c39f472eSBen Skeggs 108c39f472eSBen Skeggs chan->addr = nv_device_resource_start(device, bar) + 109c39f472eSBen Skeggs addr + size * chan->chid; 110c39f472eSBen Skeggs chan->size = size; 111c39f472eSBen Skeggs nvkm_event_send(&priv->cevent, 1, 0, NULL, 0); 112c39f472eSBen Skeggs return 0; 113c39f472eSBen Skeggs } 114c39f472eSBen Skeggs 115c39f472eSBen Skeggs void 116c39f472eSBen Skeggs nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan) 117c39f472eSBen Skeggs { 118c39f472eSBen Skeggs struct nouveau_fifo *priv = (void *)nv_object(chan)->engine; 119c39f472eSBen Skeggs unsigned long flags; 120c39f472eSBen Skeggs 121c39f472eSBen Skeggs if (chan->user) 122c39f472eSBen Skeggs iounmap(chan->user); 123c39f472eSBen Skeggs 124c39f472eSBen Skeggs spin_lock_irqsave(&priv->lock, flags); 125c39f472eSBen Skeggs priv->channel[chan->chid] = NULL; 126c39f472eSBen Skeggs spin_unlock_irqrestore(&priv->lock, flags); 127c39f472eSBen Skeggs 128c39f472eSBen Skeggs nouveau_gpuobj_ref(NULL, &chan->pushgpu); 129c39f472eSBen Skeggs nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma); 130c39f472eSBen Skeggs nouveau_namedb_destroy(&chan->namedb); 131c39f472eSBen Skeggs } 132c39f472eSBen Skeggs 133c39f472eSBen Skeggs void 134c39f472eSBen Skeggs _nouveau_fifo_channel_dtor(struct nouveau_object *object) 135c39f472eSBen Skeggs { 136c39f472eSBen Skeggs struct nouveau_fifo_chan *chan = (void *)object; 137c39f472eSBen Skeggs nouveau_fifo_channel_destroy(chan); 138c39f472eSBen Skeggs } 139c39f472eSBen Skeggs 140c39f472eSBen Skeggs int 141c39f472eSBen Skeggs _nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size) 142c39f472eSBen Skeggs { 143c39f472eSBen Skeggs struct nouveau_fifo_chan *chan = (void *)object; 144c39f472eSBen Skeggs *addr = chan->addr; 145c39f472eSBen Skeggs *size = chan->size; 146c39f472eSBen Skeggs return 0; 147c39f472eSBen Skeggs } 148c39f472eSBen Skeggs 149c39f472eSBen Skeggs u32 150c39f472eSBen Skeggs _nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr) 151c39f472eSBen Skeggs { 152c39f472eSBen Skeggs struct nouveau_fifo_chan *chan = (void *)object; 153c39f472eSBen Skeggs if (unlikely(!chan->user)) { 154c39f472eSBen Skeggs chan->user = ioremap(chan->addr, chan->size); 155c39f472eSBen Skeggs if (WARN_ON_ONCE(chan->user == NULL)) 156c39f472eSBen Skeggs return 0; 157c39f472eSBen Skeggs } 158c39f472eSBen Skeggs return ioread32_native(chan->user + addr); 159c39f472eSBen Skeggs } 160c39f472eSBen Skeggs 161c39f472eSBen Skeggs void 162c39f472eSBen Skeggs _nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data) 163c39f472eSBen Skeggs { 164c39f472eSBen Skeggs struct nouveau_fifo_chan *chan = (void *)object; 165c39f472eSBen Skeggs if (unlikely(!chan->user)) { 166c39f472eSBen Skeggs chan->user = ioremap(chan->addr, chan->size); 167c39f472eSBen Skeggs if (WARN_ON_ONCE(chan->user == NULL)) 168c39f472eSBen Skeggs return; 169c39f472eSBen Skeggs } 170c39f472eSBen Skeggs iowrite32_native(data, chan->user + addr); 171c39f472eSBen Skeggs } 172c39f472eSBen Skeggs 173c39f472eSBen Skeggs int 174c39f472eSBen Skeggs nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size, 175c39f472eSBen Skeggs struct nvkm_notify *notify) 176c39f472eSBen Skeggs { 177c39f472eSBen Skeggs union { 178c39f472eSBen Skeggs struct nvif_notify_uevent_req none; 179c39f472eSBen Skeggs } *req = data; 180c39f472eSBen Skeggs int ret; 181c39f472eSBen Skeggs 182c39f472eSBen Skeggs if (nvif_unvers(req->none)) { 183c39f472eSBen Skeggs notify->size = sizeof(struct nvif_notify_uevent_rep); 184c39f472eSBen Skeggs notify->types = 1; 185c39f472eSBen Skeggs notify->index = 0; 186c39f472eSBen Skeggs } 187c39f472eSBen Skeggs 188c39f472eSBen Skeggs return ret; 189c39f472eSBen Skeggs } 190c39f472eSBen Skeggs 191c39f472eSBen Skeggs void 192c39f472eSBen Skeggs nouveau_fifo_uevent(struct nouveau_fifo *fifo) 193c39f472eSBen Skeggs { 194c39f472eSBen Skeggs struct nvif_notify_uevent_rep rep = { 195c39f472eSBen Skeggs }; 196c39f472eSBen Skeggs nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); 197c39f472eSBen Skeggs } 198c39f472eSBen Skeggs 199c39f472eSBen Skeggs int 200c39f472eSBen Skeggs _nouveau_fifo_channel_ntfy(struct nouveau_object *object, u32 type, 201c39f472eSBen Skeggs struct nvkm_event **event) 202c39f472eSBen Skeggs { 203c39f472eSBen Skeggs struct nouveau_fifo *fifo = (void *)object->engine; 204c39f472eSBen Skeggs switch (type) { 205c39f472eSBen Skeggs case G82_CHANNEL_DMA_V0_NTFY_UEVENT: 206c39f472eSBen Skeggs if (nv_mclass(object) >= G82_CHANNEL_DMA) { 207c39f472eSBen Skeggs *event = &fifo->uevent; 208c39f472eSBen Skeggs return 0; 209c39f472eSBen Skeggs } 210c39f472eSBen Skeggs break; 211c39f472eSBen Skeggs default: 212c39f472eSBen Skeggs break; 213c39f472eSBen Skeggs } 214c39f472eSBen Skeggs return -EINVAL; 215c39f472eSBen Skeggs } 216c39f472eSBen Skeggs 217c39f472eSBen Skeggs static int 218c39f472eSBen Skeggs nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object) 219c39f472eSBen Skeggs { 220c39f472eSBen Skeggs int engidx = nv_hclass(priv) & 0xff; 221c39f472eSBen Skeggs 222c39f472eSBen Skeggs while (object && object->parent) { 223c39f472eSBen Skeggs if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && 224c39f472eSBen Skeggs (nv_hclass(object->parent) & 0xff) == engidx) 225c39f472eSBen Skeggs return nouveau_fifo_chan(object)->chid; 226c39f472eSBen Skeggs object = object->parent; 227c39f472eSBen Skeggs } 228c39f472eSBen Skeggs 229c39f472eSBen Skeggs return -1; 230c39f472eSBen Skeggs } 231c39f472eSBen Skeggs 232c39f472eSBen Skeggs const char * 233c39f472eSBen Skeggs nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid) 234c39f472eSBen Skeggs { 235c39f472eSBen Skeggs struct nouveau_fifo_chan *chan = NULL; 236c39f472eSBen Skeggs unsigned long flags; 237c39f472eSBen Skeggs 238c39f472eSBen Skeggs spin_lock_irqsave(&fifo->lock, flags); 239c39f472eSBen Skeggs if (chid >= fifo->min && chid <= fifo->max) 240c39f472eSBen Skeggs chan = (void *)fifo->channel[chid]; 241c39f472eSBen Skeggs spin_unlock_irqrestore(&fifo->lock, flags); 242c39f472eSBen Skeggs 243c39f472eSBen Skeggs return nouveau_client_name(chan); 244c39f472eSBen Skeggs } 245c39f472eSBen Skeggs 246c39f472eSBen Skeggs void 247c39f472eSBen Skeggs nouveau_fifo_destroy(struct nouveau_fifo *priv) 248c39f472eSBen Skeggs { 249c39f472eSBen Skeggs kfree(priv->channel); 250c39f472eSBen Skeggs nvkm_event_fini(&priv->uevent); 251c39f472eSBen Skeggs nvkm_event_fini(&priv->cevent); 252c39f472eSBen Skeggs nouveau_engine_destroy(&priv->base); 253c39f472eSBen Skeggs } 254c39f472eSBen Skeggs 255c39f472eSBen Skeggs int 256c39f472eSBen Skeggs nouveau_fifo_create_(struct nouveau_object *parent, 257c39f472eSBen Skeggs struct nouveau_object *engine, 258c39f472eSBen Skeggs struct nouveau_oclass *oclass, 259c39f472eSBen Skeggs int min, int max, int length, void **pobject) 260c39f472eSBen Skeggs { 261c39f472eSBen Skeggs struct nouveau_fifo *priv; 262c39f472eSBen Skeggs int ret; 263c39f472eSBen Skeggs 264c39f472eSBen Skeggs ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO", 265c39f472eSBen Skeggs "fifo", length, pobject); 266c39f472eSBen Skeggs priv = *pobject; 267c39f472eSBen Skeggs if (ret) 268c39f472eSBen Skeggs return ret; 269c39f472eSBen Skeggs 270c39f472eSBen Skeggs priv->min = min; 271c39f472eSBen Skeggs priv->max = max; 272c39f472eSBen Skeggs priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL); 273c39f472eSBen Skeggs if (!priv->channel) 274c39f472eSBen Skeggs return -ENOMEM; 275c39f472eSBen Skeggs 276c39f472eSBen Skeggs ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent); 277c39f472eSBen Skeggs if (ret) 278c39f472eSBen Skeggs return ret; 279c39f472eSBen Skeggs 280c39f472eSBen Skeggs priv->chid = nouveau_fifo_chid; 281c39f472eSBen Skeggs spin_lock_init(&priv->lock); 282c39f472eSBen Skeggs return 0; 283c39f472eSBen Skeggs } 284