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