diff --git a/src/asahi/drm-shim/asahi_noop.c b/src/asahi/drm-shim/asahi_noop.c index 2beb6d6fdf17..37ef11143e3e 100644 --- a/src/asahi/drm-shim/asahi_noop.c +++ b/src/asahi/drm-shim/asahi_noop.c @@ -1308,6 +1308,14 @@ shim_features(void) return features; } +static uint64_t +shim_vm_end(const struct drm_asahi_params_global *params) +{ + if (params == ¶ms_g15g && shim_env_on("ASAHI_SHIM_G15G_HAL200")) + return UINT64_C(0x3ffffff8000); + return params->vm_end; +} + static int asahi_ioctl_get_param(int fd, unsigned long request, void *arg) { @@ -1323,6 +1331,11 @@ asahi_ioctl_get_param(int fd, unsigned long request, void *arg) size_t size = MIN2((size_t)gp->size, sizeof(struct drm_asahi_params_global)); struct drm_asahi_params_global params = *shim_params(); params.features = shim_features(); + if (shim_params() == ¶ms_g15g && + shim_env_on("ASAHI_SHIM_G15G_HAL200")) { + params.gpu_hal_generation = DRM_ASAHI_GPU_HAL_200; + params.vm_end = shim_vm_end(shim_params()); + } const char *command_limit = getenv("ASAHI_SHIM_COMMAND_LIMIT"); if (command_limit) { unsigned limit = strtoul(command_limit, NULL, 0); @@ -1410,6 +1423,7 @@ asahi_ioctl_vm_bind_unlocked(int fd, unsigned long request, void *arg) { const struct drm_asahi_vm_bind *bind = arg; const struct drm_asahi_params_global *params = shim_params(); + const uint64_t vm_end = shim_vm_end(params); for (uint32_t i = 0; i < bind->num_binds; ++i) { const struct drm_asahi_gem_bind_op *op = @@ -1425,13 +1439,13 @@ asahi_ioctl_vm_bind_unlocked(int fd, unsigned long request, void *arg) return -EINVAL; } - if (end < start || start < params->vm_start || end > params->vm_end) { + if (end < start || start < params->vm_start || end > vm_end) { fprintf(stderr, "shim: gem_bind: Invalid map range %#llx..%#llx " "(not contained in user range %#llx..%#llx)\n", (unsigned long long)start, (unsigned long long)end, (unsigned long long)params->vm_start, - (unsigned long long)params->vm_end); + (unsigned long long)vm_end); return -EINVAL; } diff --git a/src/asahi/drm-shim/meson.build b/src/asahi/drm-shim/meson.build index 80821e6c18d0..8f96ca8ece99 100644 --- a/src/asahi/drm-shim/meson.build +++ b/src/asahi/drm-shim/meson.build @@ -29,3 +29,21 @@ libasahi_noop_drm_shim = shared_library( gnu_symbol_visibility : 'hidden', install : true, ) + +if with_tests + asahi_vm_limits_test = executable( + 'asahi-vm-limits', 'test-vm-limits.c', + include_directories : [inc_include], + dependencies : [dep_libdrm], + ) + foreach hal : ['legacy', 'hal200'] + test( + 'asahi-vm-limits-' + hal, prog_python, + args : [files('../../gallium/drivers/asahi/tests/run-shim.py'), + libasahi_noop_drm_shim, asahi_vm_limits_test], + env : ['ASAHI_SHIM_CHIP=g15g', + 'ASAHI_SHIM_G15G_HAL200=' + (hal == 'hal200' ? '1' : '0')], + suite : ['asahi'], + ) + endforeach +endif diff --git a/src/asahi/drm-shim/test-vm-limits.c b/src/asahi/drm-shim/test-vm-limits.c new file mode 100644 index 000000000000..acd531c66a28 --- /dev/null +++ b/src/asahi/drm-shim/test-vm-limits.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: MIT */ +#include +#include +#include +#include +#include +#include +#include +#include "drm-uapi/asahi_drm.h" + +#define CHECK(x) do { if (!(x)) { fprintf(stderr, "%u: %s\n", __LINE__, #x); abort(); } } while (0) + +int main(void) +{ + int fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC); + CHECK(fd >= 0); + struct drm_asahi_params_global params = {0}; + struct drm_asahi_get_params get = { + .pointer = (uintptr_t)¶ms, .size = sizeof(params), + }; + CHECK(!drmIoctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &get)); + struct drm_asahi_vm_create vm = {0}; + CHECK(!drmIoctl(fd, DRM_IOCTL_ASAHI_VM_CREATE, &vm)); + struct drm_asahi_gem_create bo = {.size = 0x4000}; + CHECK(!drmIoctl(fd, DRM_IOCTL_ASAHI_GEM_CREATE, &bo)); + struct drm_asahi_gem_bind_op op = { + .handle = bo.handle, .range = 0x4000, + }; + struct drm_asahi_vm_bind bind = { + .vm_id = vm.vm_id, .num_binds = 1, + .stride = sizeof(op), .userptr = (uintptr_t)&op, + }; + const uint64_t addresses[] = {params.vm_start, UINT64_C(0x30000000000), + params.vm_end - 0x4000, params.vm_end}; + for (unsigned i = 0; i < 4; ++i) { + op.addr = addresses[i]; + int ret = drmIoctl(fd, DRM_IOCTL_ASAHI_VM_BIND, &bind); + CHECK((ret == 0) == (op.addr + op.range <= params.vm_end)); + } + close(fd); + puts("PASS reported VM limits match bind admission"); + return 0; +} diff --git a/src/asahi/lib/agx_chip.c b/src/asahi/lib/agx_chip.c index da139589e67c..a02fc564462b 100644 --- a/src/asahi/lib/agx_chip.c +++ b/src/asahi/lib/agx_chip.c @@ -7,6 +7,8 @@ #include +#include "util/bitscan.h" + enum agx_chip agx_chip_from_params(const struct drm_asahi_params_global *params) { @@ -276,6 +278,41 @@ agx_chip_driver_supported(enum agx_chip chip) } } +/* The firmware interface version does not determine the GPU record layout. + * Both T8122 interfaces consume G15 records and Gen4 sampler words. Keep the + * physical chip as G15G so compiler scheduling and hardware workarounds agree. + */ +static bool +agx_t8122_params_supported(const struct drm_asahi_params_global *params) +{ + if (params->chip_id != 0x8122 || params->num_dies != 1 || + params->num_clusters_total != 1 || + params->usc_generation != AGX_ISA_AGX3) + return false; + + if (params->gpu_hal_generation == DRM_ASAHI_GPU_HAL_LEGACY) + return true; + + if (params->gpu_hal_generation != DRM_ASAHI_GPU_HAL_200 || + params->gpu_revision != 0x20 || params->num_cores_per_cluster != 10) + return false; + + const uint64_t mask = params->core_masks[0]; + const unsigned cores = util_bitcount64(mask); + if ((mask >> 10) || (cores != 8 && cores != 10)) + return false; + for (unsigned i = 1; i < DRM_ASAHI_MAX_CLUSTERS; ++i) { + if (params->core_masks[i]) + return false; + } + + return agx_chip_command_stream_generation(AGX_CHIP_G15G) == + AGX_CS_GENERATION_G15 && + agx_chip_sampler_generation(AGX_CHIP_G15G) == + AGX_SAMPLER_GENERATION_GEN4 && + agx_chip_sampler_heap_element_size(AGX_CHIP_G15G) == 32; +} + bool agx_params_driver_supported(const struct drm_asahi_params_global *params) { @@ -301,13 +338,7 @@ agx_params_driver_supported(const struct drm_asahi_params_global *params) params->gpu_hal_generation == DRM_ASAHI_GPU_HAL_200; } case AGX_CHIP_G15G: - /* T8122/M3: one die, one cluster, AGX3 shaders on the legacy firmware - * interface (14.8.3), through the kernel's T8122 runtime. The exact - * identity/runtime checks apply without a Mesa environment opt-in. */ - return params->chip_id == 0x8122 && params->num_dies == 1 && - params->num_clusters_total == 1 && - params->usc_generation == AGX_ISA_AGX3 && - params->gpu_hal_generation == DRM_ASAHI_GPU_HAL_LEGACY; + return agx_t8122_params_supported(params); case AGX_CHIP_G15S: /* T6030/M3 Pro: one die, two clusters, AGX3 shaders on the legacy * (pre-HAL200) firmware interface. */ diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h index d53e5eeddcc0..24f84eb15924 100644 --- a/src/asahi/lib/agx_device.h +++ b/src/asahi/lib/agx_device.h @@ -520,6 +520,15 @@ agx_native_graphics(const struct agx_device *dev) return agx_chip_native_agx3(dev->chip); } +/* This interface carries native sampler state in GPU records, not in the + * firmware command's optional sampler-heap fields. */ +static inline bool +agx_stream_sampler_state(const struct agx_device *dev) +{ + return dev->chip == AGX_CHIP_G15G && + dev->params.gpu_hal_generation == DRM_ASAHI_GPU_HAL_200; +} + /* T6040 uses the G17P architecture profile, while capability rollout may * still be product-specific. Device admission has already checked USC/HAL. */ static inline bool diff --git a/src/asahi/lib/tests/test-chip-admission.c b/src/asahi/lib/tests/test-chip-admission.c index 532be1c49646..62bf2de3139d 100644 --- a/src/asahi/lib/tests/test-chip-admission.c +++ b/src/asahi/lib/tests/test-chip-admission.c @@ -223,9 +223,51 @@ main(void) bad.num_clusters_total = 2; assert(!agx_params_driver_supported(&bad)); - bad = g15g; - bad.gpu_hal_generation = DRM_ASAHI_GPU_HAL_200; + struct drm_asahi_params_global modern = g15g; + modern.gpu_hal_generation = DRM_ASAHI_GPU_HAL_200; + modern.gpu_revision = 0x20; + assert(agx_params_driver_supported(&modern)); + assert(agx_params_native_kernel_abi_supported(&modern)); + enum agx_chip modern_chip = agx_chip_from_params(&modern); + assert(modern_chip == AGX_CHIP_G15G); + assert(agx_chip_command_stream_generation(modern_chip) == + AGX_CS_GENERATION_G15); + assert(agx_chip_sampler_generation(modern_chip) == + AGX_SAMPLER_GENERATION_GEN4); + assert(agx_chip_sampler_heap_element_size(modern_chip) == 32); + assert(agx_chip_isa_encoding(modern_chip) == + agx_chip_isa_encoding(agx_chip_from_params(&g15g))); + assert(agx_chip_cdm_wide_visibility(modern_chip)); + assert(!agx_chip_sampler_has_lod_bias(modern_chip)); + modern.core_masks[0] = 0x3cf; + assert(agx_params_driver_supported(&modern)); + modern.core_masks[0] = 0x3ff; + + bad = modern; + bad.gpu_hal_generation = DRM_ASAHI_GPU_HAL_300; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.gpu_revision = 0x21; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.num_cores_per_cluster = 9; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.core_masks[0] = 0x1ff; assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.core_masks[0] = 0x7ff; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.core_masks[1] = 1; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.gpu_variant = 'S'; + assert(!agx_params_driver_supported(&bad)); + bad = modern; + bad.features = DRM_ASAHI_FEATURE_EXACT_PRIOR_BARRIERS | + DRM_ASAHI_FEATURE_PER_COMMAND_INPUT_SYNCS; + assert(!agx_params_native_kernel_abi_supported(&bad)); bad = g15g; bad.usc_generation = 2; diff --git a/src/asahi/vulkan/hk_queue.c b/src/asahi/vulkan/hk_queue.c index 4c7eb7eeee4f..bf443fdeceaf 100644 --- a/src/asahi/vulkan/hk_queue.c +++ b/src/asahi/vulkan/hk_queue.c @@ -134,7 +134,7 @@ asahi_fill_cdm_command(struct hk_device *dev, struct hk_cs *cs, .ts.end.offset = cs->timestamp.end.offset_B, }; - if (cs->uses_sampler_heap) { + if (cs->uses_sampler_heap && !agx_stream_sampler_state(&dev->dev)) { cmd->sampler_heap = dev->samplers.table.bo->va->addr; cmd->sampler_count = dev->samplers.table.alloc; } @@ -296,7 +296,7 @@ asahi_fill_vdm_command(struct hk_device *dev, struct hk_cs *cs, c->isp_scissor_base = cs->uploaded_scissor; c->isp_dbias_base = cs->uploaded_zbias; - if (cs->uses_sampler_heap) { + if (cs->uses_sampler_heap && !agx_stream_sampler_state(&dev->dev)) { c->sampler_heap = dev->samplers.table.bo->va->addr; c->sampler_count = dev->samplers.table.alloc; } diff --git a/src/gallium/drivers/asahi/agx_pipe.c b/src/gallium/drivers/asahi/agx_pipe.c index c769f062345d..a25aba3fdc13 100644 --- a/src/gallium/drivers/asahi/agx_pipe.c +++ b/src/gallium/drivers/asahi/agx_pipe.c @@ -1508,7 +1508,8 @@ agx_cmdbuf(struct agx_device *dev, struct drm_asahi_cmd_render *c, c->isp_dbias_base = depth_bias_ptr; c->isp_oclqry_base = visibility_result_ptr; - if (batch->sampler_heap.bo) { + if (batch->sampler_heap.bo && + !agx_stream_sampler_state(dev)) { c->sampler_heap = batch->sampler_heap.bo->va->addr; c->sampler_count = batch->sampler_heap.count; } @@ -1673,6 +1674,11 @@ agx_flush_compute(struct agx_context *ctx, struct agx_batch *batch, .sampler_count = batch->sampler_heap.count, }; + if (agx_stream_sampler_state(dev)) { + cmdbuf->sampler_heap = 0; + cmdbuf->sampler_count = 0; + } + if (batch->cs_scratch) { // The commented out lines *may* be related to subgroup-level preemption, // which we can't support without implementing threadgroup memory in the