1*a04d0423SBen Skeggs /* 2*a04d0423SBen Skeggs * Copyright 2014 Red Hat Inc. 3*a04d0423SBen Skeggs * 4*a04d0423SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 5*a04d0423SBen Skeggs * copy of this software and associated documentation files (the "Software"), 6*a04d0423SBen Skeggs * to deal in the Software without restriction, including without limitation 7*a04d0423SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*a04d0423SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the 9*a04d0423SBen Skeggs * Software is furnished to do so, subject to the following conditions: 10*a04d0423SBen Skeggs * 11*a04d0423SBen Skeggs * The above copyright notice and this permission notice shall be included in 12*a04d0423SBen Skeggs * all copies or substantial portions of the Software. 13*a04d0423SBen Skeggs * 14*a04d0423SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*a04d0423SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*a04d0423SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17*a04d0423SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18*a04d0423SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19*a04d0423SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20*a04d0423SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE. 21*a04d0423SBen Skeggs * 22*a04d0423SBen Skeggs * Authors: Ben Skeggs <bskeggs@redhat.com> 23*a04d0423SBen Skeggs */ 24*a04d0423SBen Skeggs 25*a04d0423SBen Skeggs #include "object.h" 26*a04d0423SBen Skeggs #include "client.h" 27*a04d0423SBen Skeggs #include "driver.h" 28*a04d0423SBen Skeggs #include "ioctl.h" 29*a04d0423SBen Skeggs 30*a04d0423SBen Skeggs int 31*a04d0423SBen Skeggs nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) 32*a04d0423SBen Skeggs { 33*a04d0423SBen Skeggs struct nvif_client *client = nvif_client(object); 34*a04d0423SBen Skeggs union { 35*a04d0423SBen Skeggs struct nvif_ioctl_v0 v0; 36*a04d0423SBen Skeggs } *args = data; 37*a04d0423SBen Skeggs 38*a04d0423SBen Skeggs if (size >= sizeof(*args) && args->v0.version == 0) { 39*a04d0423SBen Skeggs args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; 40*a04d0423SBen Skeggs args->v0.path_nr = 0; 41*a04d0423SBen Skeggs while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) { 42*a04d0423SBen Skeggs args->v0.path[args->v0.path_nr++] = object->handle; 43*a04d0423SBen Skeggs if (object->parent == object) 44*a04d0423SBen Skeggs break; 45*a04d0423SBen Skeggs object = object->parent; 46*a04d0423SBen Skeggs } 47*a04d0423SBen Skeggs } else 48*a04d0423SBen Skeggs return -ENOSYS; 49*a04d0423SBen Skeggs 50*a04d0423SBen Skeggs return client->driver->ioctl(client->base.priv, client->super, data, size, hack); 51*a04d0423SBen Skeggs } 52*a04d0423SBen Skeggs 53*a04d0423SBen Skeggs int 54*a04d0423SBen Skeggs nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count) 55*a04d0423SBen Skeggs { 56*a04d0423SBen Skeggs struct { 57*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 58*a04d0423SBen Skeggs struct nvif_ioctl_sclass_v0 sclass; 59*a04d0423SBen Skeggs } *args; 60*a04d0423SBen Skeggs u32 size = count * sizeof(args->sclass.oclass[0]); 61*a04d0423SBen Skeggs int ret; 62*a04d0423SBen Skeggs 63*a04d0423SBen Skeggs if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) 64*a04d0423SBen Skeggs return -ENOMEM; 65*a04d0423SBen Skeggs args->ioctl.version = 0; 66*a04d0423SBen Skeggs args->ioctl.type = NVIF_IOCTL_V0_SCLASS; 67*a04d0423SBen Skeggs args->sclass.version = 0; 68*a04d0423SBen Skeggs args->sclass.count = count; 69*a04d0423SBen Skeggs 70*a04d0423SBen Skeggs memcpy(args->sclass.oclass, oclass, size); 71*a04d0423SBen Skeggs ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); 72*a04d0423SBen Skeggs ret = ret ? ret : args->sclass.count; 73*a04d0423SBen Skeggs memcpy(oclass, args->sclass.oclass, size); 74*a04d0423SBen Skeggs kfree(args); 75*a04d0423SBen Skeggs return ret; 76*a04d0423SBen Skeggs } 77*a04d0423SBen Skeggs 78*a04d0423SBen Skeggs u32 79*a04d0423SBen Skeggs nvif_object_rd(struct nvif_object *object, int size, u64 addr) 80*a04d0423SBen Skeggs { 81*a04d0423SBen Skeggs struct { 82*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 83*a04d0423SBen Skeggs struct nvif_ioctl_rd_v0 rd; 84*a04d0423SBen Skeggs } args = { 85*a04d0423SBen Skeggs .ioctl.type = NVIF_IOCTL_V0_RD, 86*a04d0423SBen Skeggs .rd.size = size, 87*a04d0423SBen Skeggs .rd.addr = addr, 88*a04d0423SBen Skeggs }; 89*a04d0423SBen Skeggs int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); 90*a04d0423SBen Skeggs if (ret) { 91*a04d0423SBen Skeggs /*XXX: warn? */ 92*a04d0423SBen Skeggs return 0; 93*a04d0423SBen Skeggs } 94*a04d0423SBen Skeggs return args.rd.data; 95*a04d0423SBen Skeggs } 96*a04d0423SBen Skeggs 97*a04d0423SBen Skeggs void 98*a04d0423SBen Skeggs nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data) 99*a04d0423SBen Skeggs { 100*a04d0423SBen Skeggs struct { 101*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 102*a04d0423SBen Skeggs struct nvif_ioctl_wr_v0 wr; 103*a04d0423SBen Skeggs } args = { 104*a04d0423SBen Skeggs .ioctl.type = NVIF_IOCTL_V0_WR, 105*a04d0423SBen Skeggs .wr.size = size, 106*a04d0423SBen Skeggs .wr.addr = addr, 107*a04d0423SBen Skeggs .wr.data = data, 108*a04d0423SBen Skeggs }; 109*a04d0423SBen Skeggs int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); 110*a04d0423SBen Skeggs if (ret) { 111*a04d0423SBen Skeggs /*XXX: warn? */ 112*a04d0423SBen Skeggs } 113*a04d0423SBen Skeggs } 114*a04d0423SBen Skeggs 115*a04d0423SBen Skeggs int 116*a04d0423SBen Skeggs nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size) 117*a04d0423SBen Skeggs { 118*a04d0423SBen Skeggs struct { 119*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 120*a04d0423SBen Skeggs struct nvif_ioctl_mthd_v0 mthd; 121*a04d0423SBen Skeggs } *args; 122*a04d0423SBen Skeggs u8 stack[128]; 123*a04d0423SBen Skeggs int ret; 124*a04d0423SBen Skeggs 125*a04d0423SBen Skeggs if (sizeof(*args) + size > sizeof(stack)) { 126*a04d0423SBen Skeggs if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) 127*a04d0423SBen Skeggs return -ENOMEM; 128*a04d0423SBen Skeggs } else { 129*a04d0423SBen Skeggs args = (void *)stack; 130*a04d0423SBen Skeggs } 131*a04d0423SBen Skeggs args->ioctl.version = 0; 132*a04d0423SBen Skeggs args->ioctl.type = NVIF_IOCTL_V0_MTHD; 133*a04d0423SBen Skeggs args->mthd.version = 0; 134*a04d0423SBen Skeggs args->mthd.method = mthd; 135*a04d0423SBen Skeggs 136*a04d0423SBen Skeggs memcpy(args->mthd.data, data, size); 137*a04d0423SBen Skeggs ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); 138*a04d0423SBen Skeggs memcpy(data, args->mthd.data, size); 139*a04d0423SBen Skeggs if (args != (void *)stack) 140*a04d0423SBen Skeggs kfree(args); 141*a04d0423SBen Skeggs return ret; 142*a04d0423SBen Skeggs } 143*a04d0423SBen Skeggs 144*a04d0423SBen Skeggs void 145*a04d0423SBen Skeggs nvif_object_unmap(struct nvif_object *object) 146*a04d0423SBen Skeggs { 147*a04d0423SBen Skeggs if (object->map.size) { 148*a04d0423SBen Skeggs struct nvif_client *client = nvif_client(object); 149*a04d0423SBen Skeggs struct { 150*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 151*a04d0423SBen Skeggs struct nvif_ioctl_unmap unmap; 152*a04d0423SBen Skeggs } args = { 153*a04d0423SBen Skeggs .ioctl.type = NVIF_IOCTL_V0_UNMAP, 154*a04d0423SBen Skeggs }; 155*a04d0423SBen Skeggs 156*a04d0423SBen Skeggs if (object->map.ptr) { 157*a04d0423SBen Skeggs client->driver->unmap(client, object->map.ptr, 158*a04d0423SBen Skeggs object->map.size); 159*a04d0423SBen Skeggs object->map.ptr = NULL; 160*a04d0423SBen Skeggs } 161*a04d0423SBen Skeggs 162*a04d0423SBen Skeggs nvif_object_ioctl(object, &args, sizeof(args), NULL); 163*a04d0423SBen Skeggs object->map.size = 0; 164*a04d0423SBen Skeggs } 165*a04d0423SBen Skeggs } 166*a04d0423SBen Skeggs 167*a04d0423SBen Skeggs int 168*a04d0423SBen Skeggs nvif_object_map(struct nvif_object *object) 169*a04d0423SBen Skeggs { 170*a04d0423SBen Skeggs struct nvif_client *client = nvif_client(object); 171*a04d0423SBen Skeggs struct { 172*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 173*a04d0423SBen Skeggs struct nvif_ioctl_map_v0 map; 174*a04d0423SBen Skeggs } args = { 175*a04d0423SBen Skeggs .ioctl.type = NVIF_IOCTL_V0_MAP, 176*a04d0423SBen Skeggs }; 177*a04d0423SBen Skeggs int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); 178*a04d0423SBen Skeggs if (ret == 0) { 179*a04d0423SBen Skeggs object->map.size = args.map.length; 180*a04d0423SBen Skeggs object->map.ptr = client->driver->map(client, args.map.handle, 181*a04d0423SBen Skeggs object->map.size); 182*a04d0423SBen Skeggs if (ret = -ENOMEM, object->map.ptr) 183*a04d0423SBen Skeggs return 0; 184*a04d0423SBen Skeggs nvif_object_unmap(object); 185*a04d0423SBen Skeggs } 186*a04d0423SBen Skeggs return ret; 187*a04d0423SBen Skeggs } 188*a04d0423SBen Skeggs 189*a04d0423SBen Skeggs struct ctor { 190*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 191*a04d0423SBen Skeggs struct nvif_ioctl_new_v0 new; 192*a04d0423SBen Skeggs }; 193*a04d0423SBen Skeggs 194*a04d0423SBen Skeggs void 195*a04d0423SBen Skeggs nvif_object_fini(struct nvif_object *object) 196*a04d0423SBen Skeggs { 197*a04d0423SBen Skeggs struct ctor *ctor = container_of(object->data, typeof(*ctor), new.data); 198*a04d0423SBen Skeggs if (object->parent) { 199*a04d0423SBen Skeggs struct { 200*a04d0423SBen Skeggs struct nvif_ioctl_v0 ioctl; 201*a04d0423SBen Skeggs struct nvif_ioctl_del del; 202*a04d0423SBen Skeggs } args = { 203*a04d0423SBen Skeggs .ioctl.type = NVIF_IOCTL_V0_DEL, 204*a04d0423SBen Skeggs }; 205*a04d0423SBen Skeggs 206*a04d0423SBen Skeggs nvif_object_unmap(object); 207*a04d0423SBen Skeggs nvif_object_ioctl(object, &args, sizeof(args), NULL); 208*a04d0423SBen Skeggs if (object->data) { 209*a04d0423SBen Skeggs object->size = 0; 210*a04d0423SBen Skeggs object->data = NULL; 211*a04d0423SBen Skeggs kfree(ctor); 212*a04d0423SBen Skeggs } 213*a04d0423SBen Skeggs nvif_object_ref(NULL, &object->parent); 214*a04d0423SBen Skeggs } 215*a04d0423SBen Skeggs } 216*a04d0423SBen Skeggs 217*a04d0423SBen Skeggs int 218*a04d0423SBen Skeggs nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *), 219*a04d0423SBen Skeggs u32 handle, u32 oclass, void *data, u32 size, 220*a04d0423SBen Skeggs struct nvif_object *object) 221*a04d0423SBen Skeggs { 222*a04d0423SBen Skeggs struct ctor *ctor; 223*a04d0423SBen Skeggs int ret = 0; 224*a04d0423SBen Skeggs 225*a04d0423SBen Skeggs object->parent = NULL; 226*a04d0423SBen Skeggs object->object = object; 227*a04d0423SBen Skeggs nvif_object_ref(parent, &object->parent); 228*a04d0423SBen Skeggs kref_init(&object->refcount); 229*a04d0423SBen Skeggs object->handle = handle; 230*a04d0423SBen Skeggs object->oclass = oclass; 231*a04d0423SBen Skeggs object->data = NULL; 232*a04d0423SBen Skeggs object->size = 0; 233*a04d0423SBen Skeggs object->dtor = dtor; 234*a04d0423SBen Skeggs object->map.ptr = NULL; 235*a04d0423SBen Skeggs object->map.size = 0; 236*a04d0423SBen Skeggs 237*a04d0423SBen Skeggs if (object->parent) { 238*a04d0423SBen Skeggs if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) { 239*a04d0423SBen Skeggs nvif_object_fini(object); 240*a04d0423SBen Skeggs return -ENOMEM; 241*a04d0423SBen Skeggs } 242*a04d0423SBen Skeggs object->data = ctor->new.data; 243*a04d0423SBen Skeggs object->size = size; 244*a04d0423SBen Skeggs memcpy(object->data, data, size); 245*a04d0423SBen Skeggs 246*a04d0423SBen Skeggs ctor->ioctl.version = 0; 247*a04d0423SBen Skeggs ctor->ioctl.type = NVIF_IOCTL_V0_NEW; 248*a04d0423SBen Skeggs ctor->new.version = 0; 249*a04d0423SBen Skeggs ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF; 250*a04d0423SBen Skeggs ctor->new.token = (unsigned long)(void *)object; 251*a04d0423SBen Skeggs ctor->new.handle = handle; 252*a04d0423SBen Skeggs ctor->new.oclass = oclass; 253*a04d0423SBen Skeggs 254*a04d0423SBen Skeggs ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) + 255*a04d0423SBen Skeggs object->size, &object->priv); 256*a04d0423SBen Skeggs } 257*a04d0423SBen Skeggs 258*a04d0423SBen Skeggs if (ret) 259*a04d0423SBen Skeggs nvif_object_fini(object); 260*a04d0423SBen Skeggs return ret; 261*a04d0423SBen Skeggs } 262*a04d0423SBen Skeggs 263*a04d0423SBen Skeggs static void 264*a04d0423SBen Skeggs nvif_object_del(struct nvif_object *object) 265*a04d0423SBen Skeggs { 266*a04d0423SBen Skeggs nvif_object_fini(object); 267*a04d0423SBen Skeggs kfree(object); 268*a04d0423SBen Skeggs } 269*a04d0423SBen Skeggs 270*a04d0423SBen Skeggs int 271*a04d0423SBen Skeggs nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass, 272*a04d0423SBen Skeggs void *data, u32 size, struct nvif_object **pobject) 273*a04d0423SBen Skeggs { 274*a04d0423SBen Skeggs struct nvif_object *object = kzalloc(sizeof(*object), GFP_KERNEL); 275*a04d0423SBen Skeggs if (object) { 276*a04d0423SBen Skeggs int ret = nvif_object_init(parent, nvif_object_del, handle, 277*a04d0423SBen Skeggs oclass, data, size, object); 278*a04d0423SBen Skeggs if (ret) 279*a04d0423SBen Skeggs kfree(object); 280*a04d0423SBen Skeggs *pobject = object; 281*a04d0423SBen Skeggs return ret; 282*a04d0423SBen Skeggs } 283*a04d0423SBen Skeggs return -ENOMEM; 284*a04d0423SBen Skeggs } 285*a04d0423SBen Skeggs 286*a04d0423SBen Skeggs static void 287*a04d0423SBen Skeggs nvif_object_put(struct kref *kref) 288*a04d0423SBen Skeggs { 289*a04d0423SBen Skeggs struct nvif_object *object = 290*a04d0423SBen Skeggs container_of(kref, typeof(*object), refcount); 291*a04d0423SBen Skeggs object->dtor(object); 292*a04d0423SBen Skeggs } 293*a04d0423SBen Skeggs 294*a04d0423SBen Skeggs void 295*a04d0423SBen Skeggs nvif_object_ref(struct nvif_object *object, struct nvif_object **pobject) 296*a04d0423SBen Skeggs { 297*a04d0423SBen Skeggs if (object) 298*a04d0423SBen Skeggs kref_get(&object->refcount); 299*a04d0423SBen Skeggs if (*pobject) 300*a04d0423SBen Skeggs kref_put(&(*pobject)->refcount, nvif_object_put); 301*a04d0423SBen Skeggs *pobject = object; 302*a04d0423SBen Skeggs } 303