static int nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) { union { struct nv50_disp_mthd_v0 v0; struct nv50_disp_mthd_v1 v1; } *args = data; struct nv50_disp_root *root = nv50_disp_root(object); struct nv50_disp *disp = root->disp; struct nvkm_outp *temp, *outp = NULL; struct nvkm_head *head; u16 type, mask = 0; int hidx, ret = -ENOSYS; if (mthd != NV50_DISP_MTHD) return -EINVAL; nvif_ioctl(object, "disp mthd size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; hidx = args->v0.head; } else if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) { nvif_ioctl(object, "disp mthd vers %d mthd %02x " "type %04x mask %04x\n", args->v1.version, args->v1.method, args->v1.hasht, args->v1.hashm); mthd = args->v1.method; type = args->v1.hasht; mask = args->v1.hashm; hidx = ffs((mask >> 8) & 0x0f) - 1; } else
int tu104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nvkm_object *parent = oclass->parent; union { struct volta_channel_gpfifo_a_v0 v0; } *args = data; int ret = -ENOSYS; nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " "ioffset %016llx ilength %08x " "runlist %016llx priv %d\n", args->v0.version, args->v0.vmm, args->v0.ioffset, args->v0.ilength, args->v0.runlist, args->v0.priv); if (args->v0.priv && !oclass->client->super) return -EINVAL; return gv100_fifo_gpfifo_new_(&tu104_fifo_gpfifo, fifo, &args->v0.runlist, &args->v0.chid, args->v0.vmm, args->v0.ioffset, args->v0.ilength, &args->v0.inst, args->v0.priv, &args->v0.token, oclass, pobject); } return ret; }
static int gv100_disp_wimm_new_(const struct nv50_disp_chan_func *func, const struct nv50_disp_chan_mthd *mthd, struct nv50_disp *disp, int chid, const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) { union { struct nvc37b_window_imm_channel_dma_v0 v0; } *args = argv; struct nvkm_object *parent = oclass->parent; int wndw, ret = -ENOSYS; u64 push; nvif_ioctl(parent, "create window imm channel dma size %d\n", argc); if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create window imm channel dma vers %d " "pushbuf %016llx index %d\n", args->v0.version, args->v0.pushbuf, args->v0.index); if (!(disp->wndw.mask & BIT(args->v0.index))) return -EINVAL; push = args->v0.pushbuf; wndw = args->v0.index; } else return ret; return nv50_disp_dmac_new_(func, mthd, disp, chid + wndw, wndw, push, oclass, pobject); }
static int nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { struct nv04_disp_root *root = nv04_disp_root(object); union { struct nv04_disp_mthd_v0 v0; } *args = data; struct nvkm_head *head; int id, ret = -ENOSYS; nvif_ioctl(object, "disp mthd size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; id = args->v0.head; } else return ret; if (!(head = nvkm_head_find(root->disp, id))) return -ENXIO; switch (mthd) { case NV04_DISP_SCANOUTPOS: return nvkm_head_mthd_scanoutpos(object, head, data, size); default: break; } return -EINVAL; }
int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0) { struct nvkm_device *device = disp->base.engine.subdev.device; const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); union { struct nv04_disp_scanoutpos_v0 v0; } *args = data; int ret; nvif_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); args->v0.vblanke = (blanke & 0xffff0000) >> 16; args->v0.hblanke = (blanke & 0x0000ffff); args->v0.vblanks = (blanks & 0xffff0000) >> 16; args->v0.hblanks = (blanks & 0x0000ffff); args->v0.vtotal = ( total & 0xffff0000) >> 16; args->v0.htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get()); args->v0.vline = /* vline read locks hline */ nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; } else
int nv50_dac_power(NV50_DISP_MTHD_V1) { struct nvkm_device *device = disp->base.engine.subdev.device; const u32 doff = outp->or * 0x800; union { struct nv50_disp_dac_pwr_v0 v0; } *args = data; u32 stat; int ret; nvif_ioctl(object, "disp dac pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " "vsync %d hsync %d\n", args->v0.version, args->v0.state, args->v0.data, args->v0.vsync, args->v0.hsync); stat = 0x00000040 * !args->v0.state; stat |= 0x00000010 * !args->v0.data; stat |= 0x00000004 * !args->v0.vsync; stat |= 0x00000001 * !args->v0.hsync; } else return ret; nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) break; );
static int nvkm_ioctl_ntfy_new(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_ntfy_new_v0 v0; } *args = data; struct nvkm_event *event; int ret; nvif_ioctl(object, "ntfy new size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "ntfy new vers %d event %02x\n", args->v0.version, args->v0.event); ret = nvkm_object_ntfy(object, args->v0.event, &event); if (ret == 0) { ret = nvkm_client_notify_new(object, event, data, size); if (ret >= 0) { args->v0.index = ret; ret = 0; } } } return ret; }
static int nvkm_ioctl_sclass(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_sclass_v0 v0; } *args = data; struct nvkm_oclass oclass; int ret, i = 0; nvif_ioctl(object, "sclass size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "sclass vers %d count %d\n", args->v0.version, args->v0.count); if (size != args->v0.count * sizeof(args->v0.oclass[0])) return -EINVAL; while (object->func->sclass && object->func->sclass(object, i, &oclass) >= 0) { if (i < args->v0.count) { args->v0.oclass[i].oclass = oclass.base.oclass; args->v0.oclass[i].minver = oclass.base.minver; args->v0.oclass[i].maxver = oclass.base.maxver; } i++; } args->v0.count = i; } return ret; }
int nv50_disp_base_new(const struct nv50_disp_dmac_func *func, const struct nv50_disp_chan_mthd *mthd, struct nv50_disp_root *root, int chid, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nv50_disp_base_channel_dma_v0 v0; } *args = data; struct nvkm_object *parent = oclass->parent; struct nv50_disp *disp = root->disp; int head, ret = -ENOSYS; u64 push; nvif_ioctl(parent, "create disp base channel dma size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp base channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; } else return ret; return nv50_disp_dmac_new_(func, mthd, root, chid + head, head, push, oclass, pobject); }
static int nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type, void *data, u32 size, u8 owner, u8 *route, u64 *token) { struct nvkm_object *object; int ret; if (handle) object = nvkm_client_search(client, handle); else object = &client->object; if (unlikely(!object)) { nvif_ioctl(&client->object, "object not found\n"); return -ENOENT; } if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) { nvif_ioctl(&client->object, "route != owner\n"); return -EACCES; } *route = object->route; *token = object->token; if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) { if (nvkm_ioctl_v0[type].version == 0) ret = nvkm_ioctl_v0[type].func(object, data, size); } return ret; }
int nvkm_ioctl(struct nvkm_client *client, bool supervisor, void *data, u32 size, void **hack) { struct nvkm_object *object = &client->object; union { struct nvif_ioctl_v0 v0; } *args = data; int ret; client->super = supervisor; nvif_ioctl(object, "size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "vers %d type %02x object %016llx owner %02x\n", args->v0.version, args->v0.type, args->v0.object, args->v0.owner); ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type, data, size, args->v0.owner, &args->v0.route, &args->v0.token); } nvif_ioctl(object, "return %d\n", ret); if (hack) { *hack = client->data; client->data = NULL; } client->super = false; return ret; }
int nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, const struct nv50_disp_chan_mthd *mthd, struct nv50_disp_root *root, int chid, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nv50_disp_overlay_v0 v0; } *args = data; struct nvkm_object *parent = oclass->parent; struct nv50_disp *disp = root->disp; int head, ret; nvif_ioctl(parent, "create disp overlay size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); if (args->v0.head > disp->base.head.nr) return -EINVAL; head = args->v0.head; } else return ret; return nv50_disp_chan_new_(func, mthd, root, chid + head, head, oclass, pobject); }
int nv50_pior_power(NV50_DISP_MTHD_V1) { struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = outp->or * 0x800; union { struct nv50_disp_pior_pwr_v0 v0; } *args = data; u32 ctrl, type; int ret; nvif_ioctl(object, "disp pior pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", args->v0.version, args->v0.state, args->v0.type); if (args->v0.type > 0x0f) return -EINVAL; ctrl = !!args->v0.state; type = args->v0.type; } else return ret; nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) break; );
static int nvkm_ioctl_wr(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_wr_v0 v0; } *args = data; int ret; nvif_ioctl(object, "wr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n", args->v0.version, args->v0.size, args->v0.addr, args->v0.data); } else return ret; switch (args->v0.size) { case 1: return nvkm_object_wr08(object, args->v0.addr, args->v0.data); case 2: return nvkm_object_wr16(object, args->v0.addr, args->v0.data); case 4: return nvkm_object_wr32(object, args->v0.addr, args->v0.data); default: break; } return -EINVAL; }
int nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, const struct nv50_disp_chan_mthd *mthd, struct nv50_disp_root *root, int ctrl, int user, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nv50_disp_overlay_v0 v0; } *args = data; struct nvkm_object *parent = oclass->parent; struct nv50_disp *disp = root->disp; int head, ret = -ENOSYS; nvif_ioctl(parent, "create disp overlay size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; head = args->v0.head; } else return ret; return nv50_disp_chan_new_(func, mthd, root, ctrl + head, user + head, head, oclass, pobject); }
static int nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nvkm_object *parent = oclass->parent; union { struct nv03_channel_dma_v0 v0; } *args = data; struct nv04_fifo *fifo = nv04_fifo(base); struct nv04_fifo_chan *chan = NULL; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; int ret; nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); if (!args->v0.pushbuf) return -EINVAL; } else return ret; if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) return -ENOMEM; *pobject = &chan->base.object; ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base, 0x1000, 0x1000, false, 0, args->v0.pushbuf, (1ULL << NVKM_ENGINE_DMAOBJ) | (1ULL << NVKM_ENGINE_GR) | (1ULL << NVKM_ENGINE_MPEG) | (1ULL << NVKM_ENGINE_SW), 0, 0xc00000, 0x1000, oclass, &chan->base); chan->fifo = fifo; if (ret) return ret; args->v0.chid = chan->base.chid; chan->ramfc = chan->base.chid * 128; nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); nvkm_done(imem->ramfc); return 0; }
int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) { struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); const u32 hdmi = (head * 0x400); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; u32 ctrl; int ret; nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; ctrl |= args->v0.max_ac_packet << 16; ctrl |= args->v0.rekey; } else return ret; if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); nvkm_wr32(device, 0x690008 + hdmi, 0x000d0282); nvkm_wr32(device, 0x69000c + hdmi, 0x0000006f); nvkm_wr32(device, 0x690010 + hdmi, 0x00000000); nvkm_wr32(device, 0x690014 + hdmi, 0x00000000); nvkm_wr32(device, 0x690018 + hdmi, 0x00000000); nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); /* ??? InfoFrame? */ nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010); nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000001); /* ??? */ nvkm_wr32(device, 0x690080 + hdmi, 0x82000000); /* HDMI_CTRL */ nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); return 0; }
static int nvkm_ioctl_unmap(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_unmap none; } *args = data; int ret; nvif_ioctl(object, "unmap size %d\n", size); if (nvif_unvers(args->none)) { nvif_ioctl(object, "unmap\n"); } return ret; }
static int nvkm_ioctl_nop(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_nop_v0 v0; } *args = data; int ret; nvif_ioctl(object, "nop size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "nop vers %lld\n", args->v0.version); args->v0.version = NVIF_VERSION_LATEST; } return ret; }
static int nvkm_ioctl_mthd(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_mthd_v0 v0; } *args = data; int ret; nvif_ioctl(object, "mthd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "mthd vers %d mthd %02x\n", args->v0.version, args->v0.method); ret = nvkm_object_mthd(object, args->v0.method, data, size); } return ret; }
static int nvkm_ioctl_del(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_del none; } *args = data; int ret; nvif_ioctl(object, "delete size %d\n", size); if (nvif_unvers(args->none)) { nvif_ioctl(object, "delete\n"); nvkm_object_fini(object, false); nvkm_object_del(&object); } return ret; }
static int nvkm_ioctl_map(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_map_v0 v0; } *args = data; int ret; nvif_ioctl(object, "map size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "map vers %d\n", args->v0.version); ret = nvkm_object_map(object, &args->v0.handle, &args->v0.length); } return ret; }
static int nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size) { struct nvkm_object *object = &udev->object; struct nvkm_device *device = udev->device; union { struct nv_device_time_v0 v0; } *args = data; int ret = -ENOSYS; nvif_ioctl(object, "device time size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(object, "device time vers %d\n", args->v0.version); args->v0.time = nvkm_timer_read(device->timer); } return ret; }
static int nvkm_ioctl_ntfy_put(struct nvkm_object *object, void *data, u32 size) { struct nvkm_client *client = object->client; union { struct nvif_ioctl_ntfy_put_v0 v0; } *args = data; int ret; nvif_ioctl(object, "ntfy put size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "ntfy put vers %d index %d\n", args->v0.version, args->v0.index); ret = nvkm_client_notify_put(client, args->v0.index); } return ret; }
int nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nv_device_v0 v0; } *args = data; struct nvkm_client *client = oclass->client; struct nvkm_object *parent = &client->object; const struct nvkm_object_func *func; struct nvkm_udevice *udev; int ret = -ENOSYS; nvif_ioctl(parent, "create device size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create device v%d device %016llx\n", args->v0.version, args->v0.device); } else return ret; /* give priviledged clients register access */ if (client->super) func = &nvkm_udevice_super; else func = &nvkm_udevice; if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL))) return -ENOMEM; nvkm_object_ctor(func, oclass, &udev->object); *pobject = &udev->object; /* find the device that matches what the client requested */ if (args->v0.device != ~0) udev->device = nvkm_device_find(args->v0.device); else udev->device = nvkm_device_find(client->device); if (!udev->device) return -ENODEV; return 0; }
static int nvkm_ioctl_rd(struct nvkm_object *object, void *data, u32 size) { union { struct nvif_ioctl_rd_v0 v0; } *args = data; union { u8 b08; u16 b16; u32 b32; } v; int ret; nvif_ioctl(object, "rd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "rd vers %d size %d addr %016llx\n", args->v0.version, args->v0.size, args->v0.addr); switch (args->v0.size) { case 1: ret = nvkm_object_rd08(object, args->v0.addr, &v.b08); args->v0.data = v.b08; break; case 2: ret = nvkm_object_rd16(object, args->v0.addr, &v.b16); args->v0.data = v.b16; break; case 4: ret = nvkm_object_rd32(object, args->v0.addr, &v.b32); args->v0.data = v.b32; break; default: ret = -EINVAL; break; } } return ret; }
static int gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { nvif_ioctl(object, "fermi mthd %08x\n", mthd); switch (mthd) { case FERMI_A_ZBC_COLOR: return gf100_fermi_mthd_zbc_color(object, data, size); case FERMI_A_ZBC_DEPTH: return gf100_fermi_mthd_zbc_depth(object, data, size); default: break; } return -EINVAL; }
static int nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { struct nvkm_udevice *udev = nvkm_udevice(object); nvif_ioctl(object, "device mthd %08x\n", mthd); switch (mthd) { case NV_DEVICE_V0_INFO: return nvkm_udevice_info(udev, data, size); case NV_DEVICE_V0_TIME: return nvkm_udevice_time(udev, data, size); default: break; } return -EINVAL; }
int gf100_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { union { struct gf100_dma_v0 v0; } *args; struct nvkm_object *parent = oclass->parent; struct gf100_dmaobj *dmaobj; u32 kind, user, unkn; int ret; if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) return -ENOMEM; *pdmaobj = &dmaobj->base; ret = nvkm_dmaobj_ctor(&gf100_dmaobj_func, dma, oclass, &data, &size, &dmaobj->base); if (ret) return ret; ret = -ENOSYS; args = data; nvif_ioctl(parent, "create gf100 dma size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n", args->v0.version, args->v0.priv, args->v0.kind); kind = args->v0.kind; user = args->v0.priv; unkn = 0; } else if (size == 0) { if (dmaobj->base.target != NV_MEM_TARGET_VM) { kind = GF100_DMA_V0_KIND_PITCH; user = GF100_DMA_V0_PRIV_US; unkn = 2; } else { kind = GF100_DMA_V0_KIND_VM; user = GF100_DMA_V0_PRIV_VM; unkn = 0; } } else return ret; if (user > 2) return -EINVAL; dmaobj->flags0 |= (kind << 22) | (user << 20) | oclass->base.oclass; dmaobj->flags5 |= (unkn << 16); switch (dmaobj->base.target) { case NV_MEM_TARGET_VM: dmaobj->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: dmaobj->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: dmaobj->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: dmaobj->flags0 |= 0x00030000; break; default: return -EINVAL; } switch (dmaobj->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: dmaobj->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: dmaobj->flags0 |= 0x00080000; break; } return 0; }
int nv50_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { union { struct nv50_dma_v0 v0; } *args; struct nvkm_object *parent = oclass->parent; struct nv50_dmaobj *dmaobj; u32 user, part, comp, kind; int ret; if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) return -ENOMEM; *pdmaobj = &dmaobj->base; ret = nvkm_dmaobj_ctor(&nv50_dmaobj_func, dma, oclass, &data, &size, &dmaobj->base); if (ret) return ret; args = data; nvif_ioctl(parent, "create nv50 dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create nv50 dma vers %d priv %d part %d " "comp %d kind %02x\n", args->v0.version, args->v0.priv, args->v0.part, args->v0.comp, args->v0.kind); user = args->v0.priv; part = args->v0.part; comp = args->v0.comp; kind = args->v0.kind; } else if (size == 0) { if (dmaobj->base.target != NV_MEM_TARGET_VM) { user = NV50_DMA_V0_PRIV_US; part = NV50_DMA_V0_PART_256; comp = NV50_DMA_V0_COMP_NONE; kind = NV50_DMA_V0_KIND_PITCH; } else { user = NV50_DMA_V0_PRIV_VM; part = NV50_DMA_V0_PART_VM; comp = NV50_DMA_V0_COMP_VM; kind = NV50_DMA_V0_KIND_VM; } } else return ret; if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) return -EINVAL; dmaobj->flags0 = (comp << 29) | (kind << 22) | (user << 20) | oclass->base.oclass; dmaobj->flags5 = (part << 16); switch (dmaobj->base.target) { case NV_MEM_TARGET_VM: dmaobj->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: dmaobj->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: dmaobj->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: dmaobj->flags0 |= 0x00030000; break; default: return -EINVAL; } switch (dmaobj->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: dmaobj->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: dmaobj->flags0 |= 0x00080000; break; default: return -EINVAL; } return 0; }