diff --git a/src/freedreno/vulkan/tu_device.cc b/src/freedreno/vulkan/tu_device.cc index 15cad025027..174c24dfe21 100644 --- a/src/freedreno/vulkan/tu_device.cc +++ b/src/freedreno/vulkan/tu_device.cc @@ -1311,6 +1311,20 @@ tu_physical_device_init(struct tu_physical_device *device, device->memory.type_count++; } + /* Provide fallback UBWC config values if the kernel doesn't support + * providing them. This should match what the kernel programs. + */ + if (!device->ubwc_config.highest_bank_bit) { + device->ubwc_config.highest_bank_bit = info.highest_bank_bit; + } + if (device->ubwc_config.bank_swizzle_levels == ~0) { + device->ubwc_config.bank_swizzle_levels = info.ubwc_swizzle; + } + if (device->ubwc_config.macrotile_mode == FDL_MACROTILE_INVALID) { + device->ubwc_config.macrotile_mode = + (enum fdl_macrotile_mode) info.macrotile_mode; + } + fd_get_driver_uuid(device->driver_uuid); fd_get_device_uuid(device->device_uuid, &device->dev_id); diff --git a/src/freedreno/vulkan/tu_device.h b/src/freedreno/vulkan/tu_device.h index 6f57e42cb13..a26ec7c7c17 100644 --- a/src/freedreno/vulkan/tu_device.h +++ b/src/freedreno/vulkan/tu_device.h @@ -124,6 +124,8 @@ struct tu_physical_device bool has_cached_non_coherent_memory; uintptr_t level1_dcache_size; + struct fdl_ubwc_config ubwc_config; + bool has_preemption; struct { diff --git a/src/freedreno/vulkan/tu_knl_drm_msm.cc b/src/freedreno/vulkan/tu_knl_drm_msm.cc index 9e5cf65d591..1a7de24a467 100644 --- a/src/freedreno/vulkan/tu_knl_drm_msm.cc +++ b/src/freedreno/vulkan/tu_knl_drm_msm.cc @@ -149,6 +149,39 @@ tu_drm_get_priorities(const struct tu_physical_device *dev) return val; } +static uint32_t +tu_drm_get_highest_bank_bit(const struct tu_physical_device *dev) +{ + uint64_t value; + int ret = tu_drm_get_param(dev->local_fd, MSM_PARAM_HIGHEST_BANK_BIT, &value); + if (ret) + return 0; + + return value; +} + +static enum fdl_macrotile_mode +tu_drm_get_macrotile_mode(const struct tu_physical_device *dev) +{ + uint64_t value; + int ret = tu_drm_get_param(dev->local_fd, MSM_PARAM_MACROTILE_MODE, &value); + if (ret) + return FDL_MACROTILE_INVALID; + + return (enum fdl_macrotile_mode) value; +} + +static uint32_t +tu_drm_get_ubwc_swizzle(const struct tu_physical_device *dev) +{ + uint64_t value; + int ret = tu_drm_get_param(dev->local_fd, MSM_PARAM_UBWC_SWIZZLE, &value); + if (ret) + return ~0; + + return value; +} + static bool tu_drm_is_memory_type_supported(int fd, uint32_t flags) { @@ -1274,6 +1307,10 @@ tu_knl_drm_msm_load(struct tu_instance *instance, device->submitqueue_priority_count = tu_drm_get_priorities(device); + device->ubwc_config.highest_bank_bit = tu_drm_get_highest_bank_bit(device); + device->ubwc_config.bank_swizzle_levels = tu_drm_get_ubwc_swizzle(device); + device->ubwc_config.macrotile_mode = tu_drm_get_macrotile_mode(device); + device->syncobj_type = vk_drm_syncobj_get_type(fd); /* we don't support DRM_CAP_SYNCOBJ_TIMELINE, but drm-shim does */ if (!(device->syncobj_type.features & VK_SYNC_FEATURE_TIMELINE)) diff --git a/src/freedreno/vulkan/tu_knl_drm_virtio.cc b/src/freedreno/vulkan/tu_knl_drm_virtio.cc index 8a8ea6c0074..afb86d018b6 100644 --- a/src/freedreno/vulkan/tu_knl_drm_virtio.cc +++ b/src/freedreno/vulkan/tu_knl_drm_virtio.cc @@ -87,7 +87,7 @@ struct tu_virtio_device { struct u_vector zombie_vmas_stage_2; }; -static int tu_drm_get_param(struct tu_device *dev, uint32_t param, uint64_t *value); +static int tu_drm_get_param(struct vdrm_device *vdrm, uint32_t param, uint64_t *value); /** * Helper for simple pass-thru ioctls @@ -149,7 +149,7 @@ query_faults(struct tu_device *dev, uint64_t *value) if (vdrm_shmem_has_field(vdev->shmem, global_faults)) { global_faults = vdev->shmem->global_faults; } else { - int ret = tu_drm_get_param(dev, MSM_PARAM_FAULTS, &global_faults); + int ret = tu_drm_get_param(vdev->vdrm, MSM_PARAM_FAULTS, &global_faults); if (ret) return ret; } @@ -256,7 +256,7 @@ virtio_device_finish(struct tu_device *dev) } static int -tu_drm_get_param(struct tu_device *dev, uint32_t param, uint64_t *value) +tu_drm_get_param(struct vdrm_device *vdrm, uint32_t param, uint64_t *value) { /* Technically this requires a pipe, but the kernel only supports one pipe * anyway at the time of writing and most of these are clearly pipe @@ -266,7 +266,7 @@ tu_drm_get_param(struct tu_device *dev, uint32_t param, uint64_t *value) .param = param, }; - int ret = virtio_simple_ioctl(dev->vdev->vdrm, DRM_IOCTL_MSM_GET_PARAM, &req); + int ret = virtio_simple_ioctl(vdrm, DRM_IOCTL_MSM_GET_PARAM, &req); if (ret) return ret; @@ -275,16 +275,49 @@ tu_drm_get_param(struct tu_device *dev, uint32_t param, uint64_t *value) return 0; } +static uint32_t +tu_drm_get_highest_bank_bit(struct vdrm_device *vdrm) +{ + uint64_t value; + int ret = tu_drm_get_param(vdrm, MSM_PARAM_HIGHEST_BANK_BIT, &value); + if (ret) + return 0; + + return value; +} + +static enum fdl_macrotile_mode +tu_drm_get_macrotile_mode(struct vdrm_device *vdrm) +{ + uint64_t value; + int ret = tu_drm_get_param(vdrm, MSM_PARAM_MACROTILE_MODE, &value); + if (ret) + return FDL_MACROTILE_INVALID; + + return (enum fdl_macrotile_mode) value; +} + +static uint32_t +tu_drm_get_ubwc_swizzle(struct vdrm_device *vdrm) +{ + uint64_t value; + int ret = tu_drm_get_param(vdrm, MSM_PARAM_UBWC_SWIZZLE, &value); + if (ret) + return ~0; + + return value; +} + static int virtio_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) { - return tu_drm_get_param(dev, MSM_PARAM_TIMESTAMP, ts); + return tu_drm_get_param(dev->vdev->vdrm, MSM_PARAM_TIMESTAMP, ts); } static int virtio_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) { - int ret = tu_drm_get_param(dev, MSM_PARAM_SUSPENDS, suspend_count); + int ret = tu_drm_get_param(dev->vdev->vdrm, MSM_PARAM_SUSPENDS, suspend_count); return ret; } @@ -1335,6 +1368,15 @@ tu_knl_drm_virtio_load(struct tu_instance *instance, */ bool has_preemption = virtio_has_preemption(vdrm); + /* If virglrenderer is too old, we may need another round-trip to get this. + */ + if (caps.u.msm.highest_bank_bit == 0) + caps.u.msm.highest_bank_bit = tu_drm_get_highest_bank_bit(vdrm); + + /* TODO add these to the caps struct */ + uint32_t bank_swizzle_levels = tu_drm_get_ubwc_swizzle(vdrm); + enum fdl_macrotile_mode macrotile_mode = tu_drm_get_macrotile_mode(vdrm); + vdrm_device_close(vdrm); mesa_logd("wire_format_version: %u", caps.wire_format_version); @@ -1349,6 +1391,7 @@ tu_knl_drm_virtio_load(struct tu_instance *instance, mesa_logd("gmem_base: 0x%0" PRIx64, caps.u.msm.gmem_base); mesa_logd("chip_id: 0x%0" PRIx64, caps.u.msm.chip_id); mesa_logd("max_freq: %u", caps.u.msm.max_freq); + mesa_logd("highest_bank_bit: %u", caps.u.msm.highest_bank_bit); if (caps.wire_format_version != 2) { return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, @@ -1389,9 +1432,13 @@ tu_knl_drm_virtio_load(struct tu_instance *instance, device->gmem_base = caps.u.msm.gmem_base; device->va_start = caps.u.msm.va_start; device->va_size = caps.u.msm.va_size; + device->ubwc_config.highest_bank_bit = caps.u.msm.highest_bank_bit; device->has_set_iova = true; device->has_preemption = has_preemption; + device->ubwc_config.bank_swizzle_levels = bank_swizzle_levels; + device->ubwc_config.macrotile_mode = macrotile_mode; + device->gmem_size = debug_get_num_option("TU_GMEM", device->gmem_size); device->has_cached_coherent_memory = caps.u.msm.has_cached_coherent; diff --git a/src/freedreno/vulkan/tu_knl_kgsl.cc b/src/freedreno/vulkan/tu_knl_kgsl.cc index 13b592e9a9b..818f7e611e1 100644 --- a/src/freedreno/vulkan/tu_knl_kgsl.cc +++ b/src/freedreno/vulkan/tu_knl_kgsl.cc @@ -1561,6 +1561,17 @@ tu_knl_kgsl_load(struct tu_instance *instance, int fd) if (get_kgsl_prop(fd, KGSL_PROP_UCHE_GMEM_VADDR, &gmem_iova, sizeof(gmem_iova))) goto fail; + uint32_t highest_bank_bit; + if (get_kgsl_prop(fd, KGSL_PROP_HIGHEST_BANK_BIT, &highest_bank_bit, + sizeof(highest_bank_bit))) + goto fail; + + uint32_t ubwc_version; + if (get_kgsl_prop(fd, KGSL_PROP_UBWC_MODE, &ubwc_version, + sizeof(ubwc_version))) + goto fail; + + /* kgsl version check? */ device->instance = instance; @@ -1599,6 +1610,45 @@ tu_knl_kgsl_load(struct tu_instance *instance, int fd) /* preemption is always supported on kgsl */ device->has_preemption = true; + device->ubwc_config.highest_bank_bit = highest_bank_bit; + + /* The other config values can be partially inferred from the UBWC version, + * but kgsl also hardcodes overrides for specific a6xx versions that we + * have to follow here. Yuck. + */ + switch (ubwc_version) { + case KGSL_UBWC_1_0: + device->ubwc_config.bank_swizzle_levels = 0x7; + device->ubwc_config.macrotile_mode = FDL_MACROTILE_4_CHANNEL; + break; + case KGSL_UBWC_2_0: + device->ubwc_config.bank_swizzle_levels = 0x6; + device->ubwc_config.macrotile_mode = FDL_MACROTILE_4_CHANNEL; + break; + case KGSL_UBWC_3_0: + device->ubwc_config.bank_swizzle_levels = 0x6; + device->ubwc_config.macrotile_mode = FDL_MACROTILE_4_CHANNEL; + break; + case KGSL_UBWC_4_0: + device->ubwc_config.bank_swizzle_levels = 0x6; + device->ubwc_config.macrotile_mode = FDL_MACROTILE_8_CHANNEL; + break; + default: + return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, + "unknown UBWC version 0x%x", ubwc_version); + } + + /* kgsl unfortunately hardcodes some settings for certain GPUs and doesn't + * expose them in the uAPI so hardcode them here to match. + */ + if (device->dev_id.gpu_id == 663 || device->dev_id.gpu_id == 680) { + device->ubwc_config.macrotile_mode = FDL_MACROTILE_8_CHANNEL; + } + if (device->dev_id.gpu_id == 663) { + /* level2_swizzling_dis = 1 */ + device->ubwc_config.bank_swizzle_levels = 0x4; + } + instance->knl = &kgsl_knl_funcs; result = tu_physical_device_init(device, instance);