1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> 3bf215546Sopenharmony_ci * Copyright 2019 Collabora, Ltd. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include <inttypes.h> 26bf215546Sopenharmony_ci#include "agx_device.h" 27bf215546Sopenharmony_ci#include "agx_bo.h" 28bf215546Sopenharmony_ci#include "decode.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ciunsigned AGX_FAKE_HANDLE = 0; 31bf215546Sopenharmony_ciuint64_t AGX_FAKE_LO = 0; 32bf215546Sopenharmony_ciuint64_t AGX_FAKE_HI = (1ull << 32); 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_cistatic void 35bf215546Sopenharmony_ciagx_bo_free(struct agx_device *dev, struct agx_bo *bo) 36bf215546Sopenharmony_ci{ 37bf215546Sopenharmony_ci#if __APPLE__ 38bf215546Sopenharmony_ci const uint64_t handle = bo->handle; 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci kern_return_t ret = IOConnectCallScalarMethod(dev->fd, 41bf215546Sopenharmony_ci AGX_SELECTOR_FREE_MEM, 42bf215546Sopenharmony_ci &handle, 1, NULL, NULL); 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci if (ret) 45bf215546Sopenharmony_ci fprintf(stderr, "error freeing BO mem: %u\n", ret); 46bf215546Sopenharmony_ci#else 47bf215546Sopenharmony_ci free(bo->ptr.cpu); 48bf215546Sopenharmony_ci#endif 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci /* Reset the handle */ 51bf215546Sopenharmony_ci memset(bo, 0, sizeof(*bo)); 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_civoid 55bf215546Sopenharmony_ciagx_shmem_free(struct agx_device *dev, unsigned handle) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci#if __APPLE__ 58bf215546Sopenharmony_ci const uint64_t input = handle; 59bf215546Sopenharmony_ci kern_return_t ret = IOConnectCallScalarMethod(dev->fd, 60bf215546Sopenharmony_ci AGX_SELECTOR_FREE_SHMEM, 61bf215546Sopenharmony_ci &input, 1, NULL, NULL); 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci if (ret) 64bf215546Sopenharmony_ci fprintf(stderr, "error freeing shmem: %u\n", ret); 65bf215546Sopenharmony_ci#else 66bf215546Sopenharmony_ci#endif 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cistruct agx_bo 70bf215546Sopenharmony_ciagx_shmem_alloc(struct agx_device *dev, size_t size, bool cmdbuf) 71bf215546Sopenharmony_ci{ 72bf215546Sopenharmony_ci struct agx_bo bo; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci#if __APPLE__ 75bf215546Sopenharmony_ci struct agx_create_shmem_resp out = {}; 76bf215546Sopenharmony_ci size_t out_sz = sizeof(out); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci uint64_t inputs[2] = { 79bf215546Sopenharmony_ci size, 80bf215546Sopenharmony_ci cmdbuf ? 1 : 0 // 2 - error reporting, 1 - no error reporting 81bf215546Sopenharmony_ci }; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci kern_return_t ret = IOConnectCallMethod(dev->fd, 84bf215546Sopenharmony_ci AGX_SELECTOR_CREATE_SHMEM, inputs, 2, NULL, 0, NULL, 85bf215546Sopenharmony_ci NULL, &out, &out_sz); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci assert(ret == 0); 88bf215546Sopenharmony_ci assert(out_sz == sizeof(out)); 89bf215546Sopenharmony_ci assert(out.size == size); 90bf215546Sopenharmony_ci assert(out.map != 0); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci bo = (struct agx_bo) { 93bf215546Sopenharmony_ci .type = cmdbuf ? AGX_ALLOC_CMDBUF : AGX_ALLOC_MEMMAP, 94bf215546Sopenharmony_ci .handle = out.id, 95bf215546Sopenharmony_ci .ptr.cpu = out.map, 96bf215546Sopenharmony_ci .size = out.size, 97bf215546Sopenharmony_ci .guid = 0, /* TODO? */ 98bf215546Sopenharmony_ci }; 99bf215546Sopenharmony_ci#else 100bf215546Sopenharmony_ci bo = (struct agx_bo) { 101bf215546Sopenharmony_ci .type = cmdbuf ? AGX_ALLOC_CMDBUF : AGX_ALLOC_MEMMAP, 102bf215546Sopenharmony_ci .handle = AGX_FAKE_HANDLE++, 103bf215546Sopenharmony_ci .ptr.cpu = calloc(1, size), 104bf215546Sopenharmony_ci .size = size, 105bf215546Sopenharmony_ci .guid = 0, /* TODO? */ 106bf215546Sopenharmony_ci }; 107bf215546Sopenharmony_ci#endif 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci if (dev->debug & AGX_DBG_TRACE) 110bf215546Sopenharmony_ci agxdecode_track_alloc(&bo); 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci return bo; 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic struct agx_bo * 116bf215546Sopenharmony_ciagx_bo_alloc(struct agx_device *dev, size_t size, 117bf215546Sopenharmony_ci uint32_t flags) 118bf215546Sopenharmony_ci{ 119bf215546Sopenharmony_ci struct agx_bo *bo; 120bf215546Sopenharmony_ci unsigned handle = 0; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci#if __APPLE__ 123bf215546Sopenharmony_ci uint32_t mode = 0x430; // shared, ? 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci uint32_t args_in[24] = { 0 }; 126bf215546Sopenharmony_ci args_in[4] = 0x4000101; //0x1000101; // unk 127bf215546Sopenharmony_ci args_in[5] = mode; 128bf215546Sopenharmony_ci args_in[16] = size; 129bf215546Sopenharmony_ci args_in[20] = flags; 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci uint64_t out[10] = { 0 }; 132bf215546Sopenharmony_ci size_t out_sz = sizeof(out); 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci kern_return_t ret = IOConnectCallMethod(dev->fd, 135bf215546Sopenharmony_ci AGX_SELECTOR_ALLOCATE_MEM, NULL, 0, args_in, 136bf215546Sopenharmony_ci sizeof(args_in), NULL, 0, out, &out_sz); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci assert(ret == 0); 139bf215546Sopenharmony_ci assert(out_sz == sizeof(out)); 140bf215546Sopenharmony_ci handle = (out[3] >> 32ull); 141bf215546Sopenharmony_ci#else 142bf215546Sopenharmony_ci /* Faked software path until we have a DRM driver */ 143bf215546Sopenharmony_ci handle = (++AGX_FAKE_HANDLE); 144bf215546Sopenharmony_ci#endif 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci pthread_mutex_lock(&dev->bo_map_lock); 147bf215546Sopenharmony_ci bo = agx_lookup_bo(dev, handle); 148bf215546Sopenharmony_ci pthread_mutex_unlock(&dev->bo_map_lock); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /* Fresh handle */ 151bf215546Sopenharmony_ci assert(!memcmp(bo, &((struct agx_bo) {}), sizeof(*bo))); 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci bo->type = AGX_ALLOC_REGULAR; 154bf215546Sopenharmony_ci bo->size = size; 155bf215546Sopenharmony_ci bo->flags = flags; 156bf215546Sopenharmony_ci bo->dev = dev; 157bf215546Sopenharmony_ci bo->handle = handle; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci ASSERTED bool lo = (flags & 0x08000000); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci#if __APPLE__ 162bf215546Sopenharmony_ci bo->ptr.gpu = out[0]; 163bf215546Sopenharmony_ci bo->ptr.cpu = (void *) out[1]; 164bf215546Sopenharmony_ci bo->guid = out[5]; 165bf215546Sopenharmony_ci#else 166bf215546Sopenharmony_ci if (lo) { 167bf215546Sopenharmony_ci bo->ptr.gpu = AGX_FAKE_LO; 168bf215546Sopenharmony_ci AGX_FAKE_LO += bo->size; 169bf215546Sopenharmony_ci } else { 170bf215546Sopenharmony_ci bo->ptr.gpu = AGX_FAKE_HI; 171bf215546Sopenharmony_ci AGX_FAKE_HI += bo->size; 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci bo->ptr.gpu = (((uint64_t) bo->handle) << (lo ? 16 : 24)); 175bf215546Sopenharmony_ci bo->ptr.cpu = calloc(1, bo->size); 176bf215546Sopenharmony_ci#endif 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci assert(bo->ptr.gpu < (1ull << (lo ? 32 : 40))); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci return bo; 181bf215546Sopenharmony_ci} 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_civoid 184bf215546Sopenharmony_ciagx_bo_reference(struct agx_bo *bo) 185bf215546Sopenharmony_ci{ 186bf215546Sopenharmony_ci if (bo) { 187bf215546Sopenharmony_ci ASSERTED int count = p_atomic_inc_return(&bo->refcnt); 188bf215546Sopenharmony_ci assert(count != 1); 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_civoid 193bf215546Sopenharmony_ciagx_bo_unreference(struct agx_bo *bo) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci if (!bo) 196bf215546Sopenharmony_ci return; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /* Don't return to cache if there are still references */ 199bf215546Sopenharmony_ci if (p_atomic_dec_return(&bo->refcnt)) 200bf215546Sopenharmony_ci return; 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci struct agx_device *dev = bo->dev; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci pthread_mutex_lock(&dev->bo_map_lock); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci /* Someone might have imported this BO while we were waiting for the 207bf215546Sopenharmony_ci * lock, let's make sure it's still not referenced before freeing it. 208bf215546Sopenharmony_ci */ 209bf215546Sopenharmony_ci if (p_atomic_read(&bo->refcnt) == 0) { 210bf215546Sopenharmony_ci if (dev->debug & AGX_DBG_TRACE) 211bf215546Sopenharmony_ci agxdecode_track_free(bo); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci /* TODO: cache */ 214bf215546Sopenharmony_ci agx_bo_free(dev, bo); 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci } 217bf215546Sopenharmony_ci pthread_mutex_unlock(&dev->bo_map_lock); 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_cistruct agx_bo * 221bf215546Sopenharmony_ciagx_bo_create(struct agx_device *dev, unsigned size, unsigned flags) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci struct agx_bo *bo; 224bf215546Sopenharmony_ci assert(size > 0); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci /* To maximize BO cache usage, don't allocate tiny BOs */ 227bf215546Sopenharmony_ci size = ALIGN_POT(size, 4096); 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* TODO: Cache fetch */ 230bf215546Sopenharmony_ci bo = agx_bo_alloc(dev, size, flags); 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci if (!bo) { 233bf215546Sopenharmony_ci fprintf(stderr, "BO creation failed\n"); 234bf215546Sopenharmony_ci return NULL; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci p_atomic_set(&bo->refcnt, 1); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci if (dev->debug & AGX_DBG_TRACE) 240bf215546Sopenharmony_ci agxdecode_track_alloc(bo); 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci return bo; 243bf215546Sopenharmony_ci} 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_cistatic void 246bf215546Sopenharmony_ciagx_get_global_ids(struct agx_device *dev) 247bf215546Sopenharmony_ci{ 248bf215546Sopenharmony_ci#if __APPLE__ 249bf215546Sopenharmony_ci uint64_t out[2] = {}; 250bf215546Sopenharmony_ci size_t out_sz = sizeof(out); 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallStructMethod(dev->fd, 253bf215546Sopenharmony_ci AGX_SELECTOR_GET_GLOBAL_IDS, 254bf215546Sopenharmony_ci NULL, 0, &out, &out_sz); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci assert(ret == 0); 257bf215546Sopenharmony_ci assert(out_sz == sizeof(out)); 258bf215546Sopenharmony_ci assert(out[1] > out[0]); 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci dev->next_global_id = out[0]; 261bf215546Sopenharmony_ci dev->last_global_id = out[1]; 262bf215546Sopenharmony_ci#else 263bf215546Sopenharmony_ci dev->next_global_id = 0; 264bf215546Sopenharmony_ci dev->last_global_id = 0x1000000; 265bf215546Sopenharmony_ci#endif 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ciuint64_t 269bf215546Sopenharmony_ciagx_get_global_id(struct agx_device *dev) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci if (unlikely(dev->next_global_id >= dev->last_global_id)) { 272bf215546Sopenharmony_ci agx_get_global_ids(dev); 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci return dev->next_global_id++; 276bf215546Sopenharmony_ci} 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci/* Tries to open an AGX device, returns true if successful */ 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_cibool 281bf215546Sopenharmony_ciagx_open_device(void *memctx, struct agx_device *dev) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci#if __APPLE__ 284bf215546Sopenharmony_ci kern_return_t ret; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci /* TODO: Support other models */ 287bf215546Sopenharmony_ci CFDictionaryRef matching = IOServiceNameMatching("AGXAcceleratorG13G_B0"); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci io_service_t service = 290bf215546Sopenharmony_ci IOServiceGetMatchingService(kIOMasterPortDefault, matching); 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci if (!service) 293bf215546Sopenharmony_ci return false; 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci ret = IOServiceOpen(service, mach_task_self(), AGX_SERVICE_TYPE, &dev->fd); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci if (ret) 298bf215546Sopenharmony_ci return false; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci const char *api = "Equestria"; 301bf215546Sopenharmony_ci char in[16] = { 0 }; 302bf215546Sopenharmony_ci assert(strlen(api) < sizeof(in)); 303bf215546Sopenharmony_ci memcpy(in, api, strlen(api)); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci ret = IOConnectCallStructMethod(dev->fd, AGX_SELECTOR_SET_API, in, 306bf215546Sopenharmony_ci sizeof(in), NULL, NULL); 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci /* Oddly, the return codes are flipped for SET_API */ 309bf215546Sopenharmony_ci if (ret != 1) 310bf215546Sopenharmony_ci return false; 311bf215546Sopenharmony_ci#else 312bf215546Sopenharmony_ci /* Only open a fake AGX device on other operating systems if forced */ 313bf215546Sopenharmony_ci if (!getenv("AGX_FAKE_DEVICE")) 314bf215546Sopenharmony_ci return false; 315bf215546Sopenharmony_ci#endif 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci dev->memctx = memctx; 318bf215546Sopenharmony_ci util_sparse_array_init(&dev->bo_map, sizeof(struct agx_bo), 512); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci dev->queue = agx_create_command_queue(dev); 321bf215546Sopenharmony_ci dev->cmdbuf = agx_shmem_alloc(dev, 0x4000, true); // length becomes kernelCommandDataSize 322bf215546Sopenharmony_ci dev->memmap = agx_shmem_alloc(dev, 0x10000, false); 323bf215546Sopenharmony_ci agx_get_global_ids(dev); 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci return true; 326bf215546Sopenharmony_ci} 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_civoid 329bf215546Sopenharmony_ciagx_close_device(struct agx_device *dev) 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci util_sparse_array_finish(&dev->bo_map); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci#if __APPLE__ 334bf215546Sopenharmony_ci kern_return_t ret = IOServiceClose(dev->fd); 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci if (ret) 337bf215546Sopenharmony_ci fprintf(stderr, "Error from IOServiceClose: %u\n", ret); 338bf215546Sopenharmony_ci#endif 339bf215546Sopenharmony_ci} 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci#if __APPLE__ 342bf215546Sopenharmony_cistatic struct agx_notification_queue 343bf215546Sopenharmony_ciagx_create_notification_queue(mach_port_t connection) 344bf215546Sopenharmony_ci{ 345bf215546Sopenharmony_ci struct agx_create_notification_queue_resp resp; 346bf215546Sopenharmony_ci size_t resp_size = sizeof(resp); 347bf215546Sopenharmony_ci assert(resp_size == 0x10); 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallStructMethod(connection, 350bf215546Sopenharmony_ci AGX_SELECTOR_CREATE_NOTIFICATION_QUEUE, 351bf215546Sopenharmony_ci NULL, 0, &resp, &resp_size); 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci assert(resp_size == sizeof(resp)); 354bf215546Sopenharmony_ci assert(ret == 0); 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci mach_port_t notif_port = IODataQueueAllocateNotificationPort(); 357bf215546Sopenharmony_ci IOConnectSetNotificationPort(connection, 0, notif_port, resp.unk2); 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci return (struct agx_notification_queue) { 360bf215546Sopenharmony_ci .port = notif_port, 361bf215546Sopenharmony_ci .queue = resp.queue, 362bf215546Sopenharmony_ci .id = resp.unk2 363bf215546Sopenharmony_ci }; 364bf215546Sopenharmony_ci} 365bf215546Sopenharmony_ci#endif 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_cistruct agx_command_queue 368bf215546Sopenharmony_ciagx_create_command_queue(struct agx_device *dev) 369bf215546Sopenharmony_ci{ 370bf215546Sopenharmony_ci#if __APPLE__ 371bf215546Sopenharmony_ci struct agx_command_queue queue = {}; 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci { 374bf215546Sopenharmony_ci uint8_t buffer[1024 + 8] = { 0 }; 375bf215546Sopenharmony_ci const char *path = "/tmp/a.out"; 376bf215546Sopenharmony_ci assert(strlen(path) < 1022); 377bf215546Sopenharmony_ci memcpy(buffer + 0, path, strlen(path)); 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci /* Copy to the end */ 380bf215546Sopenharmony_ci unsigned END_LEN = MIN2(strlen(path), 1024 - strlen(path)); 381bf215546Sopenharmony_ci unsigned SKIP = strlen(path) - END_LEN; 382bf215546Sopenharmony_ci unsigned OFFS = 1024 - END_LEN; 383bf215546Sopenharmony_ci memcpy(buffer + OFFS, path + SKIP, END_LEN); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci buffer[1024] = 0x2; 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci struct agx_create_command_queue_resp out = {}; 388bf215546Sopenharmony_ci size_t out_sz = sizeof(out); 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallStructMethod(dev->fd, 391bf215546Sopenharmony_ci AGX_SELECTOR_CREATE_COMMAND_QUEUE, 392bf215546Sopenharmony_ci buffer, sizeof(buffer), 393bf215546Sopenharmony_ci &out, &out_sz); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci assert(ret == 0); 396bf215546Sopenharmony_ci assert(out_sz == sizeof(out)); 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci queue.id = out.id; 399bf215546Sopenharmony_ci assert(queue.id); 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci queue.notif = agx_create_notification_queue(dev->fd); 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci { 405bf215546Sopenharmony_ci uint64_t scalars[2] = { 406bf215546Sopenharmony_ci queue.id, 407bf215546Sopenharmony_ci queue.notif.id 408bf215546Sopenharmony_ci }; 409bf215546Sopenharmony_ci 410bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallScalarMethod(dev->fd, 411bf215546Sopenharmony_ci 0x1D, 412bf215546Sopenharmony_ci scalars, 2, NULL, NULL); 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci assert(ret == 0); 415bf215546Sopenharmony_ci } 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci { 418bf215546Sopenharmony_ci uint64_t scalars[2] = { 419bf215546Sopenharmony_ci queue.id, 420bf215546Sopenharmony_ci 0x1ffffffffull 421bf215546Sopenharmony_ci }; 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallScalarMethod(dev->fd, 424bf215546Sopenharmony_ci 0x31, 425bf215546Sopenharmony_ci scalars, 2, NULL, NULL); 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci assert(ret == 0); 428bf215546Sopenharmony_ci } 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci return queue; 431bf215546Sopenharmony_ci#else 432bf215546Sopenharmony_ci return (struct agx_command_queue) { 433bf215546Sopenharmony_ci 0 434bf215546Sopenharmony_ci }; 435bf215546Sopenharmony_ci#endif 436bf215546Sopenharmony_ci} 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_civoid 439bf215546Sopenharmony_ciagx_submit_cmdbuf(struct agx_device *dev, unsigned cmdbuf, unsigned mappings, uint64_t scalar) 440bf215546Sopenharmony_ci{ 441bf215546Sopenharmony_ci#if __APPLE__ 442bf215546Sopenharmony_ci struct agx_submit_cmdbuf_req req = { 443bf215546Sopenharmony_ci .count = 1, 444bf215546Sopenharmony_ci .command_buffer_shmem_id = cmdbuf, 445bf215546Sopenharmony_ci .segment_list_shmem_id = mappings, 446bf215546Sopenharmony_ci .notify_1 = 0xABCD, 447bf215546Sopenharmony_ci .notify_2 = 0x1234, 448bf215546Sopenharmony_ci }; 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci ASSERTED kern_return_t ret = IOConnectCallMethod(dev->fd, 451bf215546Sopenharmony_ci AGX_SELECTOR_SUBMIT_COMMAND_BUFFERS, 452bf215546Sopenharmony_ci &scalar, 1, 453bf215546Sopenharmony_ci &req, sizeof(req), 454bf215546Sopenharmony_ci NULL, 0, NULL, 0); 455bf215546Sopenharmony_ci assert(ret == 0); 456bf215546Sopenharmony_ci return; 457bf215546Sopenharmony_ci#endif 458bf215546Sopenharmony_ci} 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci/* 461bf215546Sopenharmony_ci * Wait for a frame to finish rendering. 462bf215546Sopenharmony_ci * 463bf215546Sopenharmony_ci * The macOS kernel indicates that rendering has finished using a notification 464bf215546Sopenharmony_ci * queue. The kernel will send two messages on the notification queue. The 465bf215546Sopenharmony_ci * second message indicates that rendering has completed. This simple routine 466bf215546Sopenharmony_ci * waits for both messages. It's important that IODataQueueDequeue is used in a 467bf215546Sopenharmony_ci * loop to flush the entire queue before calling 468bf215546Sopenharmony_ci * IODataQueueWaitForAvailableData. Otherwise, we can race and get stuck in 469bf215546Sopenharmony_ci * WaitForAvailabaleData. 470bf215546Sopenharmony_ci */ 471bf215546Sopenharmony_civoid 472bf215546Sopenharmony_ciagx_wait_queue(struct agx_command_queue queue) 473bf215546Sopenharmony_ci{ 474bf215546Sopenharmony_ci#if __APPLE__ 475bf215546Sopenharmony_ci uint64_t data[4]; 476bf215546Sopenharmony_ci unsigned sz = sizeof(data); 477bf215546Sopenharmony_ci unsigned message_id = 0; 478bf215546Sopenharmony_ci uint64_t magic_numbers[2] = { 0xABCD, 0x1234 }; 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci while (message_id < 2) { 481bf215546Sopenharmony_ci IOReturn ret = IODataQueueWaitForAvailableData(queue.notif.queue, queue.notif.port); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci if (ret) { 484bf215546Sopenharmony_ci fprintf(stderr, "Error waiting for available data\n"); 485bf215546Sopenharmony_ci return; 486bf215546Sopenharmony_ci } 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci while (IODataQueueDequeue(queue.notif.queue, data, &sz) == kIOReturnSuccess) { 489bf215546Sopenharmony_ci assert(sz == sizeof(data)); 490bf215546Sopenharmony_ci assert(data[0] == magic_numbers[message_id]); 491bf215546Sopenharmony_ci message_id++; 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci } 494bf215546Sopenharmony_ci#endif 495bf215546Sopenharmony_ci} 496