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