int nouveau_client_create_(const char *name, u64 devname, const char *cfg, const char *dbg, int length, void **pobject) { struct nouveau_object *device; struct nouveau_client *client; int ret; device = (void *)nouveau_device_find(devname); if (!device) return -ENODEV; ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass, NV_CLIENT_CLASS, NULL, (1ULL << NVDEV_ENGINE_DEVICE), length, pobject); client = *pobject; if (ret) return ret; ret = nouveau_handle_create(nv_object(client), ~0, ~0, nv_object(client), &client->root); if (ret) return ret; /* prevent init/fini being called, os in in charge of this */ atomic_set(&nv_object(client)->usecount, 2); nouveau_object_ref(device, &client->device); snprintf(client->name, sizeof(client->name), "%s", name); client->debug = nouveau_dbgopt(dbg, "CLIENT"); return 0; }
int nv50_disp_chan_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, int chid, int length, void **pobject) { struct nv50_disp_base *base = (void *)parent; struct nv50_disp_chan *chan; int ret; if (base->chan & (1 << chid)) return -EBUSY; base->chan |= (1 << chid); ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, (1ULL << NVDEV_ENGINE_DMAOBJ), length, pobject); chan = *pobject; if (ret) return ret; chan->chid = chid; return 0; }
int nouveau_fifo_channel_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, int bar, u32 addr, u32 size, u32 pushbuf, u64 engmask, int len, void **ptr) { struct nouveau_device *device = nv_device(engine); struct nouveau_fifo *priv = (void *)engine; struct nouveau_fifo_chan *chan; struct nouveau_dmaeng *dmaeng; unsigned long flags; int ret; /* create base object class */ ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, engmask, len, ptr); chan = *ptr; if (ret) return ret; /* validate dma object representing push buffer */ chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf); if (!chan->pushdma) return -ENOENT; dmaeng = (void *)chan->pushdma->base.engine; switch (chan->pushdma->base.oclass->handle) { case NV_DMA_FROM_MEMORY_CLASS: case NV_DMA_IN_MEMORY_CLASS: break; default: return -EINVAL; } ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu); if (ret) return ret; /* find a free fifo channel */ spin_lock_irqsave(&priv->lock, flags); for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { if (!priv->channel[chan->chid]) { priv->channel[chan->chid] = nv_object(chan); break; } } spin_unlock_irqrestore(&priv->lock, flags); if (chan->chid == priv->max) { nv_error(priv, "no free channels\n"); return -ENOSPC; } /* map fifo control registers */ #ifdef __NetBSD__ if (bar == 0) { /* * We already map BAR 0 in the engine device base, so * grab a subregion of that. */ bus_space_tag_t mmiot = nv_subdev(device)->mmiot; bus_space_handle_t mmioh = nv_subdev(device)->mmioh; bus_size_t mmiosz = nv_subdev(device)->mmiosz; /* Check whether it lies inside the region. */ if (mmiosz < addr || mmiosz - addr < chan->chid*size || mmiosz - addr - chan->chid*size < size) { ret = EIO; nv_error(priv, "fifo channel out of range:" " addr 0x%"PRIxMAX " chid 0x%"PRIxMAX" size 0x%"PRIxMAX " mmiosz 0x%"PRIxMAX"\n", (uintmax_t)addr, (uintmax_t)chan->chid, (uintmax_t)size, (uintmax_t)mmiosz); return ret; } /* Grab a subregion. */ /* XXX errno NetBSD->Linux */ ret = -bus_space_subregion(mmiot, mmioh, (addr + chan->chid*size), size, &chan->bsh); if (ret) { nv_error(priv, "bus_space_subregion failed: %d\n", ret); return ret; } /* Success! No need to unmap a subregion. */ chan->mapped = false; chan->bst = mmiot; } else { chan->bst = nv_device_resource_tag(device, bar); /* XXX errno NetBSD->Linux */ ret = -bus_space_map(chan->bst, (nv_device_resource_start(device, bar) + addr + (chan->chid * size)), size, 0, &chan->bsh); if (ret) { nv_error(priv, "failed to map fifo channel:" " bar %d addr %"PRIxMAX" + %"PRIxMAX " + (%"PRIxMAX" * %"PRIxMAX") = %"PRIxMAX " size %"PRIxMAX": %d\n", bar, (uintmax_t)nv_device_resource_start(device, bar), (uintmax_t)addr, (uintmax_t)chan->chid, (uintmax_t)size, (uintmax_t)(nv_device_resource_start(device, bar) + addr + (chan->chid * size)), (uintmax_t)size, ret); return ret; } chan->mapped = true; } #else chan->user = ioremap(nv_device_resource_start(device, bar) + addr + (chan->chid * size), size); if (!chan->user) return -EFAULT; #endif nouveau_event_trigger(priv->cevent, 0); chan->size = size; return 0; }
int nouveau_fifo_channel_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, int bar, u32 addr, u32 size, u32 pushbuf, u64 engmask, int len, void **ptr) { struct nouveau_device *device = nv_device(engine); struct nouveau_fifo *priv = (void *)engine; struct nouveau_fifo_chan *chan; struct nouveau_dmaeng *dmaeng; unsigned long flags; int ret; /* create base object class */ ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, engmask, len, ptr); chan = *ptr; if (ret) return ret; /* validate dma object representing push buffer */ chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf); if (!chan->pushdma) return -ENOENT; dmaeng = (void *)chan->pushdma->base.engine; switch (chan->pushdma->base.oclass->handle) { case NV_DMA_FROM_MEMORY_CLASS: case NV_DMA_IN_MEMORY_CLASS: break; default: return -EINVAL; } ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu); if (ret) return ret; /* find a free fifo channel */ spin_lock_irqsave(&priv->lock, flags); for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { if (!priv->channel[chan->chid]) { priv->channel[chan->chid] = nv_object(chan); break; } } spin_unlock_irqrestore(&priv->lock, flags); if (chan->chid == priv->max) { nv_error(priv, "no free channels\n"); return -ENOSPC; } /* map fifo control registers */ #ifdef __NetBSD__ chan->bst = nv_device_resource_tag(device, bar); /* XXX errno NetBSD->Linux */ ret = -bus_space_map(chan->bst, nv_device_resource_start(device, bar) + addr + (chan->chid * size), size, 0, &chan->bsh); if (ret) return ret; chan->mapped = true; #else chan->user = ioremap(nv_device_resource_start(device, bar) + addr + (chan->chid * size), size); if (!chan->user) return -EFAULT; #endif nouveau_event_trigger(priv->cevent, 0); chan->size = size; return 0; }