diff options
170 files changed, 8260 insertions, 5474 deletions
diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index e52d0ce186fe..a740e491dfcc 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -5,6 +5,13 @@ The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core Next (GCN) architecture. +Module Parameters +================= + +The amdgpu driver supports the following module parameters: + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c + Core Driver Infrastructure ========================== @@ -115,3 +122,8 @@ pp_power_profile_mode .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c :doc: pp_power_profile_mode +busy_percent +~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: busy_percent diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 71b9b861f60e..8a440b9fa0fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -190,6 +190,7 @@ struct amdgpu_job; struct amdgpu_irq_src; struct amdgpu_fpriv; struct amdgpu_bo_va_mapping; +struct amdgpu_atif; enum amdgpu_cp_irq { AMDGPU_CP_IRQ_GFX_EOP = 0, @@ -683,8 +684,8 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, unsigned ring_id); void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr); -void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); +void amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); @@ -930,6 +931,11 @@ struct amdgpu_ngg { bool init; }; +struct sq_work { + struct work_struct work; + unsigned ih_data; +}; + struct amdgpu_gfx { struct mutex gpu_clock_mutex; struct amdgpu_gfx_config config; @@ -970,6 +976,8 @@ struct amdgpu_gfx { struct amdgpu_irq_src priv_inst_irq; struct amdgpu_irq_src cp_ecc_error_irq; struct amdgpu_irq_src sq_irq; + struct sq_work sq_work; + /* gfx status */ uint32_t gfx_current_status; /* ce ram size*/ @@ -1271,43 +1279,6 @@ struct amdgpu_vram_scratch { /* * ACPI */ -struct amdgpu_atif_notification_cfg { - bool enabled; - int command_code; -}; - -struct amdgpu_atif_notifications { - bool display_switch; - bool expansion_mode_change; - bool thermal_state; - bool forced_power_state; - bool system_power_state; - bool display_conf_change; - bool px_gfx_switch; - bool brightness_change; - bool dgpu_display_event; -}; - -struct amdgpu_atif_functions { - bool system_params; - bool sbios_requests; - bool select_active_disp; - bool lid_state; - bool get_tv_standard; - bool set_tv_standard; - bool get_panel_expansion_mode; - bool set_panel_expansion_mode; - bool temperature_change; - bool graphics_device_types; -}; - -struct amdgpu_atif { - struct amdgpu_atif_notifications notifications; - struct amdgpu_atif_functions functions; - struct amdgpu_atif_notification_cfg notification_cfg; - struct amdgpu_encoder *encoder_for_bl; -}; - struct amdgpu_atcs_functions { bool get_ext_state; bool pcie_perf_req; @@ -1468,7 +1439,7 @@ struct amdgpu_device { #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_regs[AMDGPU_DEBUGFS_MAX_COMPONENTS]; #endif - struct amdgpu_atif atif; + struct amdgpu_atif *atif; struct amdgpu_atcs atcs; struct mutex srbm_mutex; /* GRBM index mutex. Protects concurrent access to GRBM index */ @@ -1896,6 +1867,12 @@ static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; static inline bool amdgpu_has_atpx(void) { return false; } #endif +#if defined(CONFIG_VGA_SWITCHEROO) && defined(CONFIG_ACPI) +void *amdgpu_atpx_get_dhandle(void); +#else +static inline void *amdgpu_atpx_get_dhandle(void) { return NULL; } +#endif + /* * KMS */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 8fa850a070e0..0d8c3fc6eace 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -34,6 +34,45 @@ #include "amd_acpi.h" #include "atom.h" +struct amdgpu_atif_notification_cfg { + bool enabled; + int command_code; +}; + +struct amdgpu_atif_notifications { + bool display_switch; + bool expansion_mode_change; + bool thermal_state; + bool forced_power_state; + bool system_power_state; + bool display_conf_change; + bool px_gfx_switch; + bool brightness_change; + bool dgpu_display_event; +}; + +struct amdgpu_atif_functions { + bool system_params; + bool sbios_requests; + bool select_active_disp; + bool lid_state; + bool get_tv_standard; + bool set_tv_standard; + bool get_panel_expansion_mode; + bool set_panel_expansion_mode; + bool temperature_change; + bool graphics_device_types; +}; + +struct amdgpu_atif { + acpi_handle handle; + + struct amdgpu_atif_notifications notifications; + struct amdgpu_atif_functions functions; + struct amdgpu_atif_notification_cfg notification_cfg; + struct amdgpu_encoder *encoder_for_bl; +}; + /* Call the ATIF method */ /** @@ -46,8 +85,9 @@ * Executes the requested ATIF function (all asics). * Returns a pointer to the acpi output buffer. */ -static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, - struct acpi_buffer *params) +static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, + int function, + struct acpi_buffer *params) { acpi_status status; union acpi_object atif_arg_elements[2]; @@ -70,7 +110,8 @@ static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, atif_arg_elements[1].integer.value = 0; } - status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); + status = acpi_evaluate_object(atif->handle, NULL, &atif_arg, + &buffer); /* Fail only if calling the method fails and ATIF is supported */ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { @@ -141,15 +182,14 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas * (all asics). * returns 0 on success, error on failure. */ -static int amdgpu_atif_verify_interface(acpi_handle handle, - struct amdgpu_atif *atif) +static int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) { union acpi_object *info; struct atif_verify_interface output; size_t size; int err = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); if (!info) return -EIO; @@ -176,6 +216,35 @@ out: return err; } +static acpi_handle amdgpu_atif_probe_handle(acpi_handle dhandle) +{ + acpi_handle handle = NULL; + char acpi_method_name[255] = { 0 }; + struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; + acpi_status status; + + /* For PX/HG systems, ATIF and ATPX are in the iGPU's namespace, on dGPU only + * systems, ATIF is in the dGPU's namespace. + */ + status = acpi_get_handle(dhandle, "ATIF", &handle); + if (ACPI_SUCCESS(status)) + goto out; + + if (amdgpu_has_atpx()) { + status = acpi_get_handle(amdgpu_atpx_get_dhandle(), "ATIF", + &handle); + if (ACPI_SUCCESS(status)) + goto out; + } + + DRM_DEBUG_DRIVER("No ATIF handle found\n"); + return NULL; +out: + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name); + return handle; +} + /** * amdgpu_atif_get_notification_params - determine notify configuration * @@ -188,15 +257,16 @@ out: * where n is specified in the result if a notifier is used. * Returns 0 on success, error on failure. */ -static int amdgpu_atif_get_notification_params(acpi_handle handle, - struct amdgpu_atif_notification_cfg *n) +static int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) { union acpi_object *info; + struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg; struct atif_system_params params; size_t size; int err = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, + NULL); if (!info) { err = -EIO; goto out; @@ -250,14 +320,15 @@ out: * (all asics). * Returns 0 on success, error on failure. */ -static int amdgpu_atif_get_sbios_requests(acpi_handle handle, - struct atif_sbios_requests *req) +static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, + struct atif_sbios_requests *req) { union acpi_object *info; size_t size; int count = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, + NULL); if (!info) return -EIO; @@ -290,11 +361,10 @@ out: * Returns NOTIFY code */ static int amdgpu_atif_handler(struct amdgpu_device *adev, - struct acpi_bus_event *event) + struct acpi_bus_event *event) { - struct amdgpu_atif *atif = &adev->atif; + struct amdgpu_atif *atif = adev->atif; struct atif_sbios_requests req; - acpi_handle handle; int count; DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", @@ -303,14 +373,14 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) return NOTIFY_DONE; - if (!atif->notification_cfg.enabled || + if (!atif || + !atif->notification_cfg.enabled || event->type != atif->notification_cfg.command_code) /* Not our event */ return NOTIFY_DONE; /* Check pending SBIOS requests */ - handle = ACPI_HANDLE(&adev->pdev->dev); - count = amdgpu_atif_get_sbios_requests(handle, &req); + count = amdgpu_atif_get_sbios_requests(atif, &req); if (count <= 0) return NOTIFY_DONE; @@ -641,8 +711,8 @@ static int amdgpu_acpi_event(struct notifier_block *nb, */ int amdgpu_acpi_init(struct amdgpu_device *adev) { - acpi_handle handle; - struct amdgpu_atif *atif = &adev->atif; + acpi_handle handle, atif_handle; + struct amdgpu_atif *atif; struct amdgpu_atcs *atcs = &adev->atcs; int ret; @@ -658,12 +728,26 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); } + /* Probe for ATIF, and initialize it if found */ + atif_handle = amdgpu_atif_probe_handle(handle); + if (!atif_handle) + goto out; + + atif = kzalloc(sizeof(*atif), GFP_KERNEL); + if (!atif) { + DRM_WARN("Not enough memory to initialize ATIF\n"); + goto out; + } + atif->handle = atif_handle; + /* Call the ATIF method */ - ret = amdgpu_atif_verify_interface(handle, atif); + ret = amdgpu_atif_verify_interface(atif); if (ret) { DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); + kfree(atif); goto out; } + adev->atif = atif; if (atif->notifications.brightness_change) { struct drm_encoder *tmp; @@ -693,8 +777,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) } if (atif->functions.system_params) { - ret = amdgpu_atif_get_notification_params(handle, - &atif->notification_cfg); + ret = amdgpu_atif_get_notification_params(atif); if (ret) { DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", ret); @@ -720,4 +803,6 @@ out: void amdgpu_acpi_fini(struct amdgpu_device *adev) { unregister_acpi_notifier(&adev->acpi_nb); + if (adev->atif) + kfree(adev->atif); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index daa06e7c5bb7..b33f1680c9a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -32,7 +32,7 @@ struct amdgpu_atpx_functions { bool switch_start; bool switch_end; bool disp_connectors_mapping; - bool disp_detetion_ports; + bool disp_detection_ports; }; struct amdgpu_atpx { @@ -90,6 +90,12 @@ bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays; } +#if defined(CONFIG_ACPI) +void *amdgpu_atpx_get_dhandle(void) { + return amdgpu_atpx_priv.dhandle; +} +#endif + /** * amdgpu_atpx_call - call an ATPX method * @@ -156,7 +162,7 @@ static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mas f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; - f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; + f->disp_detection_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index e950730f1933..693ec5ea4950 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -314,17 +314,17 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, (adev->pdev->revision == 0x81) || (adev->pdev->device == 0x665f)) { info->is_kicker = true; - strcpy(fw_name, "radeon/bonaire_k_smc.bin"); + strcpy(fw_name, "amdgpu/bonaire_k_smc.bin"); } else { - strcpy(fw_name, "radeon/bonaire_smc.bin"); + strcpy(fw_name, "amdgpu/bonaire_smc.bin"); } break; case CHIP_HAWAII: if (adev->pdev->revision == 0x80) { info->is_kicker = true; - strcpy(fw_name, "radeon/hawaii_k_smc.bin"); + strcpy(fw_name, "amdgpu/hawaii_k_smc.bin"); } else { - strcpy(fw_name, "radeon/hawaii_smc.bin"); + strcpy(fw_name, "amdgpu/hawaii_smc.bin"); } break; case CHIP_TOPAZ: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 64b3a1ed04dc..0120b24fae1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -104,7 +104,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, failed: for (j = 0; j < i; j++) - drm_sched_entity_fini(&adev->rings[j]->sched, + drm_sched_entity_destroy(&adev->rings[j]->sched, &ctx->rings[j].entity); kfree(ctx->fences); ctx->fences = NULL; @@ -178,7 +178,7 @@ static void amdgpu_ctx_do_release(struct kref *ref) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - drm_sched_entity_fini(&ctx->adev->rings[i]->sched, + drm_sched_entity_destroy(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity); } @@ -444,7 +444,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr) idr_init(&mgr->ctx_handles); } -void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) +void amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr) { struct amdgpu_ctx *ctx; struct idr *idp; @@ -466,14 +466,14 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - max_wait = drm_sched_entity_do_release(&ctx->adev->rings[i]->sched, + max_wait = drm_sched_entity_flush(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity, max_wait); } } mutex_unlock(&mgr->lock); } -void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) +void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) { struct amdgpu_ctx *ctx; struct idr *idp; @@ -492,7 +492,7 @@ void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) continue; if (kref_read(&ctx->refcount) == 1) - drm_sched_entity_cleanup(&ctx->adev->rings[i]->sched, + drm_sched_entity_fini(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity); else DRM_ERROR("ctx %p is still alive\n", ctx); @@ -506,7 +506,7 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) struct idr *idp; uint32_t id; - amdgpu_ctx_mgr_entity_cleanup(mgr); + amdgpu_ctx_mgr_entity_fini(mgr); idp = &mgr->ctx_handles; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d82d0d314285..9883fa9bb41b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1076,7 +1076,7 @@ static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = { /** * amdgpu_device_ip_set_clockgating_state - set the CG state * - * @adev: amdgpu_device pointer + * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: clockgating state (gate or ungate) * @@ -1110,7 +1110,7 @@ int amdgpu_device_ip_set_clockgating_state(void *dev, /** * amdgpu_device_ip_set_powergating_state - set the PG state * - * @adev: amdgpu_device pointer + * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: powergating state (gate or ungate) * @@ -1221,7 +1221,7 @@ bool amdgpu_device_ip_is_idle(struct amdgpu_device *adev, * amdgpu_device_ip_get_ip_block - get a hw IP pointer * * @adev: amdgpu_device pointer - * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) + * @type: Type of hardware IP (SMU, GFX, UVD, etc.) * * Returns a pointer to the hardware IP block structure * if it exists for the asic, otherwise NULL. @@ -1707,10 +1707,6 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) if (amdgpu_emu_mode == 1) return 0; - r = amdgpu_ib_ring_tests(adev); - if (r) - DRM_ERROR("ib ring test failed (%d).\n", r); - for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; @@ -1730,17 +1726,34 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) } } - if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) { - /* enable gfx powergating */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); - /* enable gfxoff */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - AMD_PG_STATE_GATE); - } + return 0; +} + +static int amdgpu_device_ip_late_set_pg_state(struct amdgpu_device *adev) +{ + int i = 0, r; + if (amdgpu_emu_mode == 1) + return 0; + + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_blocks[i].status.valid) + continue; + /* skip CG for VCE/UVD, it's handled specially */ + if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && + adev->ip_blocks[i].version->funcs->set_powergating_state) { + /* enable powergating to save power */ + r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev, + AMD_PG_STATE_GATE); + if (r) { + DRM_ERROR("set_powergating_state(gate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + return r; + } + } + } return 0; } @@ -1774,6 +1787,9 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) } } + amdgpu_device_ip_late_set_cg_state(adev); + amdgpu_device_ip_late_set_pg_state(adev); + queue_delayed_work(system_wq, &adev->late_init_work, msecs_to_jiffies(AMDGPU_RESUME_MS)); @@ -1812,6 +1828,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) adev->ip_blocks[i].version->funcs->name, r); return r; } + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false); r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); /* XXX handle errors */ if (r) { @@ -1900,7 +1918,11 @@ static void amdgpu_device_ip_late_init_func_handler(struct work_struct *work) { struct amdgpu_device *adev = container_of(work, struct amdgpu_device, late_init_work.work); - amdgpu_device_ip_late_set_cg_state(adev); + int r; + + r = amdgpu_ib_ring_tests(adev); + if (r) + DRM_ERROR("ib ring test failed (%d).\n", r); } /** @@ -1921,12 +1943,6 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_request_full_gpu(adev, false); - /* ungate SMC block powergating */ - if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - AMD_PG_STATE_UNGATE); - /* ungate SMC block first */ r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, AMD_CG_STATE_UNGATE); @@ -1934,6 +1950,10 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) DRM_ERROR("set_clockgating_state(ungate) SMC failed %d\n", r); } + /* call smu to disable gfx off feature first when suspend */ + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false); + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue; @@ -2209,7 +2229,7 @@ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev) * amdgpu_device_init - initialize the driver * * @adev: amdgpu_device pointer - * @pdev: drm dev pointer + * @ddev: drm dev pointer * @pdev: pci dev pointer * @flags: driver flags * @@ -2582,8 +2602,9 @@ void amdgpu_device_fini(struct amdgpu_device *adev) /** * amdgpu_device_suspend - initiate device suspend * - * @pdev: drm dev pointer - * @state: suspend state + * @dev: drm dev pointer + * @suspend: suspend state + * @fbcon : notify the fbdev of suspend * * Puts the hw in the suspend state (all asics). * Returns 0 for success or an error on failure. @@ -2681,7 +2702,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) /** * amdgpu_device_resume - initiate device resume * - * @pdev: drm dev pointer + * @dev: drm dev pointer + * @resume: resume state + * @fbcon : notify the fbdev of resume * * Bring the hw back to operating state (all asics). * Returns 0 for success or an error on failure. @@ -3144,6 +3167,7 @@ out: * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf * * @adev: amdgpu device pointer + * @from_hypervisor: request from hypervisor * * do VF FLR and reinitialize Asic * return 0 means successed otherwise failed @@ -3191,7 +3215,7 @@ error: * * @adev: amdgpu device pointer * @job: which job trigger hang - * @force forces reset regardless of amdgpu_gpu_recovery + * @force: forces reset regardless of amdgpu_gpu_recovery * * Attempt to reset the GPU if it has hung (all asics). * Returns 0 for success or an error on failure. @@ -3291,8 +3315,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, */ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) { - u32 mask; - int ret; + struct pci_dev *pdev; + enum pci_bus_speed speed_cap; + enum pcie_link_width link_width; if (amdgpu_pcie_gen_cap) adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap; @@ -3310,27 +3335,61 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) } if (adev->pm.pcie_gen_mask == 0) { - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (!ret) { - adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + /* asic caps */ + pdev = adev->pdev; + speed_cap = pcie_get_speed_cap(pdev); + if (speed_cap == PCI_SPEED_UNKNOWN) { + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); - - if (mask & DRM_PCIE_SPEED_25) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1; - if (mask & DRM_PCIE_SPEED_50) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2; - if (mask & DRM_PCIE_SPEED_80) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3; } else { - adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK; + if (speed_cap == PCIE_SPEED_16_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4); + else if (speed_cap == PCIE_SPEED_8_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); + else if (speed_cap == PCIE_SPEED_5_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2); + else + adev->pm.pcie_gen_mask |= CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1; + } + /* platform caps */ + pdev = adev->ddev->pdev->bus->self; + speed_cap = pcie_get_speed_cap(pdev); + if (speed_cap == PCI_SPEED_UNKNOWN) { + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); + } else { + if (speed_cap == PCIE_SPEED_16_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4); + else if (speed_cap == PCIE_SPEED_8_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3); + else if (speed_cap == PCIE_SPEED_5_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); + else + adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1; + } } if (adev->pm.pcie_mlw_mask == 0) { - ret = drm_pcie_get_max_link_width(adev->ddev, &mask); - if (!ret) { - switch (mask) { - case 32: + pdev = adev->ddev->pdev->bus->self; + link_width = pcie_get_width_cap(pdev); + if (link_width == PCIE_LNK_WIDTH_UNKNOWN) { + adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_PCIE_MLW_MASK; + } else { + switch (link_width) { + case PCIE_LNK_X32: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | @@ -3339,7 +3398,7 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 16: + case PCIE_LNK_X16: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | @@ -3347,36 +3406,34 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 12: + case PCIE_LNK_X12: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 8: + case PCIE_LNK_X8: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 4: + case PCIE_LNK_X4: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 2: + case PCIE_LNK_X2: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 1: + case PCIE_LNK_X1: adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1; break; default: break; } - } else { - adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK; } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c index 77ad59ade85c..1c4595562f8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c @@ -28,6 +28,7 @@ #include "amdgpu_i2c.h" #include "amdgpu_dpm.h" #include "atom.h" +#include "amd_pcie.h" void amdgpu_dpm_print_class_info(u32 class, u32 class2) { @@ -936,9 +937,11 @@ enum amdgpu_pcie_gen amdgpu_get_pcie_gen_support(struct amdgpu_device *adev, case AMDGPU_PCIE_GEN3: return AMDGPU_PCIE_GEN3; default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) + if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) && + (default_gen == AMDGPU_PCIE_GEN3)) return AMDGPU_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) + else if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) && + (default_gen == AMDGPU_PCIE_GEN2)) return AMDGPU_PCIE_GEN2; else return AMDGPU_PCIE_GEN1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index 9acfbee91c40..ff24e1cc5b65 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -287,12 +287,6 @@ enum amdgpu_pcie_gen { #define amdgpu_dpm_force_performance_level(adev, l) \ ((adev)->powerplay.pp_funcs->force_performance_level((adev)->powerplay.pp_handle, (l))) -#define amdgpu_dpm_powergate_uvd(adev, g) \ - ((adev)->powerplay.pp_funcs->powergate_uvd((adev)->powerplay.pp_handle, (g))) - -#define amdgpu_dpm_powergate_vce(adev, g) \ - ((adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g))) - #define amdgpu_dpm_get_current_power_state(adev) \ ((adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)) @@ -347,6 +341,10 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->set_clockgating_by_smu(\ (adev)->powerplay.pp_handle, msg_id)) +#define amdgpu_dpm_set_powergating_by_smu(adev, block_type, gate) \ + ((adev)->powerplay.pp_funcs->set_powergating_by_smu(\ + (adev)->powerplay.pp_handle, block_type, gate)) + #define amdgpu_dpm_get_power_profile_mode(adev, buf) \ ((adev)->powerplay.pp_funcs->get_power_profile_mode(\ (adev)->powerplay.pp_handle, buf)) @@ -359,10 +357,6 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\ (adev)->powerplay.pp_handle, type, parameter, size)) -#define amdgpu_dpm_set_mmhub_powergating_by_smu(adev) \ - ((adev)->powerplay.pp_funcs->set_mmhub_powergating_by_smu( \ - (adev)->powerplay.pp_handle)) - struct amdgpu_dpm { struct amdgpu_ps *ps; /* number of valid power states */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index a549483032b0..06aede194bf8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1,10 +1,3 @@ -/** - * \file amdgpu_drv.c - * AMD Amdgpu driver - * - * \author Gareth Hughes <gareth@valinux.com> - */ - /* * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -122,7 +115,8 @@ uint amdgpu_pg_mask = 0xffffffff; uint amdgpu_sdma_phase_quantum = 32; char *amdgpu_disable_cu = NULL; char *amdgpu_virtual_display = NULL; -uint amdgpu_pp_feature_mask = 0xffff3fff; /* gfxoff (bit 15) disabled by default */ +/* OverDrive(bit 14),gfxoff(bit 15),stutter mode(bit 17) disabled by default*/ +uint amdgpu_pp_feature_mask = 0xfffd3fff; int amdgpu_ngg = 0; int amdgpu_prim_buf_per_se = 0; int amdgpu_pos_buf_per_se = 0; @@ -135,102 +129,239 @@ int amdgpu_gpu_recovery = -1; /* auto */ int amdgpu_emu_mode = 0; uint amdgpu_smu_memory_pool_size = 0; +/** + * DOC: vramlimit (int) + * Restrict the total amount of VRAM in MiB for testing. The default is 0 (Use full VRAM). + */ MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); +/** + * DOC: vis_vramlimit (int) + * Restrict the amount of CPU visible VRAM in MiB for testing. The default is 0 (Use full CPU visible VRAM). + */ MODULE_PARM_DESC(vis_vramlimit, "Restrict visible VRAM for testing, in megabytes"); module_param_named(vis_vramlimit, amdgpu_vis_vram_limit, int, 0444); +/** + * DOC: gartsize (uint) + * Restrict the size of GART in Mib (32, 64, etc.) for testing. The default is -1 (The size depends on asic). + */ MODULE_PARM_DESC(gartsize, "Size of GART to setup in megabytes (32, 64, etc., -1=auto)"); module_param_named(gartsize, amdgpu_gart_size, uint, 0600); +/** + * DOC: gttsize (int) + * Restrict the size of GTT domain in MiB for testing. The default is -1 (It's VRAM size if 3GB < VRAM < 3/4 RAM, + * otherwise 3/4 RAM size). + */ MODULE_PARM_DESC(gttsize, "Size of the GTT domain in megabytes (-1 = auto)"); module_param_named(gttsize, amdgpu_gtt_size, int, 0600); +/** + * DOC: moverate (int) + * Set maximum buffer migration rate in MB/s. The default is -1 (8 MB/s). + */ MODULE_PARM_DESC(moverate, "Maximum buffer migration rate in MB/s. (32, 64, etc., -1=auto, 0=1=disabled)"); module_param_named(moverate, amdgpu_moverate, int, 0600); +/** + * DOC: benchmark (int) + * Run benchmarks. The default is 0 (Skip benchmarks). + */ MODULE_PARM_DESC(benchmark, "Run benchmark"); module_param_named(benchmark, amdgpu_benchmarking, int, 0444); +/** + * DOC: test (int) + * Test BO GTT->VRAM and VRAM->GTT GPU copies. The default is 0 (Skip test, only set 1 to run test). + */ MODULE_PARM_DESC(test, "Run tests"); module_param_named(test, amdgpu_testing, int, 0444); +/** + * DOC: audio (int) + * Set HDMI/DPAudio. Only affects non-DC display handling. The default is -1 (Enabled), set 0 to disabled it. + */ MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)"); module_param_named(audio, amdgpu_audio, int, 0444); +/** + * DOC: disp_priority (int) + * Set display Priority (1 = normal, 2 = high). Only affects non-DC display handling. The default is 0 (auto). + */ MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); module_param_named(disp_priority, amdgpu_disp_priority, int, 0444); +/** + * DOC: hw_i2c (int) + * To enable hw i2c engine. Only affects non-DC display handling. The default is 0 (Disabled). + */ MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); module_param_named(hw_i2c, amdgpu_hw_i2c, int, 0444); +/** + * DOC: pcie_gen2 (int) + * To disable PCIE Gen2/3 mode (0 = disable, 1 = enable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (-1 = auto, 0 = disable, 1 = enable)"); module_param_named(pcie_gen2, amdgpu_pcie_gen2, int, 0444); +/** + * DOC: msi (int) + * To disable Message Signaled Interrupts (MSI) functionality (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(msi, amdgpu_msi, int, 0444); +/** + * DOC: lockup_timeout (int) + * Set GPU scheduler timeout value in ms. Value 0 is invalidated, will be adjusted to 10000. + * Negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET). The default is 10000. + */ MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms > 0 (default 10000)"); module_param_named(lockup_timeout, amdgpu_lockup_timeout, int, 0444); +/** + * DOC: dpm (int) + * Override for dynamic power management setting (1 = enable, 0 = disable). The default is -1 (auto). + */ MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(dpm, amdgpu_dpm, int, 0444); +/** + * DOC: fw_load_type (int) + * Set different firmware loading type for debugging (0 = direct, 1 = SMU, 2 = PSP). The default is -1 (auto). + */ MODULE_PARM_DESC(fw_load_type, "firmware loading type (0 = direct, 1 = SMU, 2 = PSP, -1 = auto)"); module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444); +/** + * DOC: aspm (int) + * To disable ASPM (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(aspm, amdgpu_aspm, int, 0444); +/** + * DOC: runpm (int) + * Override for runtime power management control for dGPUs in PX/HG laptops. The amdgpu driver can dynamically power down + * the dGPU on PX/HG laptops when it is idle. The default is -1 (auto enable). Setting the value to 0 disables this functionality. + */ MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)"); module_param_named(runpm, amdgpu_runtime_pm, int, 0444); +/** + * DOC: ip_block_mask (uint) + * Override what IP blocks are enabled on the GPU. Each GPU is a collection of IP blocks (gfx, display, video, etc.). + * Use this parameter to disable specific blocks. Note that the IP blocks do not have a fixed index. Some asics may not have + * some IPs or may include multiple instances of an IP so the ordering various from asic to asic. See the driver output in + * the kernel log for the list of IPs on the asic. The default is 0xffffffff (enable all blocks on a device). + */ MODULE_PARM_DESC(ip_block_mask, "IP Block Mask (all blocks enabled (default))"); module_param_named(ip_block_mask, amdgpu_ip_block_mask, uint, 0444); +/** + * DOC: bapm (int) + * Bidirectional Application Power Management (BAPM) used to dynamically share TDP between CPU and GPU. Set value 0 to disable it. + * The default -1 (auto, enabled) + */ MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(bapm, amdgpu_bapm, int, 0444); +/** + * DOC: deep_color (int) + * Set 1 to enable Deep Color support. Only affects non-DC display handling. The default is 0 (disabled). + */ MODULE_PARM_DESC(deep_color, "Deep Color support (1 = enable, 0 = disable (default))"); module_param_named(deep_color, amdgpu_deep_color, int, 0444); +/** + * DOC: vm_size (int) + * Override the size of the GPU's per client virtual address space in GiB. The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_size, "VM address space size in gigabytes (default 64GB)"); module_param_named(vm_size, amdgpu_vm_size, int, 0444); +/** + * DOC: vm_fragment_size (int) + * Override VM fragment size in bits (4, 5, etc. 4 = 64K, 9 = 2M). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_fragment_size, "VM fragment size in bits (4, 5, etc. 4 = 64K (default), Max 9 = 2M)"); module_param_named(vm_fragment_size, amdgpu_vm_fragment_size, int, 0444); +/** + * DOC: vm_block_size (int) + * Override VM page table size in bits (default depending on vm_size and hw setup). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default depending on vm_size)"); module_param_named(vm_block_size, amdgpu_vm_block_size, int, 0444); +/** + * DOC: vm_fault_stop (int) + * Stop on VM fault for debugging (0 = never, 1 = print first, 2 = always). The default is 0 (No stop). + */ MODULE_PARM_DESC(vm_fault_stop, "Stop on VM fault (0 = never (default), 1 = print first, 2 = always)"); module_param_named(vm_fault_stop, amdgpu_vm_fault_stop, int, 0444); +/** + * DOC: vm_debug (int) + * Debug VM handling (0 = disabled, 1 = enabled). The default is 0 (Disabled). + */ MODULE_PARM_DESC(vm_debug, "Debug VM handling (0 = disabled (default), 1 = enabled)"); module_param_named(vm_debug, amdgpu_vm_debug, int, 0644); +/** + * DOC: vm_update_mode (int) + * Override VM update mode. VM updated by using CPU (0 = never, 1 = Graphics only, 2 = Compute only, 3 = Both). The default + * is -1 (Only in large BAR(LB) systems Compute VM tables will be updated by CPU, otherwise 0, never). + */ MODULE_PARM_DESC(vm_update_mode, "VM update using CPU (0 = never (default except for large BAR(LB)), 1 = Graphics only, 2 = Compute only (default for LB), 3 = Both"); module_param_named(vm_update_mode, amdgpu_vm_update_mode, int, 0444); +/** + * DOC: vram_page_split (int) + * Override the number of pages after we split VRAM allocations (default 512, -1 = disable). The default is 512. + */ MODULE_PARM_DESC(vram_page_split, "Number of pages after we split VRAM allocations (default 512, -1 = disable)"); module_param_named(vram_page_split, amdgpu_vram_page_split, int, 0444); +/** + * DOC: exp_hw_support (int) + * Enable experimental hw support (1 = enable). The default is 0 (disabled). + */ MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))"); module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444); +/** + * DOC: dc (int) + * Disable/Enable Display Core driver for debugging (1 = enable, 0 = disable). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(dc, "Display Core driver (1 = enable, 0 = disable, -1 = auto (default))"); module_param_named(dc, amdgpu_dc, int, 0444); MODULE_PARM_DESC(dc_log, "Display Core Log Level (0 = minimal (default), 1 = chatty"); module_param_named(dc_log, amdgpu_dc_log, int, 0444); +/** + * DOC: sched_jobs (int) + * Override the max number of jobs supported in the sw queue. The default is 32. + */ MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)"); module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444); +/** + * DOC: sched_hw_submission (int) + * Override the max number of HW submissions. The default is 2. + */ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)"); module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); +/** + * DOC: ppfeaturemask (uint) + * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. + * The default is the current set of stable power features. + */ MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444); @@ -240,58 +371,135 @@ module_param_named(no_evict, amdgpu_no_evict, int, 0444); MODULE_PARM_DESC(direct_gma_size, "Direct GMA size in megabytes (max 96MB)"); module_param_named(direct_gma_size, amdgpu_direct_gma_size, int, 0444); +/** + * DOC: pcie_gen_cap (uint) + * Override PCIE gen speed capabilities. See the CAIL flags in drivers/gpu/drm/amd/include/amd_pcie.h. + * The default is 0 (automatic for each asic). + */ MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))"); module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444); +/** + * DOC: pcie_lane_cap (uint) + * Override PCIE lanes capabilities. See the CAIL flags in drivers/gpu/drm/amd/include/amd_pcie.h. + * The default is 0 (automatic for each asic). + */ MODULE_PARM_DESC(pcie_lane_cap, "PCIE Lane Caps (0: autodetect (default))"); module_param_named(pcie_lane_cap, amdgpu_pcie_lane_cap, uint, 0444); +/** + * DOC: cg_mask (uint) + * Override Clockgating features enabled on GPU (0 = disable clock gating). See the AMD_CG_SUPPORT flags in + * drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffff (all enabled). + */ MODULE_PARM_DESC(cg_mask, "Clockgating flags mask (0 = disable clock gating)"); module_param_named(cg_mask, amdgpu_cg_mask, uint, 0444); +/** + * DOC: pg_mask (uint) + * Override Powergating features enabled on GPU (0 = disable power gating). See the AMD_PG_SUPPORT flags in + * drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffff (all enabled). + */ MODULE_PARM_DESC(pg_mask, "Powergating flags mask (0 = disable power gating)"); module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444); +/** + * DOC: sdma_phase_quantum (uint) + * Override SDMA context switch phase quantum (x 1K GPU clock cycles, 0 = no change). The default is 32. + */ MODULE_PARM_DESC(sdma_phase_quantum, "SDMA context switch phase quantum (x 1K GPU clock cycles, 0 = no change (default 32))"); module_param_named(sdma_phase_quantum, amdgpu_sdma_phase_quantum, uint, 0444); +/** + * DOC: disable_cu (charp) + * Set to disable CUs (It's set like se.sh.cu,...). The default is NULL. + */ MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)"); module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444); +/** + * DOC: virtual_display (charp) + * Set to enable virtual display feature. This feature provides a virtual display hardware on headless boards + * or in virtualized environments. It will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x. It's the pci address of + * the device, plus the number of crtcs to expose. E.g., 0000:26:00.0,4 would enable 4 virtual crtcs on the pci + * device at 26:00.0. The default is NULL. + */ MODULE_PARM_DESC(virtual_display, "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x)"); module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444); +/** + * DOC: ngg (int) + * Set to enable Next Generation Graphics (1 = enable). The default is 0 (disabled). + */ MODULE_PARM_DESC(ngg, "Next Generation Graphics (1 = enable, 0 = disable(default depending on gfx))"); module_param_named(ngg, amdgpu_ngg, int, 0444); +/** + * DOC: prim_buf_per_se (int) + * Override the size of Primitive Buffer per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(prim_buf_per_se, "the size of Primitive Buffer per Shader Engine (default depending on gfx)"); module_param_named(prim_buf_per_se, amdgpu_prim_buf_per_se, int, 0444); +/** + * DOC: pos_buf_per_se (int) + * Override the size of Position Buffer per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(pos_buf_per_se, "the size of Position Buffer per Shader Engine (default depending on gfx)"); module_param_named(pos_buf_per_se, amdgpu_pos_buf_per_se, int, 0444); +/** + * DOC: cntl_sb_buf_per_se (int) + * Override the size of Control Sideband per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(cntl_sb_buf_per_se, "the size of Control Sideband per Shader Engine (default depending on gfx)"); module_param_named(cntl_sb_buf_per_se, amdgpu_cntl_sb_buf_per_se, int, 0444); +/** + * DOC: param_buf_per_se (int) + * Override the size of Off-Chip Pramater Cache per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(param_buf_per_se, "the size of Off-Chip Pramater Cache per Shader Engine (default depending on gfx)"); module_param_named(param_buf_per_se, amdgpu_param_buf_per_se, int, 0444); +/** + * DOC: job_hang_limit (int) + * Set how much time allow a job hang and not drop it. The default is 0. + */ MODULE_PARM_DESC(job_hang_limit, "how much time allow a job hang and not drop it (default 0)"); module_param_named(job_hang_limit, amdgpu_job_hang_limit, int ,0444); +/** + * DOC: lbpw (int) + * Override Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(lbpw, "Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(lbpw, amdgpu_lbpw, int, 0444); MODULE_PARM_DESC(compute_multipipe, "Force compute queues to be spread across pipes (1 = enable, 0 = disable, -1 = auto)"); module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444); +/** + * DOC: gpu_recovery (int) + * Set to enable GPU recovery mechanism (1 = enable, 0 = disable). The default is -1 (auto, disabled except SRIOV). + */ MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)"); module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444); +/** + * DOC: emu_mode (int) + * Set value 1 to enable emulation mode. This is only needed when running on an emulator. The default is 0 (disabled). + */ MODULE_PARM_DESC(emu_mode, "Emulation mode, (1 = enable, 0 = disable)"); module_param_named(emu_mode, amdgpu_emu_mode, int, 0444); +/** + * DOC: si_support (int) + * Set SI support driver. This parameter works after set config CONFIG_DRM_AMDGPU_SI. For SI asic, when radeon driver is enabled, + * set value 0 to use radeon driver, while set value 1 to use amdgpu driver. The default is using radeon driver when it available, + * otherwise using amdgpu driver. + */ #ifdef CONFIG_DRM_AMDGPU_SI #if defined(CONFIG_DRM_RADEON) || defined(CONFIG_DRM_RADEON_MODULE) @@ -305,6 +513,12 @@ MODULE_PARM_DESC(si_support, "SI support (1 = enabled (default), 0 = disabled)") module_param_named(si_support, amdgpu_si_support, int, 0444); #endif +/** + * DOC: cik_support (int) + * Set CIK support driver. This parameter works after set config CONFIG_DRM_AMDGPU_CIK. For CIK asic, when radeon driver is enabled, + * set value 0 to use radeon driver, while set value 1 to use amdgpu driver. The default is using radeon driver when it available, + * otherwise using amdgpu driver. + */ #ifdef CONFIG_DRM_AMDGPU_CIK #if defined(CONFIG_DRM_RADEON) || defined(CONFIG_DRM_RADEON_MODULE) @@ -318,6 +532,11 @@ MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled) module_param_named(cik_support, amdgpu_cik_support, int, 0444); #endif +/** + * DOC: smu_memory_pool_size (uint) + * It is used to reserve gtt for smu debug usage, setting value 0 to disable it. The actual size is value * 256MiB. + * E.g. 0x1 = 256Mbyte, 0x2 = 512Mbyte, 0x4 = 1 Gbyte, 0x8 = 2GByte. The default is 0 (disabled). + */ MODULE_PARM_DESC(smu_memory_pool_size, "reserve gtt for smu debug usage, 0 = disable," "0x1 = 256Mbyte, 0x2 = 512Mbyte, 0x4 = 1 Gbyte, 0x8 = 2GByte"); @@ -664,7 +883,7 @@ retry_init: err_pci: pci_disable_device(pdev); err_free: - drm_dev_unref(dev); + drm_dev_put(dev); return ret; } @@ -674,7 +893,7 @@ amdgpu_pci_remove(struct pci_dev *pdev) struct drm_device *dev = pci_get_drvdata(pdev); drm_dev_unregister(dev); - drm_dev_unref(dev); + drm_dev_put(dev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -860,7 +1079,7 @@ static int amdgpu_flush(struct file *f, fl_owner_t id) struct drm_file *file_priv = f->private_data; struct amdgpu_fpriv *fpriv = file_priv->driver_priv; - amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr); + amdgpu_ctx_mgr_entity_flush(&fpriv->ctx_mgr); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index bc5fd8ebab5d..811c62927c38 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -146,7 +146,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | AMDGPU_GEM_CREATE_VRAM_CLEARED, - true, NULL, &gobj); + ttm_bo_type_kernel, NULL, &gobj); if (ret) { pr_err("failed to allocate framebuffer (%d)\n", aligned_size); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index dd11b7313ca0..36113cb60ca2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -234,7 +234,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, } t = offset / AMDGPU_GPU_PAGE_SIZE; - p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; for (i = 0; i < pages; i++, p++) { #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS adev->gart.pages[p] = NULL; @@ -243,7 +243,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, if (!adev->gart.ptr) continue; - for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { + for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; @@ -282,7 +282,7 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, for (i = 0; i < pages; i++) { page_base = dma_addr[i]; - for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { + for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; } @@ -319,7 +319,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS t = offset / AMDGPU_GPU_PAGE_SIZE; - p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; for (i = 0; i < pages; i++, p++) adev->gart.pages[p] = pagelist ? pagelist[i] : NULL; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h index 456295c00291..9f9e9dc87da1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h @@ -37,6 +37,8 @@ struct amdgpu_bo; #define AMDGPU_GPU_PAGE_SHIFT 12 #define AMDGPU_GPU_PAGE_ALIGN(a) (((a) + AMDGPU_GPU_PAGE_MASK) & ~AMDGPU_GPU_PAGE_MASK) +#define AMDGPU_GPU_PAGES_IN_CPU_PAGE (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE) + struct amdgpu_gart { u64 table_addr; struct amdgpu_bo *robj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 89743cdc1c2c..bcbdcf997d20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -265,7 +265,7 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, r = amdgpu_gem_object_create(adev, size, args->in.alignment, (u32)(0xffffffff & args->in.domains), - flags, false, resv, &gobj); + flags, ttm_bo_type_device, resv, &gobj); if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { if (!r) { struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); @@ -317,7 +317,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, /* create a gem object to contain this object in */ r = amdgpu_gem_object_create(adev, args->size, 0, AMDGPU_GEM_DOMAIN_CPU, - 0, 0, NULL, &gobj); + 0, ttm_bo_type_device, NULL, &gobj); if (r) return r; @@ -766,7 +766,7 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, amdgpu_display_supported_domains(adev)); r = amdgpu_gem_object_create(adev, args->size, 0, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, - false, NULL, &gobj); + ttm_bo_type_device, NULL, &gobj); if (r) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 31f8170313b4..ce7739832d29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -231,6 +231,12 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE) fence_flags |= AMDGPU_FENCE_FLAG_TC_WB_ONLY; + /* wrap the last IB with fence */ + if (job && job->uf_addr) { + amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence, + fence_flags | AMDGPU_FENCE_FLAG_64BIT); + } + r = amdgpu_fence_emit(ring, f, fence_flags); if (r) { dev_err(adev->dev, "failed to emit fence (%d)\n", r); @@ -243,12 +249,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ring->funcs->insert_end) ring->funcs->insert_end(ring); - /* wrap the last IB with fence */ - if (job && job->uf_addr) { - amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence, - fence_flags | AMDGPU_FENCE_FLAG_64BIT); - } - if (patch_offset != ~0 && ring->funcs->patch_cond_exec) amdgpu_ring_patch_cond_exec(ring, patch_offset); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index a1c78f90eadf..3a072a7a39f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -578,11 +578,6 @@ void amdgpu_vmid_mgr_init(struct amdgpu_device *adev) list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru); } } - - adev->vm_manager.fence_context = - dma_fence_context_alloc(AMDGPU_MAX_RINGS); - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) - adev->vm_manager.seqno[i] = 0; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 72a3e8c68876..a365ea2383d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -58,7 +58,8 @@ * * @adev: amdgpu device pointer * @mm: process address space - * @mn: MMU notifier structur + * @mn: MMU notifier structure + * @type: type of MMU notifier * @work: destruction work item * @node: hash table node to find structure by adev and mn * @lock: rw semaphore protecting the notifier nodes @@ -266,7 +267,7 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, * amdgpu_mn_invalidate_range_start_hsa - callback to notify about mm change * * @mn: our notifier - * @mn: the mm this callback is about + * @mm: the mm this callback is about * @start: start of updated range * @end: end of updated range * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 113edffb5960..f1404adc3a90 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -918,6 +918,36 @@ fail: return -EINVAL; } +/** + * DOC: busy_percent + * + * The amdgpu driver provides a sysfs API for reading how busy the GPU + * is as a percentage. The file gpu_busy_percent is used for this. + * The SMU firmware computes a percentage of load based on the + * aggregate activity level in the IP cores. + */ +static ssize_t amdgpu_get_busy_percent(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int r, value, size = sizeof(value); + + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* read the IP busy sensor */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, + (void *)&value, &size); + if (r) + return r; + + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state); static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, amdgpu_get_dpm_forced_performance_level, @@ -951,6 +981,8 @@ static DEVICE_ATTR(pp_power_profile_mode, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, amdgpu_get_pp_od_clk_voltage, amdgpu_set_pp_od_clk_voltage); +static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, + amdgpu_get_busy_percent, NULL); static ssize_t amdgpu_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -1697,10 +1729,10 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) { - if (adev->powerplay.pp_funcs->powergate_uvd) { + if (adev->powerplay.pp_funcs->set_powergating_by_smu) { /* enable/disable UVD */ mutex_lock(&adev->pm.mutex); - amdgpu_dpm_powergate_uvd(adev, !enable); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable); mutex_unlock(&adev->pm.mutex); } else { if (enable) { @@ -1719,10 +1751,10 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) { - if (adev->powerplay.pp_funcs->powergate_vce) { + if (adev->powerplay.pp_funcs->set_powergating_by_smu) { /* enable/disable VCE */ mutex_lock(&adev->pm.mutex); - amdgpu_dpm_powergate_vce(adev, !enable); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable); mutex_unlock(&adev->pm.mutex); } else { if (enable) { @@ -1854,6 +1886,13 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) "pp_od_clk_voltage\n"); return ret; } + ret = device_create_file(adev->dev, + &dev_attr_gpu_busy_percent); + if (ret) { + DRM_ERROR("failed to create device file " + "gpu_busy_level\n"); + return ret; + } ret = amdgpu_debugfs_pm_init(adev); if (ret) { DRM_ERROR("Failed to register debugfs file for dpm!\n"); @@ -1889,6 +1928,7 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) &dev_attr_pp_power_profile_mode); device_remove_file(adev->dev, &dev_attr_pp_od_clk_voltage); + device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); } void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) @@ -1919,7 +1959,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) if (!amdgpu_device_has_dc_support(adev)) { mutex_lock(&adev->pm.mutex); amdgpu_dpm_get_active_displays(adev); - adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtcs; + adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index b2286bc41aec..df7226ad64b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -191,7 +191,6 @@ error: /** * amdgpu_gem_map_attach - &dma_buf_ops.attach implementation * @dma_buf: shared DMA buffer - * @target_dev: target device * @attach: DMA-buf attachment * * Makes sure that the shared DMA buffer can be accessed by the target device. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index e3878256743a..57b14dccd8e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright 2009 VMware, Inc. * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 0c084d3d0865..0246cb87d9e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -162,7 +162,7 @@ error_mem: static void amdgpu_ttm_global_fini(struct amdgpu_device *adev) { if (adev->mman.mem_global_referenced) { - drm_sched_entity_fini(adev->mman.entity.sched, + drm_sched_entity_destroy(adev->mman.entity.sched, &adev->mman.entity); mutex_destroy(&adev->mman.gtt_window_lock); drm_global_item_unref(&adev->mman.bo_global_ref.ref); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index cc15d3230402..3e70eb61a960 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -53,11 +53,11 @@ /* Firmware Names */ #ifdef CONFIG_DRM_AMDGPU_CIK -#define FIRMWARE_BONAIRE "radeon/bonaire_uvd.bin" -#define FIRMWARE_KABINI "radeon/kabini_uvd.bin" -#define FIRMWARE_KAVERI "radeon/kaveri_uvd.bin" -#define FIRMWARE_HAWAII "radeon/hawaii_uvd.bin" -#define FIRMWARE_MULLINS "radeon/mullins_uvd.bin" +#define FIRMWARE_BONAIRE "amdgpu/bonaire_uvd.bin" +#define FIRMWARE_KABINI "amdgpu/kabini_uvd.bin" +#define FIRMWARE_KAVERI "amdgpu/kaveri_uvd.bin" +#define FIRMWARE_HAWAII "amdgpu/hawaii_uvd.bin" +#define FIRMWARE_MULLINS "amdgpu/mullins_uvd.bin" #endif #define FIRMWARE_TONGA "amdgpu/tonga_uvd.bin" #define FIRMWARE_CARRIZO "amdgpu/carrizo_uvd.bin" @@ -309,7 +309,7 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { kfree(adev->uvd.inst[j].saved_bo); - drm_sched_entity_fini(&adev->uvd.inst[j].ring.sched, &adev->uvd.inst[j].entity); + drm_sched_entity_destroy(&adev->uvd.inst[j].ring.sched, &adev->uvd.inst[j].entity); amdgpu_bo_free_kernel(&adev->uvd.inst[j].vcpu_bo, &adev->uvd.inst[j].gpu_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 23d960ec1cf2..6ae1ad7e83b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -40,11 +40,11 @@ /* Firmware Names */ #ifdef CONFIG_DRM_AMDGPU_CIK -#define FIRMWARE_BONAIRE "radeon/bonaire_vce.bin" -#define FIRMWARE_KABINI "radeon/kabini_vce.bin" -#define FIRMWARE_KAVERI "radeon/kaveri_vce.bin" -#define FIRMWARE_HAWAII "radeon/hawaii_vce.bin" -#define FIRMWARE_MULLINS "radeon/mullins_vce.bin" +#define FIRMWARE_BONAIRE "amdgpu/bonaire_vce.bin" +#define FIRMWARE_KABINI "amdgpu/kabini_vce.bin" +#define FIRMWARE_KAVERI "amdgpu/kaveri_vce.bin" +#define FIRMWARE_HAWAII "amdgpu/hawaii_vce.bin" +#define FIRMWARE_MULLINS "amdgpu/mullins_vce.bin" #endif #define FIRMWARE_TONGA "amdgpu/tonga_vce.bin" #define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin" @@ -222,7 +222,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) if (adev->vce.vcpu_bo == NULL) return 0; - drm_sched_entity_fini(&adev->vce.ring[0].sched, &adev->vce.entity); + drm_sched_entity_destroy(&adev->vce.ring[0].sched, &adev->vce.entity); amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, (void **)&adev->vce.cpu_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 422d1a434db4..712af5c1a5d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1082,7 +1082,7 @@ restart: struct amdgpu_vm_bo_base, vm_status); bo_base->moved = false; - list_move(&bo_base->vm_status, &vm->idle); + list_del_init(&bo_base->vm_status); bo = bo_base->bo->parent; if (!bo) @@ -1567,7 +1567,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, if (nodes) { addr = nodes->start << PAGE_SHIFT; max_entries = (nodes->size - pfn) * - (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + AMDGPU_GPU_PAGES_IN_CPU_PAGE; } else { addr = 0; max_entries = S64_MAX; @@ -1578,7 +1578,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, max_entries = min(max_entries, 16ull * 1024ull); for (count = 1; - count < max_entries / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + count < max_entries / AMDGPU_GPU_PAGES_IN_CPU_PAGE; ++count) { uint64_t idx = pfn + count; @@ -1592,7 +1592,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, dma_addr = pages_addr; } else { addr = pages_addr[pfn]; - max_entries = count * (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + max_entries = count * AMDGPU_GPU_PAGES_IN_CPU_PAGE; } } else if (flags & AMDGPU_PTE_VALID) { @@ -1607,7 +1607,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, if (r) return r; - pfn += (last - start + 1) / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + pfn += (last - start + 1) / AMDGPU_GPU_PAGES_IN_CPU_PAGE; if (nodes && nodes->size == pfn) { pfn = 0; ++nodes; @@ -2643,7 +2643,7 @@ error_free_root: vm->root.base.bo = NULL; error_free_sched_entity: - drm_sched_entity_fini(&ring->sched, &vm->entity); + drm_sched_entity_destroy(&ring->sched, &vm->entity); return r; } @@ -2780,7 +2780,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); } - drm_sched_entity_fini(vm->entity.sched, &vm->entity); + drm_sched_entity_destroy(vm->entity.sched, &vm->entity); if (!RB_EMPTY_ROOT(&vm->va.rb_root)) { dev_err(adev->dev, "still active bo inside vm\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index b6333f92ba45..f7a4bd5885a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -112,7 +112,7 @@ u64 amdgpu_vram_mgr_bo_invisible_size(struct amdgpu_bo *bo) unsigned pages = mem->num_pages; u64 usage = 0; - if (adev->gmc.visible_vram_size == adev->gmc.real_vram_size) + if (amdgpu_gmc_vram_full_visible(&adev->gmc)) return 0; if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT) diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index b18c31a701e2..e9934de1b9cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = kcalloc(4, ws, GFP_ATOMIC); + ectx.ws = kcalloc(4, ws, GFP_KERNEL); else ectx.ws = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index c9d45cffca56..d2469453dca2 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -49,10 +49,10 @@ #include "gmc/gmc_7_1_d.h" #include "gmc/gmc_7_1_sh_mask.h" -MODULE_FIRMWARE("radeon/bonaire_smc.bin"); -MODULE_FIRMWARE("radeon/bonaire_k_smc.bin"); -MODULE_FIRMWARE("radeon/hawaii_smc.bin"); -MODULE_FIRMWARE("radeon/hawaii_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_smc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_smc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_k_smc.bin"); #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b @@ -5815,7 +5815,7 @@ static int ci_dpm_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); err = request_firmware(&adev->pm.fw, fw_name, adev->dev); if (err) goto out; @@ -5846,8 +5846,7 @@ static int ci_dpm_init(struct amdgpu_device *adev) adev->pm.dpm.priv = pi; pi->sys_pcie_mask = - (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> - CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK; pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; @@ -6767,6 +6766,19 @@ static int ci_dpm_read_sensor(void *handle, int idx, } } +static int ci_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + ci_dpm_powergate_uvd(handle, gate); + break; + default: + break; + } + return 0; +} + static const struct amd_ip_funcs ci_dpm_ip_funcs = { .name = "ci_dpm", .early_init = ci_dpm_early_init, @@ -6804,7 +6816,7 @@ static const struct amd_pm_funcs ci_dpm_funcs = { .debugfs_print_current_performance_level = &ci_dpm_debugfs_print_current_performance_level, .force_performance_level = &ci_dpm_force_performance_level, .vblank_too_short = &ci_dpm_vblank_too_short, - .powergate_uvd = &ci_dpm_powergate_uvd, + .set_powergating_by_smu = &ci_set_powergating_by_smu, .set_fan_control_mode = &ci_dpm_set_fan_control_mode, .get_fan_control_mode = &ci_dpm_get_fan_control_mode, .set_fan_speed_percent = &ci_dpm_set_fan_speed_percent, diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index a7576255cc30..d0fa2aac2388 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -54,16 +54,16 @@ static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev); static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev); static int cik_sdma_soft_reset(void *handle); -MODULE_FIRMWARE("radeon/bonaire_sdma.bin"); -MODULE_FIRMWARE("radeon/bonaire_sdma1.bin"); -MODULE_FIRMWARE("radeon/hawaii_sdma.bin"); -MODULE_FIRMWARE("radeon/hawaii_sdma1.bin"); -MODULE_FIRMWARE("radeon/kaveri_sdma.bin"); -MODULE_FIRMWARE("radeon/kaveri_sdma1.bin"); -MODULE_FIRMWARE("radeon/kabini_sdma.bin"); -MODULE_FIRMWARE("radeon/kabini_sdma1.bin"); -MODULE_FIRMWARE("radeon/mullins_sdma.bin"); -MODULE_FIRMWARE("radeon/mullins_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_sdma.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_sdma.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_sdma.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/kabini_sdma.bin"); +MODULE_FIRMWARE("amdgpu/kabini_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/mullins_sdma.bin"); +MODULE_FIRMWARE("amdgpu/mullins_sdma1.bin"); u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev); @@ -132,9 +132,9 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev) for (i = 0; i < adev->sdma.num_instances; i++) { if (i == 0) - snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma1.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); if (err) goto out; @@ -177,9 +177,8 @@ static uint64_t cik_sdma_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2; + return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) & 0x3fffc) >> 2; } /** @@ -192,9 +191,8 @@ static uint64_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], (lower_32_bits(ring->wptr) << 2) & 0x3fffc); } @@ -248,7 +246,7 @@ static void cik_sdma_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ u32 ref_and_mask; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA0_MASK; else ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA1_MASK; @@ -1290,8 +1288,10 @@ static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &cik_sdma_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs cik_sdma_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index cd6bf291a853..de184a886057 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -44,30 +44,30 @@ static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v6_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v6_0_get_cu_info(struct amdgpu_device *adev); -MODULE_FIRMWARE("radeon/tahiti_pfp.bin"); -MODULE_FIRMWARE("radeon/tahiti_me.bin"); -MODULE_FIRMWARE("radeon/tahiti_ce.bin"); -MODULE_FIRMWARE("radeon/tahiti_rlc.bin"); - -MODULE_FIRMWARE("radeon/pitcairn_pfp.bin"); -MODULE_FIRMWARE("radeon/pitcairn_me.bin"); -MODULE_FIRMWARE("radeon/pitcairn_ce.bin"); -MODULE_FIRMWARE("radeon/pitcairn_rlc.bin"); - -MODULE_FIRMWARE("radeon/verde_pfp.bin"); -MODULE_FIRMWARE("radeon/verde_me.bin"); -MODULE_FIRMWARE("radeon/verde_ce.bin"); -MODULE_FIRMWARE("radeon/verde_rlc.bin"); - -MODULE_FIRMWARE("radeon/oland_pfp.bin"); -MODULE_FIRMWARE("radeon/oland_me.bin"); -MODULE_FIRMWARE("radeon/oland_ce.bin"); -MODULE_FIRMWARE("radeon/oland_rlc.bin"); - -MODULE_FIRMWARE("radeon/hainan_pfp.bin"); -MODULE_FIRMWARE("radeon/hainan_me.bin"); -MODULE_FIRMWARE("radeon/hainan_ce.bin"); -MODULE_FIRMWARE("radeon/hainan_rlc.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_pfp.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_me.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_ce.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/pitcairn_pfp.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_me.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_ce.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/verde_pfp.bin"); +MODULE_FIRMWARE("amdgpu/verde_me.bin"); +MODULE_FIRMWARE("amdgpu/verde_ce.bin"); +MODULE_FIRMWARE("amdgpu/verde_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/oland_pfp.bin"); +MODULE_FIRMWARE("amdgpu/oland_me.bin"); +MODULE_FIRMWARE("amdgpu/oland_ce.bin"); +MODULE_FIRMWARE("amdgpu/oland_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/hainan_pfp.bin"); +MODULE_FIRMWARE("amdgpu/hainan_me.bin"); +MODULE_FIRMWARE("amdgpu/hainan_ce.bin"); +MODULE_FIRMWARE("amdgpu/hainan_rlc.bin"); static u32 gfx_v6_0_get_csb_size(struct amdgpu_device *adev); static void gfx_v6_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *buffer); @@ -335,7 +335,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); if (err) goto out; @@ -346,7 +346,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); if (err) goto out; @@ -357,7 +357,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); if (err) goto out; @@ -368,7 +368,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 42b6144c1fd5..95452c5a9df6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -57,36 +57,36 @@ static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v7_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v7_0_set_gds_init(struct amdgpu_device *adev); -MODULE_FIRMWARE("radeon/bonaire_pfp.bin"); -MODULE_FIRMWARE("radeon/bonaire_me.bin"); -MODULE_FIRMWARE("radeon/bonaire_ce.bin"); -MODULE_FIRMWARE("radeon/bonaire_rlc.bin"); -MODULE_FIRMWARE("radeon/bonaire_mec.bin"); - -MODULE_FIRMWARE("radeon/hawaii_pfp.bin"); -MODULE_FIRMWARE("radeon/hawaii_me.bin"); -MODULE_FIRMWARE("radeon/hawaii_ce.bin"); -MODULE_FIRMWARE("radeon/hawaii_rlc.bin"); -MODULE_FIRMWARE("radeon/hawaii_mec.bin"); - -MODULE_FIRMWARE("radeon/kaveri_pfp.bin"); -MODULE_FIRMWARE("radeon/kaveri_me.bin"); -MODULE_FIRMWARE("radeon/kaveri_ce.bin"); -MODULE_FIRMWARE("radeon/kaveri_rlc.bin"); -MODULE_FIRMWARE("radeon/kaveri_mec.bin"); -MODULE_FIRMWARE("radeon/kaveri_mec2.bin"); - -MODULE_FIRMWARE("radeon/kabini_pfp.bin"); -MODULE_FIRMWARE("radeon/kabini_me.bin"); -MODULE_FIRMWARE("radeon/kabini_ce.bin"); -MODULE_FIRMWARE("radeon/kabini_rlc.bin"); -MODULE_FIRMWARE("radeon/kabini_mec.bin"); - -MODULE_FIRMWARE("radeon/mullins_pfp.bin"); -MODULE_FIRMWARE("radeon/mullins_me.bin"); -MODULE_FIRMWARE("radeon/mullins_ce.bin"); -MODULE_FIRMWARE("radeon/mullins_rlc.bin"); -MODULE_FIRMWARE("radeon/mullins_mec.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_pfp.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_me.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_ce.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_rlc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_mec.bin"); + +MODULE_FIRMWARE("amdgpu/hawaii_pfp.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_me.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_ce.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_rlc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_mec.bin"); + +MODULE_FIRMWARE("amdgpu/kaveri_pfp.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_me.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_ce.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_rlc.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_mec.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_mec2.bin"); + +MODULE_FIRMWARE("amdgpu/kabini_pfp.bin"); +MODULE_FIRMWARE("amdgpu/kabini_me.bin"); +MODULE_FIRMWARE("amdgpu/kabini_ce.bin"); +MODULE_FIRMWARE("amdgpu/kabini_rlc.bin"); +MODULE_FIRMWARE("amdgpu/kabini_mec.bin"); + +MODULE_FIRMWARE("amdgpu/mullins_pfp.bin"); +MODULE_FIRMWARE("amdgpu/mullins_me.bin"); +MODULE_FIRMWARE("amdgpu/mullins_ce.bin"); +MODULE_FIRMWARE("amdgpu/mullins_rlc.bin"); +MODULE_FIRMWARE("amdgpu/mullins_mec.bin"); static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] = { @@ -925,7 +925,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); if (err) goto out; @@ -933,7 +933,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); if (err) goto out; @@ -941,7 +941,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); if (err) goto out; @@ -949,7 +949,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); if (err) goto out; @@ -958,7 +958,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) goto out; if (adev->asic_type == CHIP_KAVERI) { - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec2.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); if (err) goto out; @@ -967,7 +967,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) goto out; } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 807ee0dd623c..551f21bad6d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -704,6 +704,17 @@ static const u32 stoney_mgcg_cgcg_init[] = mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200, }; + +static const char * const sq_edc_source_names[] = { + "SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred", + "SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch", + "SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data return", + "SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR", + "SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS", + "SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS", + "SQ_EDC_INFO_SOURCE_TA: EDC source is TA", +}; + static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev); @@ -2006,6 +2017,8 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, return 0; } +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work); + static int gfx_v8_0_sw_init(void *handle) { int i, j, k, r, ring_id; @@ -2069,6 +2082,8 @@ static int gfx_v8_0_sw_init(void *handle) return r; } + INIT_WORK(&adev->gfx.sq_work.work, gfx_v8_0_sq_irq_work_func); + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; gfx_v8_0_scratch_init(adev); @@ -5581,24 +5596,18 @@ static int gfx_v8_0_late_init(void *handle) return r; } - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); - return 0; } static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, bool enable) { - if ((adev->asic_type == CHIP_POLARIS11) || + if (((adev->asic_type == CHIP_POLARIS11) || (adev->asic_type == CHIP_POLARIS12) || - (adev->asic_type == CHIP_VEGAM)) + (adev->asic_type == CHIP_VEGAM)) && + adev->powerplay.pp_funcs->set_powergating_by_smu) /* Send msg to SMU via Powerplay */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - enable ? - AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable); WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0); } @@ -6955,16 +6964,14 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev, return 0; } -static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - struct amdgpu_iv_entry *entry) +static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev, unsigned ih_data) { - u8 enc, se_id; + u32 enc, se_id, sh_id, cu_id; char type[20]; + int sq_edc_source = -1; - /* Parse all fields according to SQ_INTERRUPT* registers */ - enc = (entry->src_data[0] >> 26) & 0x3; - se_id = (entry->src_data[0] >> 24) & 0x3; + enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING); + se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID); switch (enc) { case 0: @@ -6974,19 +6981,37 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, "reg_timestamp %d, thread_trace_buff_full %d," "wlt %d, thread_trace %d.\n", se_id, - (entry->src_data[0] >> 7) & 0x1, - (entry->src_data[0] >> 6) & 0x1, - (entry->src_data[0] >> 5) & 0x1, - (entry->src_data[0] >> 4) & 0x1, - (entry->src_data[0] >> 3) & 0x1, - (entry->src_data[0] >> 2) & 0x1, - (entry->src_data[0] >> 1) & 0x1, - entry->src_data[0] & 0x1 + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, IMMED_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_REG_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_CMD_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, CMD_TIMESTAMP), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, REG_TIMESTAMP), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE_BUF_FULL), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, WLT), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE) ); break; case 1: case 2: + cu_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID); + sh_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID); + + /* + * This function can be called either directly from ISR + * or from BH in which case we can access SQ_EDC_INFO + * instance + */ + if (in_task()) { + mutex_lock(&adev->grbm_idx_mutex); + gfx_v8_0_select_se_sh(adev, se_id, sh_id, cu_id); + + sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE); + + gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); + mutex_unlock(&adev->grbm_idx_mutex); + } + if (enc == 1) sprintf(type, "instruction intr"); else @@ -6994,17 +7019,46 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, DRM_INFO( "SQ %s detected: " - "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n", - type, se_id, - (entry->src_data[0] >> 20) & 0xf, - (entry->src_data[0] >> 18) & 0x3, - (entry->src_data[0] >> 14) & 0xf, - (entry->src_data[0] >> 10) & 0xf - ); + "se_id %d, sh_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d " + "trap %s, sq_ed_info.source %s.\n", + type, se_id, sh_id, cu_id, + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false", + (sq_edc_source != -1) ? sq_edc_source_names[sq_edc_source] : "unavailable" + ); break; default: DRM_ERROR("SQ invalid encoding type\n."); - return -EINVAL; + } +} + +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work) +{ + + struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.sq_work.work); + struct sq_work *sq_work = container_of(work, struct sq_work, work); + + gfx_v8_0_parse_sq_irq(adev, sq_work->ih_data); +} + +static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + unsigned ih_data = entry->src_data[0]; + + /* + * Try to submit work so SQ_EDC_INFO can be accessed from + * BH. If previous work submission hasn't finished yet + * just print whatever info is possible directly from the ISR. + */ + if (work_pending(&adev->gfx.sq_work.work)) { + gfx_v8_0_parse_sq_irq(adev, ih_data); + } else { + adev->gfx.sq_work.ih_data = ih_data; + schedule_work(&adev->gfx.sq_work.work); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index a69153435ea7..ac46eabe3bcd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3714,6 +3714,10 @@ static int gfx_v9_0_set_powergating_state(void *handle, /* update mgcg state */ gfx_v9_0_update_gfx_mg_power_gating(adev, enable); + + /* set gfx off through smu */ + if (enable && adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true); break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 79f9ac29019b..75317f283c69 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -41,11 +41,11 @@ static void gmc_v6_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v6_0_wait_for_idle(void *handle); -MODULE_FIRMWARE("radeon/tahiti_mc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_mc.bin"); -MODULE_FIRMWARE("radeon/verde_mc.bin"); -MODULE_FIRMWARE("radeon/oland_mc.bin"); -MODULE_FIRMWARE("radeon/si58_mc.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_mc.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin"); +MODULE_FIRMWARE("amdgpu/verde_mc.bin"); +MODULE_FIRMWARE("amdgpu/oland_mc.bin"); +MODULE_FIRMWARE("amdgpu/si58_mc.bin"); #define MC_SEQ_MISC0__MT__MASK 0xf0000000 #define MC_SEQ_MISC0__MT__GDDR1 0x10000000 @@ -134,9 +134,9 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) is_58_fw = true; if (is_58_fw) - snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin"); + snprintf(fw_name, sizeof(fw_name), "amdgpu/si58_mc.bin"); else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 7147bfe25a23..78339309a00c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -47,8 +47,8 @@ static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v7_0_wait_for_idle(void *handle); -MODULE_FIRMWARE("radeon/bonaire_mc.bin"); -MODULE_FIRMWARE("radeon/hawaii_mc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_mc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_mc.bin"); MODULE_FIRMWARE("amdgpu/topaz_mc.bin"); static const u32 golden_settings_iceland_a11[] = @@ -147,10 +147,7 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - if (adev->asic_type == CHIP_TOPAZ) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 46de1fd18a7b..3f57f6463dc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -3306,6 +3306,19 @@ static int kv_dpm_read_sensor(void *handle, int idx, } } +static int kv_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + kv_dpm_powergate_uvd(handle, gate); + break; + default: + break; + } + return 0; +} + static const struct amd_ip_funcs kv_dpm_ip_funcs = { .name = "kv_dpm", .early_init = kv_dpm_early_init, @@ -3342,7 +3355,7 @@ static const struct amd_pm_funcs kv_dpm_funcs = { .print_power_state = &kv_dpm_print_power_state, .debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level, .force_performance_level = &kv_dpm_force_performance_level, - .powergate_uvd = &kv_dpm_powergate_uvd, + .set_powergating_by_smu = kv_set_powergating_by_smu, .enable_bapm = &kv_dpm_enable_bapm, .get_vce_clock_state = amdgpu_get_vce_clock_state, .check_state_equal = kv_check_state_equal, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 3d53c4413f13..e70a0d4d6db4 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -471,8 +471,8 @@ void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, RENG_EXECUTE_ON_REG_UPDATE, 1); WREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE, pctl1_reng_execute); - if (adev->powerplay.pp_funcs->set_mmhub_powergating_by_smu) - amdgpu_dpm_set_mmhub_powergating_by_smu(adev); + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true); } else { pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index c7190c39c4f5..cee4fae76d20 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -202,8 +202,7 @@ static uint64_t sdma_v2_4_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - u32 wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; + u32 wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) >> 2; return wptr; } @@ -218,9 +217,8 @@ static uint64_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], lower_32_bits(ring->wptr) << 2); + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], lower_32_bits(ring->wptr) << 2); } static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) @@ -273,7 +271,7 @@ static void sdma_v2_4_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -1213,8 +1211,10 @@ static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v2_4_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v2_4_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index aa9ab299fd32..99616dd9594f 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -365,9 +365,7 @@ static uint64_t sdma_v3_0_ring_get_wptr(struct amdgpu_ring *ring) /* XXX check if swapping is necessary on BE */ wptr = ring->adev->wb.wb[ring->wptr_offs] >> 2; } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - - wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; + wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) >> 2; } return wptr; @@ -394,9 +392,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring) WRITE_ONCE(*wb, (lower_32_bits(ring->wptr) << 2)); } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], lower_32_bits(ring->wptr) << 2); + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], lower_32_bits(ring->wptr) << 2); } } @@ -450,7 +446,7 @@ static void sdma_v3_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -1655,8 +1651,10 @@ static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v3_0_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v3_0_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index ca53b3fba422..572ca63cf676 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -296,13 +296,12 @@ static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring) DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr); } else { u32 lowbit, highbit; - int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2; - highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; + lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR)) >> 2; + highbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n", - me, highbit, lowbit); + ring->me, highbit, lowbit); wptr = highbit; wptr = wptr << 32; wptr |= lowbit; @@ -339,17 +338,15 @@ static void sdma_v4_0_ring_set_wptr(struct amdgpu_ring *ring) ring->doorbell_index, ring->wptr << 2); WDOORBELL64(ring->doorbell_index, ring->wptr << 2); } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - DRM_DEBUG("Not using doorbell -- " "mmSDMA%i_GFX_RB_WPTR == 0x%08x " "mmSDMA%i_GFX_RB_WPTR_HI == 0x%08x\n", - me, + ring->me, lower_32_bits(ring->wptr << 2), - me, + ring->me, upper_32_bits(ring->wptr << 2)); - WREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); - WREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); } } @@ -430,7 +427,7 @@ static void sdma_v4_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) u32 ref_and_mask = 0; const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio_funcs->hdp_flush_reg; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0; else ref_and_mask = nbio_hf_reg->ref_and_mask_sdma1; @@ -1651,8 +1648,10 @@ static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v4_0_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v4_0_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index d51318c695e6..db327b412562 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -56,16 +56,16 @@ #define BIOS_SCRATCH_4 0x5cd -MODULE_FIRMWARE("radeon/tahiti_smc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_smc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin"); -MODULE_FIRMWARE("radeon/verde_smc.bin"); -MODULE_FIRMWARE("radeon/verde_k_smc.bin"); -MODULE_FIRMWARE("radeon/oland_smc.bin"); -MODULE_FIRMWARE("radeon/oland_k_smc.bin"); -MODULE_FIRMWARE("radeon/hainan_smc.bin"); -MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); -MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_smc.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_smc.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/verde_smc.bin"); +MODULE_FIRMWARE("amdgpu/verde_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/oland_smc.bin"); +MODULE_FIRMWARE("amdgpu/oland_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/hainan_smc.bin"); +MODULE_FIRMWARE("amdgpu/hainan_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/banks_k_2_smc.bin"); static const struct amd_pm_funcs si_dpm_funcs; @@ -7318,8 +7318,7 @@ static int si_dpm_init(struct amdgpu_device *adev) pi = &eg_pi->rv7xx; si_pi->sys_pcie_mask = - (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> - CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK; si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); @@ -7667,7 +7666,7 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); err = request_firmware(&adev->pm.fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index bfddf97dd13e..8ee1c2eaaa14 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -470,7 +470,7 @@ static int uvd_v6_0_sw_fini(void *handle) return r; if (uvd_v6_0_enc_support(adev)) { - drm_sched_entity_fini(&adev->uvd.inst->ring_enc[0].sched, &adev->uvd.inst->entity_enc); + drm_sched_entity_destroy(&adev->uvd.inst->ring_enc[0].sched, &adev->uvd.inst->entity_enc); for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst->ring_enc[i]); @@ -1569,7 +1569,6 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = { static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_UVD, .align_mask = 0xf, - .nop = PACKET0(mmUVD_NO_OP, 0), .support_64bit_ptrs = false, .get_rptr = uvd_v6_0_ring_get_rptr, .get_wptr = uvd_v6_0_ring_get_wptr, @@ -1587,7 +1586,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { .emit_hdp_flush = uvd_v6_0_ring_emit_hdp_flush, .test_ring = uvd_v6_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, - .insert_nop = amdgpu_ring_insert_nop, + .insert_nop = uvd_v6_0_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 57d32f21b3a6..ba244d3b74db 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -491,7 +491,7 @@ static int uvd_v7_0_sw_fini(void *handle) return r; for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { - drm_sched_entity_fini(&adev->uvd.inst[j].ring_enc[0].sched, &adev->uvd.inst[j].entity_enc); + drm_sched_entity_destroy(&adev->uvd.inst[j].ring_enc[0].sched, &adev->uvd.inst[j].entity_enc); for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]); diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 47f70827195b..d48e877b682e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -56,7 +56,7 @@ static uint64_t vce_v2_0_ring_get_rptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(mmVCE_RB_RPTR); else return RREG32(mmVCE_RB_RPTR2); @@ -73,7 +73,7 @@ static uint64_t vce_v2_0_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(mmVCE_RB_WPTR); else return RREG32(mmVCE_RB_WPTR2); @@ -90,7 +90,7 @@ static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr)); else WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr)); @@ -627,8 +627,10 @@ static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v2_0_ring_funcs; + adev->vce.ring[i].me = i; + } } static const struct amdgpu_irq_src_funcs vce_v2_0_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 0999c843f623..99604d0262ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -86,9 +86,9 @@ static uint64_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) v = RREG32(mmVCE_RB_RPTR); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) v = RREG32(mmVCE_RB_RPTR2); else v = RREG32(mmVCE_RB_RPTR3); @@ -118,9 +118,9 @@ static uint64_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) v = RREG32(mmVCE_RB_WPTR); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) v = RREG32(mmVCE_RB_WPTR2); else v = RREG32(mmVCE_RB_WPTR3); @@ -149,9 +149,9 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr)); else WREG32(mmVCE_RB_WPTR3, lower_32_bits(ring->wptr)); @@ -900,7 +900,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { .emit_frame_size = 4 + /* vce_v3_0_emit_pipeline_sync */ 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ - .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ + .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ .emit_ib = amdgpu_vce_ring_emit_ib, .emit_fence = amdgpu_vce_ring_emit_fence, .test_ring = amdgpu_vce_ring_test_ring, @@ -924,7 +924,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 6 + /* vce_v3_0_emit_vm_flush */ 4 + /* vce_v3_0_emit_pipeline_sync */ 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ - .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ + .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ .emit_ib = vce_v3_0_ring_emit_ib, .emit_vm_flush = vce_v3_0_emit_vm_flush, .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, @@ -942,12 +942,16 @@ static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) int i; if (adev->asic_type >= CHIP_STONEY) { - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in VM mode\n"); } else { - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in physical mode\n"); } } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 8fd1b742985a..575bf9709389 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -60,9 +60,9 @@ static uint64_t vce_v4_0_ring_get_rptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR2)); else return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR3)); @@ -82,9 +82,9 @@ static uint64_t vce_v4_0_ring_get_wptr(struct amdgpu_ring *ring) if (ring->use_doorbell) return adev->wb.wb[ring->wptr_offs]; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR2)); else return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR3)); @@ -108,10 +108,10 @@ static void vce_v4_0_ring_set_wptr(struct amdgpu_ring *ring) return; } - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR), lower_32_bits(ring->wptr)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR2), lower_32_bits(ring->wptr)); else @@ -1088,8 +1088,10 @@ static void vce_v4_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v4_0_ring_vm_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in VM mode\n"); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index af16973f2c41..94911871eb9b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -28,11 +28,11 @@ AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o +AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o endif ifneq ($(CONFIG_DEBUG_FS),) -AMDGPUDM += amdgpu_dm_crc.o +AMDGPUDM += amdgpu_dm_crc.o amdgpu_dm_debugfs.o endif subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 66bd3cc3e387..ca017c1dd4da 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -39,6 +39,9 @@ #include "dm_helpers.h" #include "dm_services_types.h" #include "amdgpu_dm_mst_types.h" +#if defined(CONFIG_DEBUG_FS) +#include "amdgpu_dm_debugfs.h" +#endif #include "ivsrcid/ivsrcid_vislands30.h" @@ -1532,7 +1535,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* * Temporary disable until pplib/smu interaction is implemented */ - dm->dc->debug.disable_stutter = true; + dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; break; #endif default: @@ -2173,6 +2176,46 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) return color_space; } +static void reduce_mode_colour_depth(struct dc_crtc_timing *timing_out) +{ + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + + timing_out->display_color_depth--; +} + +static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out, + const struct drm_display_info *info) +{ + int normalized_clk; + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + do { + normalized_clk = timing_out->pix_clk_khz; + /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ + if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) + normalized_clk /= 2; + /* Adjusting pix clock following on HDMI spec based on colour depth */ + switch (timing_out->display_color_depth) { + case COLOR_DEPTH_101010: + normalized_clk = (normalized_clk * 30) / 24; + break; + case COLOR_DEPTH_121212: + normalized_clk = (normalized_clk * 36) / 24; + break; + case COLOR_DEPTH_161616: + normalized_clk = (normalized_clk * 48) / 24; + break; + default: + return; + } + if (normalized_clk <= info->max_tmds_clock) + return; + reduce_mode_colour_depth(timing_out); + + } while (timing_out->display_color_depth > COLOR_DEPTH_888); + +} /*****************************************************************************/ static void @@ -2181,6 +2224,7 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, const struct drm_connector *connector) { struct dc_crtc_timing *timing_out = &stream->timing; + const struct drm_display_info *info = &connector->display_info; memset(timing_out, 0, sizeof(struct dc_crtc_timing)); @@ -2189,8 +2233,10 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->v_border_top = 0; timing_out->v_border_bottom = 0; /* TODO: un-hardcode */ - - if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) + if (drm_mode_is_420_only(info, mode_in) + && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; else @@ -2226,6 +2272,8 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + adjust_colour_depth_from_display_info(timing_out, info); } static void fill_audio_info(struct audio_info *audio_info, @@ -3619,6 +3667,13 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, &aconnector->base, &aencoder->base); drm_connector_register(&aconnector->base); +#if defined(CONFIG_DEBUG_FS) + res = connector_debugfs_init(aconnector); + if (res) { + DRM_ERROR("Failed to create debugfs for connector"); + goto out_free; + } +#endif if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_eDP) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c new file mode 100644 index 000000000000..cf5ea69e46ad --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include <linux/debugfs.h> + +#include "dc.h" +#include "dc_link.h" + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_debugfs.h" + +static ssize_t dp_link_rate_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read link rate */ + return 1; +} + +static ssize_t dp_link_rate_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write link rate */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read lane count */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write lane count */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read voltage swing */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write voltage swing */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read pre-emphasis */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write pre-emphasis */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read PHY test pattern */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write PHY test pattern */ + return 1; +} + +static const struct file_operations dp_link_rate_fops = { + .owner = THIS_MODULE, + .read = dp_link_rate_debugfs_read, + .write = dp_link_rate_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_lane_count_fops = { + .owner = THIS_MODULE, + .read = dp_lane_count_debugfs_read, + .write = dp_lane_count_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_voltage_swing_fops = { + .owner = THIS_MODULE, + .read = dp_voltage_swing_debugfs_read, + .write = dp_voltage_swing_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_pre_emphasis_fops = { + .owner = THIS_MODULE, + .read = dp_pre_emphasis_debugfs_read, + .write = dp_pre_emphasis_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_phy_test_pattern_fops = { + .owner = THIS_MODULE, + .read = dp_phy_test_pattern_debugfs_read, + .write = dp_phy_test_pattern_debugfs_write, + .llseek = default_llseek +}; + +static const struct { + char *name; + const struct file_operations *fops; +} dp_debugfs_entries[] = { + {"link_rate", &dp_link_rate_fops}, + {"lane_count", &dp_lane_count_fops}, + {"voltage_swing", &dp_voltage_swing_fops}, + {"pre_emphasis", &dp_pre_emphasis_fops}, + {"phy_test_pattern", &dp_phy_test_pattern_fops} +}; + +int connector_debugfs_init(struct amdgpu_dm_connector *connector) +{ + int i; + struct dentry *ent, *dir = connector->base.debugfs_entry; + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + for (i = 0; i < ARRAY_SIZE(dp_debugfs_entries); i++) { + ent = debugfs_create_file(dp_debugfs_entries[i].name, + 0644, + dir, + connector, + dp_debugfs_entries[i].fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + } + } + + return 0; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h index 7a65206a6d21..d9ed1b2aa811 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,13 +23,12 @@ * */ -#ifndef __SOC_BOUNDING_BOX_H__ -#define __SOC_BOUNDING_BOX_H__ +#ifndef __AMDGPU_DM_DEBUGFS_H__ +#define __AMDGPU_DM_DEBUGFS_H__ -#include "dml_common_defs.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box); -voltage_scaling_st dml_socbb_voltage_scaling(const soc_bounding_box_st *box, enum voltage_state voltage); -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage); +int connector_debugfs_init(struct amdgpu_dm_connector *connector); #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c new file mode 100644 index 000000000000..50e863024f58 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -0,0 +1,535 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + */ +#include <linux/string.h> +#include <linux/acpi.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/amdgpu_drm.h> +#include "dm_services.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_irq.h" +#include "amdgpu_pm.h" +#include "dm_pp_smu.h" + + +bool dm_pp_apply_display_requirements( + const struct dc_context *ctx, + const struct dm_pp_display_configuration *pp_display_cfg) +{ + struct amdgpu_device *adev = ctx->driver_context; + int i; + + if (adev->pm.dpm_enabled) { + + memset(&adev->pm.pm_display_cfg, 0, + sizeof(adev->pm.pm_display_cfg)); + + adev->pm.pm_display_cfg.cpu_cc6_disable = + pp_display_cfg->cpu_cc6_disable; + + adev->pm.pm_display_cfg.cpu_pstate_disable = + pp_display_cfg->cpu_pstate_disable; + + adev->pm.pm_display_cfg.cpu_pstate_separation_time = + pp_display_cfg->cpu_pstate_separation_time; + + adev->pm.pm_display_cfg.nb_pstate_switch_disable = + pp_display_cfg->nb_pstate_switch_disable; + + adev->pm.pm_display_cfg.num_display = + pp_display_cfg->display_count; + adev->pm.pm_display_cfg.num_path_including_non_display = + pp_display_cfg->display_count; + + adev->pm.pm_display_cfg.min_core_set_clock = + pp_display_cfg->min_engine_clock_khz/10; + adev->pm.pm_display_cfg.min_core_set_clock_in_sr = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_mem_set_clock = + pp_display_cfg->min_memory_clock_khz/10; + + adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_dcef_set_clk = + pp_display_cfg->min_dcfclock_khz/10; + + adev->pm.pm_display_cfg.multi_monitor_in_sync = + pp_display_cfg->all_displays_in_sync; + adev->pm.pm_display_cfg.min_vblank_time = + pp_display_cfg->avail_mclk_switch_time_us; + + adev->pm.pm_display_cfg.display_clk = + pp_display_cfg->disp_clk_khz/10; + + adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; + + adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; + adev->pm.pm_display_cfg.line_time_in_us = + pp_display_cfg->line_time_in_us; + + adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; + adev->pm.pm_display_cfg.crossfire_display_index = -1; + adev->pm.pm_display_cfg.min_bus_bandwidth = 0; + + for (i = 0; i < pp_display_cfg->display_count; i++) { + const struct dm_pp_single_disp_config *dc_cfg = + &pp_display_cfg->disp_configs[i]; + adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; + } + + /* TODO: complete implementation of + * pp_display_configuration_change(). + * Follow example of: + * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c + * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ + if (adev->powerplay.pp_funcs->display_configuration_change) + adev->powerplay.pp_funcs->display_configuration_change( + adev->powerplay.pp_handle, + &adev->pm.pm_display_cfg); + + /* TODO: replace by a separate call to 'apply display cfg'? */ + amdgpu_pm_compute_clocks(adev); + } + + return true; +} + +static void get_default_clock_levels( + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *clks) +{ + uint32_t disp_clks_in_khz[6] = { + 300000, 400000, 496560, 626090, 685720, 757900 }; + uint32_t sclks_in_khz[6] = { + 300000, 360000, 423530, 514290, 626090, 720000 }; + uint32_t mclks_in_khz[2] = { 333000, 800000 }; + + switch (clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, disp_clks_in_khz, + sizeof(disp_clks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, sclks_in_khz, + sizeof(sclks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + clks->num_levels = 2; + memmove(clks->clocks_in_khz, mclks_in_khz, + sizeof(mclks_in_khz)); + break; + default: + clks->num_levels = 0; + break; + } +} + +static enum amd_pp_clock_type dc_to_pp_clock_type( + enum dm_pp_clock_type dm_pp_clk_type) +{ + enum amd_pp_clock_type amd_pp_clk_type = 0; + + switch (dm_pp_clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + amd_pp_clk_type = amd_pp_disp_clock; + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + amd_pp_clk_type = amd_pp_sys_clock; + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + amd_pp_clk_type = amd_pp_mem_clock; + break; + case DM_PP_CLOCK_TYPE_DCEFCLK: + amd_pp_clk_type = amd_pp_dcef_clock; + break; + case DM_PP_CLOCK_TYPE_DCFCLK: + amd_pp_clk_type = amd_pp_dcf_clock; + break; + case DM_PP_CLOCK_TYPE_PIXELCLK: + amd_pp_clk_type = amd_pp_pixel_clock; + break; + case DM_PP_CLOCK_TYPE_FCLK: + amd_pp_clk_type = amd_pp_f_clock; + break; + case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: + amd_pp_clk_type = amd_pp_phy_clock; + break; + case DM_PP_CLOCK_TYPE_DPPCLK: + amd_pp_clk_type = amd_pp_dpp_clock; + break; + default: + DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", + dm_pp_clk_type); + break; + } + + return amd_pp_clk_type; +} + +static void pp_to_dc_clock_levels( + const struct amd_pp_clocks *pp_clks, + struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->count, + DM_PP_MAX_CLOCK_LEVELS); + + dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + dc_clks->num_levels = pp_clks->count; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < dc_clks->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); + dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; + } +} + +static void pp_to_dc_clock_levels_with_latency( + const struct pp_clock_levels_with_latency *pp_clks, + struct dm_pp_clock_levels_with_latency *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_DEBUG("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; + } +} + +static void pp_to_dc_clock_levels_with_voltage( + const struct pp_clock_levels_with_voltage *pp_clks, + struct dm_pp_clock_levels_with_voltage *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; + } +} + +bool dm_pp_get_clock_levels_by_type( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *dc_clks) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct amd_pp_clocks pp_clks = { 0 }; + struct amd_pp_simple_clock_info validation_clks = { 0 }; + uint32_t i; + + if (adev->powerplay.pp_funcs->get_clock_by_type) { + if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, + dc_to_pp_clock_type(clk_type), &pp_clks)) { + /* Error in pplib. Provide default values. */ + get_default_clock_levels(clk_type, dc_clks); + return true; + } + } + + pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); + + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( + pp_handle, &validation_clks)) { + /* Error in pplib. Provide default values. */ + DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); + validation_clks.engine_max_clock = 72000; + validation_clks.memory_max_clock = 80000; + validation_clks.level = 0; + } + } + + DRM_INFO("DM_PPLIB: Validation clocks:\n"); + DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", + validation_clks.engine_max_clock); + DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", + validation_clks.memory_max_clock); + DRM_INFO("DM_PPLIB: level : %d\n", + validation_clks.level); + + /* Translate 10 kHz to kHz. */ + validation_clks.engine_max_clock *= 10; + validation_clks.memory_max_clock *= 10; + + /* Determine the highest non-boosted level from the Validation Clocks */ + if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { + /* This clock is higher the validation clock. + * Than means the previous one is the highest + * non-boosted one. */ + DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { + DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_latency( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_latency *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_latency pp_clks = { 0 }; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) + return false; + + if (pp_funcs->get_clock_by_type_with_latency(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clks)) + return false; + + pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_voltage( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_voltage *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_voltage pp_clk_info = {0}; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clk_info)) + return false; + + pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_notify_wm_clock_changes( + const struct dc_context *ctx, + struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_power_level_change_request( + const struct dc_context *ctx, + struct dm_pp_power_level_change_request *level_change_req) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_clock_for_voltage_request( + const struct dc_context *ctx, + struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct pp_display_clock_request pp_clock_request = {0}; + int ret = 0; + + pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); + pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; + + if (!pp_clock_request.clock_type) + return false; + + if (adev->powerplay.pp_funcs->display_clock_voltage_request) + ret = adev->powerplay.pp_funcs->display_clock_voltage_request( + adev->powerplay.pp_handle, + &pp_clock_request); + if (ret) + return false; + return true; +} + +bool dm_pp_get_static_clocks( + const struct dc_context *ctx, + struct dm_pp_static_clock_info *static_clk_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct amd_pp_clock_info pp_clk_info = {0}; + int ret = 0; + + if (adev->powerplay.pp_funcs->get_current_clocks) + ret = adev->powerplay.pp_funcs->get_current_clocks( + adev->powerplay.pp_handle, + &pp_clk_info); + if (ret) + return false; + + static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; + + return true; +} + +void pp_rv_set_display_requirement(struct pp_smu *pp, + struct pp_smu_display_requirement_rv *req) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->display_configuration_changed) + return; + + amdgpu_dpm_display_configuration_changed(adev); +} + +void pp_rv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; + struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; + struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; + int32_t i; + + wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; + wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; + + for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { + if (ranges->reader_wm_sets[i].wm_inst > 3) + wm_dce_clocks[i].wm_set_id = WM_SET_A; + else + wm_dce_clocks[i].wm_set_id = + ranges->reader_wm_sets[i].wm_inst; + wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].max_drain_clk_khz; + wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].min_drain_clk_khz; + wm_dce_clocks[i].wm_max_mem_clk_in_khz = + ranges->reader_wm_sets[i].max_fill_clk_khz; + wm_dce_clocks[i].wm_min_mem_clk_in_khz = + ranges->reader_wm_sets[i].min_fill_clk_khz; + } + + for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { + if (ranges->writer_wm_sets[i].wm_inst > 3) + wm_soc_clocks[i].wm_set_id = WM_SET_A; + else + wm_soc_clocks[i].wm_set_id = + ranges->writer_wm_sets[i].wm_inst; + wm_soc_clocks[i].wm_max_socclk_clk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + wm_soc_clocks[i].wm_min_socclk_clk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + wm_soc_clocks[i].wm_max_mem_clk_in_khz = + ranges->writer_wm_sets[i].max_drain_clk_khz; + wm_soc_clocks[i].wm_min_mem_clk_in_khz = + ranges->writer_wm_sets[i].min_drain_clk_khz; + } + + pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges); +} + +void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->notify_smu_enable_pwe) + return; + + pp_funcs->notify_smu_enable_pwe(pp_handle); +} + +void dm_pp_get_funcs_rv( + struct dc_context *ctx, + struct pp_smu_funcs_rv *funcs) +{ + funcs->pp_smu.ctx = ctx; + funcs->set_display_requirement = pp_rv_set_display_requirement; + funcs->set_wm_ranges = pp_rv_set_wm_ranges; + funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index e861929dd981..9f0a217603ad 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -35,6 +35,8 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" + + unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long current_time_stamp, unsigned long long last_time_stamp) @@ -72,326 +74,4 @@ bool dm_read_persistent_data(struct dc_context *ctx, /**** power component interfaces ****/ -bool dm_pp_apply_display_requirements( - const struct dc_context *ctx, - const struct dm_pp_display_configuration *pp_display_cfg) -{ - struct amdgpu_device *adev = ctx->driver_context; - - if (adev->pm.dpm_enabled) { - - memset(&adev->pm.pm_display_cfg, 0, - sizeof(adev->pm.pm_display_cfg)); - - adev->pm.pm_display_cfg.cpu_cc6_disable = - pp_display_cfg->cpu_cc6_disable; - - adev->pm.pm_display_cfg.cpu_pstate_disable = - pp_display_cfg->cpu_pstate_disable; - - adev->pm.pm_display_cfg.cpu_pstate_separation_time = - pp_display_cfg->cpu_pstate_separation_time; - - adev->pm.pm_display_cfg.nb_pstate_switch_disable = - pp_display_cfg->nb_pstate_switch_disable; - - adev->pm.pm_display_cfg.num_display = - pp_display_cfg->display_count; - adev->pm.pm_display_cfg.num_path_including_non_display = - pp_display_cfg->display_count; - - adev->pm.pm_display_cfg.min_core_set_clock = - pp_display_cfg->min_engine_clock_khz/10; - adev->pm.pm_display_cfg.min_core_set_clock_in_sr = - pp_display_cfg->min_engine_clock_deep_sleep_khz/10; - adev->pm.pm_display_cfg.min_mem_set_clock = - pp_display_cfg->min_memory_clock_khz/10; - - adev->pm.pm_display_cfg.multi_monitor_in_sync = - pp_display_cfg->all_displays_in_sync; - adev->pm.pm_display_cfg.min_vblank_time = - pp_display_cfg->avail_mclk_switch_time_us; - - adev->pm.pm_display_cfg.display_clk = - pp_display_cfg->disp_clk_khz/10; - - adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; - - adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; - adev->pm.pm_display_cfg.line_time_in_us = - pp_display_cfg->line_time_in_us; - - adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; - adev->pm.pm_display_cfg.crossfire_display_index = -1; - adev->pm.pm_display_cfg.min_bus_bandwidth = 0; - - /* TODO: complete implementation of - * pp_display_configuration_change(). - * Follow example of: - * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c - * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ - if (adev->powerplay.pp_funcs->display_configuration_change) - adev->powerplay.pp_funcs->display_configuration_change( - adev->powerplay.pp_handle, - &adev->pm.pm_display_cfg); - - /* TODO: replace by a separate call to 'apply display cfg'? */ - amdgpu_pm_compute_clocks(adev); - } - - return true; -} - -static void get_default_clock_levels( - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *clks) -{ - uint32_t disp_clks_in_khz[6] = { - 300000, 400000, 496560, 626090, 685720, 757900 }; - uint32_t sclks_in_khz[6] = { - 300000, 360000, 423530, 514290, 626090, 720000 }; - uint32_t mclks_in_khz[2] = { 333000, 800000 }; - - switch (clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, disp_clks_in_khz, - sizeof(disp_clks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, sclks_in_khz, - sizeof(sclks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - clks->num_levels = 2; - memmove(clks->clocks_in_khz, mclks_in_khz, - sizeof(mclks_in_khz)); - break; - default: - clks->num_levels = 0; - break; - } -} - -static enum amd_pp_clock_type dc_to_pp_clock_type( - enum dm_pp_clock_type dm_pp_clk_type) -{ - enum amd_pp_clock_type amd_pp_clk_type = 0; - - switch (dm_pp_clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - amd_pp_clk_type = amd_pp_disp_clock; - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - amd_pp_clk_type = amd_pp_sys_clock; - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - amd_pp_clk_type = amd_pp_mem_clock; - break; - default: - DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", - dm_pp_clk_type); - break; - } - - return amd_pp_clk_type; -} - -static void pp_to_dc_clock_levels( - const struct amd_pp_clocks *pp_clks, - struct dm_pp_clock_levels *dc_clks, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->count, - DM_PP_MAX_CLOCK_LEVELS); - - dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - dc_clks->num_levels = pp_clks->count; - - DRM_INFO("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < dc_clks->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); - /* translate 10kHz to kHz */ - dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10; - } -} - -static void pp_to_dc_clock_levels_with_latency( - const struct pp_clock_levels_with_latency *pp_clks, - struct dm_pp_clock_levels_with_latency *clk_level_info, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->num_levels, - DM_PP_MAX_CLOCK_LEVELS); - - clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - clk_level_info->num_levels = pp_clks->num_levels; - - DRM_DEBUG("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_DEBUG("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; - clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; - } -} - -bool dm_pp_get_clock_levels_by_type( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *dc_clks) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct amd_pp_clocks pp_clks = { 0 }; - struct amd_pp_simple_clock_info validation_clks = { 0 }; - uint32_t i; - - if (adev->powerplay.pp_funcs->get_clock_by_type) { - if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, - dc_to_pp_clock_type(clk_type), &pp_clks)) { - /* Error in pplib. Provide default values. */ - get_default_clock_levels(clk_type, dc_clks); - return true; - } - } - - pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); - - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( - pp_handle, &validation_clks)) { - /* Error in pplib. Provide default values. */ - DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); - validation_clks.engine_max_clock = 72000; - validation_clks.memory_max_clock = 80000; - validation_clks.level = 0; - } - } - - DRM_INFO("DM_PPLIB: Validation clocks:\n"); - DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", - validation_clks.engine_max_clock); - DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", - validation_clks.memory_max_clock); - DRM_INFO("DM_PPLIB: level : %d\n", - validation_clks.level); - - /* Translate 10 kHz to kHz. */ - validation_clks.engine_max_clock *= 10; - validation_clks.memory_max_clock *= 10; - - /* Determine the highest non-boosted level from the Validation Clocks */ - if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { - /* This clock is higher the validation clock. - * Than means the previous one is the highest - * non-boosted one. */ - DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { - DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_latency( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_latency *clk_level_info) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct pp_clock_levels_with_latency pp_clks = { 0 }; - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - - if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) - return false; - - if (pp_funcs->get_clock_by_type_with_latency(pp_handle, - dc_to_pp_clock_type(clk_type), - &pp_clks)) - return false; - - pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_voltage( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_voltage *clk_level_info) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_notify_wm_clock_changes( - const struct dc_context *ctx, - struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_power_level_change_request( - const struct dc_context *ctx, - struct dm_pp_power_level_change_request *level_change_req) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_clock_for_voltage_request( - const struct dc_context *ctx, - struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_get_static_clocks( - const struct dc_context *ctx, - struct dm_pp_static_clock_info *static_clk_info) -{ - /* TODO: to be implemented */ - return false; -} - -void dm_pp_get_funcs_rv( - struct dc_context *ctx, - struct pp_smu_funcs_rv *funcs) -{} -/**** end of power component interfaces ****/ diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c7f0b27e457e..be8a2494355a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -3762,6 +3762,200 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info, + unsigned int record_offset) +{ + unsigned int j; + struct bios_parser *bp; + ATOM_BRACKET_LAYOUT_RECORD *record; + ATOM_COMMON_RECORD_HEADER *record_header; + enum bp_result result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + record = NULL; + record_header = NULL; + + for (;;) { + + record_header = (ATOM_COMMON_RECORD_HEADER *) + GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->ucRecordType == 0xff || + record_header->ucRecordSize == 0) { + break; + } + + if (record_header->ucRecordType == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(ATOM_BRACKET_LAYOUT_RECORD) + <= record_header->ucRecordSize) { + record = (ATOM_BRACKET_LAYOUT_RECORD *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->ucRecordSize; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->ucLength; + slot_layout_info->width = record->ucWidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->ucConnNum; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->asConnInfo[j].ucConnectorType); + switch (record->asConnInfo[j].ucConnectorType) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->asConnInfo[j].ucPosition; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->asConnInfo[j].usConnectorObjectId); + } + return result; +} + + +enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + unsigned int record_offset; + struct bios_parser *bp; + enum bp_result result; + ATOM_OBJECT *object; + ATOM_OBJECT_TABLE *object_table; + unsigned int genericTableOffset; + + bp = BP_FROM_DCB(dcb); + object = NULL; + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + + genericTableOffset = bp->object_info_tbl_offset + + bp->object_info_tbl.v1_3->usMiscObjectTableOffset; + object_table = (ATOM_OBJECT_TABLE *) + GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset); + if (!object_table) + return BP_RESULT_FAILURE; + + result = BP_RESULT_NORECORD; + for (i = 0; i < object_table->ucNumberOfObjects; ++i) { + + if (bracket_layout_id == + object_table->asObjects[i].usObjectID) { + + object = &object_table->asObjects[i]; + record_offset = object->usRecordOffset + + bp->object_info_tbl_offset; + + result = update_slot_layout_info(dcb, i, + slot_layout_info, record_offset); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + /******************************************************************************/ static const struct dc_vbios_funcs vbios_funcs = { @@ -3836,6 +4030,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */ .bios_parser_destroy = bios_parser_destroy, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index b8cef7af3c4a..aeb56e402ccc 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -43,6 +43,29 @@ #include "bios_parser_interface.h" #include "bios_parser_common.h" + +/* Temporarily add in defines until ObjectID.h patch is updated in a few days */ +#ifndef GENERIC_OBJECT_ID_BRACKET_LAYOUT +#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05 +#endif /* GENERIC_OBJECT_ID_BRACKET_LAYOUT */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 */ + +#define DC_LOGGER \ + bp->base.ctx->logger + #define LAST_RECORD_TYPE 0xff #define SMU9_SYSPLL0_ID 0 @@ -86,7 +109,6 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( #define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table) - static void destruct(struct bios_parser *bp) { kfree(bp->base.bios_local_image); @@ -1854,6 +1876,198 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +static enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info) +{ + unsigned int record_offset; + unsigned int j; + struct atom_display_object_path_v2 *object; + struct atom_bracket_layout_record *record; + struct atom_common_record_header *record_header; + enum bp_result result; + struct bios_parser *bp; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + record = NULL; + record_header = NULL; + result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + object = &v1_4->display_path[i]; + record_offset = (unsigned int) + (object->disp_recordoffset) + + (unsigned int)(bp->object_info_tbl_offset); + + for (;;) { + + record_header = (struct atom_common_record_header *) + GET_IMAGE(struct atom_common_record_header, + record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->record_type == 0xff || + record_header->record_size == 0) { + break; + } + + if (record_header->record_type == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(struct atom_bracket_layout_record) + <= record_header->record_size) { + record = (struct atom_bracket_layout_record *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->record_size; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->bracketlen; + slot_layout_info->width = record->bracketwidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->conn_num; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->conn_info[j].connector_type); + switch (record->conn_info[j].connector_type) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->conn_info[j].position; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->conn_info[j].connectorobjid); + } + return result; +} + + +static enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + struct bios_parser *bp = BP_FROM_DCB(dcb); + enum bp_result result; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + result = BP_RESULT_NORECORD; + for (i = 0; i < v1_4->number_of_path; ++i) { + + if (bracket_layout_id == + v1_4->display_path[i].display_objid) { + result = update_slot_layout_info(dcb, i, + slot_layout_info); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + static const struct dc_vbios_funcs vbios_funcs = { .get_connectors_number = bios_parser_get_connectors_number, @@ -1925,6 +2139,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .bios_parser_destroy = firmware_parser_destroy, .get_smu_clock_info = bios_parser_get_smu_clock_info, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 752b08a42d3e..2b5dc499a35e 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -59,36 +59,7 @@ bios_cmd_table_para_revision(bp->base.ctx->driver_context, \ GET_INDEX_INTO_MASTER_TABLE(command, fname)) -static void init_dig_encoder_control(struct bios_parser *bp); -static void init_transmitter_control(struct bios_parser *bp); -static void init_set_pixel_clock(struct bios_parser *bp); -static void init_set_crtc_timing(struct bios_parser *bp); - -static void init_select_crtc_source(struct bios_parser *bp); -static void init_enable_crtc(struct bios_parser *bp); - -static void init_external_encoder_control(struct bios_parser *bp); -static void init_enable_disp_power_gating(struct bios_parser *bp); -static void init_set_dce_clock(struct bios_parser *bp); -static void init_get_smu_clock_info(struct bios_parser *bp); - -void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) -{ - init_dig_encoder_control(bp); - init_transmitter_control(bp); - init_set_pixel_clock(bp); - - init_set_crtc_timing(bp); - - init_select_crtc_source(bp); - init_enable_crtc(bp); - - init_external_encoder_control(bp); - init_enable_disp_power_gating(bp); - init_set_dce_clock(bp); - init_get_smu_clock_info(bp); -} static uint32_t bios_cmd_table_para_revision(void *dev, uint32_t index) @@ -829,3 +800,20 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) return 0; } +void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) +{ + init_dig_encoder_control(bp); + init_transmitter_control(bp); + init_set_pixel_clock(bp); + + init_set_crtc_timing(bp); + + init_select_crtc_source(bp); + init_enable_crtc(bp); + + init_external_encoder_control(bp); + init_enable_disp_power_gating(bp); + init_set_dce_clock(bp); + init_get_smu_clock_info(bp); + +} diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 49a4ea45466d..e44b8d3d6891 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -31,6 +31,8 @@ #include "resource.h" #include "dcn10/dcn10_resource.h" +#include "dcn10/dcn10_hubbub.h" + #include "dcn_calc_math.h" #define DC_LOGGER \ @@ -423,6 +425,10 @@ static void dcn_bw_calc_rq_dlg_ttu( int total_flip_bytes = 0; int i; + memset(dlg_regs, 0, sizeof(*dlg_regs)); + memset(ttu_regs, 0, sizeof(*ttu_regs)); + memset(rq_regs, 0, sizeof(*rq_regs)); + for (i = 0; i < number_of_planes; i++) { total_active_bw += v->read_bandwidth[i]; total_prefetch_bw += v->prefetch_bandwidth[i]; @@ -501,6 +507,7 @@ static void split_stream_across_pipes( resource_build_scaling_params(secondary_pipe); } +#if 0 static void calc_wm_sets_and_perf_params( struct dc_state *context, struct dcn_bw_internal_vars *v) @@ -582,6 +589,7 @@ static void calc_wm_sets_and_perf_params( if (v->voltage_level >= 3) context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; } +#endif static bool dcn_bw_apply_registry_override(struct dc *dc) { @@ -883,7 +891,26 @@ bool dcn_validate_bandwidth( ASSERT(pipe->plane_res.scl_data.ratios.vert.value != dc_fixpt_one.value || v->scaler_rec_out_width[input_idx] == v->viewport_height[input_idx]); } - v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + + if (dc->debug.optimized_watermark) { + /* + * this method requires us to always re-calculate watermark when dcc change + * between flip. + */ + v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + } else { + /* + * allow us to disable dcc on the fly without re-calculating WM + * + * extra overhead for DCC is quite small. for 1080p WM without + * DCC is only 0.417us lower (urgent goes from 6.979us to 6.562us) + */ + unsigned int bpe; + + v->dcc_enable[input_idx] = dc->res_pool->hubbub->funcs->dcc_support_pixel_format( + pipe->plane_state->format, &bpe) ? dcn_bw_yes : dcn_bw_no; + } + v->source_pixel_format[input_idx] = tl_pixel_format_to_bw_defs( pipe->plane_state->format); v->source_surface_mode[input_idx] = tl_sw_mode_to_bw_defs( @@ -976,43 +1003,60 @@ bool dcn_validate_bandwidth( bw_consumed = v->fabric_and_dram_bandwidth; display_pipe_configuration(v); - calc_wm_sets_and_perf_params(context, v); - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / + /*calc_wm_sets_and_perf_params(context, v);*/ + /* Only 1 set is used by dcn since no noticeable + * performance improvement was measured and due to hw bug DEGVIDCN10-254 + */ + dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v); + + context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = + v->stutter_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + v->stutter_enter_plus_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = + v->dram_clock_change_watermark * 1000; + context->bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000; + context->bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000; + context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; + + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / (ddr4_dram_factor_single_Channel * v->number_of_channels)); if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) { - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); } - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); - context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000); + context->bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); + context->bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000); - context->bw.dcn.calc_clk.dispclk_khz = (int)(v->dispclk * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(v->dispclk * 1000); if (dc->debug.max_disp_clk == true) - context->bw.dcn.calc_clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); - if (context->bw.dcn.calc_clk.dispclk_khz < + if (context->bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz) { - context->bw.dcn.calc_clk.dispclk_khz = + context->bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; - + context->bw.dcn.clk.dppclk_khz = context->bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; switch (v->voltage_level) { case 0: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000); break; case 1: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000); break; case 2: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000); break; default: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000); break; } @@ -1225,27 +1269,27 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks) + struct dc_clocks *clocks) { unsigned vdd_level, vdd_level_temp; unsigned dcf_clk; /*find a common supported voltage level*/ vdd_level = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_khz); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->fclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclk_khz); /*find that level conresponding dcfclk*/ vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); @@ -1331,21 +1375,14 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) { struct pp_smu_funcs_rv *pp = dc->res_pool->pp_smu; struct pp_smu_wm_range_sets ranges = {0}; - int max_fclk_khz, nom_fclk_khz, mid_fclk_khz, min_fclk_khz; - int max_dcfclk_khz, min_dcfclk_khz; - int socclk_khz; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; const int overdrive = 5000000; /* 5 GHz to cover Overdrive */ - unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels); if (!pp->set_wm_ranges) return; kernel_fpu_begin(); - max_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 * 1000000 / factor; - nom_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 * 1000000 / factor; - mid_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 * 1000000 / factor; min_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 * 1000000 / 32; - max_dcfclk_khz = dc->dcn_soc->dcfclkv_max0p9 * 1000; min_dcfclk_khz = dc->dcn_soc->dcfclkv_min0p65 * 1000; socclk_khz = dc->dcn_soc->socclk * 1000; kernel_fpu_end(); @@ -1353,105 +1390,46 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) /* Now notify PPLib/SMU about which Watermarks sets they should select * depending on DPM state they are in. And update BW MGR GFX Engine and * Memory clock member variables for Watermarks calculations for each - * Watermark Set + * Watermark Set. Only one watermark set for dcn1 due to hw bug DEGVIDCN10-254. */ /* SOCCLK does not affect anytihng but writeback for DCN so for now we dont * care what the value is, hence min to overdrive level */ - ranges.num_reader_wm_sets = WM_COUNT; - ranges.num_writer_wm_sets = WM_COUNT; + ranges.num_reader_wm_sets = WM_SET_COUNT; + ranges.num_writer_wm_sets = WM_SET_COUNT; ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz; - ranges.reader_wm_sets[0].max_drain_clk_khz = max_dcfclk_khz; + ranges.reader_wm_sets[0].max_drain_clk_khz = overdrive; ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[0].max_fill_clk_khz = min_fclk_khz; + ranges.reader_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz; ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz; - ranges.writer_wm_sets[0].max_drain_clk_khz = min_fclk_khz; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[1].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[1].min_fill_clk_khz = mid_fclk_khz; - ranges.reader_wm_sets[1].max_fill_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[1].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[1].min_drain_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].max_drain_clk_khz = mid_fclk_khz; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[2].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[2].min_fill_clk_khz = nom_fclk_khz; - ranges.reader_wm_sets[2].max_fill_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[2].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[2].min_drain_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].max_drain_clk_khz = nom_fclk_khz; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[3].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[3].min_fill_clk_khz = max_fclk_khz; - ranges.reader_wm_sets[3].max_fill_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[3].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[3].min_drain_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].max_drain_clk_khz = max_fclk_khz; + ranges.writer_wm_sets[0].max_drain_clk_khz = overdrive; if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[0].max_drain_clk_khz = 654000; + ranges.reader_wm_sets[0].max_drain_clk_khz = 5000000; ranges.reader_wm_sets[0].min_fill_clk_khz = 800000; - ranges.reader_wm_sets[0].max_fill_clk_khz = 800000; + ranges.reader_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[0].max_fill_clk_khz = 757000; + ranges.writer_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].min_drain_clk_khz = 800000; - ranges.writer_wm_sets[0].max_drain_clk_khz = 800000; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[1].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[1].min_fill_clk_khz = 933000; - ranges.reader_wm_sets[1].max_fill_clk_khz = 933000; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[1].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[1].min_drain_clk_khz = 933000; - ranges.writer_wm_sets[1].max_drain_clk_khz = 933000; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[2].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[2].min_fill_clk_khz = 1067000; - ranges.reader_wm_sets[2].max_fill_clk_khz = 1067000; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[2].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[2].min_drain_clk_khz = 1067000; - ranges.writer_wm_sets[2].max_drain_clk_khz = 1067000; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[3].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[3].min_fill_clk_khz = 1200000; - ranges.reader_wm_sets[3].max_fill_clk_khz = 1200000; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[3].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[3].min_drain_clk_khz = 1200000; - ranges.writer_wm_sets[3].max_drain_clk_khz = 1200000; + ranges.writer_wm_sets[0].max_drain_clk_khz = 5000000; } + ranges.reader_wm_sets[1] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[1].wm_inst = WM_B; + + ranges.reader_wm_sets[2] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[2].wm_inst = WM_C; + + ranges.reader_wm_sets[3] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[3].wm_inst = WM_D; + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ pp->set_wm_ranges(&pp->pp_smu, &ranges); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 53ce7fa864b4..2a785bbf2b8f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -944,12 +944,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) dc->optimized_required = false; - /* 3rd param should be true, temp w/a for RV*/ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - dc->hwss.set_bandwidth(dc, context, dc->ctx->dce_version < DCN_VERSION_1_0); -#else dc->hwss.set_bandwidth(dc, context, true); -#endif return true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 267c76766dea..e1ebdf7b5eaf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -352,19 +352,19 @@ void context_clock_trace( DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); #endif } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 08b7ee526f0f..fa56c0fc02bf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -33,6 +33,7 @@ #include "dc_link_dp.h" #include "dc_link_ddc.h" #include "link_hwss.h" +#include "opp.h" #include "link_encoder.h" #include "hw_sequencer.h" @@ -1284,29 +1285,15 @@ static enum dc_status enable_link_dp( max_link_rate = LINK_RATE_HIGH3; if (link_settings.link_rate == max_link_rate) { - if (state->dis_clk->funcs->set_min_clocks_state) { - if (state->dis_clk->cur_min_clks_state < DM_PP_CLOCKS_STATE_NOMINAL) - state->dis_clk->funcs->set_min_clocks_state( - state->dis_clk, DM_PP_CLOCKS_STATE_NOMINAL); - } else { - uint32_t dp_phyclk_in_khz; - const struct clocks_value clocks_value = - state->dis_clk->cur_clocks_value; - - /* 27mhz = 27000000hz= 27000khz */ - dp_phyclk_in_khz = link_settings.link_rate * 27000; - - if (((clocks_value.max_non_dp_phyclk_in_khz != 0) && - (dp_phyclk_in_khz > clocks_value.max_non_dp_phyclk_in_khz)) || - (dp_phyclk_in_khz > clocks_value.max_dp_phyclk_in_khz)) { - state->dis_clk->funcs->apply_clock_voltage_request( - state->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - dp_phyclk_in_khz, - false, - true); - } - } + struct dc_clocks clocks = state->bw.dcn.clk; + + /* dce/dcn compat, do not update dispclk */ + clocks.dispclk_khz = 0; + /* 27mhz = 27000000hz= 27000khz */ + clocks.phyclk_khz = link_settings.link_rate * 27000; + + state->dis_clk->funcs->update_clocks( + state->dis_clk, &clocks, false); } dp_enable_link_phy( @@ -2396,9 +2383,10 @@ void core_link_enable_stream( core_dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - COLOR_DEPTH_UNDEFINED); + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + COLOR_DEPTH_UNDEFINED); core_dc->hwss.enable_stream(pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 509f265663d2..84586b679d73 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -3,6 +3,7 @@ #include "dc.h" #include "dc_link_dp.h" #include "dm_helpers.h" +#include "opp.h" #include "inc/core_types.h" #include "link_hwss.h" @@ -1999,7 +2000,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd { union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}}; union device_service_irq device_service_clear = { { 0 } }; - enum dc_status result = DDC_RESULT_UNKNOWN; + enum dc_status result; bool status = false; /* For use cases related to down stream connection status change, * PSR and device auto test, refer to function handle_sst_hpd_irq @@ -2511,8 +2512,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, controller_test_pattern, color_depth); } break; @@ -2524,8 +2525,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index fca22550417a..c5fc5250e2bf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1948,7 +1948,7 @@ void dc_resource_state_construct( const struct dc *dc, struct dc_state *dst_ctx) { - dst_ctx->dis_clk = dc->res_pool->display_clock; + dst_ctx->dis_clk = dc->res_pool->dccg; } enum dc_status dc_validate_global_state( diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7ebce7669eea..0cb7e10d2505 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.47" +#define DC_VER "3.1.52" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -186,6 +186,10 @@ enum wm_report_mode { WM_REPORT_OVERRIDE = 1, }; +/* + * For any clocks that may differ per pipe + * only the max is stored in this structure + */ struct dc_clocks { int dispclk_khz; int max_supported_dppclk_khz; @@ -194,6 +198,7 @@ struct dc_clocks { int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; + int phyclk_khz; }; struct dc_debug { @@ -228,6 +233,7 @@ struct dc_debug { int urgent_latency_ns; int percent_of_ideal_drambw; int dram_clock_change_latency_ns; + bool optimized_watermark; int always_scale; bool disable_pplib_clock_request; bool disable_clock_gate; diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index d9b84ec7954c..90082bab71f0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -198,6 +198,10 @@ struct dc_vbios_funcs { void (*post_init)(struct dc_bios *bios); void (*bios_parser_destroy)(struct dc_bios **dcb); + + enum bp_result (*get_board_layout_info)( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info); }; struct bios_registers { diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index d31023d57b58..14afbc5c0a62 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -199,6 +199,7 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, + SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, SURFACE_PIXEL_FORMAT_INVALID /*grow 444 video here if necessary */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 88b09dd758ba..ca137757a69e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -133,7 +133,7 @@ static bool calculate_fb_and_fractional_fb_divider( uint64_t feedback_divider; feedback_divider = - (uint64_t)(target_pix_clk_khz * ref_divider * post_divider); + (uint64_t)target_pix_clk_khz * ref_divider * post_divider; feedback_divider *= 10; /* additional factor, since we divide by 10 afterwards */ feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor); @@ -145,8 +145,8 @@ static bool calculate_fb_and_fractional_fb_divider( * of fractional feedback decimal point and the fractional FB Divider precision * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/ - feedback_divider += (uint64_t) - (5 * calc_pll_cs->fract_fb_divider_precision_factor); + feedback_divider += 5ULL * + calc_pll_cs->fract_fb_divider_precision_factor; feedback_divider = div_u64(feedback_divider, calc_pll_cs->fract_fb_divider_precision_factor * 10); @@ -203,8 +203,8 @@ static bool calc_fb_divider_checking_tolerance( &fract_feedback_divider); /*Actual calculated value*/ - actual_calc_clk_khz = (uint64_t)(feedback_divider * - calc_pll_cs->fract_fb_divider_factor) + + actual_calc_clk_khz = (uint64_t)feedback_divider * + calc_pll_cs->fract_fb_divider_factor + fract_feedback_divider; actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz; actual_calc_clk_khz = diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 8a581c67bf2d..6882dc953a2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -38,7 +38,7 @@ #include "dal_asic_id.h" #define TO_DCE_CLOCKS(clocks)\ - container_of(clocks, struct dce_disp_clk, base) + container_of(clocks, struct dce_dccg, base) #define REG(reg) \ (clk_dce->regs->reg) @@ -101,99 +101,78 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStatePerformance*/ { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; -/* Starting point for each divider range.*/ -enum dce_divider_range_start { - DIVIDER_RANGE_01_START = 200, /* 2.00*/ - DIVIDER_RANGE_02_START = 1600, /* 16.00*/ - DIVIDER_RANGE_03_START = 3200, /* 32.00*/ - DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ +/* Starting DID for each range */ +enum dentist_base_divider_id { + DENTIST_BASE_DID_1 = 0x08, + DENTIST_BASE_DID_2 = 0x40, + DENTIST_BASE_DID_3 = 0x60, + DENTIST_MAX_DID = 0x80 }; -/* Ranges for divider identifiers (Divider ID or DID) - mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ -enum dce_divider_id_register_setting { - DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, - DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, - DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, - DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 +/* Starting point and step size for each divider range.*/ +enum dentist_divider_range { + DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ + DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ + DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ + DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ + DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ + DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 }; -/* Step size between each divider within a range. - Incrementing the DENTIST_DISPCLK_WDIVIDER by one - will increment the divider by this much.*/ -enum dce_divider_range_step_size { - DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ - DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ - DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ -}; - -static bool dce_divider_range_construct( - struct dce_divider_range *div_range, - int range_start, - int range_step, - int did_min, - int did_max) +static int dentist_get_divider_from_did(int did) { - div_range->div_range_start = range_start; - div_range->div_range_step = range_step; - div_range->did_min = did_min; - div_range->did_max = did_max; - - if (div_range->div_range_step == 0) { - div_range->div_range_step = 1; - /*div_range_step cannot be zero*/ - BREAK_TO_DEBUGGER(); + if (did < DENTIST_BASE_DID_1) + did = DENTIST_BASE_DID_1; + if (did > DENTIST_MAX_DID) + did = DENTIST_MAX_DID; + + if (did < DENTIST_BASE_DID_2) { + return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP + * (did - DENTIST_BASE_DID_1); + } else if (did < DENTIST_BASE_DID_3) { + return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP + * (did - DENTIST_BASE_DID_2); + } else { + return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP + * (did - DENTIST_BASE_DID_3); } - /* Calculate this based on the other inputs.*/ - /* See DividerRange.h for explanation of */ - /* the relationship between divider id (DID) and a divider.*/ - /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/ - /* Maximum divider identified in this range = - * (Number of Divider IDs)*Step size between dividers - * + The start of this range.*/ - div_range->div_range_end = (did_max - did_min) * range_step - + range_start; - return true; -} - -static int dce_divider_range_calc_divider( - struct dce_divider_range *div_range, - int did) -{ - /* Is this DID within our range?*/ - if ((did < div_range->did_min) || (did >= div_range->did_max)) - return INVALID_DIVIDER; - - return ((did - div_range->did_min) * div_range->div_range_step) - + div_range->div_range_start; - } -static int dce_divider_range_get_divider( - struct dce_divider_range *div_range, - int ranges_num, - int did) +/* SW will adjust DP REF Clock average value for all purposes + * (DP DTO / DP Audio DTO and DP GTC) + if clock is spread for all cases: + -if SS enabled on DP Ref clock and HW de-spreading enabled with SW + calculations for DS_INCR/DS_MODULO (this is planned to be default case) + -if SS enabled on DP Ref clock and HW de-spreading enabled with HW + calculations (not planned to be used, but average clock should still + be valid) + -if SS enabled on DP Ref clock and HW de-spreading disabled + (should not be case with CIK) then SW should program all rates + generated according to average value (case as with previous ASICs) + */ +static int dccg_adjust_dp_ref_freq_for_ss(struct dce_dccg *clk_dce, int dp_ref_clk_khz) { - int div = INVALID_DIVIDER; - int i; + if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { + struct fixed31_32 ss_percentage = dc_fixpt_div_int( + dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, + clk_dce->dprefclk_ss_divider), 200); + struct fixed31_32 adj_dp_ref_clk_khz; - for (i = 0; i < ranges_num; i++) { - /* Calculate divider with given divider ID*/ - div = dce_divider_range_calc_divider(&div_range[i], did); - /* Found a valid return divider*/ - if (div != INVALID_DIVIDER) - break; + ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); + adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); + dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); } - return div; + return dp_ref_clk_khz; } -static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) +static int dce_get_dp_ref_freq_khz(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int dprefclk_wdivider; int dprefclk_src_sel; int dp_ref_clk_khz = 600000; - int target_div = INVALID_DIVIDER; + int target_div; /* ASSERT DP Reference Clock source is from DFS*/ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel); @@ -204,80 +183,27 @@ static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ - target_div = dce_divider_range_get_divider( - clk_dce->divider_ranges, - DIVIDER_RANGE_MAX, - dprefclk_wdivider); - - if (target_div != INVALID_DIVIDER) { - /* Calculate the current DFS clock, in kHz.*/ - dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR - * clk_dce->dentist_vco_freq_khz) / target_div; - } + target_div = dentist_get_divider_from_did(dprefclk_wdivider); - /* SW will adjust DP REF Clock average value for all purposes - * (DP DTO / DP Audio DTO and DP GTC) - if clock is spread for all cases: - -if SS enabled on DP Ref clock and HW de-spreading enabled with SW - calculations for DS_INCR/DS_MODULO (this is planned to be default case) - -if SS enabled on DP Ref clock and HW de-spreading enabled with HW - calculations (not planned to be used, but average clock should still - be valid) - -if SS enabled on DP Ref clock and HW de-spreading disabled - (should not be case with CIK) then SW should program all rates - generated according to average value (case as with previous ASICs) - */ - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; + /* Calculate the current DFS clock, in kHz.*/ + dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_dce->dentist_vco_freq_khz) / target_div; - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz); } -/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS - * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit - * clock implementation - */ -static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) +static int dce12_get_dp_ref_freq_khz(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); - int dp_ref_clk_khz = 600000; - - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, 600000); } + static enum dm_pp_clocks_state dce_get_required_clocks_state( - struct display_clock *clk, - struct state_dependent_clocks *req_clocks) + struct dccg *clk, + struct dc_clocks *req_clocks) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int i; enum dm_pp_clocks_state low_req_clk; @@ -286,53 +212,30 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( * all required clocks */ for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--) - if (req_clocks->display_clk_khz > + if (req_clocks->dispclk_khz > clk_dce->max_clks_by_state[i].display_clk_khz - || req_clocks->pixel_clk_khz > + || req_clocks->phyclk_khz > clk_dce->max_clks_by_state[i].pixel_clk_khz) break; low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { - DC_LOG_WARNING("%s: clocks unsupported disp_clk %d pix_clk %d", - __func__, - req_clocks->display_clk_khz, - req_clocks->pixel_clk_khz); - low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + /* set max clock state for high phyclock, invalid on exceeding display clock */ + if (clk_dce->max_clks_by_state[clk->max_clks_state].display_clk_khz + < req_clocks->dispclk_khz) + low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + else + low_req_clk = clk->max_clks_state; } return low_req_clk; } -static bool dce_clock_set_min_clocks_state( - struct display_clock *clk, - enum dm_pp_clocks_state clocks_state) -{ - struct dm_pp_power_level_change_request level_change_req = { - clocks_state }; - - if (clocks_state > clk->max_clks_state) { - /*Requested state exceeds max supported state.*/ - DC_LOG_WARNING("Requested state exceeds max supported state"); - return false; - } else if (clocks_state == clk->cur_min_clks_state) { - /*if we're trying to set the same state, we can just return - * since nothing needs to be done*/ - return true; - } - - /* get max clock state from PPLIB */ - if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req)) - clk->cur_min_clks_state = clocks_state; - - return true; -} - static int dce_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_pixel_clock_parameters pxl_clk_params = { 0 }; struct dc_bios *bp = clk->ctx->dc_bios; int actual_clock = requested_clk_khz; @@ -364,10 +267,10 @@ static int dce_set_clock( } static int dce_psr_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct dc_context *ctx = clk_dce->base.ctx; struct dc *core_dc = ctx->dc; struct dmcu *dmcu = core_dc->res_pool->dmcu; @@ -380,10 +283,10 @@ static int dce_psr_set_clock( } static int dce112_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_set_dce_clock_parameters dce_clk_params; struct dc_bios *bp = clk->ctx->dc_bios; struct dc *core_dc = clk->ctx->dc; @@ -432,7 +335,7 @@ static int dce112_set_clock( return actual_clock; } -static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce) { struct dc_debug *debug = &clk_dce->base.ctx->dc->debug; struct dc_bios *bp = clk_dce->base.ctx->dc_bios; @@ -488,11 +391,9 @@ static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) if (!debug->disable_dfs_bypass && bp->integrated_info) if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) clk_dce->dfs_bypass_enabled = true; - - clk_dce->use_max_disp_clk = debug->max_disp_clk; } -static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_ss_info(struct dce_dccg *clk_dce) { struct dc_bios *bp = clk_dce->base.ctx->dc_bios; int ss_info_num = bp->funcs->get_ss_entry_number( @@ -548,139 +449,263 @@ static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) } } -static bool dce_apply_clock_voltage_request( - struct display_clock *clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk) +static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) +{ + return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); +} + +static void dce12_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) { - bool send_request = false; struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - case DM_PP_CLOCK_TYPE_PIXELCLK: - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - break; - default: - BREAK_TO_DEBUGGER(); - return false; + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; + clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } - clock_voltage_req.clk_type = clocks_type; - clock_voltage_req.clocks_in_khz = clocks_in_khz; - - /* to pplib */ - if (pre_mode_set) { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (clocks_in_khz > clk->cur_clocks_value.dispclk_in_khz) { - clk->cur_clocks_value.dispclk_notify_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.dispclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.dispclk_in_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_pixelclk_in_khz) { - clk->cur_clocks_value.pixelclk_notify_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.pixelclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_pixelclk_in_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_non_dp_phyclk_in_khz) { - clk->cur_clocks_value.phyclk_notigy_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.phyclk_notigy_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_non_dp_phyclk_in_khz = clocks_in_khz; - break; - default: - ASSERT(0); - break; - } + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; + clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + } +} + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + bool dispclk_increase = new_clocks->dispclk_khz > dccg->clks.dispclk_khz; + int disp_clk_threshold = new_clocks->max_supported_dppclk_khz; + bool cur_dpp_div = dccg->clks.dispclk_khz > dccg->clks.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return new_clocks->dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (new_clocks->dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return new_clocks->dispclk_khz; } else { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (!clk->cur_clocks_value.dispclk_notify_pplib_done) - send_request = true; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (!clk->cur_clocks_value.pixelclk_notify_pplib_done) - send_request = true; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (!clk->cur_clocks_value.phyclk_notigy_pplib_done) - send_request = true; - break; - default: - ASSERT(0); - break; - } + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return new_clocks->dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (dccg->clks.dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return new_clocks->dispclk_khz; } - if (send_request) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (clk->ctx->dce_version >= DCN_VERSION_1_0) { - struct dc *core_dc = clk->ctx->dc; - /*use dcfclk request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = - dcn_find_dcfclk_suits_all(core_dc, &clk->cur_clocks_value); - } + + return disp_clk_threshold; +} + +static void dcn1_ramp_up_dispclk_with_dpp(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + struct dc *dc = dccg->ctx->dc; + int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(dccg, new_clocks); + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + int i; + + /* set disp clk to dpp clk threshold */ + dccg->funcs->set_dispclk(dccg, dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz) + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + dccg->clks.dppclk_khz = new_clocks->dppclk_khz; + dccg->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; +} + +static void dcn1_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dc *dc = dccg->ctx->dc; + struct pp_smu_display_requirement_rv *smu_req_cur = + &dc->res_pool->pp_smu_req; + struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; + struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; + struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + bool send_request_to_increase = false; + bool send_request_to_lower = false; + + if (new_clocks->phyclk_khz) + smu_req.display_count = 1; + else + smu_req.display_count = 0; + + if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz + || new_clocks->phyclk_khz > dccg->clks.phyclk_khz + || new_clocks->fclk_khz > dccg->clks.fclk_khz + || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) + send_request_to_increase = true; + + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; + + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) { + dccg->clks.fclk_khz = new_clocks->fclk_khz; + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK; + clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz; + smu_req.hard_min_fclk_khz = new_clocks->fclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) { + dccg->clks.dcfclk_khz = new_clocks->dcfclk_khz; + smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz; + + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, + new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) { + dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz; + + send_request_to_lower = true; + } + + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + if (send_request_to_increase) { + /*use dcfclk to request voltage*/ + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + } + + /* dcn1 dppclk is tied to dispclk */ + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + send_request_to_lower = true; + } + + if (!send_request_to_increase && send_request_to_lower) { + /*use dcfclk to request voltage*/ + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + } + + + *smu_req_cur = smu_req; +} #endif - dm_pp_apply_clock_for_voltage_request( - clk->ctx, &clock_voltage_req); + +static void dce_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dm_pp_power_level_change_request level_change_req; + + level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks); + /* get max clock state from PPLIB */ + if ((level_change_req.power_level < dccg->cur_min_clks_state && safe_to_lower) + || level_change_req.power_level > dccg->cur_min_clks_state) { + if (dm_pp_apply_power_level_change_request(dccg->ctx, &level_change_req)) + dccg->cur_min_clks_state = level_change_req.power_level; } - if (update_dp_phyclk && (clocks_in_khz > - clk->cur_clocks_value.max_dp_phyclk_in_khz)) - clk->cur_clocks_value.max_dp_phyclk_in_khz = clocks_in_khz; - return true; + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + } } +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +static const struct display_clock_funcs dcn1_funcs = { + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dcn1_update_clocks +}; +#endif static const struct display_clock_funcs dce120_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, - .apply_clock_voltage_request = dce_apply_clock_voltage_request, - .set_clock = dce112_set_clock + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dce12_update_clocks }; static const struct display_clock_funcs dce112_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce112_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce110_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_psr_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce_psr_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce_set_clock, + .update_clocks = dce_update_clocks }; -static void dce_disp_clk_construct( - struct dce_disp_clk *clk_dce, +static void dce_dccg_construct( + struct dce_dccg *clk_dce, struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct display_clock *base = &clk_dce->base; + struct dccg *base = &clk_dce->base; base->ctx = ctx; base->funcs = &dce_funcs; @@ -700,34 +725,15 @@ static void dce_disp_clk_construct( dce_clock_read_integrated_info(clk_dce); dce_clock_read_ss_info(clk_dce); - - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_01], - DIVIDER_RANGE_01_START, - DIVIDER_RANGE_01_STEP_SIZE, - DIVIDER_RANGE_01_BASE_DIVIDER_ID, - DIVIDER_RANGE_02_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_02], - DIVIDER_RANGE_02_START, - DIVIDER_RANGE_02_STEP_SIZE, - DIVIDER_RANGE_02_BASE_DIVIDER_ID, - DIVIDER_RANGE_03_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_03], - DIVIDER_RANGE_03_START, - DIVIDER_RANGE_03_STEP_SIZE, - DIVIDER_RANGE_03_BASE_DIVIDER_ID, - DIVIDER_RANGE_MAX_DIVIDER_ID); } -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -738,19 +744,19 @@ struct display_clock *dce_disp_clk_create( dce80_max_clks_by_state, sizeof(dce80_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); return &clk_dce->base; } -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -761,7 +767,7 @@ struct display_clock *dce110_disp_clk_create( dce110_max_clks_by_state, sizeof(dce110_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce110_funcs; @@ -769,13 +775,13 @@ struct display_clock *dce110_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -786,7 +792,7 @@ struct display_clock *dce112_disp_clk_create( dce112_max_clks_by_state, sizeof(dce112_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce112_funcs; @@ -794,10 +800,9 @@ struct display_clock *dce112_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) +struct dccg *dce120_dccg_create(struct dc_context *ctx) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); - struct dm_pp_clock_levels_with_voltage clk_level_info = {0}; + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -808,28 +813,59 @@ struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) dce120_max_clks_by_state, sizeof(dce120_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); clk_dce->base.funcs = &dce120_funcs; - /* new in dce120 */ - if (!ctx->dc->debug.disable_pplib_clock_request && - dm_pp_get_clock_levels_by_type_with_voltage( - ctx, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clk_level_info) - && clk_level_info.num_levels) - clk_dce->max_displ_clk_in_khz = - clk_level_info.data[clk_level_info.num_levels - 1].clocks_in_khz; - else - clk_dce->max_displ_clk_in_khz = 1133000; + return &clk_dce->base; +} + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +struct dccg *dcn1_dccg_create(struct dc_context *ctx) +{ + struct dc_debug *debug = &ctx->dc->debug; + struct dc_bios *bp = ctx->dc_bios; + struct dc_firmware_info fw_info = { { 0 } }; + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + + if (clk_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + clk_dce->base.ctx = ctx; + clk_dce->base.funcs = &dcn1_funcs; + + clk_dce->dfs_bypass_disp_clk = 0; + + clk_dce->dprefclk_ss_percentage = 0; + clk_dce->dprefclk_ss_divider = 1000; + clk_dce->ss_on_dprefclk = false; + + if (bp->integrated_info) + clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; + if (clk_dce->dentist_vco_freq_khz == 0) { + bp->funcs->get_firmware_info(bp, &fw_info); + clk_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq; + if (clk_dce->dentist_vco_freq_khz == 0) + clk_dce->dentist_vco_freq_khz = 3600000; + } + + if (!debug->disable_dfs_bypass && bp->integrated_info) + if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) + clk_dce->dfs_bypass_enabled = true; + + dce_clock_read_ss_info(clk_dce); return &clk_dce->base; } +#endif -void dce_disp_clk_destroy(struct display_clock **disp_clk) +void dce_dccg_destroy(struct dccg **dccg) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(*dccg); kfree(clk_dce); - *disp_clk = NULL; + *dccg = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 0e717e0dc8f0..7ce0a54e548f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -33,6 +33,9 @@ .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL +#define CLK_COMMON_REG_LIST_DCN_BASE() \ + SR(DENTIST_DISPCLK_CNTL) + #define CLK_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -40,58 +43,41 @@ CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) +#define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) + #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ - type DENTIST_DPREFCLK_WDIVIDER; + type DENTIST_DPREFCLK_WDIVIDER; \ + type DENTIST_DISPCLK_WDIVIDER; \ + type DENTIST_DPPCLK_WDIVIDER; \ + type DENTIST_DISPCLK_CHG_DONE; \ + type DENTIST_DPPCLK_CHG_DONE; -struct dce_disp_clk_shift { +struct dccg_shift { CLK_REG_FIELD_LIST(uint8_t) }; -struct dce_disp_clk_mask { +struct dccg_mask { CLK_REG_FIELD_LIST(uint32_t) }; -struct dce_disp_clk_registers { +struct dccg_registers { uint32_t DPREFCLK_CNTL; uint32_t DENTIST_DISPCLK_CNTL; }; -/* Array identifiers and count for the divider ranges.*/ -enum dce_divider_range_count { - DIVIDER_RANGE_01 = 0, - DIVIDER_RANGE_02, - DIVIDER_RANGE_03, - DIVIDER_RANGE_MAX /* == 3*/ -}; - -enum dce_divider_error_types { - INVALID_DID = 0, - INVALID_DIVIDER = 1 -}; - -struct dce_divider_range { - int div_range_start; - /* The end of this range of dividers.*/ - int div_range_end; - /* The distance between each divider in this range.*/ - int div_range_step; - /* The divider id for the lowest divider.*/ - int did_min; - /* The divider id for the highest divider.*/ - int did_max; -}; - -struct dce_disp_clk { - struct display_clock base; - const struct dce_disp_clk_registers *regs; - const struct dce_disp_clk_shift *clk_shift; - const struct dce_disp_clk_mask *clk_mask; +struct dce_dccg { + struct dccg base; + const struct dccg_registers *regs; + const struct dccg_shift *clk_shift; + const struct dccg_mask *clk_mask; struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; - struct dce_divider_range divider_ranges[DIVIDER_RANGE_MAX]; - bool use_max_disp_clk; int dentist_vco_freq_khz; /* Cache the status of DFS-bypass feature*/ @@ -106,32 +92,33 @@ struct dce_disp_clk { int dprefclk_ss_percentage; /* DPREFCLK SS percentage Divider (100 or 1000) */ int dprefclk_ss_divider; - - /* max disp_clk from PPLIB for max validation display clock*/ - int max_displ_clk_in_khz; }; -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); + +struct dccg *dce120_dccg_create(struct dc_context *ctx); -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx); +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +struct dccg *dcn1_dccg_create(struct dc_context *ctx); +#endif -void dce_disp_clk_destroy(struct display_clock **disp_clk); +void dce_dccg_destroy(struct dccg **dccg); #endif /* _DCE_CLOCKS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 057b8afd74bc..057407892618 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -249,7 +249,6 @@ struct dce_hwseq_registers { uint32_t DISPCLK_FREQ_CHANGE_CNTL; uint32_t RBBMIF_TIMEOUT_DIS; uint32_t RBBMIF_TIMEOUT_DIS_2; - uint32_t DENTIST_DISPCLK_CNTL; uint32_t DCHUBBUB_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_VAL_R_G; @@ -496,8 +495,6 @@ struct dce_hwseq_registers { type DOMAIN7_PGFSM_PWR_STATUS; \ type DCFCLK_GATE_DIS; \ type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ - type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_WDIVIDER; \ type VGA_TEST_ENABLE; \ type VGA_TEST_RENDER_START; \ type D1VGA_MODE_ENABLE; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index 41f83ecd7469..ec3221333011 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -125,17 +125,54 @@ static void dce100_pplib_apply_display_requirements( dc->prev_display_config = *pp_display_cfg; } +/* unit: in_khz before mode set, get pixel clock from context. ASIC register + * may not be programmed yet + */ +static uint32_t get_max_pixel_clock_for_all_paths( + struct dc *dc, + struct dc_state *context) +{ + uint32_t max_pix_clk = 0; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + /* do not check under lay */ + if (pipe_ctx->top_pipe) + continue; + + if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk) + max_pix_clk = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + } + + if (max_pix_clk == 0) + ASSERT(0); + + return max_pix_clk; +} + void dce100_set_bandwidth( struct dc *dc, struct dc_state *context, bool decrease_allowed) { - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + struct dc_clocks req_clks; + + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &req_clks, + decrease_allowed); + dce100_pplib_apply_display_requirements(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 38ec0d609297..8ed8eace42be 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -135,15 +135,15 @@ static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -644,8 +644,8 @@ static void destruct(struct dce110_resource_pool *pool) dce_aud_destroy(&pool->base.audios[i]); } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.abm != NULL) dce_abm_destroy(&pool->base.abm); @@ -817,11 +817,11 @@ static bool construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -851,7 +851,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { struct irq_service_init_data init_data; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index df027013e50c..1f7f25013217 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -143,7 +143,7 @@ static void wait_for_fbc_state_changed( struct dce110_compressor *cp110, bool enabled) { - uint16_t counter = 0; + uint32_t counter = 0; uint32_t addr = mmFBC_STATUS; uint32_t value; @@ -158,7 +158,7 @@ static void wait_for_fbc_state_changed( counter++; } - if (counter == 10) { + if (counter == 1000) { DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", __func__); } else { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 353ffcbdf5ba..9cbd5036db07 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1475,7 +1475,7 @@ static void power_down_controllers(struct dc *dc) { int i; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { dc->res_pool->timing_generators[i]->funcs->disable_crtc( dc->res_pool->timing_generators[i]); } @@ -1515,12 +1515,13 @@ static void disable_vga_and_power_gate_all_controllers( struct timing_generator *tg; struct dc_context *ctx = dc->ctx; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { tg = dc->res_pool->timing_generators[i]; if (tg->funcs->disable_vga) tg->funcs->disable_vga(tg); - + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { /* Enable CLOCK gating for each pipe BEFORE controller * powergating. */ enable_display_pipe_clock_gating(ctx, @@ -1663,7 +1664,7 @@ static void dce110_set_displaymarks( } } -static void set_safe_displaymarks( +void dce110_set_safe_displaymarks( struct resource_context *res_ctx, const struct resource_pool *pool) { @@ -1755,23 +1756,15 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, } /* unit: in_khz before mode set, get pixel clock from context. ASIC register - * may not be programmed yet. - * TODO: after mode set, pre_mode_set = false, - * may read PLL register to get pixel clock + * may not be programmed yet */ static uint32_t get_max_pixel_clock_for_all_paths( struct dc *dc, - struct dc_state *context, - bool pre_mode_set) + struct dc_state *context) { uint32_t max_pix_clk = 0; int i; - if (!pre_mode_set) { - /* TODO: read ASIC register to get pixel clock */ - ASSERT(0); - } - for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1787,95 +1780,10 @@ static uint32_t get_max_pixel_clock_for_all_paths( pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; } - if (max_pix_clk == 0) - ASSERT(0); - return max_pix_clk; } /* - * Find clock state based on clock requested. if clock value is 0, simply - * set clock state as requested without finding clock state by clock value - */ - -static void apply_min_clocks( - struct dc *dc, - struct dc_state *context, - enum dm_pp_clocks_state *clocks_state, - bool pre_mode_set) -{ - struct state_dependent_clocks req_clocks = {0}; - - if (!pre_mode_set) { - /* set clock_state without verification */ - if (context->dis_clk->funcs->set_min_clocks_state) { - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - return; - } - - /* TODO: This is incorrect. Figure out how to fix. */ - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - context->dis_clk->cur_clocks_value.dispclk_in_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - context->dis_clk->cur_clocks_value.max_pixelclk_in_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - context->dis_clk->cur_clocks_value.max_non_dp_phyclk_in_khz, - pre_mode_set, - false); - return; - } - - /* get the required state based on state dependent clocks: - * display clock and pixel clock - */ - req_clocks.display_clk_khz = context->bw.dce.dispclk_khz; - - req_clocks.pixel_clk_khz = get_max_pixel_clock_for_all_paths( - dc, context, true); - - if (context->dis_clk->funcs->get_required_clocks_state) { - *clocks_state = context->dis_clk->funcs->get_required_clocks_state( - context->dis_clk, &req_clocks); - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - } else { - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - req_clocks.display_clk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - } -} - -/* * Check if FBC can be enabled */ static bool should_enable_fbc(struct dc *dc, @@ -2093,7 +2001,6 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc_bios *dcb = dc->ctx->dc_bios; enum dc_status status; int i; - enum dm_pp_clocks_state clocks_state = DM_PP_CLOCKS_STATE_INVALID; /* Reset old context */ /* look up the targets that have been removed since last commit */ @@ -2127,55 +2034,9 @@ enum dc_status dce110_apply_ctx_to_hw( PIPE_GATING_CONTROL_DISABLE); } - set_safe_displaymarks(&context->res_ctx, dc->res_pool); - if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - /*TODO: when pplib works*/ - apply_min_clocks(dc, context, &clocks_state, true); - -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (dc->ctx->dce_version >= DCN_VERSION_1_0) { - if (context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_FCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - dc->current_state->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - } else -#endif - if (context->bw.dce.dispclk_khz - > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - } - dce110_setup_audio_dto(dc, context); for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -2204,9 +2065,6 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - /* to save power */ - apply_min_clocks(dc, context, &clocks_state, false); - dcb->funcs->set_scratch_critical_state(dcb, false); if (dc->fbc_compressor) @@ -2694,15 +2552,20 @@ static void dce110_set_bandwidth( struct dc_state *context, bool decrease_allowed) { - dce110_set_displaymarks(dc, context); + struct dc_clocks req_clks; - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + if (decrease_allowed) + dce110_set_displaymarks(dc, context); + else + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &req_clks, + decrease_allowed); pplib_apply_display_requirements(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index f48d5a68d238..d6db3dbd9015 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -60,6 +60,10 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); void dce110_power_down(struct dc *dc); +void dce110_set_safe_displaymarks( + struct resource_context *res_ctx, + const struct resource_pool *pool); + void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 20c029089551..3edaa006bd57 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { #define SRI(reg_name, block, id)\ .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -679,8 +679,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1179,11 +1179,11 @@ static bool construct( } } - pool->base.display_clock = dce110_disp_clk_create(ctx, + pool->base.dccg = dce110_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1213,7 +1213,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 00c0a1ef15eb..9e1afb11e6ad 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -668,8 +668,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1000,7 +1000,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1010,7 +1010,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1020,7 +1020,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -1030,7 +1030,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; @@ -1124,11 +1124,11 @@ static bool construct( } } - pool->base.display_clock = dce112_disp_clk_create(ctx, + pool->base.dccg = dce112_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1158,7 +1158,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 2d58daccc005..8381f27a2361 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -494,8 +494,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); } static void read_dce_straps( @@ -775,7 +775,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -785,7 +785,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -795,7 +795,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -805,7 +805,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; @@ -894,11 +894,11 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dce120_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); - goto disp_clk_create_fail; + goto dccg_create_fail; } pool->base.dmcu = dce_dmcu_create(ctx, @@ -1011,7 +1011,7 @@ static bool construct( irqs_create_fail: controller_create_fail: -disp_clk_create_fail: +dccg_create_fail: clk_src_create_fail: res_create_fail: diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 48a068964722..2ac95ec2bf96 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -153,15 +153,15 @@ static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -683,8 +683,8 @@ static void destruct(struct dce110_resource_pool *pool) } } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -822,11 +822,11 @@ static bool dce80_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -852,7 +852,7 @@ static bool dce80_construct( goto res_create_fail; } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1006,11 +1006,11 @@ static bool dce81_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1037,7 +1037,7 @@ static bool dce81_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1187,11 +1187,11 @@ static bool dce83_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1218,7 +1218,7 @@ static bool dce83_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index c69fa4bfab0a..742fd497ed00 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -145,10 +145,10 @@ static bool dpp_get_optimal_number_of_taps( pixel_width = scl_data->viewport.width; /* Some ASICs does not support FP16 scaling, so we reject modes require this*/ - if (scl_data->viewport.width != scl_data->h_active && - scl_data->viewport.height != scl_data->v_active && + if (scl_data->format == PIXEL_FORMAT_FP16 && dpp->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT && - scl_data->format == PIXEL_FORMAT_FP16) + scl_data->ratios.horz.value != dc_fixpt_one.value && + scl_data->ratios.vert.value != dc_fixpt_one.value) return false; if (scl_data->viewport.width > scl_data->h_active && diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 943143efbb82..1ea91e153d3a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -190,10 +190,17 @@ static uint32_t convert_and_clamp( } +void hubbub1_wm_change_req_wa(struct hubbub *hubbub) +{ + REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1); +} + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz) + unsigned int refclk_mhz, + bool safe_to_lower) { uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0; /* @@ -202,191 +209,259 @@ void hubbub1_program_watermarks( */ uint32_t prog_wm_value; - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0); /* Repeat for water mark set A, B, C and D. */ /* clock state A */ - prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) { + hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.pte_meta_urgent_ns, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) { + hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->a.pte_meta_urgent_ns, prog_wm_value); + } + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_exit_ns, + watermarks->a.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); - - /* clock state B */ - prog_wm_value = convert_and_clamp( - watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->b.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) { + hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) { + hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_B calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->b.pte_meta_urgent_ns, prog_wm_value); + } + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_exit_ns, + watermarks->b.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state C */ - prog_wm_value = convert_and_clamp( - watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->c.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) { + hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) { + hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_C calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->c.pte_meta_urgent_ns, prog_wm_value); + } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_exit_ns, + watermarks->c.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state D */ - prog_wm_value = convert_and_clamp( - watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.urgent_ns, prog_wm_value); - - prog_wm_value = convert_and_clamp( - watermarks->d.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.pte_meta_urgent_ns, prog_wm_value); - - - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) { + hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + } - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_exit_ns, + if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) { + hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + watermarks->d.pte_meta_urgent_ns, prog_wm_value); } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); + if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns + > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.d.cstate_pstate.pstate_change_ns = + watermarks->d.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + } REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); @@ -408,6 +483,11 @@ void hubbub1_update_dchub( struct hubbub *hubbub, struct dchub_init_data *dh_data) { + if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { + ASSERT(false); + /*should not come here*/ + return; + } /* TODO: port code from dal2 */ switch (dh_data->fb_mode) { case FRAME_BUFFER_MODE_ZFB_ONLY: diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 6315a0e6b0d6..d6e596eef4c5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -185,6 +185,7 @@ struct hubbub { const struct dcn_hubbub_shift *shifts; const struct dcn_hubbub_mask *masks; unsigned int debug_test_index_pstate; + struct dcn_watermark_set watermarks; }; void hubbub1_update_dchub( @@ -194,10 +195,13 @@ void hubbub1_update_dchub( bool hubbub1_verify_allow_pstate_change_high( struct hubbub *hubbub); +void hubbub1_wm_change_req_wa(struct hubbub *hubbub); + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz); + unsigned int refclk_mhz, + bool safe_to_lower); void hubbub1_toggle_watermark_change_req( struct hubbub *hubbub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index c28085be39ff..93f52c58bc69 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -166,7 +166,7 @@ void hubp1_program_size_and_rotation( /* Program data and meta surface pitch (calculation from addrlib) * 444 or 420 luma */ - if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) { ASSERT(plane_size->video.chroma_pitch != 0); /* Chroma pitch zero can cause system hang! */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 03eb736a312f..3b2cb2d3b8a6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -337,13 +337,13 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", - dc->current_state->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.calc_clk.dppclk_khz, - dc->current_state->bw.dcn.calc_clk.max_supported_dppclk_khz, - dc->current_state->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.calc_clk.socclk_khz); + dc->current_state->bw.dcn.clk.dcfclk_khz, + dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.clk.dispclk_khz, + dc->current_state->bw.dcn.clk.dppclk_khz, + dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, + dc->current_state->bw.dcn.clk.fclk_khz, + dc->current_state->bw.dcn.clk.socclk_khz); log_mpc_crc(dc); @@ -415,6 +415,8 @@ static void dpp_pg_control( if (hws->ctx->dc->debug.disable_dpp_power_gate) return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; switch (dpp_inst) { case 0: /* DPP0 */ @@ -465,6 +467,8 @@ static void hubp_pg_control( if (hws->ctx->dc->debug.disable_hubp_power_gate) return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; switch (hubp_inst) { case 0: /* DCHUBP0 */ @@ -865,7 +869,8 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) return; mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + if (opp != NULL) + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -1010,7 +1015,7 @@ static void dcn10_init_hw(struct dc *dc) /* Reset all MPCC muxes */ dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; @@ -1343,10 +1348,11 @@ static void dcn10_enable_per_frame_crtc_position_reset( DC_SYNC_INFO("Setting up\n"); for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( - grouped_pipes[i]->stream_res.tg, - grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, - &grouped_pipes[i]->stream->triggered_crtc_reset); + if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) + grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( + grouped_pipes[i]->stream_res.tg, + grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, + &grouped_pipes[i]->stream->triggered_crtc_reset); DC_SYNC_INFO("Waiting for trigger\n"); @@ -1952,18 +1958,17 @@ static void update_dchubp_dpp( * divided by 2 */ if (plane_state->update_flags.bits.full_update) { - bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= - context->bw.dcn.cur_clk.dispclk_khz / 2; + bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <= + dc->res_pool->dccg->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, should_divided_by_2, true); - dc->current_state->bw.dcn.cur_clk.dppclk_khz = - should_divided_by_2 ? - context->bw.dcn.cur_clk.dispclk_khz / 2 : - context->bw.dcn.cur_clk.dispclk_khz; + dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ? + dc->res_pool->dccg->clks.dispclk_khz / 2 : + dc->res_pool->dccg->clks.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -2153,12 +2158,12 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; - pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; - pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; - pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; + pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz; + pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz; + pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; + pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( @@ -2220,8 +2225,6 @@ static void dcn10_apply_ctx_for_surface( int i; struct timing_generator *tg; bool removed_pipe[4] = { false }; - unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; - bool program_water_mark = false; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); DC_LOGGER_INIT(dc->ctx->logger); @@ -2269,8 +2272,7 @@ static void dcn10_apply_ctx_for_surface( hwss1_plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - DC_LOG_DC( - "Reset mpcc for pipe %d\n", + DC_LOG_DC("Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } } @@ -2283,248 +2285,41 @@ static void dcn10_apply_ctx_for_surface( if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *old_pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == stream && - pipe_ctx->plane_state && - pipe_ctx->plane_state->update_flags.bits.full_update) - program_water_mark = true; - + for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) - dcn10_disable_plane(dc, old_pipe_ctx); - } - - if (program_water_mark) { - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } + dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - /* watermark is for all pipes */ - hubbub1_program_watermarks(dc->res_pool->hubbub, - &context->bw.dcn.watermarks, ref_clk_mhz); - - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } - } -/* DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\n============== Watermark parameters ==============\n" - "a.urgent_ns: %d \n" - "a.cstate_enter_plus_exit: %d \n" - "a.cstate_exit: %d \n" - "a.pstate_change: %d \n" - "a.pte_meta_urgent: %d \n" - "b.urgent_ns: %d \n" - "b.cstate_enter_plus_exit: %d \n" - "b.cstate_exit: %d \n" - "b.pstate_change: %d \n" - "b.pte_meta_urgent: %d \n", - context->bw.dcn.watermarks.a.urgent_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.a.pte_meta_urgent_ns, - context->bw.dcn.watermarks.b.urgent_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.b.pte_meta_urgent_ns - ); - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\nc.urgent_ns: %d \n" - "c.cstate_enter_plus_exit: %d \n" - "c.cstate_exit: %d \n" - "c.pstate_change: %d \n" - "c.pte_meta_urgent: %d \n" - "d.urgent_ns: %d \n" - "d.cstate_enter_plus_exit: %d \n" - "d.cstate_exit: %d \n" - "d.pstate_change: %d \n" - "d.pte_meta_urgent: %d \n" - "========================================================\n", - context->bw.dcn.watermarks.c.urgent_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.c.pte_meta_urgent_ns, - context->bw.dcn.watermarks.d.urgent_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.d.pte_meta_urgent_ns - ); -*/ -} - -static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) -{ - return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); -} - -static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) -{ - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; - bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.cur_clk.dispclk_khz; - int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; - bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > - context->bw.dcn.cur_clk.dppclk_khz; - - /* increase clock, looking for div is 0 for current, request div is 1*/ - if (dispclk_increase) { - /* already divided by 2, no need to reach target clk with 2 steps*/ - if (cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* request disp clk is lower than maximum supported dpp clk, - * no need to reach target clk with two steps. - */ - if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* target dpp clk not request divided by 2, still within threshold */ - if (!request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - } else { - /* decrease clock, looking for current dppclk divided by 2, - * request dppclk not divided by 2. - */ - - /* current dpp clk not divided by 2, no need to ramp*/ - if (!cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* current disp clk is lower than current maximum dpp clk, - * no need to ramp - */ - if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* request dpp clk need to be divided by 2 */ - if (request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - } - - return disp_clk_threshold; -} - -static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) -{ - int i; - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; - - int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); - - /* set disp clk to dpp clk threshold */ - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - dispclk_to_dpp_threshold); - - /* update request dpp clk division option */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->plane_state) - continue; - - pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( - pipe_ctx->plane_res.dpp, - request_dpp_div, - true); - } - - /* If target clk not same as dppclk threshold, set to target clock */ - if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - } - - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dppclk_khz = - context->bw.dcn.calc_clk.dppclk_khz; - context->bw.dcn.cur_clk.max_supported_dppclk_khz = - context->bw.dcn.calc_clk.max_supported_dppclk_khz; + if (dc->hwseq->wa.DEGVIDCN10_254) + hubbub1_wm_change_req_wa(dc->res_pool->hubbub); } static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, - bool decrease_allowed) + bool safe_to_lower) { - struct pp_smu_display_requirement_rv *smu_req_cur = - &dc->res_pool->pp_smu_req; - struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; - struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; - - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - return; - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { - context->bw.dcn.cur_clk.dcfclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - smu_req.hard_min_dcefclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { - context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.cur_clk.fclk_khz)) { - context->bw.dcn.cur_clk.fclk_khz = - context->bw.dcn.calc_clk.fclk_khz; - smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; - } - - smu_req.display_count = context->stream_count; - - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); - *smu_req_cur = smu_req; + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (context->stream_count == 0) + context->bw.dcn.clk.phyclk_khz = 0; - /* make sure dcf clk is before dpp clk to - * make sure we have enough voltage to run dpp clk - */ - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &context->bw.dcn.clk, + safe_to_lower); - ramp_up_dispclk_with_dpp(dc, context); + dcn10_pplib_apply_display_requirements(dc, context); } - dcn10_pplib_apply_display_requirements(dc, context); + hubbub1_program_watermarks(dc->res_pool->hubbub, + &context->bw.dcn.watermarks, + dc->res_pool->ref_clock_inKhz / 1000, + true); - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } - - /* need to fix this function. not doing the right thing here */ } static void set_drr(struct pipe_ctx **pipe_ctx, @@ -2707,8 +2502,14 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { - if (hws->ctx->dc->res_pool->hubbub != NULL) - hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + if (hws->ctx->dc->res_pool->hubbub != NULL) { + struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; + + if (hubp->funcs->hubp_update_dchub) + hubp->funcs->hubp_update_dchub(hubp, dh_data); + else + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } } static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 21fa40ac0786..fd9dc70190a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -995,6 +995,8 @@ void dcn10_link_encoder_disable_output( if (!dcn10_is_dig_enabled(enc)) { /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */ + /*in DP_Alt_No_Connect case, we turn off the dig already, + after excuation the PHY w/a sequence, not allow touch PHY any more*/ return; } /* Power-down RX and disable GPU PHY should be paired. diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 2da325ce781b..771e0cf29bba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -65,6 +65,68 @@ #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +const struct _vcs_dpi_ip_params_st dcn1_0_ip = { + .rob_buffer_size_kbytes = 64, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs = 42, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_enable = 1, + .pte_chunk_size_kbytes = 2, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 2, + .line_buffer_size_bits = 589824, + .max_line_buffer_lines = 12, + .IsLineBufferBppFixed = 0, + .LineBufferFixedBpp = -1, + .writeback_luma_buffer_size_kbytes = 12, + .writeback_chroma_buffer_size_kbytes = 8, + .max_num_dpp = 4, + .max_num_wb = 2, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 4, + .max_vscl_ratio = 4, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.10, + .min_vblank_lines = 14, + .dppclk_delay_subtotal = 90, + .dispclk_delay_subtotal = 42, + .dcfclk_cstate_latency = 10, + .max_inter_dcn_tile_repeaters = 8, + .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, + .bug_forcing_LC_req_same_size_fixed = 0, +}; + +const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 80.0, + .max_request_size_bytes = 256, + .downspread_percent = 0.5, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 128, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 2, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 17.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, +}; + #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 @@ -437,7 +499,7 @@ static const struct dc_debug debug_defaults_drv = { */ .min_disp_clk_khz = 100000, - .disable_pplib_clock_request = true, + .disable_pplib_clock_request = false, .disable_pplib_wm_range = false, .pplib_wm_report_mode = WM_REPORT_DEFAULT, .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, @@ -681,6 +743,7 @@ static struct dce_hwseq *dcn10_hwseq_create( hws->masks = &hwseq_mask; hws->wa.DEGVIDCN10_253 = true; hws->wa.false_optc_underflow = true; + hws->wa.DEGVIDCN10_254 = true; } return hws; } @@ -791,8 +854,8 @@ static void destruct(struct dcn10_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); kfree(pool->base.pp_smu); } @@ -1005,8 +1068,7 @@ static bool construct( ctx->dc_bios->regs = &bios_regs; - pool->base.res_cap = &res_cap; - + pool->base.res_cap = &res_cap; pool->base.funcs = &dcn10_res_pool_funcs; /* @@ -1072,8 +1134,8 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dcn1_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index eac4bfe12257..58ed2055ef9f 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -40,7 +40,7 @@ enum wm_set_id { WM_B, WM_C, WM_D, - WM_COUNT, + WM_SET_COUNT, }; struct pp_smu_wm_set_range { @@ -53,10 +53,10 @@ struct pp_smu_wm_set_range { struct pp_smu_wm_range_sets { uint32_t num_reader_wm_sets; - struct pp_smu_wm_set_range reader_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range reader_wm_sets[WM_SET_COUNT]; uint32_t num_writer_wm_sets; - struct pp_smu_wm_set_range writer_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range writer_wm_sets[WM_SET_COUNT]; }; struct pp_smu_display_requirement_rv { diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index ab8c77d4e6df..2b83f922ac02 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -137,7 +137,7 @@ struct dm_pp_clock_range_for_wm_set { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_eng_clk_in_khz; uint32_t wm_max_eng_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -150,7 +150,7 @@ struct dm_pp_clock_range_for_dmif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_dcfclk_clk_in_khz; uint32_t wm_max_dcfclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -158,7 +158,7 @@ struct dm_pp_clock_range_for_mcif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_socclk_clk_in_khz; uint32_t wm_max_socclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index f83a608f93e9..d97ca6528f9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -36,11 +36,10 @@ CFLAGS_display_mode_lib.o := $(dml_ccflags) CFLAGS_display_pipe_clocks.o := $(dml_ccflags) CFLAGS_dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_display_rq_dlg_helpers.o := $(dml_ccflags) -CFLAGS_soc_bounding_box.o := $(dml_ccflags) CFLAGS_dml_common_defs.o := $(dml_ccflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ - soc_bounding_box.o dml_common_defs.o + dml_common_defs.o AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index fd9d97aab071..dddeb0d4db8f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -26,67 +26,8 @@ #include "display_mode_lib.h" #include "dc_features.h" -static const struct _vcs_dpi_ip_params_st dcn1_0_ip = { - .rob_buffer_size_kbytes = 64, - .det_buffer_size_kbytes = 164, - .dpte_buffer_size_in_pte_reqs = 42, - .dpp_output_buffer_pixels = 2560, - .opp_output_buffer_lines = 1, - .pixel_chunk_size_kbytes = 8, - .pte_enable = 1, - .pte_chunk_size_kbytes = 2, - .meta_chunk_size_kbytes = 2, - .writeback_chunk_size_kbytes = 2, - .line_buffer_size_bits = 589824, - .max_line_buffer_lines = 12, - .IsLineBufferBppFixed = 0, - .LineBufferFixedBpp = -1, - .writeback_luma_buffer_size_kbytes = 12, - .writeback_chroma_buffer_size_kbytes = 8, - .max_num_dpp = 4, - .max_num_wb = 2, - .max_dchub_pscl_bw_pix_per_clk = 4, - .max_pscl_lb_bw_pix_per_clk = 2, - .max_lb_vscl_bw_pix_per_clk = 4, - .max_vscl_hscl_bw_pix_per_clk = 4, - .max_hscl_ratio = 4, - .max_vscl_ratio = 4, - .hscl_mults = 4, - .vscl_mults = 4, - .max_hscl_taps = 8, - .max_vscl_taps = 8, - .dispclk_ramp_margin_percent = 1, - .underscan_factor = 1.10, - .min_vblank_lines = 14, - .dppclk_delay_subtotal = 90, - .dispclk_delay_subtotal = 42, - .dcfclk_cstate_latency = 10, - .max_inter_dcn_tile_repeaters = 8, - .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, - .bug_forcing_LC_req_same_size_fixed = 0, -}; - -static const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .urgent_latency_us = 4.0, - .writeback_latency_us = 12.0, - .ideal_dram_bw_after_urgent_percent = 80.0, - .max_request_size_bytes = 256, - .downspread_percent = 0.5, - .dram_page_open_time_ns = 50.0, - .dram_rw_turnaround_time_ns = 17.5, - .dram_return_buffer_per_channel_bytes = 8192, - .round_trip_ping_latency_dcfclk_cycles = 128, - .urgent_out_of_order_return_per_channel_bytes = 256, - .channel_interleave_bytes = 256, - .num_banks = 8, - .num_chans = 2, - .vmm_page_size_bytes = 4096, - .dram_clock_change_latency_us = 17.0, - .writeback_dram_clock_change_latency_us = 23.0, - .return_bus_width_bytes = 64, -}; +extern const struct _vcs_dpi_ip_params_st dcn1_0_ip; +extern const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc; static void set_soc_bounding_box(struct _vcs_dpi_soc_bounding_box_st *soc, enum dml_project project) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 3c2abcb8a1b0..635206248889 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -27,7 +27,6 @@ #include "dml_common_defs.h" -#include "soc_bounding_box.h" #include "dml1_display_rq_dlg_calc.h" enum dml_project { diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 7fa0375939ae..6943801c5fd3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -64,10 +64,9 @@ struct _vcs_dpi_voltage_scaling_st { double dscclk_mhz; double dcfclk_mhz; double socclk_mhz; - double dram_speed_mhz; + double dram_speed_mts; double fabricclk_mhz; double dispclk_mhz; - double dram_bw_per_chan_gbps; double phyclk_mhz; double dppclk_mhz; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c b/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c deleted file mode 100644 index 324239c77958..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "soc_bounding_box.h" -#include "display_mode_lib.h" -#include "dc_features.h" - -#include "dml_inline_defs.h" - -/* - * NOTE: - * This file is gcc-parseable HW gospel, coming straight from HW engineers. - * - * It doesn't adhere to Linux kernel style and sometimes will do things in odd - * ways. Unless there is something clearly wrong with it the code should - * remain as-is as it provides us with a guarantee from HW that it is correct. - */ - -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box) -{ - to_box->dram_clock_change_latency_us = from_box->dram_clock_change_latency_us; - to_box->sr_exit_time_us = from_box->sr_exit_time_us; - to_box->sr_enter_plus_exit_time_us = from_box->sr_enter_plus_exit_time_us; - to_box->urgent_latency_us = from_box->urgent_latency_us; - to_box->writeback_latency_us = from_box->writeback_latency_us; -} - -voltage_scaling_st dml_socbb_voltage_scaling( - const soc_bounding_box_st *soc, - enum voltage_state voltage) -{ - const voltage_scaling_st *voltage_state; - const voltage_scaling_st * const voltage_end = soc->clock_limits + DC__VOLTAGE_STATES; - - for (voltage_state = soc->clock_limits; - voltage_state < voltage_end && voltage_state->state != voltage; - voltage_state++) { - } - - if (voltage_state < voltage_end) - return *voltage_state; - return soc->clock_limits[DC__VOLTAGE_STATES - 1]; -} - -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage) -{ - double return_bw; - - voltage_scaling_st state = dml_socbb_voltage_scaling(box, voltage); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.dcfclk_mhz, - state.dram_bw_per_chan_gbps * 1000.0 * (double) box->num_chans - * box->ideal_dram_bw_after_urgent_percent / 100.0); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.fabricclk_mhz, return_bw); - - return return_bw; -} diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 4beddca0180c..00d728e629fa 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -163,7 +163,7 @@ struct resource_pool { unsigned int audio_count; struct audio_support audio_support; - struct display_clock *display_clock; + struct dccg *dccg; struct irq_service *irqs; struct abm *abm; @@ -256,8 +256,7 @@ struct dce_bw_output { }; struct dcn_bw_output { - struct dc_clocks cur_clk; - struct dc_clocks calc_clk; + struct dc_clocks clk; struct dcn_watermark_set watermarks; }; @@ -282,7 +281,7 @@ struct dc_state { struct dcn_bw_internal_vars dcn_bw_vars; #endif - struct display_clock *dis_clk; + struct dccg *dis_clk; struct kref refcount; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h index 132d18d4b293..ddbb673caa08 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h @@ -625,7 +625,7 @@ bool dcn_validate_bandwidth( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks); + struct dc_clocks *clocks); void dcn_bw_update_from_pplib(struct dc *dc); void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h index f5f69cd81f6f..3c7ccb68ecdb 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h @@ -27,23 +27,7 @@ #define __DISPLAY_CLOCK_H__ #include "dm_services_types.h" - - -struct clocks_value { - int dispclk_in_khz; - int max_pixelclk_in_khz; - int max_non_dp_phyclk_in_khz; - int max_dp_phyclk_in_khz; - bool dispclk_notify_pplib_done; - bool pixelclk_notify_pplib_done; - bool phyclk_notigy_pplib_done; - int dcfclock_in_khz; - int dppclk_in_khz; - int mclk_in_khz; - int phyclk_in_khz; - int common_vdd_level; -}; - +#include "dc.h" /* Structure containing all state-dependent clocks * (dependent on "enum clocks_state") */ @@ -52,34 +36,23 @@ struct state_dependent_clocks { int pixel_clk_khz; }; -struct display_clock { +struct dccg { struct dc_context *ctx; const struct display_clock_funcs *funcs; enum dm_pp_clocks_state max_clks_state; enum dm_pp_clocks_state cur_min_clks_state; - struct clocks_value cur_clocks_value; + struct dc_clocks clks; }; struct display_clock_funcs { - int (*set_clock)(struct display_clock *disp_clk, + void (*update_clocks)(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower); + int (*set_dispclk)(struct dccg *dccg, int requested_clock_khz); - enum dm_pp_clocks_state (*get_required_clocks_state)( - struct display_clock *disp_clk, - struct state_dependent_clocks *req_clocks); - - bool (*set_min_clocks_state)(struct display_clock *disp_clk, - enum dm_pp_clocks_state dm_pp_clocks_state); - - int (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk); - - bool (*apply_clock_voltage_request)( - struct display_clock *disp_clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk); + int (*get_dp_ref_clk_frequency)(struct dccg *dccg); }; #endif /* __DISPLAY_CLOCK_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index a71770ed4b9f..2506601120af 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -44,6 +44,7 @@ struct dce_hwseq_wa { bool blnd_crtc_trigger; bool DEGVIDCN10_253; bool false_optc_underflow; + bool DEGVIDCN10_254; }; struct hwseq_wa_state { @@ -171,7 +172,7 @@ struct hw_sequencer_funcs { void (*set_bandwidth)( struct dc *dc, struct dc_state *context, - bool decrease_allowed); + bool safe_to_lower); void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, int vmin, int vmax); diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index dcdfa0f01551..604bea01fc13 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -78,7 +78,7 @@ const struct irq_source_info *find_irq_source_info( struct irq_service *irq_service, enum dc_irq_source source) { - if (source > DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) + if (source >= DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) return NULL; return &irq_service->info[source]; diff --git a/drivers/gpu/drm/amd/display/include/grph_object_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_defs.h index 2941b882b0b6..58bb42ed85ca 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_defs.h @@ -37,6 +37,10 @@ * ******************************************************************** */ +#define MAX_CONNECTOR_NUMBER_PER_SLOT (16) +#define MAX_BOARD_SLOTS (4) +#define INVALID_CONNECTOR_INDEX ((unsigned int)(-1)) + /* HPD unit id - HW direct translation */ enum hpd_source_id { HPD_SOURCEID1 = 0, @@ -136,5 +140,47 @@ enum sync_source { SYNC_SOURCE_DUAL_GPU_PIN }; +/* connector sizes in millimeters - from BiosParserTypes.hpp */ +#define CONNECTOR_SIZE_DVI 40 +#define CONNECTOR_SIZE_VGA 32 +#define CONNECTOR_SIZE_HDMI 16 +#define CONNECTOR_SIZE_DP 16 +#define CONNECTOR_SIZE_MINI_DP 9 +#define CONNECTOR_SIZE_UNKNOWN 30 + +enum connector_layout_type { + CONNECTOR_LAYOUT_TYPE_UNKNOWN, + CONNECTOR_LAYOUT_TYPE_DVI_D, + CONNECTOR_LAYOUT_TYPE_DVI_I, + CONNECTOR_LAYOUT_TYPE_VGA, + CONNECTOR_LAYOUT_TYPE_HDMI, + CONNECTOR_LAYOUT_TYPE_DP, + CONNECTOR_LAYOUT_TYPE_MINI_DP, +}; +struct connector_layout_info { + struct graphics_object_id connector_id; + enum connector_layout_type connector_type; + unsigned int length; + unsigned int position; /* offset in mm from right side of the board */ +}; + +/* length and width in mm */ +struct slot_layout_info { + unsigned int length; + unsigned int width; + unsigned int num_of_connectors; + struct connector_layout_info connectors[MAX_CONNECTOR_NUMBER_PER_SLOT]; +}; + +struct board_layout_info { + unsigned int num_of_slots; + /* indicates valid information in bracket layout structure. */ + unsigned int is_number_of_slots_valid : 1; + unsigned int is_slots_size_valid : 1; + unsigned int is_connector_offsets_valid : 1; + unsigned int is_connector_lengths_valid : 1; + + struct slot_layout_info slots[MAX_BOARD_SLOTS]; +}; #endif diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h index c4197432eb7c..33b3d755fe65 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_id.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h @@ -197,6 +197,11 @@ enum transmitter_color_depth { TRANSMITTER_COLOR_DEPTH_48 /* 16 bits */ }; +enum dp_alt_mode { + DP_Alt_mode__Unknown = 0, + DP_Alt_mode__Connect, + DP_Alt_mode__NoConnect, +}; /* ***************************************************************************** * graphics_object_id struct @@ -287,4 +292,15 @@ static inline enum engine_id dal_graphics_object_id_get_engine_id( return (enum engine_id) id.id; return ENGINE_ID_UNKNOWN; } + +static inline bool dal_graphics_object_id_equal( + struct graphics_object_id id_1, + struct graphics_object_id id_2) +{ + if ((id_1.id == id_2.id) && (id_1.enum_id == id_2.enum_id) && + (id_1.type == id_2.type)) { + return true; + } + return false; +} #endif diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 98edaefa2b47..ee69c949bfbf 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1723,8 +1723,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1802,8 +1802,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_degamma), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; diff --git a/drivers/gpu/drm/amd/include/amd_pcie.h b/drivers/gpu/drm/amd/include/amd_pcie.h index 5eb895fd98bf..9cb9ceb4d74d 100644 --- a/drivers/gpu/drm/amd/include/amd_pcie.h +++ b/drivers/gpu/drm/amd/include/amd_pcie.h @@ -27,6 +27,7 @@ #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00010000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00020000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00040000 +#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4 0x00080000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK 0xFFFF0000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT 16 @@ -34,6 +35,7 @@ #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00000001 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00000002 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00000004 +#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4 0x00000008 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK 0x0000FFFF #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT 0 diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index b178176b72ac..265621d8945c 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -128,47 +128,57 @@ enum PP_FEATURE_MASK { PP_OVERDRIVE_MASK = 0x4000, PP_GFXOFF_MASK = 0x8000, PP_ACG_MASK = 0x10000, + PP_STUTTER_MODE = 0x20000, }; +/** + * struct amd_ip_funcs - general hooks for managing amdgpu IP Blocks + */ struct amd_ip_funcs { - /* Name of IP block */ + /** @name: Name of IP block */ char *name; - /* sets up early driver state (pre sw_init), does not configure hw - Optional */ + /** + * @early_init: + * + * sets up early driver state (pre sw_init), + * does not configure hw - Optional + */ int (*early_init)(void *handle); - /* sets up late driver/hw state (post hw_init) - Optional */ + /** @late_init: sets up late driver/hw state (post hw_init) - Optional */ int (*late_init)(void *handle); - /* sets up driver state, does not configure hw */ + /** @sw_init: sets up driver state, does not configure hw */ int (*sw_init)(void *handle); - /* tears down driver state, does not configure hw */ + /** @sw_fini: tears down driver state, does not configure hw */ int (*sw_fini)(void *handle); - /* sets up the hw state */ + /** @hw_init: sets up the hw state */ int (*hw_init)(void *handle); - /* tears down the hw state */ + /** @hw_fini: tears down the hw state */ int (*hw_fini)(void *handle); + /** @late_fini: final cleanup */ void (*late_fini)(void *handle); - /* handles IP specific hw/sw changes for suspend */ + /** @suspend: handles IP specific hw/sw changes for suspend */ int (*suspend)(void *handle); - /* handles IP specific hw/sw changes for resume */ + /** @resume: handles IP specific hw/sw changes for resume */ int (*resume)(void *handle); - /* returns current IP block idle status */ + /** @is_idle: returns current IP block idle status */ bool (*is_idle)(void *handle); - /* poll for idle */ + /** @wait_for_idle: poll for idle */ int (*wait_for_idle)(void *handle); - /* check soft reset the IP block */ + /** @check_soft_reset: check soft reset the IP block */ bool (*check_soft_reset)(void *handle); - /* pre soft reset the IP block */ + /** @pre_soft_reset: pre soft reset the IP block */ int (*pre_soft_reset)(void *handle); - /* soft reset the IP block */ + /** @soft_reset: soft reset the IP block */ int (*soft_reset)(void *handle); - /* post soft reset the IP block */ + /** @post_soft_reset: post soft reset the IP block */ int (*post_soft_reset)(void *handle); - /* enable/disable cg for the IP block */ + /** @set_clockgating_state: enable/disable cg for the IP block */ int (*set_clockgating_state)(void *handle, enum amd_clockgating_state state); - /* enable/disable pg for the IP block */ + /** @set_powergating_state: enable/disable pg for the IP block */ int (*set_powergating_state)(void *handle, enum amd_powergating_state state); - /* get current clockgating status */ + /** @get_clockgating_state: get current clockgating status */ void (*get_clockgating_state)(void *handle, u32 *flags); }; diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index 092d800b703a..33b4de4ad66e 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -1433,7 +1433,10 @@ struct atom_smc_dpm_info_v4_1 uint8_t acggfxclkspreadpercent; uint16_t acggfxclkspreadfreq; - uint32_t boardreserved[10]; + uint8_t Vr2_I2C_address; + uint8_t padding_vr2[3]; + + uint32_t boardreserved[9]; }; /* diff --git a/drivers/gpu/drm/amd/include/dm_pp_interface.h b/drivers/gpu/drm/amd/include/dm_pp_interface.h index 7852952d1fde..1d93a0c574c9 100644 --- a/drivers/gpu/drm/amd/include/dm_pp_interface.h +++ b/drivers/gpu/drm/amd/include/dm_pp_interface.h @@ -23,6 +23,8 @@ #ifndef _DM_PP_INTERFACE_ #define _DM_PP_INTERFACE_ +#include "dm_services_types.h" + #define PP_MAX_CLOCK_LEVELS 16 enum amd_pp_display_config_type{ @@ -189,39 +191,4 @@ struct pp_display_clock_request { uint32_t clock_freq_in_khz; }; -#define PP_MAX_WM_SETS 4 - -enum pp_wm_set_id { - DC_WM_SET_A = 0, - DC_WM_SET_B, - DC_WM_SET_C, - DC_WM_SET_D, - DC_WM_SET_INVALID = 0xffff, -}; - -struct pp_wm_set_with_dmif_clock_range_soc15 { - enum pp_wm_set_id wm_set_id; - uint32_t wm_min_dcefclk_in_khz; - uint32_t wm_max_dcefclk_in_khz; - uint32_t wm_min_memclk_in_khz; - uint32_t wm_max_memclk_in_khz; -}; - -struct pp_wm_set_with_mcif_clock_range_soc15 { - enum pp_wm_set_id wm_set_id; - uint32_t wm_min_socclk_in_khz; - uint32_t wm_max_socclk_in_khz; - uint32_t wm_min_memclk_in_khz; - uint32_t wm_max_memclk_in_khz; -}; - -struct pp_wm_sets_with_clock_ranges_soc15 { - uint32_t num_wm_sets_dmif; - uint32_t num_wm_sets_mcif; - struct pp_wm_set_with_dmif_clock_range_soc15 - wm_sets_dmif[PP_MAX_WM_SETS]; - struct pp_wm_set_with_mcif_clock_range_soc15 - wm_sets_mcif[PP_MAX_WM_SETS]; -}; - #endif /* _DM_PP_INTERFACE_ */ diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 06f08f34a110..6a41b81c7325 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -192,7 +192,6 @@ struct amd_pp_simple_clock_info; struct amd_pp_display_configuration; struct amd_pp_clock_info; struct pp_display_clock_request; -struct pp_wm_sets_with_clock_ranges_soc15; struct pp_clock_levels_with_voltage; struct pp_clock_levels_with_latency; struct amd_pp_clocks; @@ -232,16 +231,19 @@ struct amd_pm_funcs { void (*debugfs_print_current_performance_level)(void *handle, struct seq_file *m); int (*switch_power_profile)(void *handle, enum PP_SMC_POWER_PROFILE type, bool en); /* export to amdgpu */ - void (*powergate_uvd)(void *handle, bool gate); - void (*powergate_vce)(void *handle, bool gate); struct amd_vce_state *(*get_vce_clock_state)(void *handle, u32 idx); int (*dispatch_tasks)(void *handle, enum amd_pp_task task_id, enum amd_pm_state_type *user_state); int (*load_firmware)(void *handle); int (*wait_for_fw_loading_complete)(void *handle); + int (*set_powergating_by_smu)(void *handle, + uint32_t block_type, bool gate); int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id); int (*set_power_limit)(void *handle, uint32_t n); int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit); + int (*get_power_profile_mode)(void *handle, char *buf); + int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); + int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); /* export to DC */ u32 (*get_sclk)(void *handle, bool low); u32 (*get_mclk)(void *handle, bool low); @@ -261,15 +263,12 @@ struct amd_pm_funcs { enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); int (*set_watermarks_for_clocks_ranges)(void *handle, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + void *clock_ranges); int (*display_clock_voltage_request)(void *handle, struct pp_display_clock_request *clock); int (*get_display_mode_validation_clocks)(void *handle, struct amd_pp_simple_clock_info *clocks); - int (*get_power_profile_mode)(void *handle, char *buf); - int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); - int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); - int (*set_mmhub_powergating_by_smu)(void *handle); + int (*notify_smu_enable_pwe)(void *handle); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index d567be49c31b..145e5c403bea 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -221,29 +221,7 @@ static int pp_sw_reset(void *handle) static int pp_set_powergating_state(void *handle, enum amd_powergating_state state) { - struct amdgpu_device *adev = handle; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - int ret; - - if (!hwmgr || !hwmgr->pm_en) - return 0; - - if (hwmgr->hwmgr_func->gfx_off_control) { - /* Enable/disable GFX off through SMU */ - ret = hwmgr->hwmgr_func->gfx_off_control(hwmgr, - state == AMD_PG_STATE_GATE); - if (ret) - pr_err("gfx off control failed!\n"); - } - - if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) { - pr_debug("%s was not implemented.\n", __func__); - return 0; - } - - /* Enable/disable GFX per cu powergating through SMU */ - return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr, - state == AMD_PG_STATE_GATE); + return 0; } static int pp_suspend(void *handle) @@ -1118,17 +1096,17 @@ static int pp_get_clock_by_type_with_voltage(void *handle, } static int pp_set_watermarks_for_clocks_ranges(void *handle, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct pp_hwmgr *hwmgr = handle; int ret = 0; - if (!hwmgr || !hwmgr->pm_en ||!wm_with_clock_ranges) + if (!hwmgr || !hwmgr->pm_en || !clock_ranges) return -EINVAL; mutex_lock(&hwmgr->smu_lock); ret = phm_set_watermarks_for_clocks_ranges(hwmgr, - wm_with_clock_ranges); + clock_ranges); mutex_unlock(&hwmgr->smu_lock); return ret; @@ -1168,19 +1146,78 @@ static int pp_get_display_mode_validation_clocks(void *handle, return ret; } -static int pp_set_mmhub_powergating_by_smu(void *handle) +static int pp_dpm_powergate_mmhub(void *handle) { struct pp_hwmgr *hwmgr = handle; if (!hwmgr || !hwmgr->pm_en) return -EINVAL; - if (hwmgr->hwmgr_func->set_mmhub_powergating_by_smu == NULL) { + if (hwmgr->hwmgr_func->powergate_mmhub == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - return hwmgr->hwmgr_func->set_mmhub_powergating_by_smu(hwmgr); + return hwmgr->hwmgr_func->powergate_mmhub(hwmgr); +} + +static int pp_dpm_powergate_gfx(void *handle, bool gate) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr || !hwmgr->pm_en) + return 0; + + if (hwmgr->hwmgr_func->powergate_gfx == NULL) { + pr_info("%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->powergate_gfx(hwmgr, gate); +} + +static int pp_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + int ret = 0; + + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + case AMD_IP_BLOCK_TYPE_VCN: + pp_dpm_powergate_uvd(handle, gate); + break; + case AMD_IP_BLOCK_TYPE_VCE: + pp_dpm_powergate_vce(handle, gate); + break; + case AMD_IP_BLOCK_TYPE_GMC: + pp_dpm_powergate_mmhub(handle); + break; + case AMD_IP_BLOCK_TYPE_GFX: + ret = pp_dpm_powergate_gfx(handle, gate); + break; + default: + break; + } + return ret; +} + +static int pp_notify_smu_enable_pwe(void *handle) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL;; + + if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) { + pr_info("%s was not implemented.\n", __func__); + return -EINVAL;; + } + + mutex_lock(&hwmgr->smu_lock); + hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); + mutex_unlock(&hwmgr->smu_lock); + + return 0; } static const struct amd_pm_funcs pp_dpm_funcs = { @@ -1189,8 +1226,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .force_performance_level = pp_dpm_force_performance_level, .get_performance_level = pp_dpm_get_performance_level, .get_current_power_state = pp_dpm_get_current_power_state, - .powergate_vce = pp_dpm_powergate_vce, - .powergate_uvd = pp_dpm_powergate_uvd, .dispatch_tasks = pp_dpm_dispatch_tasks, .set_fan_control_mode = pp_dpm_set_fan_control_mode, .get_fan_control_mode = pp_dpm_get_fan_control_mode, @@ -1210,6 +1245,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .get_vce_clock_state = pp_dpm_get_vce_clock_state, .switch_power_profile = pp_dpm_switch_power_profile, .set_clockgating_by_smu = pp_set_clockgating_by_smu, + .set_powergating_by_smu = pp_set_powergating_by_smu, .get_power_profile_mode = pp_get_power_profile_mode, .set_power_profile_mode = pp_set_power_profile_mode, .odn_edit_dpm_table = pp_odn_edit_dpm_table, @@ -1227,5 +1263,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, - .set_mmhub_powergating_by_smu = pp_set_mmhub_powergating_by_smu, + .notify_smu_enable_pwe = pp_notify_smu_enable_pwe, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index a0bb921fac22..53207e76b0f3 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -435,7 +435,7 @@ int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { PHM_FUNC_CHECK(hwmgr); @@ -443,7 +443,7 @@ int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, return -EINVAL; return hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, - wm_with_clock_ranges); + clock_ranges); } int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c index 7047e29755c3..01dc46dc9c8a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c @@ -1544,14 +1544,14 @@ void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc, switch (hwmgr->chip_id) { case CHIP_TONGA: case CHIP_FIJI: - *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc/4); - *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc/4); + *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4; + *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4; return; case CHIP_POLARIS11: case CHIP_POLARIS10: case CHIP_POLARIS12: - *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc/100); - *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc/100); + *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100; + *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100; return; default: break; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c index 5325661fedff..d27c1c9df286 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c @@ -512,14 +512,82 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI return 0; } +static void pp_atomfwctrl_copy_vbios_bootup_values_3_2(struct pp_hwmgr *hwmgr, + struct pp_atomfwctrl_bios_boot_up_values *boot_values, + struct atom_firmware_info_v3_2 *fw_info) +{ + uint32_t frequency = 0; + + boot_values->ulRevision = fw_info->firmware_revision; + boot_values->ulGfxClk = fw_info->bootup_sclk_in10khz; + boot_values->ulUClk = fw_info->bootup_mclk_in10khz; + boot_values->usVddc = fw_info->bootup_vddc_mv; + boot_values->usVddci = fw_info->bootup_vddci_mv; + boot_values->usMvddc = fw_info->bootup_mvddc_mv; + boot_values->usVddGfx = fw_info->bootup_vddgfx_mv; + boot_values->ucCoolingID = fw_info->coolingsolution_id; + boot_values->ulSocClk = 0; + boot_values->ulDCEFClk = 0; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_SOCCLK_ID, &frequency)) + boot_values->ulSocClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_DCEFCLK_ID, &frequency)) + boot_values->ulDCEFClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_ECLK_ID, &frequency)) + boot_values->ulEClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_VCLK_ID, &frequency)) + boot_values->ulVClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_DCLK_ID, &frequency)) + boot_values->ulDClk = frequency; +} + +static void pp_atomfwctrl_copy_vbios_bootup_values_3_1(struct pp_hwmgr *hwmgr, + struct pp_atomfwctrl_bios_boot_up_values *boot_values, + struct atom_firmware_info_v3_1 *fw_info) +{ + uint32_t frequency = 0; + + boot_values->ulRevision = fw_info->firmware_revision; + boot_values->ulGfxClk = fw_info->bootup_sclk_in10khz; + boot_values->ulUClk = fw_info->bootup_mclk_in10khz; + boot_values->usVddc = fw_info->bootup_vddc_mv; + boot_values->usVddci = fw_info->bootup_vddci_mv; + boot_values->usMvddc = fw_info->bootup_mvddc_mv; + boot_values->usVddGfx = fw_info->bootup_vddgfx_mv; + boot_values->ucCoolingID = fw_info->coolingsolution_id; + boot_values->ulSocClk = 0; + boot_values->ulDCEFClk = 0; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_SOCCLK_ID, &frequency)) + boot_values->ulSocClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_DCEFCLK_ID, &frequency)) + boot_values->ulDCEFClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_ECLK_ID, &frequency)) + boot_values->ulEClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_VCLK_ID, &frequency)) + boot_values->ulVClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_DCLK_ID, &frequency)) + boot_values->ulDClk = frequency; +} + int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_bios_boot_up_values *boot_values) { - struct atom_firmware_info_v3_1 *info = NULL; + struct atom_firmware_info_v3_2 *fwinfo_3_2; + struct atom_firmware_info_v3_1 *fwinfo_3_1; + struct atom_common_table_header *info = NULL; uint16_t ix; ix = GetIndexIntoMasterDataTable(firmwareinfo); - info = (struct atom_firmware_info_v3_1 *) + info = (struct atom_common_table_header *) smu_atom_get_data_table(hwmgr->adev, ix, NULL, NULL, NULL); @@ -528,16 +596,18 @@ int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr *hwmgr, return -EINVAL; } - boot_values->ulRevision = info->firmware_revision; - boot_values->ulGfxClk = info->bootup_sclk_in10khz; - boot_values->ulUClk = info->bootup_mclk_in10khz; - boot_values->usVddc = info->bootup_vddc_mv; - boot_values->usVddci = info->bootup_vddci_mv; - boot_values->usMvddc = info->bootup_mvddc_mv; - boot_values->usVddGfx = info->bootup_vddgfx_mv; - boot_values->ucCoolingID = info->coolingsolution_id; - boot_values->ulSocClk = 0; - boot_values->ulDCEFClk = 0; + if ((info->format_revision == 3) && (info->content_revision == 2)) { + fwinfo_3_2 = (struct atom_firmware_info_v3_2 *)info; + pp_atomfwctrl_copy_vbios_bootup_values_3_2(hwmgr, + boot_values, fwinfo_3_2); + } else if ((info->format_revision == 3) && (info->content_revision == 1)) { + fwinfo_3_1 = (struct atom_firmware_info_v3_1 *)info; + pp_atomfwctrl_copy_vbios_bootup_values_3_1(hwmgr, + boot_values, fwinfo_3_1); + } else { + pr_info("Fw info table revision does not match!"); + return -EINVAL; + } return 0; } @@ -629,5 +699,7 @@ int pp_atomfwctrl_get_smc_dpm_information(struct pp_hwmgr *hwmgr, param->acggfxclkspreadpercent = info->acggfxclkspreadpercent; param->acggfxclkspreadfreq = info->acggfxclkspreadfreq; + param->Vr2_I2C_address = info->Vr2_I2C_address; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h index fe10aa4db5e6..22e21668c93a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h @@ -136,6 +136,9 @@ struct pp_atomfwctrl_bios_boot_up_values { uint32_t ulUClk; uint32_t ulSocClk; uint32_t ulDCEFClk; + uint32_t ulEClk; + uint32_t ulVClk; + uint32_t ulDClk; uint16_t usVddc; uint16_t usVddci; uint16_t usMvddc; @@ -207,6 +210,8 @@ struct pp_atomfwctrl_smc_dpm_parameters uint8_t acggfxclkspreadenabled; uint8_t acggfxclkspreadpercent; uint16_t acggfxclkspreadfreq; + + uint8_t Vr2_I2C_address; }; int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index 35bd9870ab10..4e1fd5393845 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -183,10 +183,10 @@ static int get_vddc_lookup_table( ATOM_Tonga_Voltage_Lookup_Record, entries, vddc_lookup_pp_tables, i); record->us_calculated = 0; - record->us_vdd = atom_record->usVdd; - record->us_cac_low = atom_record->usCACLow; - record->us_cac_mid = atom_record->usCACMid; - record->us_cac_high = atom_record->usCACHigh; + record->us_vdd = le16_to_cpu(atom_record->usVdd); + record->us_cac_low = le16_to_cpu(atom_record->usCACLow); + record->us_cac_mid = le16_to_cpu(atom_record->usCACMid); + record->us_cac_high = le16_to_cpu(atom_record->usCACHigh); } *lookup_table = table; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index d4bc83e81389..a63e00653324 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -993,7 +993,7 @@ static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; + clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; clocks->data[i].latency_in_us = latency_required ? smu10_get_mem_latency(hwmgr, pclk_vol_table->entries[i].clk) : @@ -1044,7 +1044,7 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; + clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol; clocks->num_levels++; } @@ -1108,9 +1108,10 @@ static int smu10_read_sensor(struct pp_hwmgr *hwmgr, int idx, } static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct smu10_hwmgr *data = hwmgr->backend; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; Watermarks_t *table = &(data->water_marks_table); int result = 0; @@ -1126,7 +1127,7 @@ static int smu10_smus_notify_pwe(struct pp_hwmgr *hwmgr) return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SetRccPfcPmeRestoreRegister); } -static int smu10_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) +static int smu10_powergate_mmhub(struct pp_hwmgr *hwmgr) { return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); } @@ -1182,10 +1183,11 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .asic_setup = smu10_setup_asic_task, .power_state_set = smu10_set_power_state_tasks, .dynamic_state_management_disable = smu10_disable_dpm_tasks, - .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu, + .powergate_mmhub = smu10_powergate_mmhub, .smus_notify_pwe = smu10_smus_notify_pwe, .gfx_off_control = smu10_gfx_off_control, .display_clock_voltage_request = smu10_display_clock_voltage_request, + .powergate_gfx = smu10_gfx_off_control, }; int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 41495621d94a..683b29a99366 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -416,7 +416,7 @@ int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, * Powerplay will only control the static per CU Power Gating. * Dynamic per CU Power Gating will be done in gfx. */ -int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable) +int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable) { struct amdgpu_device *adev = hwmgr->adev; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h index be7f66d2b234..fc8f8a6acc72 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h @@ -33,6 +33,6 @@ int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate); int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr); int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id); -int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable); +int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable); #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index b89d6fb8559b..077b79938528 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1578,7 +1578,7 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) data->current_profile_setting.sclk_up_hyst = 0; data->current_profile_setting.sclk_down_hyst = 100; data->current_profile_setting.sclk_activity = SMU7_SCLK_TARGETACTIVITY_DFLT; - data->current_profile_setting.bupdate_sclk = 1; + data->current_profile_setting.bupdate_mclk = 1; data->current_profile_setting.mclk_up_hyst = 0; data->current_profile_setting.mclk_down_hyst = 100; data->current_profile_setting.mclk_activity = SMU7_MCLK_TARGETACTIVITY_DFLT; @@ -3183,7 +3183,7 @@ static int smu7_get_pp_table_entry_callback_func_v1(struct pp_hwmgr *hwmgr, performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap, state_entry->ucPCIEGenLow); performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap, - state_entry->ucPCIELaneHigh); + state_entry->ucPCIELaneLow); performance_level = &(smu7_power_state->performance_levels [smu7_power_state->performance_level_count++]); @@ -5044,7 +5044,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_fan_control_mode = smu7_get_fan_control_mode, .force_clock_level = smu7_force_clock_level, .print_clock_levels = smu7_print_clock_levels, - .enable_per_cu_power_gating = smu7_enable_per_cu_power_gating, + .powergate_gfx = smu7_powergate_gfx, .get_sclk_od = smu7_get_sclk_od, .set_sclk_od = smu7_set_sclk_od, .get_mclk_od = smu7_get_mclk_od, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c index 93a3d022ba47..3effb5583d1f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c @@ -652,7 +652,7 @@ int smu_get_voltage_dependency_table_ppt_v1( } int smu_set_watermarks_for_clocks_ranges(void *wt_table, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) { uint32_t i; struct watermarks *table = wt_table; @@ -660,49 +660,49 @@ int smu_set_watermarks_for_clocks_ranges(void *wt_table, if (!table || !wm_with_clock_ranges) return -EINVAL; - if (wm_with_clock_ranges->num_wm_sets_dmif > 4 || wm_with_clock_ranges->num_wm_sets_mcif > 4) + if (wm_with_clock_ranges->num_wm_dmif_sets > 4 || wm_with_clock_ranges->num_wm_mcif_sets > 4) return -EINVAL; - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) { table->WatermarkRow[1][i].MinClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz) / + 1000); table->WatermarkRow[1][i].MaxClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) / + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz) / 100); table->WatermarkRow[1][i].MinUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz) / + 1000); table->WatermarkRow[1][i].MaxUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz) / + 1000); table->WatermarkRow[1][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id; + wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; } - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) { table->WatermarkRow[0][i].MinClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MaxClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MinUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MaxUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz) / + 1000); table->WatermarkRow[0][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id; + wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h index 916cc01e7652..5454289d5226 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h @@ -107,7 +107,7 @@ int smu_get_voltage_dependency_table_ppt_v1( struct phm_ppt_v1_clock_voltage_dependency_table *dep_table); int smu_set_watermarks_for_clocks_ranges(void *wt_table, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT #define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 3b8d36df52e9..5e771bc119d6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -55,12 +55,6 @@ static const uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2}; -#define MEM_FREQ_LOW_LATENCY 25000 -#define MEM_FREQ_HIGH_LATENCY 80000 -#define MEM_LATENCY_HIGH 245 -#define MEM_LATENCY_LOW 35 -#define MEM_LATENCY_ERR 0xFFFF - #define mmDF_CS_AON0_DramBaseAddress0 0x0044 #define mmDF_CS_AON0_DramBaseAddress0_BASE_IDX 0 @@ -3223,7 +3217,7 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, /* Find the lowest MCLK frequency that is within * the tolerable latency defined in DAL */ - latency = 0; + latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency; for (i = 0; i < data->mclk_latency_table.count; i++) { if ((data->mclk_latency_table.entries[i].latency <= latency) && (data->mclk_latency_table.entries[i].frequency >= @@ -4064,28 +4058,17 @@ static void vega10_get_sclks(struct pp_hwmgr *hwmgr, table_info->vdd_dep_on_sclk; uint32_t i; + clocks->num_levels = 0; for (i = 0; i < dep_table->count; i++) { if (dep_table->entries[i].clk) { clocks->data[clocks->num_levels].clocks_in_khz = - dep_table->entries[i].clk; + dep_table->entries[i].clk * 10; clocks->num_levels++; } } } -static uint32_t vega10_get_mem_latency(struct pp_hwmgr *hwmgr, - uint32_t clock) -{ - if (clock >= MEM_FREQ_LOW_LATENCY && - clock < MEM_FREQ_HIGH_LATENCY) - return MEM_LATENCY_HIGH; - else if (clock >= MEM_FREQ_HIGH_LATENCY) - return MEM_LATENCY_LOW; - else - return MEM_LATENCY_ERR; -} - static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, struct pp_clock_levels_with_latency *clocks) { @@ -4094,26 +4077,22 @@ static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = table_info->vdd_dep_on_mclk; struct vega10_hwmgr *data = hwmgr->backend; + uint32_t j = 0; uint32_t i; - clocks->num_levels = 0; - data->mclk_latency_table.count = 0; - for (i = 0; i < dep_table->count; i++) { if (dep_table->entries[i].clk) { - clocks->data[clocks->num_levels].clocks_in_khz = - data->mclk_latency_table.entries - [data->mclk_latency_table.count].frequency = - dep_table->entries[i].clk; - clocks->data[clocks->num_levels].latency_in_us = - data->mclk_latency_table.entries - [data->mclk_latency_table.count].latency = - vega10_get_mem_latency(hwmgr, - dep_table->entries[i].clk); - clocks->num_levels++; - data->mclk_latency_table.count++; + + clocks->data[j].clocks_in_khz = + dep_table->entries[i].clk * 10; + data->mclk_latency_table.entries[j].frequency = + dep_table->entries[i].clk; + clocks->data[j].latency_in_us = + data->mclk_latency_table.entries[j].latency = 25; + j++; } } + clocks->num_levels = data->mclk_latency_table.count = j; } static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr, @@ -4126,7 +4105,7 @@ static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr, uint32_t i; for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].latency_in_us = 0; clocks->num_levels++; } @@ -4142,7 +4121,7 @@ static void vega10_get_socclocks(struct pp_hwmgr *hwmgr, uint32_t i; for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].latency_in_us = 0; clocks->num_levels++; } @@ -4202,7 +4181,7 @@ static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table-> entries[dep_table->entries[i].vddInd].us_vdd); clocks->num_levels++; @@ -4215,9 +4194,10 @@ static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_range) { struct vega10_hwmgr *data = hwmgr->backend; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; Watermarks_t *table = &(data->smc_state_table.water_marks_table); int result = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 782e2098824d..57492878874f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -81,6 +81,7 @@ static void vega12_set_default_registry_data(struct pp_hwmgr *hwmgr) data->registry_data.disallowed_features = 0x0; data->registry_data.od_state_in_dc_support = 0; + data->registry_data.thermal_support = 1; data->registry_data.skip_baco_hardware = 0; data->registry_data.log_avfs_param = 0; @@ -453,37 +454,30 @@ static int vega12_setup_asic_task(struct pp_hwmgr *hwmgr) */ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state) { - dpm_state->soft_min_level = 0xff; - dpm_state->soft_max_level = 0xff; - dpm_state->hard_min_level = 0xff; - dpm_state->hard_max_level = 0xff; + dpm_state->soft_min_level = 0x0; + dpm_state->soft_max_level = 0xffff; + dpm_state->hard_min_level = 0x0; + dpm_state->hard_max_level = 0xffff; } -static int vega12_get_number_dpm_level(struct pp_hwmgr *hwmgr, - PPCLK_e clkID, uint32_t *num_dpm_level) +static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, + PPCLK_e clk_id, uint32_t *num_of_levels) { - int result; - /* - * SMU expects the Clock ID to be in the top 16 bits. - * Lower 16 bits specify the level however 0xFF is a - * special argument the returns the total number of levels - */ - PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_GetDpmFreqByIndex, (clkID << 16 | 0xFF)) == 0, - "[GetNumberDpmLevel] Failed to get DPM levels from SMU for CLKID!", - return -EINVAL); - - result = vega12_read_arg_from_smc(hwmgr, num_dpm_level); + int ret = 0; - PP_ASSERT_WITH_CODE(*num_dpm_level < MAX_REGULAR_DPM_NUMBER, - "[GetNumberDPMLevel] Number of DPM levels is greater than limit", - return -EINVAL); + ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_GetDpmFreqByIndex, + (clk_id << 16 | 0xFF)); + PP_ASSERT_WITH_CODE(!ret, + "[GetNumOfDpmLevel] failed to get dpm levels!", + return ret); - PP_ASSERT_WITH_CODE(*num_dpm_level != 0, - "[GetNumberDPMLevel] Number of CLK Levels is zero!", - return -EINVAL); + vega12_read_arg_from_smc(hwmgr, num_of_levels); + PP_ASSERT_WITH_CODE(*num_of_levels > 0, + "[GetNumOfDpmLevel] number of clk levels is invalid!", + return -EINVAL); - return result; + return ret; } static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, @@ -509,6 +503,31 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, return result; } +static int vega12_setup_single_dpm_table(struct pp_hwmgr *hwmgr, + struct vega12_single_dpm_table *dpm_table, PPCLK_e clk_id) +{ + int ret = 0; + uint32_t i, num_of_levels, clk; + + ret = vega12_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels); + PP_ASSERT_WITH_CODE(!ret, + "[SetupSingleDpmTable] failed to get clk levels!", + return ret); + + dpm_table->count = num_of_levels; + + for (i = 0; i < num_of_levels; i++) { + ret = vega12_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk); + PP_ASSERT_WITH_CODE(!ret, + "[SetupSingleDpmTable] failed to get clk of specific level!", + return ret); + dpm_table->dpm_levels[i].value = clk; + dpm_table->dpm_levels[i].enabled = true; + } + + return ret; +} + /* * This function is to initialize all DPM state tables * for SMU based on the dependency table. @@ -519,224 +538,136 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, */ static int vega12_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) { - uint32_t num_levels, i, clock; struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - struct vega12_single_dpm_table *dpm_table; + int ret = 0; memset(&data->dpm_table, 0, sizeof(data->dpm_table)); - /* Initialize Sclk DPM and SOC DPM table based on allow Sclk values */ + /* socclk */ dpm_table = &(data->dpm_table.soc_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_SOCCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_SOCCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get socclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* gfxclk */ dpm_table = &(data->dpm_table.gfx_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_GFXCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_GFXCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); - /* Initialize Mclk DPM table based on allow Mclk values */ - dpm_table = &(data->dpm_table.mem_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_UCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_UCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!", - return -EINVAL); - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + /* memclk */ + dpm_table = &(data->dpm_table.mem_table); + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get memclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* eclk */ dpm_table = &(data->dpm_table.eclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_ECLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_ECLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_VCE].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get eclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* vclk */ dpm_table = &(data->dpm_table.vclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_VCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_VCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get vclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* dclk */ dpm_table = &(data->dpm_table.dclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_DCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); - /* Assume there is no headless Vega12 for now */ + /* dcefclk */ dpm_table = &(data->dpm_table.dcef_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_DCEFCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DCEFCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* pixclk */ dpm_table = &(data->dpm_table.pixel_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_PIXCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_PIXCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get pixclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* dispclk */ dpm_table = &(data->dpm_table.display_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_DISPCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DISPCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dispclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* phyclk */ dpm_table = &(data->dpm_table.phy_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_PHYCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_PHYCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get phyclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); /* save a copy of the default DPM table */ @@ -803,6 +734,9 @@ static int vega12_init_smc_table(struct pp_hwmgr *hwmgr) data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk; data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk; data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID; + data->vbios_boot_state.eclock = boot_up_values.ulEClk; + data->vbios_boot_state.dclock = boot_up_values.ulDClk; + data->vbios_boot_state.vclock = boot_up_values.ulVClk; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, (uint32_t)(data->vbios_boot_state.dcef_clock / 100)); @@ -844,6 +778,21 @@ static int vega12_set_allowed_featuresmask(struct pp_hwmgr *hwmgr) return 0; } +static void vega12_init_powergate_state(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + + data->uvd_power_gated = true; + data->vce_power_gated = true; + + if (data->smu_features[GNLD_DPM_UVD].enabled) + data->uvd_power_gated = false; + + if (data->smu_features[GNLD_DPM_VCE].enabled) + data->vce_power_gated = false; +} + static int vega12_enable_all_smu_features(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = @@ -862,12 +811,11 @@ static int vega12_enable_all_smu_features(struct pp_hwmgr *hwmgr) enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ? true : false; data->smu_features[i].enabled = enabled; data->smu_features[i].supported = enabled; - PP_ASSERT( - !data->smu_features[i].allowed || enabled, - "[EnableAllSMUFeatures] Enabled feature is different from allowed, expected disabled!"); } } + vega12_init_powergate_state(hwmgr); + return 0; } @@ -923,6 +871,48 @@ static int vega12_power_control_set_level(struct pp_hwmgr *hwmgr) return result; } +static int vega12_get_all_clock_ranges_helper(struct pp_hwmgr *hwmgr, + PPCLK_e clkid, struct vega12_clock_range *clock) +{ + /* AC Max */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMaxDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get max ac clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->ACMax)); + + /* AC Min */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMinDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get min ac clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->ACMin)); + + /* DC Max */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDcModeMaxDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get max dc clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->DCMax)); + + return 0; +} + +static int vega12_get_all_clock_ranges(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + uint32_t i; + + for (i = 0; i < PPCLK_COUNT; i++) + PP_ASSERT_WITH_CODE(!vega12_get_all_clock_ranges_helper(hwmgr, + i, &(data->clk_range[i])), + "Failed to get clk range from SMC!", + return -EINVAL); + + return 0; +} + static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; @@ -950,6 +940,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) "Failed to power control set level!", result = tmp_result); + result = vega12_get_all_clock_ranges(hwmgr); + PP_ASSERT_WITH_CODE(!result, + "Failed to get all clock ranges!", + return result); + result = vega12_odn_initialize_default_settings(hwmgr); PP_ASSERT_WITH_CODE(!result, "Failed to power control set level!", @@ -978,76 +973,172 @@ static uint32_t vega12_find_lowest_dpm_level( break; } + if (i >= table->count) { + i = 0; + table->dpm_levels[i].enabled = true; + } + return i; } static uint32_t vega12_find_highest_dpm_level( struct vega12_single_dpm_table *table) { - uint32_t i = 0; + int32_t i = 0; + PP_ASSERT_WITH_CODE(table->count <= MAX_REGULAR_DPM_NUMBER, + "[FindHighestDPMLevel] DPM Table has too many entries!", + return MAX_REGULAR_DPM_NUMBER - 1); - if (table->count <= MAX_REGULAR_DPM_NUMBER) { - for (i = table->count; i > 0; i--) { - if (table->dpm_levels[i - 1].enabled) - return i - 1; - } - } else { - pr_info("DPM Table Has Too Many Entries!"); - return MAX_REGULAR_DPM_NUMBER - 1; + for (i = table->count - 1; i >= 0; i--) { + if (table->dpm_levels[i].enabled) + break; } - return i; + if (i < 0) { + i = 0; + table->dpm_levels[i].enabled = true; + } + + return (uint32_t)i; } static int vega12_upload_dpm_min_level(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = hwmgr->backend; - if (data->smc_state_table.gfx_boot_level != - data->dpm_table.gfx_table.dpm_state.soft_min_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMinByFreq, - PPCLK_GFXCLK<<16 | data->dpm_table.gfx_table.dpm_levels[data->smc_state_table.gfx_boot_level].value); - data->dpm_table.gfx_table.dpm_state.soft_min_level = - data->smc_state_table.gfx_boot_level; + uint32_t min_freq; + int ret = 0; + + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_GFXCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min gfxclk !", + return ret); } - if (data->smc_state_table.mem_boot_level != - data->dpm_table.mem_table.dpm_state.soft_min_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMinByFreq, - PPCLK_UCLK<<16 | data->dpm_table.mem_table.dpm_levels[data->smc_state_table.mem_boot_level].value); - data->dpm_table.mem_table.dpm_state.soft_min_level = - data->smc_state_table.mem_boot_level; + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_UCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min memclk !", + return ret); + + min_freq = data->dpm_table.mem_table.dpm_state.hard_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetHardMinByFreq, + (PPCLK_UCLK << 16) | (min_freq & 0xffff))), + "Failed to set hard min memclk !", + return ret); } - return 0; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_VCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min vclk!", + return ret); + + min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_DCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min dclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_VCE].enabled) { + min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_ECLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min eclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_SOCCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min socclk!", + return ret); + } + + return ret; } static int vega12_upload_dpm_max_level(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = hwmgr->backend; - if (data->smc_state_table.gfx_max_level != - data->dpm_table.gfx_table.dpm_state.soft_max_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMaxByFreq, - /* plus the vale by 1 to align the resolution */ - PPCLK_GFXCLK<<16 | (data->dpm_table.gfx_table.dpm_levels[data->smc_state_table.gfx_max_level].value + 1)); - data->dpm_table.gfx_table.dpm_state.soft_max_level = - data->smc_state_table.gfx_max_level; + uint32_t max_freq; + int ret = 0; + + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_GFXCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max gfxclk!", + return ret); } - if (data->smc_state_table.mem_max_level != - data->dpm_table.mem_table.dpm_state.soft_max_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMaxByFreq, - /* plus the vale by 1 to align the resolution */ - PPCLK_UCLK<<16 | (data->dpm_table.mem_table.dpm_levels[data->smc_state_table.mem_max_level].value + 1)); - data->dpm_table.mem_table.dpm_state.soft_max_level = - data->smc_state_table.mem_max_level; + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_UCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max memclk!", + return ret); } - return 0; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_VCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max vclk!", + return ret); + + max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_DCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max dclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_VCE].enabled) { + max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_ECLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max eclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_SOCCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max socclk!", + return ret); + } + + return ret; } int vega12_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) @@ -1136,8 +1227,8 @@ static int vega12_get_current_gfx_clk_freq(struct pp_hwmgr *hwmgr, uint32_t *gfx *gfx_freq = 0; - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16)) == 0, + PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16)) == 0, "[GetCurrentGfxClkFreq] Attempt to get Current GFXCLK Frequency Failed!", return -1); PP_ASSERT_WITH_CODE( @@ -1306,9 +1397,9 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( (struct vega12_hwmgr *)(hwmgr->backend); struct PP_Clocks min_clocks = {0}; struct pp_display_clock_request clock_req; - uint32_t clk_request; - if (hwmgr->display_config->num_display > 1) + if ((hwmgr->display_config->num_display > 1) && + !hwmgr->display_config->multi_monitor_in_sync) vega12_notify_smc_display_change(hwmgr, false); else vega12_notify_smc_display_change(hwmgr, true); @@ -1333,15 +1424,6 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( } } - if (data->smu_features[GNLD_DPM_UCLK].enabled) { - clk_request = (PPCLK_UCLK << 16) | (min_clocks.memoryClock) / 100; - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinByFreq, clk_request) == 0, - "[PhwVega12_NotifySMCDisplayConfigAfterPowerStateAdjustment] Attempt to set UCLK HardMin Failed!", - return -1); - data->dpm_table.mem_table.dpm_state.hard_min_level = min_clocks.memoryClock; - } - return 0; } @@ -1350,12 +1432,19 @@ static int vega12_force_dpm_highest(struct pp_hwmgr *hwmgr) struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - data->smc_state_table.gfx_boot_level = - data->smc_state_table.gfx_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - data->smc_state_table.mem_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); + uint32_t soft_level; + + soft_level = vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_level].value; + + soft_level = vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_level].value; PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload boot level to highest!", @@ -1372,13 +1461,19 @@ static int vega12_force_dpm_lowest(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + uint32_t soft_level; + + soft_level = vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.gfx_boot_level = - data->smc_state_table.gfx_max_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - data->smc_state_table.mem_max_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_level].value; + + soft_level = vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_level].value; PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload boot level to highest!", @@ -1394,17 +1489,6 @@ static int vega12_force_dpm_lowest(struct pp_hwmgr *hwmgr) static int vega12_unforce_dpm_levels(struct pp_hwmgr *hwmgr) { - struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - - data->smc_state_table.gfx_boot_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.gfx_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); - data->smc_state_table.mem_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload DPM Bootup Levels!", return -1); @@ -1412,22 +1496,28 @@ static int vega12_unforce_dpm_levels(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), "Failed to upload DPM Max Levels!", return -1); + return 0; } -#if 0 static int vega12_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level, uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask) { - struct phm_ppt_v2_information *table_info = - (struct phm_ppt_v2_information *)(hwmgr->pptable); + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct vega12_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table); + struct vega12_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table); + struct vega12_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table); - if (table_info->vdd_dep_on_sclk->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL && - table_info->vdd_dep_on_socclk->count > VEGA12_UMD_PSTATE_SOCCLK_LEVEL && - table_info->vdd_dep_on_mclk->count > VEGA12_UMD_PSTATE_MCLK_LEVEL) { + *sclk_mask = 0; + *mclk_mask = 0; + *soc_mask = 0; + + if (gfx_dpm_table->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL && + mem_dpm_table->count > VEGA12_UMD_PSTATE_MCLK_LEVEL && + soc_dpm_table->count > VEGA12_UMD_PSTATE_SOCCLK_LEVEL) { *sclk_mask = VEGA12_UMD_PSTATE_GFXCLK_LEVEL; - *soc_mask = VEGA12_UMD_PSTATE_SOCCLK_LEVEL; *mclk_mask = VEGA12_UMD_PSTATE_MCLK_LEVEL; + *soc_mask = VEGA12_UMD_PSTATE_SOCCLK_LEVEL; } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { @@ -1435,13 +1525,13 @@ static int vega12_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { *mclk_mask = 0; } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; - *soc_mask = table_info->vdd_dep_on_socclk->count - 1; - *mclk_mask = table_info->vdd_dep_on_mclk->count - 1; + *sclk_mask = gfx_dpm_table->count - 1; + *mclk_mask = mem_dpm_table->count - 1; + *soc_mask = soc_dpm_table->count - 1; } + return 0; } -#endif static void vega12_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) { @@ -1465,11 +1555,9 @@ static int vega12_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level) { int ret = 0; -#if 0 uint32_t sclk_mask = 0; uint32_t mclk_mask = 0; uint32_t soc_mask = 0; -#endif switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: @@ -1485,27 +1573,18 @@ static int vega12_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: -#if 0 ret = vega12_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask); if (ret) return ret; - vega12_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask); - vega12_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask); -#endif + vega12_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask); + vega12_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask); break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: break; } -#if 0 - if (!ret) { - if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) - vega12_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_NONE); - else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) - vega12_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_AUTO); - } -#endif + return ret; } @@ -1539,24 +1618,14 @@ static int vega12_get_clock_ranges(struct pp_hwmgr *hwmgr, PPCLK_e clock_select, bool max) { - int result; - *clock = 0; + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - if (max) { - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMaxDpmFreq, (clock_select << 16)) == 0, - "[GetClockRanges] Failed to get max clock from SMC!", - return -1); - result = vega12_read_arg_from_smc(hwmgr, clock); - } else { - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMinDpmFreq, (clock_select << 16)) == 0, - "[GetClockRanges] Failed to get min clock from SMC!", - return -1); - result = vega12_read_arg_from_smc(hwmgr, clock); - } + if (max) + *clock = data->clk_range[clock_select].ACMax; + else + *clock = data->clk_range[clock_select].ACMin; - return result; + return 0; } static int vega12_get_sclks(struct pp_hwmgr *hwmgr, @@ -1571,12 +1640,12 @@ static int vega12_get_sclks(struct pp_hwmgr *hwmgr, return -1; dpm_table = &(data->dpm_table.gfx_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1603,13 +1672,12 @@ static int vega12_get_memclocks(struct pp_hwmgr *hwmgr, return -1; dpm_table = &(data->dpm_table.mem_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_UCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_UCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { - clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; - + clocks->data[i].clocks_in_khz = dpm_table->dpm_levels[i].value * 1000; + data->mclk_latency_table.entries[i].frequency = dpm_table->dpm_levels[i].value * 100; clocks->data[i].latency_in_us = data->mclk_latency_table.entries[i].latency = vega12_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value); @@ -1633,12 +1701,12 @@ static int vega12_get_dcefclocks(struct pp_hwmgr *hwmgr, dpm_table = &(data->dpm_table.dcef_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1661,12 +1729,12 @@ static int vega12_get_socclocks(struct pp_hwmgr *hwmgr, dpm_table = &(data->dpm_table.soc_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1713,99 +1781,69 @@ static int vega12_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); Watermarks_t *table = &(data->smc_state_table.water_marks_table); - int result = 0; - uint32_t i; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; if (!data->registry_data.disable_water_mark && data->smu_features[GNLD_DPM_DCEFCLK].supported && data->smu_features[GNLD_DPM_SOCCLK].supported) { - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) { - table->WatermarkRow[WM_DCEFCLK][i].MinClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MaxClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MinUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MaxUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id; - } - - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) { - table->WatermarkRow[WM_SOCCLK][i].MinClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MaxClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MinUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MaxUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id; - } + smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges); data->water_marks_bitmap |= WaterMarksExist; data->water_marks_bitmap &= ~WaterMarksLoaded; } - return result; + return 0; } static int vega12_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - - if (hwmgr->request_dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO | - AMD_DPM_FORCED_LEVEL_LOW | - AMD_DPM_FORCED_LEVEL_HIGH)) - return -EINVAL; + uint32_t soft_min_level, soft_max_level; + int ret = 0; switch (type) { case PP_SCLK: - data->smc_state_table.gfx_boot_level = mask ? (ffs(mask) - 1) : 0; - data->smc_state_table.gfx_max_level = mask ? (fls(mask) - 1) : 0; + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_levels[soft_min_level].value; + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_max_level].value; - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), + ret = vega12_upload_dpm_min_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to lowest!", - return -EINVAL); + return ret); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), + ret = vega12_upload_dpm_max_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", - return -EINVAL); + return ret); break; case PP_MCLK: - data->smc_state_table.mem_boot_level = mask ? (ffs(mask) - 1) : 0; - data->smc_state_table.mem_max_level = mask ? (fls(mask) - 1) : 0; + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_levels[soft_min_level].value; + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_max_level].value; + + ret = vega12_upload_dpm_min_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to lowest!", - return -EINVAL); + return ret); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), + ret = vega12_upload_dpm_max_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", - return -EINVAL); + return ret); break; @@ -1838,8 +1876,8 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return -1); for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", - i, clocks.data[i].clocks_in_khz / 100, - (clocks.data[i].clocks_in_khz == now) ? "*" : ""); + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); break; case PP_MCLK: @@ -1854,8 +1892,8 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return -1); for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", - i, clocks.data[i].clocks_in_khz / 100, - (clocks.data[i].clocks_in_khz == now) ? "*" : ""); + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); break; case PP_PCIE: @@ -1867,6 +1905,205 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return size; } +static int vega12_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct vega12_single_dpm_table *dpm_table; + bool vblank_too_short = false; + bool disable_mclk_switching; + uint32_t i, latency; + + disable_mclk_switching = ((1 < hwmgr->display_config->num_display) && + !hwmgr->display_config->multi_monitor_in_sync) || + vblank_too_short; + latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency; + + /* gfxclk */ + dpm_table = &(data->dpm_table.gfx_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* memclk */ + dpm_table = &(data->dpm_table.mem_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* honour DAL's UCLK Hardmin */ + if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100)) + dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100; + + /* Hardmin is dependent on displayconfig */ + if (disable_mclk_switching) { + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + for (i = 0; i < data->mclk_latency_table.count - 1; i++) { + if (data->mclk_latency_table.entries[i].latency <= latency) { + if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) { + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value; + break; + } + } + } + } + + if (hwmgr->display_config->nb_pstate_switch_disable) + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + /* vclk */ + dpm_table = &(data->dpm_table.vclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* dclk */ + dpm_table = &(data->dpm_table.dclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* socclk */ + dpm_table = &(data->dpm_table.soc_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_SOCCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_SOCCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* eclk */ + dpm_table = &(data->dpm_table.eclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_VCEMCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_VCEMCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + return 0; +} + +static int vega12_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr, + struct vega12_single_dpm_table *dpm_table) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + PP_ASSERT_WITH_CODE(dpm_table->count > 0, + "[SetUclkToHightestDpmLevel] Dpm table has no entry!", + return -EINVAL); + PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS, + "[SetUclkToHightestDpmLevel] Dpm table has too many entries!", + return -EINVAL); + + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetHardMinByFreq, + (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)), + "[SetUclkToHightestDpmLevel] Set hard min uclk failed!", + return ret); + } + + return ret; +} + +static int vega12_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_NumOfDisplays, 0); + + ret = vega12_set_uclk_to_highest_dpm_level(hwmgr, + &data->dpm_table.mem_table); + + return ret; +} + static int vega12_display_configuration_changed_task(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); @@ -1911,6 +2148,9 @@ static void vega12_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + if (data->vce_power_gated == bgate) + return; + data->vce_power_gated = bgate; vega12_enable_disable_vce_dpm(hwmgr, !bgate); } @@ -1919,6 +2159,9 @@ static void vega12_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + if (data->uvd_power_gated == bgate) + return; + data->uvd_power_gated = bgate; vega12_enable_disable_uvd_dpm(hwmgr, !bgate); } @@ -2113,6 +2356,10 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .display_clock_voltage_request = vega12_display_clock_voltage_request, .force_clock_level = vega12_force_clock_level, .print_clock_levels = vega12_print_clock_levels, + .apply_clocks_adjust_rules = + vega12_apply_clocks_adjust_rules, + .pre_display_config_changed = + vega12_pre_display_configuration_changed_task, .display_config_changed = vega12_display_configuration_changed_task, .powergate_uvd = vega12_power_gate_uvd, .powergate_vce = vega12_power_gate_vce, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h index e81ded1ec198..e17237c90eea 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h @@ -167,6 +167,9 @@ struct vega12_vbios_boot_state { uint32_t mem_clock; uint32_t soc_clock; uint32_t dcef_clock; + uint32_t eclock; + uint32_t dclock; + uint32_t vclock; }; #define DPMTABLE_OD_UPDATE_SCLK 0x00000001 @@ -301,6 +304,12 @@ struct vega12_odn_fan_table { bool force_fan_pwm; }; +struct vega12_clock_range { + uint32_t ACMax; + uint32_t ACMin; + uint32_t DCMax; +}; + struct vega12_hwmgr { struct vega12_dpm_table dpm_table; struct vega12_dpm_table golden_dpm_table; @@ -382,6 +391,8 @@ struct vega12_hwmgr { uint32_t smu_version; struct smu_features smu_features[GNLD_FEATURES_MAX]; struct vega12_smc_state_table smc_state_table; + + struct vega12_clock_range clk_range[PPCLK_COUNT]; }; #define VEGA12_DPM2_NEAR_TDP_DEC 10 @@ -432,6 +443,8 @@ struct vega12_hwmgr { #define VEGA12_UMD_PSTATE_GFXCLK_LEVEL 0x3 #define VEGA12_UMD_PSTATE_SOCCLK_LEVEL 0x3 #define VEGA12_UMD_PSTATE_MCLK_LEVEL 0x2 +#define VEGA12_UMD_PSTATE_UVDCLK_LEVEL 0x3 +#define VEGA12_UMD_PSTATE_VCEMCLK_LEVEL 0x3 int vega12_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c index 888ddca902d8..f4f366b26fd1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c @@ -224,11 +224,7 @@ static int append_vbios_pptable(struct pp_hwmgr *hwmgr, PPTable_t *ppsmc_pptable ppsmc_pptable->AcgGfxclkSpreadPercent = smc_dpm_table.acggfxclkspreadpercent; ppsmc_pptable->AcgGfxclkSpreadFreq = smc_dpm_table.acggfxclkspreadfreq; - /* 0xFFFF will disable the ACG feature */ - if (!(hwmgr->feature_mask & PP_ACG_MASK)) { - ppsmc_pptable->AcgThresholdFreqHigh = 0xFFFF; - ppsmc_pptable->AcgThresholdFreqLow = 0xFFFF; - } + ppsmc_pptable->Vr2_I2C_address = smc_dpm_table.Vr2_I2C_address; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h index a202247c9894..429c9c4322da 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h @@ -455,7 +455,7 @@ extern int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); extern int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + void *clock_ranges); extern int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 40c98ca5feb7..b3363f26039a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -293,8 +293,7 @@ struct pp_hwmgr_func { int (*get_clock_by_type_with_voltage)(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); - int (*set_watermarks_for_clocks_ranges)(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + int (*set_watermarks_for_clocks_ranges)(struct pp_hwmgr *hwmgr, void *clock_ranges); int (*display_clock_voltage_request)(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock); int (*get_max_high_clocks)(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks); @@ -302,7 +301,7 @@ struct pp_hwmgr_func { int (*power_off_asic)(struct pp_hwmgr *hwmgr); int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask); int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf); - int (*enable_per_cu_power_gating)(struct pp_hwmgr *hwmgr, bool enable); + int (*powergate_gfx)(struct pp_hwmgr *hwmgr, bool enable); int (*get_sclk_od)(struct pp_hwmgr *hwmgr); int (*set_sclk_od)(struct pp_hwmgr *hwmgr, uint32_t value); int (*get_mclk_od)(struct pp_hwmgr *hwmgr); @@ -327,7 +326,7 @@ struct pp_hwmgr_func { enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size); int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n); - int (*set_mmhub_powergating_by_smu)(struct pp_hwmgr *hwmgr); + int (*powergate_mmhub)(struct pp_hwmgr *hwmgr); int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr); }; diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h index 2f8a3b983cce..b6ffd08784e7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h +++ b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h @@ -412,10 +412,10 @@ typedef struct { QuadraticInt_t ReservedEquation2; QuadraticInt_t ReservedEquation3; - uint16_t MinVoltageUlvGfx; - uint16_t MinVoltageUlvSoc; + uint16_t MinVoltageUlvGfx; + uint16_t MinVoltageUlvSoc; - uint32_t Reserved[14]; + uint32_t Reserved[14]; @@ -483,9 +483,9 @@ typedef struct { uint8_t padding8_4; - uint8_t PllGfxclkSpreadEnabled; - uint8_t PllGfxclkSpreadPercent; - uint16_t PllGfxclkSpreadFreq; + uint8_t PllGfxclkSpreadEnabled; + uint8_t PllGfxclkSpreadPercent; + uint16_t PllGfxclkSpreadFreq; uint8_t UclkSpreadEnabled; uint8_t UclkSpreadPercent; @@ -495,11 +495,14 @@ typedef struct { uint8_t SocclkSpreadPercent; uint16_t SocclkSpreadFreq; - uint8_t AcgGfxclkSpreadEnabled; - uint8_t AcgGfxclkSpreadPercent; - uint16_t AcgGfxclkSpreadFreq; + uint8_t AcgGfxclkSpreadEnabled; + uint8_t AcgGfxclkSpreadPercent; + uint16_t AcgGfxclkSpreadFreq; - uint32_t BoardReserved[10]; + uint8_t Vr2_I2C_address; + uint8_t padding_vr2[3]; + + uint32_t BoardReserved[9]; uint32_t MmHubPadding[7]; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 4db9c515b74f..896e42a34895 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -326,64 +326,6 @@ int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) } EXPORT_SYMBOL(drm_legacy_pci_init); -int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) -{ - struct pci_dev *root; - u32 lnkcap, lnkcap2; - - *mask = 0; - if (!dev->pdev) - return -EINVAL; - - root = dev->pdev->bus->self; - - /* we've been informed via and serverworks don't make the cut */ - if (root->vendor == PCI_VENDOR_ID_VIA || - root->vendor == PCI_VENDOR_ID_SERVERWORKS) - return -EINVAL; - - pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); - pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2); - - if (lnkcap2) { /* PCIe r3.0-compliant */ - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) - *mask |= DRM_PCIE_SPEED_25; - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) - *mask |= DRM_PCIE_SPEED_50; - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) - *mask |= DRM_PCIE_SPEED_80; - } else { /* pre-r3.0 */ - if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB) - *mask |= DRM_PCIE_SPEED_25; - if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB) - *mask |= (DRM_PCIE_SPEED_25 | DRM_PCIE_SPEED_50); - } - - DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", root->vendor, root->device, lnkcap, lnkcap2); - return 0; -} -EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask); - -int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw) -{ - struct pci_dev *root; - u32 lnkcap; - - *mlw = 0; - if (!dev->pdev) - return -EINVAL; - - root = dev->pdev->bus->self; - - pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); - - *mlw = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4; - - DRM_INFO("probing mlw for device %x:%x = %x\n", root->vendor, root->device, lnkcap); - return 0; -} -EXPORT_SYMBOL(drm_pcie_get_max_link_width); - #else void drm_pci_agp_destroy(struct drm_device *dev) {} diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index e5013a999147..45bfdf4cc107 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -78,8 +78,8 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) gpu->lastctx = NULL; mutex_unlock(&gpu->lock); - drm_sched_entity_fini(&gpu->sched, - &ctx->sched_entity[i]); + drm_sched_entity_destroy(&gpu->sched, + &ctx->sched_entity[i]); } } diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index b9302c918271..d587779a80b4 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -5676,19 +5676,29 @@ int ci_dpm_init(struct radeon_device *rdev) u16 data_offset, size; u8 frev, crev; struct ci_power_info *pi; + enum pci_bus_speed speed_cap; + struct pci_dev *root = rdev->pdev->bus->self; int ret; - u32 mask; pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL); if (pi == NULL) return -ENOMEM; rdev->pm.dpm.priv = pi; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) { pi->sys_pcie_mask = 0; - else - pi->sys_pcie_mask = mask; + } else { + if (speed_cap == PCIE_SPEED_8_0GT) + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50 | + RADEON_PCIE_SPEED_80; + else if (speed_cap == PCIE_SPEED_5_0GT) + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50; + else + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25; + } pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; pi->pcie_gen_performance.max = RADEON_PCIE_GEN1; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 7c73bc7e2f85..ebce4601a305 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -9499,9 +9499,10 @@ int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) static void cik_pcie_gen3_enable(struct radeon_device *rdev) { struct pci_dev *root = rdev->pdev->bus->self; + enum pci_bus_speed speed_cap; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(rdev->pdev->bus)) @@ -9516,23 +9517,24 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) if (!(rdev->flags & RADEON_IS_PCIE)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) return; - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if ((speed_cap != PCIE_SPEED_8_0GT) && + (speed_cap != PCIE_SPEED_5_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (speed_cap == PCIE_SPEED_5_0GT) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -9548,7 +9550,7 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { /* re-try equalization if gen3 is not already enabled */ if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; @@ -9636,9 +9638,9 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (speed_cap == PCIE_SPEED_8_0GT) tmp16 |= 3; /* gen3 */ - else if (mask & DRM_PCIE_SPEED_50) + else if (speed_cap == PCIE_SPEED_5_0GT) tmp16 |= 2; /* gen2 */ else tmp16 |= 1; /* gen1 */ diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 73d4c5348116..5e044c98fca2 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -1327,9 +1327,9 @@ enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, case RADEON_PCIE_GEN3: return RADEON_PCIE_GEN3; default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3)) + if ((sys_mask & RADEON_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3)) return RADEON_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2)) + else if ((sys_mask & RADEON_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2)) return RADEON_PCIE_GEN2; else return RADEON_PCIE_GEN1; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4a2eb409aacc..1a6f6edb3515 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1653,6 +1653,10 @@ struct radeon_pm { struct radeon_dpm dpm; }; +#define RADEON_PCIE_SPEED_25 1 +#define RADEON_PCIE_SPEED_50 2 +#define RADEON_PCIE_SPEED_80 4 + int radeon_pm_get_type_index(struct radeon_device *rdev, enum radeon_pm_state_type ps_type, int instance); diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 48f4b273e316..0c7f228db6e3 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright 2009 VMware, Inc. * diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1907c950d76f..85c604d29235 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -7082,9 +7082,10 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) static void si_pcie_gen3_enable(struct radeon_device *rdev) { struct pci_dev *root = rdev->pdev->bus->self; + enum pci_bus_speed speed_cap; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(rdev->pdev->bus)) @@ -7099,23 +7100,24 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) if (!(rdev->flags & RADEON_IS_PCIE)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) return; - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if ((speed_cap != PCIE_SPEED_8_0GT) && + (speed_cap != PCIE_SPEED_5_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (speed_cap == PCIE_SPEED_5_0GT) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -7131,7 +7133,7 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { /* re-try equalization if gen3 is not already enabled */ if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; @@ -7219,9 +7221,9 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (speed_cap == PCIE_SPEED_8_0GT) tmp16 |= 3; /* gen3 */ - else if (mask & DRM_PCIE_SPEED_50) + else if (speed_cap == PCIE_SPEED_5_0GT) tmp16 |= 2; /* gen2 */ else tmp16 |= 1; /* gen1 */ diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index fea88078cf8e..8fb60b3af015 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6899,8 +6899,9 @@ int si_dpm_init(struct radeon_device *rdev) struct ni_power_info *ni_pi; struct si_power_info *si_pi; struct atom_clock_dividers dividers; + enum pci_bus_speed speed_cap; + struct pci_dev *root = rdev->pdev->bus->self; int ret; - u32 mask; si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); if (si_pi == NULL) @@ -6910,11 +6911,20 @@ int si_dpm_init(struct radeon_device *rdev) eg_pi = &ni_pi->eg; pi = &eg_pi->rv7xx; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) { si_pi->sys_pcie_mask = 0; - else - si_pi->sys_pcie_mask = mask; + } else { + if (speed_cap == PCIE_SPEED_8_0GT) + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50 | + RADEON_PCIE_SPEED_80; + else if (speed_cap == PCIE_SPEED_5_0GT) + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50; + else + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25; + } si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(rdev); diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 6a316701da73..7d2560699b84 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -256,7 +256,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, /** - * drm_sched_entity_do_release - Destroy a context entity + * drm_sched_entity_flush - Flush a context entity * * @sched: scheduler instance * @entity: scheduler entity @@ -267,7 +267,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, * * Returns the remaining time in jiffies left from the input timeout */ -long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, +long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, long timeout) { long ret = timeout; @@ -294,7 +294,7 @@ long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, return ret; } -EXPORT_SYMBOL(drm_sched_entity_do_release); +EXPORT_SYMBOL(drm_sched_entity_flush); /** * drm_sched_entity_cleanup - Destroy a context entity @@ -306,7 +306,7 @@ EXPORT_SYMBOL(drm_sched_entity_do_release); * entity and signals all jobs with an error code if the process was killed. * */ -void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, +void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { @@ -357,7 +357,7 @@ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, dma_fence_put(entity->last_scheduled); entity->last_scheduled = NULL; } -EXPORT_SYMBOL(drm_sched_entity_cleanup); +EXPORT_SYMBOL(drm_sched_entity_fini); /** * drm_sched_entity_fini - Destroy a context entity @@ -367,13 +367,13 @@ EXPORT_SYMBOL(drm_sched_entity_cleanup); * * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() */ -void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, +void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - drm_sched_entity_do_release(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); - drm_sched_entity_cleanup(sched, entity); + drm_sched_entity_flush(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); + drm_sched_entity_fini(sched, entity); } -EXPORT_SYMBOL(drm_sched_entity_fini); +EXPORT_SYMBOL(drm_sched_entity_destroy); static void drm_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) { diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index b8a5e4ed22e6..0fb300d41a09 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -378,7 +378,7 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev) if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); - ret = -ENXIO; + ret = -EPROBE_DEFER; goto init_failed; } diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index cdb582043b4f..567f7d46d912 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -151,7 +151,7 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) enum v3d_queue q; for (q = 0; q < V3D_MAX_QUEUES; q++) { - drm_sched_entity_fini(&v3d->queue[q].sched, + drm_sched_entity_destroy(&v3d->queue[q].sched, &v3d_priv->sched_entity[q]); } diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 794cc9d5c9b0..09b2aa08363e 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ - vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ + vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ - vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ + vmwgfx_fence.o vmwgfx_bo.o vmwgfx_scrn.o vmwgfx_context.o \ vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h index 3bf75978e155..9cbba0e8ce6a 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h @@ -47,10 +47,10 @@ * the SVGA3D protocol and remain reserved; they should not be used in the * future. * - * IDs between 1040 and 1999 (inclusive) are available for use by the + * IDs between 1040 and 2999 (inclusive) are available for use by the * current SVGA3D protocol. * - * FIFO clients other than SVGA3D should stay below 1000, or at 2000 + * FIFO clients other than SVGA3D should stay below 1000, or at 3000 * and up. */ @@ -90,19 +90,19 @@ typedef enum { SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN = 1069, SVGA_3D_CMD_SURFACE_DEFINE_V2 = 1070, SVGA_3D_CMD_GENERATE_MIPMAPS = 1071, - SVGA_3D_CMD_VIDEO_CREATE_DECODER = 1072, - SVGA_3D_CMD_VIDEO_DESTROY_DECODER = 1073, - SVGA_3D_CMD_VIDEO_CREATE_PROCESSOR = 1074, - SVGA_3D_CMD_VIDEO_DESTROY_PROCESSOR = 1075, - SVGA_3D_CMD_VIDEO_DECODE_START_FRAME = 1076, - SVGA_3D_CMD_VIDEO_DECODE_RENDER = 1077, - SVGA_3D_CMD_VIDEO_DECODE_END_FRAME = 1078, - SVGA_3D_CMD_VIDEO_PROCESS_FRAME = 1079, + SVGA_3D_CMD_DEAD4 = 1072, + SVGA_3D_CMD_DEAD5 = 1073, + SVGA_3D_CMD_DEAD6 = 1074, + SVGA_3D_CMD_DEAD7 = 1075, + SVGA_3D_CMD_DEAD8 = 1076, + SVGA_3D_CMD_DEAD9 = 1077, + SVGA_3D_CMD_DEAD10 = 1078, + SVGA_3D_CMD_DEAD11 = 1079, SVGA_3D_CMD_ACTIVATE_SURFACE = 1080, SVGA_3D_CMD_DEACTIVATE_SURFACE = 1081, SVGA_3D_CMD_SCREEN_DMA = 1082, - SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE = 1083, - SVGA_3D_CMD_OPEN_CONTEXT_SURFACE = 1084, + SVGA_3D_CMD_DEAD1 = 1083, + SVGA_3D_CMD_DEAD2 = 1084, SVGA_3D_CMD_LOGICOPS_BITBLT = 1085, SVGA_3D_CMD_LOGICOPS_TRANSBLT = 1086, @@ -218,7 +218,7 @@ typedef enum { SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW = 1177, SVGA_3D_CMD_DX_PRED_COPY_REGION = 1178, SVGA_3D_CMD_DX_PRED_COPY = 1179, - SVGA_3D_CMD_DX_STRETCHBLT = 1180, + SVGA_3D_CMD_DX_PRESENTBLT = 1180, SVGA_3D_CMD_DX_GENMIPS = 1181, SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE = 1182, SVGA_3D_CMD_DX_READBACK_SUBRESOURCE = 1183, @@ -255,7 +255,7 @@ typedef enum { SVGA_3D_CMD_DX_READBACK_ALL_QUERY = 1214, SVGA_3D_CMD_DX_PRED_TRANSFER_FROM_BUFFER = 1215, SVGA_3D_CMD_DX_MOB_FENCE_64 = 1216, - SVGA_3D_CMD_DX_BIND_SHADER_ON_CONTEXT = 1217, + SVGA_3D_CMD_DX_BIND_ALL_SHADER = 1217, SVGA_3D_CMD_DX_HINT = 1218, SVGA_3D_CMD_DX_BUFFER_UPDATE = 1219, SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET = 1220, @@ -263,17 +263,47 @@ typedef enum { SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET = 1222, /* - * Reserve some IDs to be used for the DX11 shader types. + * Reserve some IDs to be used for the SM5 shader types. */ SVGA_3D_CMD_DX_RESERVED1 = 1223, SVGA_3D_CMD_DX_RESERVED2 = 1224, SVGA_3D_CMD_DX_RESERVED3 = 1225, - SVGA_3D_CMD_DX_MAX = 1226, - SVGA_3D_CMD_MAX = 1226, + SVGA_3D_CMD_DX_COND_BIND_ALL_SHADER = 1226, + SVGA_3D_CMD_DX_MAX = 1227, + + SVGA_3D_CMD_SCREEN_COPY = 1227, + + /* + * Reserve some IDs to be used for video. + */ + SVGA_3D_CMD_VIDEO_RESERVED1 = 1228, + SVGA_3D_CMD_VIDEO_RESERVED2 = 1229, + SVGA_3D_CMD_VIDEO_RESERVED3 = 1230, + SVGA_3D_CMD_VIDEO_RESERVED4 = 1231, + SVGA_3D_CMD_VIDEO_RESERVED5 = 1232, + SVGA_3D_CMD_VIDEO_RESERVED6 = 1233, + SVGA_3D_CMD_VIDEO_RESERVED7 = 1234, + SVGA_3D_CMD_VIDEO_RESERVED8 = 1235, + + SVGA_3D_CMD_GROW_OTABLE = 1236, + SVGA_3D_CMD_DX_GROW_COTABLE = 1237, + SVGA_3D_CMD_INTRA_SURFACE_COPY = 1238, + + SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 = 1239, + + SVGA_3D_CMD_DX_RESOLVE_COPY = 1240, + SVGA_3D_CMD_DX_PRED_RESOLVE_COPY = 1241, + SVGA_3D_CMD_DX_PRED_CONVERT_REGION = 1242, + SVGA_3D_CMD_DX_PRED_CONVERT = 1243, + SVGA_3D_CMD_WHOLE_SURFACE_COPY = 1244, + + SVGA_3D_CMD_MAX = 1245, SVGA_3D_CMD_FUTURE_MAX = 3000 } SVGAFifo3dCmdId; +#define SVGA_NUM_3D_CMD (SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE) + /* * FIFO command format definitions: */ @@ -302,7 +332,7 @@ typedef #include "vmware_pack_begin.h" struct { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; /* * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace @@ -328,7 +358,7 @@ typedef #include "vmware_pack_begin.h" struct { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; /* * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace @@ -460,6 +490,28 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdSurfaceCopy; /* SVGA_3D_CMD_SURFACE_COPY */ +/* + * Perform a surface copy within the same image. + * The src/dest boxes are allowed to overlap. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceImageId surface; + SVGA3dCopyBox box; +} +#include "vmware_pack_end.h" +SVGA3dCmdIntraSurfaceCopy; /* SVGA_3D_CMD_INTRA_SURFACE_COPY */ + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 srcSid; + uint32 destSid; +} +#include "vmware_pack_end.h" +SVGA3dCmdWholeSurfaceCopy; /* SVGA_3D_CMD_WHOLE_SURFACE_COPY */ + typedef #include "vmware_pack_begin.h" struct { @@ -773,6 +825,17 @@ struct { #include "vmware_pack_end.h" SVGA3dVertexElement; +/* + * Should the vertex element respect the stream value? The high bit of the + * stream should be set to indicate that the stream should be respected. If + * the high bit is not set, the stream will be ignored and replaced by the index + * of the position of the currently considered vertex element. + * + * All guests should set this bit and correctly specify the stream going + * forward. + */ +#define SVGA3D_VERTEX_ELEMENT_RESPECT_STREAM (1 << 7) + typedef #include "vmware_pack_begin.h" struct { @@ -1103,8 +1166,6 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdGenerateMipmaps; /* SVGA_3D_CMD_GENERATE_MIPMAPS */ - - typedef #include "vmware_pack_begin.h" struct { @@ -1148,38 +1209,6 @@ struct SVGA3dCmdScreenDMA { SVGA3dCmdScreenDMA; /* SVGA_3D_CMD_SCREEN_DMA */ /* - * Set Unity Surface Cookie - * - * Associates the supplied cookie with the surface id for use with - * Unity. This cookie is a hint from guest to host, there is no way - * for the guest to readback the cookie and the host is free to drop - * the cookie association at will. The default value for the cookie - * on all surfaces is 0. - */ - -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdSetUnitySurfaceCookie { - uint32 sid; - uint64 cookie; -} -#include "vmware_pack_end.h" -SVGA3dCmdSetUnitySurfaceCookie; /* SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE */ - -/* - * Open a context-specific surface in a non-context-specific manner. - */ - -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdOpenContextSurface { - uint32 sid; -} -#include "vmware_pack_end.h" -SVGA3dCmdOpenContextSurface; /* SVGA_3D_CMD_OPEN_CONTEXT_SURFACE */ - - -/* * Logic ops */ @@ -1325,7 +1354,7 @@ typedef #include "vmware_pack_begin.h" struct { SVGA3dSurfaceFormat format; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surface1Flags; uint32 numMipLevels; uint32 multisampleCount; SVGA3dTextureFilter autogenFilter; @@ -1333,7 +1362,11 @@ struct { SVGAMobId mobid; uint32 arraySize; uint32 mobPitch; - uint32 pad[5]; + SVGA3dSurface2Flags surface2Flags; + uint8 multisamplePattern; + uint8 qualityLevel; + uint8 pad0[2]; + uint32 pad1[3]; } #include "vmware_pack_end.h" SVGAOTableSurfaceEntry; @@ -1361,7 +1394,8 @@ struct { SVGAOTableShaderEntry; #define SVGA3D_OTABLE_SHADER_ENTRY_SIZE (sizeof(SVGAOTableShaderEntry)) -#define SVGA_STFLAG_PRIMARY (1 << 0) +#define SVGA_STFLAG_PRIMARY (1 << 0) +#define SVGA_STFLAG_RESERVED (1 << 1) /* Added with cap SVGA_CAP_HP_CMD_QUEUE */ typedef uint32 SVGAScreenTargetFlags; typedef @@ -1529,6 +1563,25 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */ +/* + * Guests using SVGA_3D_CMD_GROW_OTABLE are promising that + * the new OTable contains the same contents as the old one, except possibly + * for some new invalid entries at the end. + * + * (Otherwise, guests should use one of the SetOTableBase commands.) + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGAOTableType type; + PPN64 baseAddress; + uint32 sizeInBytes; + uint32 validSizeInBytes; + SVGAMobFormat ptDepth; +} +#include "vmware_pack_end.h" +SVGA3dCmdGrowOTable; /* SVGA_3D_CMD_GROW_OTABLE */ + typedef #include "vmware_pack_begin.h" struct { @@ -1616,7 +1669,7 @@ typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDefineGBSurface { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; uint32 numMipLevels; uint32 multisampleCount; @@ -1627,6 +1680,45 @@ struct SVGA3dCmdDefineGBSurface { SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ /* + * Defines a guest-backed surface, adding the arraySize field. + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDefineGBSurface_v2 { + uint32 sid; + SVGA3dSurface1Flags surfaceFlags; + SVGA3dSurfaceFormat format; + uint32 numMipLevels; + uint32 multisampleCount; + SVGA3dTextureFilter autogenFilter; + SVGA3dSize size; + uint32 arraySize; + uint32 pad; +} +#include "vmware_pack_end.h" +SVGA3dCmdDefineGBSurface_v2; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 */ + +/* + * Defines a guest-backed surface, adding the larger flags. + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDefineGBSurface_v3 { + uint32 sid; + SVGA3dSurfaceAllFlags surfaceFlags; + SVGA3dSurfaceFormat format; + uint32 numMipLevels; + uint32 multisampleCount; + SVGA3dMSPattern multisamplePattern; + SVGA3dMSQualityLevel qualityLevel; + SVGA3dTextureFilter autogenFilter; + SVGA3dSize size; + uint32 arraySize; +} +#include "vmware_pack_end.h" +SVGA3dCmdDefineGBSurface_v3; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 */ + +/* * Destroy a guest-backed surface. */ @@ -1673,7 +1765,7 @@ SVGA3dCmdBindGBSurfaceWithPitch; /* SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH */ typedef #include "vmware_pack_begin.h" -struct{ +struct SVGA3dCmdCondBindGBSurface { uint32 sid; SVGAMobId testMobid; SVGAMobId mobid; @@ -2067,6 +2159,26 @@ struct { uint32 mobOffset; } #include "vmware_pack_end.h" -SVGA3dCmdGBMobFence; /* SVGA_3D_CMD_GB_MOB_FENCE*/ +SVGA3dCmdGBMobFence; /* SVGA_3D_CMD_GB_MOB_FENCE */ + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 stid; + SVGA3dSurfaceImageId dest; + + uint32 statusMobId; + uint32 statusMobOffset; + + /* Reserved fields */ + uint32 mustBeInvalidId; + uint32 mustBeZero; +} +#include "vmware_pack_end.h" +SVGA3dCmdScreenCopy; /* SVGA_3D_CMD_SCREEN_COPY */ + +#define SVGA_SCREEN_COPY_STATUS_FAILURE 0x00 +#define SVGA_SCREEN_COPY_STATUS_SUCCESS 0x01 +#define SVGA_SCREEN_COPY_STATUS_INVALID 0xFFFFFFFF #endif /* _SVGA3D_CMD_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h index e1c0d94cc1e9..f256560049bf 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h @@ -230,9 +230,9 @@ typedef enum { SVGA3D_DEVCAP_DEAD2 = 94, /* - * Does the device support the DX commands? + * Does the device support DXContexts? */ - SVGA3D_DEVCAP_DX = 95, + SVGA3D_DEVCAP_DXCONTEXT = 95, /* * What is the maximum size of a texture array? @@ -242,21 +242,47 @@ typedef enum { SVGA3D_DEVCAP_MAX_TEXTURE_ARRAY_SIZE = 96, /* - * What is the maximum number of vertex buffers that can - * be used in the DXContext inputAssembly? + * What is the maximum number of vertex buffers or vertex input registers + * that can be expected to work correctly with a DXContext? + * + * The guest is allowed to set up to SVGA3D_DX_MAX_VERTEXBUFFERS, but + * anything in excess of this cap is not guaranteed to render correctly. + * + * Similarly, the guest can set up to SVGA3D_DX_MAX_VERTEXINPUTREGISTERS + * input registers without the SVGA3D_DEVCAP_SM4_1 cap, or + * SVGA3D_DX_SM41_MAX_VERTEXINPUTREGISTERS with the SVGA3D_DEVCAP_SM4_1, + * but only the registers up to this cap value are guaranteed to render + * correctly. + * + * If guest-drivers are able to expose a lower-limit, it's recommended + * that they clamp to this value. Otherwise, the host will make a + * best-effort on case-by-case basis if guests exceed this. */ SVGA3D_DEVCAP_DX_MAX_VERTEXBUFFERS = 97, /* - * What is the maximum number of constant buffers - * that can be expected to work correctly with a - * DX context? + * What is the maximum number of constant buffers that can be expected to + * work correctly with a DX context? + * + * The guest is allowed to set up to SVGA3D_DX_MAX_CONSTBUFFERS, but + * anything in excess of this cap is not guaranteed to render correctly. + * + * If guest-drivers are able to expose a lower-limit, it's recommended + * that they clamp to this value. Otherwise, the host will make a + * best-effort on case-by-case basis if guests exceed this. */ SVGA3D_DEVCAP_DX_MAX_CONSTANT_BUFFERS = 98, /* * Does the device support provoking vertex control? - * If zero, the first vertex will always be the provoking vertex. + * + * If this cap is present, the provokingVertexLast field in the + * rasterizer state is enabled. (Guests can then set it to FALSE, + * meaning that the first vertex is the provoking vertex, or TRUE, + * meaning that the last verteix is the provoking vertex.) + * + * If this cap is FALSE, then guests should set the provokingVertexLast + * to FALSE, otherwise rendering behavior is undefined. */ SVGA3D_DEVCAP_DX_PROVOKING_VERTEX = 99, @@ -282,7 +308,7 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_BUMPU8V8 = 119, SVGA3D_DEVCAP_DXFMT_BUMPL6V5U5 = 120, SVGA3D_DEVCAP_DXFMT_BUMPX8L8V8U8 = 121, - SVGA3D_DEVCAP_DXFMT_BUMPL8V8U8 = 122, + SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD1 = 122, SVGA3D_DEVCAP_DXFMT_ARGB_S10E5 = 123, SVGA3D_DEVCAP_DXFMT_ARGB_S23E8 = 124, SVGA3D_DEVCAP_DXFMT_A2R10G10B10 = 125, @@ -321,8 +347,8 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_R32G32_SINT = 158, SVGA3D_DEVCAP_DXFMT_R32G8X24_TYPELESS = 159, SVGA3D_DEVCAP_DXFMT_D32_FLOAT_S8X24_UINT = 160, - SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24_TYPELESS = 161, - SVGA3D_DEVCAP_DXFMT_X32_TYPELESS_G8X24_UINT = 162, + SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24 = 161, + SVGA3D_DEVCAP_DXFMT_X32_G8X24_UINT = 162, SVGA3D_DEVCAP_DXFMT_R10G10B10A2_TYPELESS = 163, SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UINT = 164, SVGA3D_DEVCAP_DXFMT_R11G11B10_FLOAT = 165, @@ -340,8 +366,8 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_R32_SINT = 177, SVGA3D_DEVCAP_DXFMT_R24G8_TYPELESS = 178, SVGA3D_DEVCAP_DXFMT_D24_UNORM_S8_UINT = 179, - SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8_TYPELESS = 180, - SVGA3D_DEVCAP_DXFMT_X24_TYPELESS_G8_UINT = 181, + SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8 = 180, + SVGA3D_DEVCAP_DXFMT_X24_G8_UINT = 181, SVGA3D_DEVCAP_DXFMT_R8G8_TYPELESS = 182, SVGA3D_DEVCAP_DXFMT_R8G8_UNORM = 183, SVGA3D_DEVCAP_DXFMT_R8G8_UINT = 184, @@ -405,6 +431,17 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_BC4_UNORM = 242, SVGA3D_DEVCAP_DXFMT_BC5_UNORM = 243, + /* + * Advertises shaderModel 4.1 support, independent blend-states, + * cube-map arrays, and a higher vertex input registers limit. + * + * (See documentation on SVGA3D_DEVCAP_DX_MAX_VERTEXBUFFERS.) + */ + SVGA3D_DEVCAP_SM41 = 244, + + SVGA3D_DEVCAP_MULTISAMPLE_2X = 245, + SVGA3D_DEVCAP_MULTISAMPLE_4X = 246, + SVGA3D_DEVCAP_MAX /* This must be the last index. */ } SVGA3dDevCapIndex; @@ -420,9 +457,7 @@ typedef enum { * MIPS: Does the format support mip levels? * ARRAY: Does the format support texture arrays? * VOLUME: Does the format support having volume? - * MULTISAMPLE_2: Does the format support 2x multisample? - * MULTISAMPLE_4: Does the format support 4x multisample? - * MULTISAMPLE_8: Does the format support 8x multisample? + * MULTISAMPLE: Does the format support multisample? */ #define SVGA3D_DXFMT_SUPPORTED (1 << 0) #define SVGA3D_DXFMT_SHADER_SAMPLE (1 << 1) @@ -433,20 +468,8 @@ typedef enum { #define SVGA3D_DXFMT_ARRAY (1 << 6) #define SVGA3D_DXFMT_VOLUME (1 << 7) #define SVGA3D_DXFMT_DX_VERTEX_BUFFER (1 << 8) -#define SVGADX_DXFMT_MULTISAMPLE_2 (1 << 9) -#define SVGADX_DXFMT_MULTISAMPLE_4 (1 << 10) -#define SVGADX_DXFMT_MULTISAMPLE_8 (1 << 11) -#define SVGADX_DXFMT_MAX (1 << 12) - -/* - * Convenience mask for any multisample capability. - * - * The multisample bits imply both load and render capability. - */ -#define SVGA3D_DXFMT_MULTISAMPLE ( \ - SVGADX_DXFMT_MULTISAMPLE_2 | \ - SVGADX_DXFMT_MULTISAMPLE_4 | \ - SVGADX_DXFMT_MULTISAMPLE_8 ) +#define SVGA3D_DXFMT_MULTISAMPLE (1 << 9) +#define SVGA3D_DXFMT_MAX (1 << 10) typedef union { Bool b; diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h index f4606d04556b..7a49c94df221 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h @@ -57,6 +57,16 @@ typedef uint32 SVGA3dInputClassification; #define SVGA3D_RESOURCE_TYPE_MAX 7 typedef uint32 SVGA3dResourceType; +#define SVGA3D_COLOR_WRITE_ENABLE_RED (1 << 0) +#define SVGA3D_COLOR_WRITE_ENABLE_GREEN (1 << 1) +#define SVGA3D_COLOR_WRITE_ENABLE_BLUE (1 << 2) +#define SVGA3D_COLOR_WRITE_ENABLE_ALPHA (1 << 3) +#define SVGA3D_COLOR_WRITE_ENABLE_ALL (SVGA3D_COLOR_WRITE_ENABLE_RED | \ + SVGA3D_COLOR_WRITE_ENABLE_GREEN | \ + SVGA3D_COLOR_WRITE_ENABLE_BLUE | \ + SVGA3D_COLOR_WRITE_ENABLE_ALPHA) +typedef uint8 SVGA3dColorWriteEnable; + #define SVGA3D_DEPTH_WRITE_MASK_ZERO 0 #define SVGA3D_DEPTH_WRITE_MASK_ALL 1 typedef uint8 SVGA3dDepthWriteMask; @@ -89,17 +99,28 @@ typedef uint8 SVGA3dCullMode; #define SVGA3D_COMPARISON_MAX 9 typedef uint8 SVGA3dComparisonFunc; +/* + * SVGA3D_MULTISAMPLE_RAST_DISABLE disables MSAA for all primitives. + * SVGA3D_MULTISAMPLE_RAST_DISABLE_LINE, which is supported in SM41, + * disables MSAA for lines only. + */ +#define SVGA3D_MULTISAMPLE_RAST_DISABLE 0 +#define SVGA3D_MULTISAMPLE_RAST_ENABLE 1 +#define SVGA3D_MULTISAMPLE_RAST_DX_MAX 1 +#define SVGA3D_MULTISAMPLE_RAST_DISABLE_LINE 2 +#define SVGA3D_MULTISAMPLE_RAST_MAX 2 +typedef uint8 SVGA3dMultisampleRastEnable; + #define SVGA3D_DX_MAX_VERTEXBUFFERS 32 +#define SVGA3D_DX_MAX_VERTEXINPUTREGISTERS 16 +#define SVGA3D_DX_SM41_MAX_VERTEXINPUTREGISTERS 32 #define SVGA3D_DX_MAX_SOTARGETS 4 #define SVGA3D_DX_MAX_SRVIEWS 128 #define SVGA3D_DX_MAX_CONSTBUFFERS 16 #define SVGA3D_DX_MAX_SAMPLERS 16 -/* Id limits */ -static const uint32 SVGA3dBlendObjectCountPerContext = 4096; -static const uint32 SVGA3dDepthStencilObjectCountPerContext = 4096; +#define SVGA3D_DX_MAX_CONSTBUF_BINDING_SIZE (4096 * 4 * (uint32)sizeof(uint32)) -typedef uint32 SVGA3dSurfaceId; typedef uint32 SVGA3dShaderResourceViewId; typedef uint32 SVGA3dRenderTargetViewId; typedef uint32 SVGA3dDepthStencilViewId; @@ -195,20 +216,6 @@ SVGA3dCmdDXInvalidateContext; /* SVGA_3D_CMD_DX_INVALIDATE_CONTEXT */ typedef #include "vmware_pack_begin.h" -struct SVGA3dReplyFormatData { - uint32 formatSupport; - uint32 msaa2xQualityLevels:5; - uint32 msaa4xQualityLevels:5; - uint32 msaa8xQualityLevels:5; - uint32 msaa16xQualityLevels:5; - uint32 msaa32xQualityLevels:5; - uint32 pad:7; -} -#include "vmware_pack_end.h" -SVGA3dReplyFormatData; - -typedef -#include "vmware_pack_begin.h" struct SVGA3dCmdDXSetSingleConstantBuffer { uint32 slot; SVGA3dShaderType type; @@ -625,6 +632,28 @@ SVGA3dCmdDXPredCopy; /* SVGA_3D_CMD_DX_PRED_COPY */ typedef #include "vmware_pack_begin.h" +struct SVGA3dCmdDXPredConvertRegion { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dBox destBox; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dBox srcBox; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredConvertRegion; /* SVGA_3D_CMD_DX_PRED_CONVERT_REGION */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXPredConvert { + SVGA3dSurfaceId dstSid; + SVGA3dSurfaceId srcSid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredConvert; /* SVGA_3D_CMD_DX_PRED_CONVERT */ + +typedef +#include "vmware_pack_begin.h" struct SVGA3dCmdDXBufferCopy { SVGA3dSurfaceId dest; SVGA3dSurfaceId src; @@ -636,23 +665,57 @@ struct SVGA3dCmdDXBufferCopy { SVGA3dCmdDXBufferCopy; /* SVGA_3D_CMD_DX_BUFFER_COPY */ -typedef uint32 SVGA3dDXStretchBltMode; -#define SVGADX_STRETCHBLT_LINEAR (1 << 0) -#define SVGADX_STRETCHBLT_FORCE_SRC_SRGB (1 << 1) +/* + * Perform a surface copy between a multisample, and a non-multisampled + * surface. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dSurfaceFormat copyFormat; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXResolveCopy; /* SVGA_3D_CMD_DX_RESOLVE_COPY */ + +/* + * Perform a predicated surface copy between a multisample, and a + * non-multisampled surface. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dSurfaceFormat copyFormat; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredResolveCopy; /* SVGA_3D_CMD_DX_PRED_RESOLVE_COPY */ + +typedef uint32 SVGA3dDXPresentBltMode; +#define SVGADX_PRESENTBLT_LINEAR (1 << 0) +#define SVGADX_PRESENTBLT_FORCE_SRC_SRGB (1 << 1) +#define SVGADX_PRESENTBLT_FORCE_SRC_XRBIAS (1 << 2) +#define SVGADX_PRESENTBLT_MODE_MAX (1 << 3) typedef #include "vmware_pack_begin.h" -struct SVGA3dCmdDXStretchBlt { +struct SVGA3dCmdDXPresentBlt { SVGA3dSurfaceId srcSid; uint32 srcSubResource; SVGA3dSurfaceId dstSid; uint32 destSubResource; SVGA3dBox boxSrc; SVGA3dBox boxDest; - SVGA3dDXStretchBltMode mode; + SVGA3dDXPresentBltMode mode; } #include "vmware_pack_end.h" -SVGA3dCmdDXStretchBlt; /* SVGA_3D_CMD_DX_STRETCHBLT */ +SVGA3dCmdDXPresentBlt; /* SVGA_3D_CMD_DX_PRESENTBLT*/ typedef #include "vmware_pack_begin.h" @@ -663,26 +726,6 @@ struct SVGA3dCmdDXGenMips { SVGA3dCmdDXGenMips; /* SVGA_3D_CMD_DX_GENMIPS */ /* - * Defines a resource/DX surface. Resources share the surfaceId namespace. - * - */ -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdDefineGBSurface_v2 { - uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; - SVGA3dSurfaceFormat format; - uint32 numMipLevels; - uint32 multisampleCount; - SVGA3dTextureFilter autogenFilter; - SVGA3dSize size; - uint32 arraySize; - uint32 pad; -} -#include "vmware_pack_end.h" -SVGA3dCmdDefineGBSurface_v2; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 */ - -/* * Update a sub-resource in a guest-backed resource. * (Inform the device that the guest-contents have been updated.) */ @@ -725,7 +768,8 @@ SVGA3dCmdDXInvalidateSubResource; /* SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE */ /* * Raw byte wise transfer from a buffer surface into another surface - * of the requested box. + * of the requested box. Supported if 3d is enabled and SVGA_CAP_DX + * is set. This command does not take a context. */ typedef #include "vmware_pack_begin.h" @@ -774,6 +818,93 @@ struct SVGA3dCmdDXSurfaceCopyAndReadback { SVGA3dCmdDXSurfaceCopyAndReadback; /* SVGA_3D_CMD_DX_SURFACE_COPY_AND_READBACK */ +/* + * SVGA_DX_HINT_NONE: Does nothing. + * + * SVGA_DX_HINT_PREFETCH_OBJECT: + * SVGA_DX_HINT_PREEVICT_OBJECT: + * Consumes a SVGAObjectRef, and hints that the host should consider + * fetching/evicting the specified object. + * + * An id of SVGA3D_INVALID_ID can be used if the guest isn't sure + * what object was affected. (For instance, if the guest knows that + * it is about to evict a DXShader, but doesn't know precisely which one, + * the device can still use this to help limit it's search, or track + * how many page-outs have happened.) + * + * SVGA_DX_HINT_PREFETCH_COBJECT: + * SVGA_DX_HINT_PREEVICT_COBJECT: + * Same as the above, except they consume an SVGACObjectRef. + */ +typedef uint32 SVGADXHintId; +#define SVGA_DX_HINT_NONE 0 +#define SVGA_DX_HINT_PREFETCH_OBJECT 1 +#define SVGA_DX_HINT_PREEVICT_OBJECT 2 +#define SVGA_DX_HINT_PREFETCH_COBJECT 3 +#define SVGA_DX_HINT_PREEVICT_COBJECT 4 +#define SVGA_DX_HINT_MAX 5 + +typedef +#include "vmware_pack_begin.h" +struct SVGAObjectRef { + SVGAOTableType type; + uint32 id; +} +#include "vmware_pack_end.h" +SVGAObjectRef; + +typedef +#include "vmware_pack_begin.h" +struct SVGACObjectRef { + SVGACOTableType type; + uint32 cid; + uint32 id; +} +#include "vmware_pack_end.h" +SVGACObjectRef; + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXHint { + SVGADXHintId hintId; + + /* + * Followed by variable sized data depending on the hintId. + */ +} +#include "vmware_pack_end.h" +SVGA3dCmdDXHint; +/* SVGA_3D_CMD_DX_HINT */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXBufferUpdate { + SVGA3dSurfaceId sid; + uint32 x; + uint32 width; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXBufferUpdate; +/* SVGA_3D_CMD_DX_BUFFER_UPDATE */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXSetConstantBufferOffset { + uint32 slot; + uint32 offsetInBytes; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXSetConstantBufferOffset; + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetVSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET */ + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetPSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_PS_CONSTANT_BUFFER_OFFSET */ + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetGSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET */ + typedef #include "vmware_pack_begin.h" @@ -790,7 +921,7 @@ struct { uint32 firstArraySlice; uint32 mipLevels; uint32 arraySize; - } tex; + } tex; /* 1d, 2d, 3d, cube */ struct { uint32 firstElement; uint32 numElements; @@ -845,6 +976,7 @@ struct SVGA3dRenderTargetViewDesc { struct { uint32 firstElement; uint32 numElements; + uint32 padding0; } buffer; struct { uint32 mipSlice; @@ -965,9 +1097,6 @@ SVGA3dInputElementDesc; typedef #include "vmware_pack_begin.h" struct { - /* - * XXX: How many of these can there be? - */ uint32 elid; uint32 numDescs; SVGA3dInputElementDesc desc[32]; @@ -1008,7 +1137,7 @@ struct SVGA3dDXBlendStatePerRT { uint8 srcBlendAlpha; uint8 destBlendAlpha; uint8 blendOpAlpha; - uint8 renderTargetWriteMask; + SVGA3dColorWriteEnable renderTargetWriteMask; uint8 logicOpEnable; uint8 logicOp; uint16 pad0; @@ -1126,7 +1255,7 @@ struct { float slopeScaledDepthBias; uint8 depthClipEnable; uint8 scissorEnable; - uint8 multisampleEnable; + SVGA3dMultisampleRastEnable multisampleEnable; uint8 antialiasedLineEnable; float lineWidth; uint8 lineStippleEnable; @@ -1153,7 +1282,7 @@ struct SVGA3dCmdDXDefineRasterizerState { float slopeScaledDepthBias; uint8 depthClipEnable; uint8 scissorEnable; - uint8 multisampleEnable; + SVGA3dMultisampleRastEnable multisampleEnable; uint8 antialiasedLineEnable; float lineWidth; uint8 lineStippleEnable; @@ -1223,21 +1352,6 @@ struct SVGA3dCmdDXDestroySamplerState { #include "vmware_pack_end.h" SVGA3dCmdDXDestroySamplerState; /* SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE */ -/* - */ -typedef -#include "vmware_pack_begin.h" -struct SVGA3dSignatureEntry { - uint8 systemValue; - uint8 reg; /* register is a reserved word */ - uint16 mask; - uint8 registerComponentType; - uint8 minPrecision; - uint16 pad0; -} -#include "vmware_pack_end.h" -SVGA3dSignatureEntry; - typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXDefineShader { @@ -1255,12 +1369,7 @@ struct SVGACOTableDXShaderEntry { uint32 sizeInBytes; uint32 offsetInBytes; SVGAMobId mobid; - uint32 numInputSignatureEntries; - uint32 numOutputSignatureEntries; - - uint32 numPatchConstantSignatureEntries; - - uint32 pad; + uint32 pad[4]; } #include "vmware_pack_end.h" SVGACOTableDXShaderEntry; @@ -1284,6 +1393,25 @@ struct SVGA3dCmdDXBindShader { #include "vmware_pack_end.h" SVGA3dCmdDXBindShader; /* SVGA_3D_CMD_DX_BIND_SHADER */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXBindAllShader { + uint32 cid; + SVGAMobId mobid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXBindAllShader; /* SVGA_3D_CMD_DX_BIND_ALL_SHADER */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXCondBindAllShader { + uint32 cid; + SVGAMobId testMobid; + SVGAMobId mobid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXCondBindAllShader; /* SVGA_3D_CMD_DX_COND_BIND_ALL_SHADER */ + /* * The maximum number of streamout decl's in each streamout entry. */ @@ -1357,7 +1485,6 @@ SVGA3dCmdDXMobFence64; /* SVGA_3D_CMD_DX_MOB_FENCE_64 */ * * This command allows the guest to bind a mob to a context-object table. */ - typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXSetCOTable { @@ -1369,6 +1496,26 @@ struct SVGA3dCmdDXSetCOTable { #include "vmware_pack_end.h" SVGA3dCmdDXSetCOTable; /* SVGA_3D_CMD_DX_SET_COTABLE */ +/* + * Guests using SVGA_3D_CMD_DX_GROW_COTABLE are promising that + * the new COTable contains the same contents as the old one, except possibly + * for some new invalid entries at the end. + * + * If there is an old cotable mob bound, it also has to still be valid. + * + * (Otherwise, guests should use the DXSetCOTableBase command.) + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXGrowCOTable { + uint32 cid; + uint32 mobid; + SVGACOTableType type; + uint32 validSizeInBytes; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXGrowCOTable; /* SVGA_3D_CMD_DX_GROW_COTABLE */ + typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXReadbackCOTable { @@ -1472,7 +1619,7 @@ struct SVGADXContextMobFormat { SVGA3dQueryId queryID[SVGA3D_MAX_QUERY]; SVGA3dCOTableData cotables[SVGA_COTABLE_MAX]; - uint32 pad7[381]; + uint32 pad7[380]; } #include "vmware_pack_end.h" SVGADXContextMobFormat; diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h index 8732490d45d5..b22a67f15660 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h @@ -63,7 +63,9 @@ * Maximum size in dwords of shader text the SVGA device will allow. * Currently 8 MB. */ -#define SVGA3D_MAX_SHADER_MEMORY (8 * 1024 * 1024 / sizeof(uint32)) +#define SVGA3D_MAX_SHADER_MEMORY_BYTES (8 * 1024 * 1024) +#define SVGA3D_MAX_SHADER_MEMORY (SVGA3D_MAX_SHADER_MEMORY_BYTES / \ + sizeof(uint32)) #define SVGA3D_MAX_CLIP_PLANES 6 diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h index b45e96309233..f2bfd3d80598 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h @@ -25,189 +25,355 @@ * **************************************************************************/ -#include <linux/kernel.h> - -#ifdef __KERNEL__ - -#include <drm/vmwgfx_drm.h> -#define surf_size_struct struct drm_vmw_size - -#else /* __KERNEL__ */ +/* + * svga3d_surfacedefs.h -- + * + * Surface definitions and inlineable utilities for SVGA3d. + */ -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0])) -#endif /* ARRAY_SIZE */ +#ifndef _SVGA3D_SURFACEDEFS_H_ +#define _SVGA3D_SURFACEDEFS_H_ -#define max_t(type, x, y) ((x) > (y) ? (x) : (y)) -#define surf_size_struct SVGA3dSize -#define u32 uint32 +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#include "includeCheck.h" -#endif /* __KERNEL__ */ +#include <linux/kernel.h> +#include <drm/vmwgfx_drm.h> #include "svga3d_reg.h" +#define surf_size_struct struct drm_vmw_size + /* - * enum svga3d_block_desc describes the active data channels in a block. - * - * There can be at-most four active channels in a block: - * 1. Red, bump W, luminance and depth are stored in the first channel. - * 2. Green, bump V and stencil are stored in the second channel. - * 3. Blue and bump U are stored in the third channel. - * 4. Alpha and bump Q are stored in the fourth channel. - * - * Block channels can be used to store compressed and buffer data: - * 1. For compressed formats, only the data channel is used and its size - * is equal to that of a singular block in the compression scheme. - * 2. For buffer formats, only the data channel is used and its size is - * exactly one byte in length. - * 3. In each case the bit depth represent the size of a singular block. - * - * Note: Compressed and IEEE formats do not use the bitMask structure. + * enum svga3d_block_desc - describes generic properties about formats. */ - enum svga3d_block_desc { - SVGA3DBLOCKDESC_NONE = 0, /* No channels are active */ - SVGA3DBLOCKDESC_BLUE = 1 << 0, /* Block with red channel - data */ - SVGA3DBLOCKDESC_U = 1 << 0, /* Block with bump U channel - data */ - SVGA3DBLOCKDESC_UV_VIDEO = 1 << 7, /* Block with alternating video - U and V */ - SVGA3DBLOCKDESC_GREEN = 1 << 1, /* Block with green channel - data */ - SVGA3DBLOCKDESC_V = 1 << 1, /* Block with bump V channel - data */ - SVGA3DBLOCKDESC_STENCIL = 1 << 1, /* Block with a stencil - channel */ - SVGA3DBLOCKDESC_RED = 1 << 2, /* Block with blue channel - data */ - SVGA3DBLOCKDESC_W = 1 << 2, /* Block with bump W channel - data */ - SVGA3DBLOCKDESC_LUMINANCE = 1 << 2, /* Block with luminance channel - data */ - SVGA3DBLOCKDESC_Y = 1 << 2, /* Block with video luminance - data */ - SVGA3DBLOCKDESC_DEPTH = 1 << 2, /* Block with depth channel */ - SVGA3DBLOCKDESC_ALPHA = 1 << 3, /* Block with an alpha - channel */ - SVGA3DBLOCKDESC_Q = 1 << 3, /* Block with bump Q channel - data */ - SVGA3DBLOCKDESC_BUFFER = 1 << 4, /* Block stores 1 byte of - data */ - SVGA3DBLOCKDESC_COMPRESSED = 1 << 5, /* Block stores n bytes of - data depending on the - compression method used */ - SVGA3DBLOCKDESC_IEEE_FP = 1 << 6, /* Block stores data in an IEEE - floating point - representation in - all channels */ - SVGA3DBLOCKDESC_PLANAR_YUV = 1 << 8, /* Three separate blocks store - data. */ - SVGA3DBLOCKDESC_U_VIDEO = 1 << 9, /* Block with U video data */ - SVGA3DBLOCKDESC_V_VIDEO = 1 << 10, /* Block with V video data */ - SVGA3DBLOCKDESC_EXP = 1 << 11, /* Shared exponent */ - SVGA3DBLOCKDESC_SRGB = 1 << 12, /* Data is in sRGB format */ - SVGA3DBLOCKDESC_2PLANAR_YUV = 1 << 13, /* 2 planes of Y, UV, - e.g., NV12. */ - SVGA3DBLOCKDESC_3PLANAR_YUV = 1 << 14, /* 3 planes of separate - Y, U, V, e.g., YV12. */ - - SVGA3DBLOCKDESC_RG = SVGA3DBLOCKDESC_RED | - SVGA3DBLOCKDESC_GREEN, - SVGA3DBLOCKDESC_RGB = SVGA3DBLOCKDESC_RG | - SVGA3DBLOCKDESC_BLUE, - SVGA3DBLOCKDESC_RGB_SRGB = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_SRGB, - SVGA3DBLOCKDESC_RGBA = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_ALPHA, - SVGA3DBLOCKDESC_RGBA_SRGB = SVGA3DBLOCKDESC_RGBA | - SVGA3DBLOCKDESC_SRGB, + /* Nothing special can be said about this format. */ + SVGA3DBLOCKDESC_NONE = 0, + + /* Format contains Blue/U data */ + SVGA3DBLOCKDESC_BLUE = 1 << 0, + SVGA3DBLOCKDESC_W = 1 << 0, + SVGA3DBLOCKDESC_BUMP_L = 1 << 0, + + /* Format contains Green/V data */ + SVGA3DBLOCKDESC_GREEN = 1 << 1, + SVGA3DBLOCKDESC_V = 1 << 1, + + /* Format contains Red/W/Luminance data */ + SVGA3DBLOCKDESC_RED = 1 << 2, + SVGA3DBLOCKDESC_U = 1 << 2, + SVGA3DBLOCKDESC_LUMINANCE = 1 << 2, + + /* Format contains Alpha/Q data */ + SVGA3DBLOCKDESC_ALPHA = 1 << 3, + SVGA3DBLOCKDESC_Q = 1 << 3, + + /* Format is a buffer */ + SVGA3DBLOCKDESC_BUFFER = 1 << 4, + + /* Format is compressed */ + SVGA3DBLOCKDESC_COMPRESSED = 1 << 5, + + /* Format uses IEEE floating point */ + SVGA3DBLOCKDESC_FP = 1 << 6, + + /* Three separate blocks store data. */ + SVGA3DBLOCKDESC_PLANAR_YUV = 1 << 7, + + /* 2 planes of Y, UV, e.g., NV12. */ + SVGA3DBLOCKDESC_2PLANAR_YUV = 1 << 8, + + /* 3 planes of separate Y, U, V, e.g., YV12. */ + SVGA3DBLOCKDESC_3PLANAR_YUV = 1 << 9, + + /* Block with a stencil channel */ + SVGA3DBLOCKDESC_STENCIL = 1 << 11, + + /* Typeless format */ + SVGA3DBLOCKDESC_TYPELESS = 1 << 12, + + /* Channels are signed integers */ + SVGA3DBLOCKDESC_SINT = 1 << 13, + + /* Channels are unsigned integers */ + SVGA3DBLOCKDESC_UINT = 1 << 14, + + /* Channels are normalized (when sampling) */ + SVGA3DBLOCKDESC_NORM = 1 << 15, + + /* Channels are in SRGB */ + SVGA3DBLOCKDESC_SRGB = 1 << 16, + + /* Shared exponent */ + SVGA3DBLOCKDESC_EXP = 1 << 17, + + /* Format contains color data. */ + SVGA3DBLOCKDESC_COLOR = 1 << 18, + /* Format contains depth data. */ + SVGA3DBLOCKDESC_DEPTH = 1 << 19, + /* Format contains bump data. */ + SVGA3DBLOCKDESC_BUMP = 1 << 20, + + /* Format contains YUV video data. */ + SVGA3DBLOCKDESC_YUV_VIDEO = 1 << 21, + + /* For mixed unsigned/signed formats. */ + SVGA3DBLOCKDESC_MIXED = 1 << 22, + + /* For distingushing CxV8U8. */ + SVGA3DBLOCKDESC_CX = 1 << 23, + + /* Different compressed format groups. */ + SVGA3DBLOCKDESC_BC1 = 1 << 24, + SVGA3DBLOCKDESC_BC2 = 1 << 25, + SVGA3DBLOCKDESC_BC3 = 1 << 26, + SVGA3DBLOCKDESC_BC4 = 1 << 27, + SVGA3DBLOCKDESC_BC5 = 1 << 28, + + SVGA3DBLOCKDESC_A_UINT = SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_A_UNORM = SVGA3DBLOCKDESC_A_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_R_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_R_UNORM = SVGA3DBLOCKDESC_R_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_R_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_R_SNORM = SVGA3DBLOCKDESC_R_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_G_UINT = SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_UNORM = SVGA3DBLOCKDESC_RG_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RG_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_SNORM = SVGA3DBLOCKDESC_RG_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGB_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_UNORM = SVGA3DBLOCKDESC_RGB_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGB_UNORM_SRGB = SVGA3DBLOCKDESC_RGB_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_RGBA_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGBA_UNORM = SVGA3DBLOCKDESC_RGBA_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGBA_UNORM_SRGB = SVGA3DBLOCKDESC_RGBA_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_RGBA_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGBA_SNORM = SVGA3DBLOCKDESC_RGBA_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGBA_FP = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_FP | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_UV = SVGA3DBLOCKDESC_U | - SVGA3DBLOCKDESC_V, + SVGA3DBLOCKDESC_V | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVL = SVGA3DBLOCKDESC_UV | - SVGA3DBLOCKDESC_LUMINANCE, + SVGA3DBLOCKDESC_BUMP_L | + SVGA3DBLOCKDESC_MIXED | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVW = SVGA3DBLOCKDESC_UV | - SVGA3DBLOCKDESC_W, + SVGA3DBLOCKDESC_W | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVWA = SVGA3DBLOCKDESC_UVW | - SVGA3DBLOCKDESC_ALPHA, + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_MIXED | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVWQ = SVGA3DBLOCKDESC_U | - SVGA3DBLOCKDESC_V | - SVGA3DBLOCKDESC_W | - SVGA3DBLOCKDESC_Q, - SVGA3DBLOCKDESC_LA = SVGA3DBLOCKDESC_LUMINANCE | - SVGA3DBLOCKDESC_ALPHA, + SVGA3DBLOCKDESC_V | + SVGA3DBLOCKDESC_W | + SVGA3DBLOCKDESC_Q | + SVGA3DBLOCKDESC_BUMP, + SVGA3DBLOCKDESC_L_UNORM = SVGA3DBLOCKDESC_LUMINANCE | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_LA_UNORM = SVGA3DBLOCKDESC_LUMINANCE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_R_FP = SVGA3DBLOCKDESC_RED | - SVGA3DBLOCKDESC_IEEE_FP, + SVGA3DBLOCKDESC_FP | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_RG_FP = SVGA3DBLOCKDESC_R_FP | - SVGA3DBLOCKDESC_GREEN, + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_RGB_FP = SVGA3DBLOCKDESC_RG_FP | - SVGA3DBLOCKDESC_BLUE, - SVGA3DBLOCKDESC_RGBA_FP = SVGA3DBLOCKDESC_RGB_FP | - SVGA3DBLOCKDESC_ALPHA, - SVGA3DBLOCKDESC_DS = SVGA3DBLOCKDESC_DEPTH | - SVGA3DBLOCKDESC_STENCIL, - SVGA3DBLOCKDESC_YUV = SVGA3DBLOCKDESC_UV_VIDEO | - SVGA3DBLOCKDESC_Y, + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_YUV = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_AYUV = SVGA3DBLOCKDESC_ALPHA | - SVGA3DBLOCKDESC_Y | - SVGA3DBLOCKDESC_U_VIDEO | - SVGA3DBLOCKDESC_V_VIDEO, - SVGA3DBLOCKDESC_RGBE = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_EXP, - SVGA3DBLOCKDESC_COMPRESSED_SRGB = SVGA3DBLOCKDESC_COMPRESSED | - SVGA3DBLOCKDESC_SRGB, - SVGA3DBLOCKDESC_NV12 = SVGA3DBLOCKDESC_PLANAR_YUV | - SVGA3DBLOCKDESC_2PLANAR_YUV, - SVGA3DBLOCKDESC_YV12 = SVGA3DBLOCKDESC_PLANAR_YUV | - SVGA3DBLOCKDESC_3PLANAR_YUV, + SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_EXP = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_EXP | + SVGA3DBLOCKDESC_COLOR, + + SVGA3DBLOCKDESC_COMP_TYPELESS = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_TYPELESS, + SVGA3DBLOCKDESC_COMP_UNORM = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_COMP_SNORM = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC1_COMP_TYPELESS = SVGA3DBLOCKDESC_BC1 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC1_COMP_UNORM = SVGA3DBLOCKDESC_BC1 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC1_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC1_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC2_COMP_TYPELESS = SVGA3DBLOCKDESC_BC2 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC2_COMP_UNORM = SVGA3DBLOCKDESC_BC2 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC2_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC2_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC3_COMP_TYPELESS = SVGA3DBLOCKDESC_BC3 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC3_COMP_UNORM = SVGA3DBLOCKDESC_BC3 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC3_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC3_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC4_COMP_TYPELESS = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC4_COMP_UNORM = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC4_COMP_SNORM = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_SNORM, + SVGA3DBLOCKDESC_BC5_COMP_TYPELESS = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC5_COMP_UNORM = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC5_COMP_SNORM = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_SNORM, + + SVGA3DBLOCKDESC_NV12 = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_PLANAR_YUV | + SVGA3DBLOCKDESC_2PLANAR_YUV | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_YV12 = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_PLANAR_YUV | + SVGA3DBLOCKDESC_3PLANAR_YUV | + SVGA3DBLOCKDESC_COLOR, + + SVGA3DBLOCKDESC_DEPTH_UINT = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_DEPTH_UNORM = SVGA3DBLOCKDESC_DEPTH_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_DS = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_STENCIL, + SVGA3DBLOCKDESC_DS_UINT = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_STENCIL | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_DS_UNORM = SVGA3DBLOCKDESC_DS_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_DEPTH_FP = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_FP, + + SVGA3DBLOCKDESC_UV_UINT = SVGA3DBLOCKDESC_UV | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_UV_SNORM = SVGA3DBLOCKDESC_UV | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_UVCX_SNORM = SVGA3DBLOCKDESC_UV_SNORM | + SVGA3DBLOCKDESC_CX, + SVGA3DBLOCKDESC_UVWQ_SNORM = SVGA3DBLOCKDESC_UVWQ | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM, }; -/* - * SVGA3dSurfaceDesc describes the actual pixel data. - * - * This structure provides the following information: - * 1. Block description. - * 2. Dimensions of a block in the surface. - * 3. Size of block in bytes. - * 4. Bit depth of the pixel data. - * 5. Channel bit depths and masks (if applicable). - */ struct svga3d_channel_def { union { u8 blue; - u8 u; + u8 w_bump; + u8 l_bump; u8 uv_video; u8 u_video; }; union { u8 green; - u8 v; u8 stencil; + u8 v_bump; u8 v_video; }; union { u8 red; - u8 w; + u8 u_bump; u8 luminance; - u8 y; + u8 y_video; u8 depth; u8 data; }; union { u8 alpha; - u8 q; + u8 q_bump; u8 exp; }; }; +/* + * struct svga3d_surface_desc - describes the actual pixel data. + * + * @format: Format + * @block_desc: Block description + * @block_size: Dimensions in pixels of a block + * @bytes_per_block: Size of block in bytes + * @pitch_bytes_per_block: Size of a block in bytes for purposes of pitch + * @bit_depth: Channel bit depths + * @bit_offset: Channel bit masks (in bits offset from the start of the pointer) + */ struct svga3d_surface_desc { SVGA3dSurfaceFormat format; enum svga3d_block_desc block_desc; + surf_size_struct block_size; u32 bytes_per_block; u32 pitch_bytes_per_block; - u32 total_bit_depth; struct svga3d_channel_def bit_depth; struct svga3d_channel_def bit_offset; }; @@ -215,729 +381,728 @@ struct svga3d_surface_desc { static const struct svga3d_surface_desc svga3d_surface_descs[] = { {SVGA3D_FORMAT_INVALID, SVGA3DBLOCKDESC_NONE, {1, 1, 1}, 0, 0, - 0, {{0}, {0}, {0}, {0}}, + {{0}, {0}, {0}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X8R8G8B8, SVGA3DBLOCKDESC_RGB, + {SVGA3D_X8R8G8B8, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_A8R8G8B8, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A8R8G8B8, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_R5G6B5, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R5G6B5, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {6}, {5}, {0}}, + {{5}, {6}, {5}, {0}}, {{0}, {5}, {11}, {0}}}, - {SVGA3D_X1R5G5B5, SVGA3DBLOCKDESC_RGB, + {SVGA3D_X1R5G5B5, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 15, {{5}, {5}, {5}, {0}}, + {{5}, {5}, {5}, {0}}, {{0}, {5}, {10}, {0}}}, - {SVGA3D_A1R5G5B5, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A1R5G5B5, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {5}, {1}}, + {{5}, {5}, {5}, {1}}, {{0}, {5}, {10}, {15}}}, - {SVGA3D_A4R4G4B4, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A4R4G4B4, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{4}, {4}, {4}, {4}}, + {{4}, {4}, {4}, {4}}, {{0}, {4}, {8}, {12}}}, - {SVGA3D_Z_D32, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D32, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D16, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D16, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D24S8, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D24S8, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {8}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_Z_D15S1, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D15S1, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {1}, {15}, {0}}, - {{0}, {15}, {0}, {0}}}, + {{0}, {1}, {15}, {0}}, + {{0}, {0}, {1}, {0}}}, - {SVGA3D_LUMINANCE8, SVGA3DBLOCKDESC_LUMINANCE, + {SVGA3D_LUMINANCE8, SVGA3DBLOCKDESC_L_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_LUMINANCE4_ALPHA4, SVGA3DBLOCKDESC_LA, - {1 , 1, 1}, 1, 1, - 8, {{0}, {0}, {4}, {4}}, + {SVGA3D_LUMINANCE4_ALPHA4, SVGA3DBLOCKDESC_LA_UNORM, + {1, 1, 1}, 1, 1, + {{0}, {0}, {4}, {4}}, {{0}, {0}, {0}, {4}}}, - {SVGA3D_LUMINANCE16, SVGA3DBLOCKDESC_LUMINANCE, + {SVGA3D_LUMINANCE16, SVGA3DBLOCKDESC_L_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_LUMINANCE8_ALPHA8, SVGA3DBLOCKDESC_LA, + {SVGA3D_LUMINANCE8_ALPHA8, SVGA3DBLOCKDESC_LA_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {8}, {8}}, + {{0}, {0}, {8}, {8}}, {{0}, {0}, {0}, {8}}}, - {SVGA3D_DXT1, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT1, SVGA3DBLOCKDESC_BC1_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT2, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT2, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT3, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT3, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT4, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT4, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT5, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT5, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BUMPU8V8, SVGA3DBLOCKDESC_UV, + {SVGA3D_BUMPU8V8, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {8}, {8}}, - {{0}, {0}, {0}, {8}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_BUMPL6V5U5, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {6}, {0}}, - {{11}, {6}, {0}, {0}}}, + {{6}, {5}, {5}, {0}}, + {{10}, {5}, {0}, {0}}}, {SVGA3D_BUMPX8L8V8U8, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, - {SVGA3D_BUMPL8V8U8, SVGA3DBLOCKDESC_UVL, + {SVGA3D_FORMAT_DEAD1, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 3, 3, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, {SVGA3D_ARGB_S10E5, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_ARGB_S23E8, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_A2R10G10B10, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A2R10G10B10, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, + {{10}, {10}, {10}, {2}}, {{0}, {10}, {20}, {30}}}, - {SVGA3D_V8U8, SVGA3DBLOCKDESC_UV, + {SVGA3D_V8U8, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, - {SVGA3D_Q8W8V8U8, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_Q8W8V8U8, SVGA3DBLOCKDESC_UVWQ_SNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, - {{24}, {16}, {8}, {0}}}, + {{8}, {8}, {8}, {8}}, + {{16}, {8}, {0}, {24}}}, - {SVGA3D_CxV8U8, SVGA3DBLOCKDESC_UV, + {SVGA3D_CxV8U8, SVGA3DBLOCKDESC_UVCX_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_X8L8V8U8, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, {SVGA3D_A2W10V10U10, SVGA3DBLOCKDESC_UVWA, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_ALPHA8, SVGA3DBLOCKDESC_ALPHA, + {SVGA3D_ALPHA8, SVGA3DBLOCKDESC_A_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {0}, {8}}, + {{0}, {0}, {0}, {8}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R_S10E5, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R_S23E8, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_RG_S10E5, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, {SVGA3D_RG_S23E8, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, {SVGA3D_BUFFER, SVGA3DBLOCKDESC_BUFFER, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D24X8, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D24X8, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {0}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_V16U16, SVGA3DBLOCKDESC_UV, + {SVGA3D_V16U16, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 4, 4, - 32, {{16}, {16}, {0}, {0}}, - {{16}, {0}, {0}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_G16R16, SVGA3DBLOCKDESC_RG, + {SVGA3D_G16R16, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, - {{0}, {0}, {16}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_A16B16G16R16, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A16B16G16R16, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_UYVY, SVGA3DBLOCKDESC_YUV, - {1, 1, 1}, 2, 2, - 16, {{8}, {0}, {8}, {0}}, + {2, 1, 1}, 4, 4, + {{8}, {0}, {8}, {0}}, {{0}, {0}, {8}, {0}}}, {SVGA3D_YUY2, SVGA3DBLOCKDESC_YUV, - {1, 1, 1}, 2, 2, - 16, {{8}, {0}, {8}, {0}}, + {2, 1, 1}, 4, 4, + {{8}, {0}, {8}, {0}}, {{8}, {0}, {0}, {0}}}, {SVGA3D_NV12, SVGA3DBLOCKDESC_NV12, {2, 2, 1}, 6, 2, - 48, {{0}, {0}, {48}, {0}}, + {{0}, {0}, {48}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_AYUV, SVGA3DBLOCKDESC_AYUV, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_R32G32B32A32_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R32G32B32A32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32A32_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R32G32B32A32_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32A32_SINT, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R32G32B32A32_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32_TYPELESS, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R32G32B32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, {SVGA3D_R32G32B32_FLOAT, SVGA3DBLOCKDESC_RGB_FP, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R32G32B32_UINT, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R32G32B32_UINT, SVGA3DBLOCKDESC_RGB_UINT, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R32G32B32_SINT, SVGA3DBLOCKDESC_UVW, + {SVGA3D_R32G32B32_SINT, SVGA3DBLOCKDESC_RGB_SINT, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R16G16B16A16_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_SNORM, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R16G16B16A16_SNORM, SVGA3DBLOCKDESC_RGBA_SNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_SINT, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R16G16B16A16_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R32G32_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G32_UINT, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G32_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G32_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R32G32_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G8X24_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G8X24_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {32}, {0}}, + {{0}, {8}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, {SVGA3D_D32_FLOAT_S8X24_UINT, SVGA3DBLOCKDESC_DS, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {32}, {0}}, + {{0}, {8}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32_FLOAT_X8X24_TYPELESS, SVGA3DBLOCKDESC_R_FP, + {SVGA3D_R32_FLOAT_X8X24, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X32_TYPELESS_G8X24_UINT, SVGA3DBLOCKDESC_GREEN, + {SVGA3D_X32_G8X24_UINT, SVGA3DBLOCKDESC_G_UINT, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {0}, {0}}, + {{0}, {8}, {0}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R10G10B10A2_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_R10G10B10A2_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, {SVGA3D_R11G11B10_FLOAT, SVGA3DBLOCKDESC_RGB_FP, {1, 1, 1}, 4, 4, - 32, {{10}, {11}, {11}, {0}}, - {{0}, {10}, {21}, {0}}}, + {{10}, {11}, {11}, {0}}, + {{22}, {11}, {0}, {0}}}, - {SVGA3D_R8G8B8A8_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_SRGB, + {SVGA3D_R8G8B8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_UNORM_SRGB, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_SINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R16G16_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_UINT, SVGA3DBLOCKDESC_RG_FP, + {SVGA3D_R16G16_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R16G16_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R32_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_D32_FLOAT, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_D32_FLOAT, SVGA3DBLOCKDESC_DEPTH_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R32_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R32_SINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R24G8_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R24G8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, + {{0}, {8}, {24}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_D24_UNORM_S8_UINT, SVGA3DBLOCKDESC_DS, + {SVGA3D_D24_UNORM_S8_UINT, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, + {{0}, {8}, {24}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_R24_UNORM_X8_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R24_UNORM_X8, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {24}, {0}}, + {{0}, {0}, {24}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X24_TYPELESS_G8_UINT, SVGA3DBLOCKDESC_GREEN, + {SVGA3D_X24_G8_UINT, SVGA3DBLOCKDESC_G_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {0}, {0}}, + {{0}, {8}, {0}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_R8G8_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_UNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_UNORM, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_UINT, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R8G8_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R16_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_UNORM, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_UNORM, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_SNORM, SVGA3DBLOCKDESC_U, + {SVGA3D_R16_SNORM, SVGA3DBLOCKDESC_R_SNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_SINT, SVGA3DBLOCKDESC_U, + {SVGA3D_R16_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_UNORM, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_UNORM, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_SNORM, SVGA3DBLOCKDESC_U, + {SVGA3D_R8_SNORM, SVGA3DBLOCKDESC_R_SNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_SINT, SVGA3DBLOCKDESC_U, + {SVGA3D_R8_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_P8, SVGA3DBLOCKDESC_RED, + {SVGA3D_P8, SVGA3DBLOCKDESC_NONE, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R9G9B9E5_SHAREDEXP, SVGA3DBLOCKDESC_RGBE, + {SVGA3D_R9G9B9E5_SHAREDEXP, SVGA3DBLOCKDESC_RGB_EXP, {1, 1, 1}, 4, 4, - 32, {{9}, {9}, {9}, {5}}, + {{9}, {9}, {9}, {5}}, {{18}, {9}, {0}, {27}}}, - {SVGA3D_R8G8_B8G8_UNORM, SVGA3DBLOCKDESC_RG, - {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, - {{0}, {8}, {0}, {0}}}, + {SVGA3D_R8G8_B8G8_UNORM, SVGA3DBLOCKDESC_NONE, + {2, 1, 1}, 4, 4, + {{0}, {8}, {8}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_G8R8_G8B8_UNORM, SVGA3DBLOCKDESC_RG, - {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {SVGA3D_G8R8_G8B8_UNORM, SVGA3DBLOCKDESC_NONE, + {2, 1, 1}, 4, 4, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_BC1_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC1_TYPELESS, SVGA3DBLOCKDESC_BC1_COMP_TYPELESS, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC1_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC1_UNORM_SRGB, SVGA3DBLOCKDESC_BC1_COMP_UNORM_SRGB, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC2_TYPELESS, SVGA3DBLOCKDESC_BC2_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC2_UNORM_SRGB, SVGA3DBLOCKDESC_BC2_COMP_UNORM_SRGB, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC3_TYPELESS, SVGA3DBLOCKDESC_BC3_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC3_UNORM_SRGB, SVGA3DBLOCKDESC_BC3_COMP_UNORM_SRGB, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC4_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_TYPELESS, SVGA3DBLOCKDESC_BC4_COMP_TYPELESS, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_ATI1, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_ATI1, SVGA3DBLOCKDESC_BC4_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC4_SNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_SNORM, SVGA3DBLOCKDESC_BC4_COMP_SNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_TYPELESS, SVGA3DBLOCKDESC_BC5_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_ATI2, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_ATI2, SVGA3DBLOCKDESC_BC5_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_SNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_SNORM, SVGA3DBLOCKDESC_BC5_COMP_SNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R10G10B10_XR_BIAS_A2_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10_XR_BIAS_A2_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_B8G8R8A8_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B8G8R8A8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_SRGB, + {SVGA3D_B8G8R8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_UNORM_SRGB, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_TYPELESS, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B8G8R8X8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_UNORM_SRGB, SVGA3DBLOCKDESC_RGB_SRGB, + {SVGA3D_B8G8R8X8_UNORM_SRGB, SVGA3DBLOCKDESC_RGB_UNORM_SRGB, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_Z_DF16, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_DF16, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_DF24, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_DF24, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {0}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_Z_D24S8_INT, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D24S8_INT, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {8}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, {SVGA3D_YV12, SVGA3DBLOCKDESC_YV12, {2, 2, 1}, 6, 2, - 48, {{0}, {0}, {48}, {0}}, + {{0}, {0}, {48}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R32G32B32A32_FLOAT, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, {SVGA3D_R16G16B16A16_FLOAT, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_R32G32_FLOAT, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R10G10B10A2_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_R8G8B8A8_SNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_SNORM, SVGA3DBLOCKDESC_RGBA_SNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, - {{24}, {16}, {8}, {0}}}, + {{8}, {8}, {8}, {8}}, + {{16}, {8}, {0}, {24}}}, {SVGA3D_R16G16_FLOAT, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_UNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_UNORM, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, - {{0}, {0}, {16}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_SNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_SNORM, SVGA3DBLOCKDESC_RG_SNORM, {1, 1, 1}, 4, 4, - 32, {{16}, {16}, {0}, {0}}, - {{16}, {0}, {0}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, {SVGA3D_R32_FLOAT, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8G8_SNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_SNORM, SVGA3DBLOCKDESC_RG_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_R16_FLOAT, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_D16_UNORM, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_D16_UNORM, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_A8_UNORM, SVGA3DBLOCKDESC_ALPHA, + {SVGA3D_A8_UNORM, SVGA3DBLOCKDESC_A_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {0}, {8}}, + {{0}, {0}, {0}, {8}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC1_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC1_UNORM, SVGA3DBLOCKDESC_BC1_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC2_UNORM, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC3_UNORM, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_B5G6R5_UNORM, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B5G6R5_UNORM, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {6}, {5}, {0}}, + {{5}, {6}, {5}, {0}}, {{0}, {5}, {11}, {0}}}, - {SVGA3D_B5G5R5A1_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B5G5R5A1_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {5}, {1}}, + {{5}, {5}, {5}, {1}}, {{0}, {5}, {10}, {15}}}, - {SVGA3D_B8G8R8A8_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B8G8R8A8_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_UNORM, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B8G8R8X8_UNORM, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_BC4_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_UNORM, SVGA3DBLOCKDESC_BC4_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_UNORM, SVGA3DBLOCKDESC_BC5_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - }; static inline u32 clamped_umul32(u32 a, u32 b) @@ -946,6 +1111,10 @@ static inline u32 clamped_umul32(u32 a, u32 b) return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; } +/** + * svga3dsurface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the + * given format. + */ static inline const struct svga3d_surface_desc * svga3dsurface_get_desc(SVGA3dSurfaceFormat format) { @@ -955,23 +1124,10 @@ svga3dsurface_get_desc(SVGA3dSurfaceFormat format) return &svga3d_surface_descs[SVGA3D_FORMAT_INVALID]; } -/* - *---------------------------------------------------------------------- - * - * svga3dsurface_get_mip_size -- - * - * Given a base level size and the mip level, compute the size of - * the mip level. - * - * Results: - * See above. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- +/** + * svga3dsurface_get_mip_size - Given a base level size and the mip level, + * compute the size of the mip level. */ - static inline surf_size_struct svga3dsurface_get_mip_size(surf_size_struct base_level, u32 mip_level) { @@ -1018,28 +1174,17 @@ svga3dsurface_calculate_pitch(const struct svga3d_surface_desc *desc, return pitch; } -/* - *----------------------------------------------------------------------------- - * - * svga3dsurface_get_image_buffer_size -- - * - * Return the number of bytes of buffer space required to store - * one image of a surface, optionally using the specified pitch. - * - * If pitch is zero, it is assumed that rows are tightly packed. +/** + * svga3dsurface_get_image_buffer_size - Calculates image buffer size. * - * This function is overflow-safe. If the result would have - * overflowed, instead we return MAX_UINT32. + * Return the number of bytes of buffer space required to store one image of a + * surface, optionally using the specified pitch. * - * Results: - * Byte count. + * If pitch is zero, it is assumed that rows are tightly packed. * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- + * This function is overflow-safe. If the result would have overflowed, instead + * we return MAX_UINT32. */ - static inline u32 svga3dsurface_get_image_buffer_size(const struct svga3d_surface_desc *desc, const surf_size_struct *size, @@ -1067,6 +1212,9 @@ svga3dsurface_get_image_buffer_size(const struct svga3d_surface_desc *desc, return total_size; } +/** + * svga3dsurface_get_serialized_size - Get the serialized size for the image. + */ static inline u32 svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, surf_size_struct base_level_size, @@ -1087,6 +1235,26 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, return total_size * num_layers; } +/** + * svga3dsurface_get_serialized_size_extended - Returns the number of bytes + * required for a surface with given parameters. Support for sample count. + */ +static inline u32 +svga3dsurface_get_serialized_size_extended(SVGA3dSurfaceFormat format, + surf_size_struct base_level_size, + u32 num_mip_levels, + u32 num_layers, + u32 num_samples) +{ + uint64_t total_size = + svga3dsurface_get_serialized_size(format, + base_level_size, + num_mip_levels, + num_layers); + total_size *= max_t(u32, 1, num_samples); + + return min_t(uint64_t, total_size, (uint64_t)U32_MAX); +} /** * svga3dsurface_get_pixel_offset - Compute the offset (in bytes) to a pixel @@ -1206,3 +1374,5 @@ svga3dsurface_is_screen_target_format(SVGA3dSurfaceFormat format) } return svga3dsurface_is_dx_screen_target_format(format); } + +#endif /* _SVGA3D_SURFACEDEFS_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h index df63f24c2e10..308370665a8e 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h @@ -45,9 +45,21 @@ #define SVGA3D_INVALID_ID ((uint32)-1) +typedef uint8 SVGABool8; /* 8-bit Bool definition */ typedef uint32 SVGA3dBool; /* 32-bit Bool definition */ typedef uint32 SVGA3dColor; /* a, r, g, b */ +typedef uint32 SVGA3dSurfaceId; + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 numerator; + uint32 denominator; +} +#include "vmware_pack_end.h" +SVGA3dFraction64; + typedef #include "vmware_pack_begin.h" struct SVGA3dCopyRect { @@ -146,7 +158,7 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_BUMPU8V8 = 20, SVGA3D_BUMPL6V5U5 = 21, SVGA3D_BUMPX8L8V8U8 = 22, - SVGA3D_BUMPL8V8U8 = 23, + SVGA3D_FORMAT_DEAD1 = 23, SVGA3D_ARGB_S10E5 = 24, /* 16-bit floating-point ARGB */ SVGA3D_ARGB_S23E8 = 25, /* 32-bit floating-point ARGB */ @@ -205,8 +217,8 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_R32G32_SINT = 59, SVGA3D_R32G8X24_TYPELESS = 60, SVGA3D_D32_FLOAT_S8X24_UINT = 61, - SVGA3D_R32_FLOAT_X8X24_TYPELESS = 62, - SVGA3D_X32_TYPELESS_G8X24_UINT = 63, + SVGA3D_R32_FLOAT_X8X24 = 62, + SVGA3D_X32_G8X24_UINT = 63, SVGA3D_R10G10B10A2_TYPELESS = 64, SVGA3D_R10G10B10A2_UINT = 65, SVGA3D_R11G11B10_FLOAT = 66, @@ -224,8 +236,8 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_R32_SINT = 78, SVGA3D_R24G8_TYPELESS = 79, SVGA3D_D24_UNORM_S8_UINT = 80, - SVGA3D_R24_UNORM_X8_TYPELESS = 81, - SVGA3D_X24_TYPELESS_G8_UINT = 82, + SVGA3D_R24_UNORM_X8 = 81, + SVGA3D_X24_G8_UINT = 82, SVGA3D_R8G8_TYPELESS = 83, SVGA3D_R8G8_UNORM = 84, SVGA3D_R8G8_UINT = 85, @@ -297,92 +309,114 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_FORMAT_MAX } SVGA3dSurfaceFormat; -typedef enum SVGA3dSurfaceFlags { - SVGA3D_SURFACE_CUBEMAP = (1 << 0), +/* + * SVGA3d Surface Flags -- + */ +#define SVGA3D_SURFACE_CUBEMAP (1 << 0) - /* - * HINT flags are not enforced by the device but are useful for - * performance. - */ - SVGA3D_SURFACE_HINT_STATIC = (1 << 1), - SVGA3D_SURFACE_HINT_DYNAMIC = (1 << 2), - SVGA3D_SURFACE_HINT_INDEXBUFFER = (1 << 3), - SVGA3D_SURFACE_HINT_VERTEXBUFFER = (1 << 4), - SVGA3D_SURFACE_HINT_TEXTURE = (1 << 5), - SVGA3D_SURFACE_HINT_RENDERTARGET = (1 << 6), - SVGA3D_SURFACE_HINT_DEPTHSTENCIL = (1 << 7), - SVGA3D_SURFACE_HINT_WRITEONLY = (1 << 8), - SVGA3D_SURFACE_MASKABLE_ANTIALIAS = (1 << 9), - SVGA3D_SURFACE_AUTOGENMIPMAPS = (1 << 10), - SVGA3D_SURFACE_DECODE_RENDERTARGET = (1 << 11), +/* + * HINT flags are not enforced by the device but are useful for + * performance. + */ +#define SVGA3D_SURFACE_HINT_STATIC (CONST64U(1) << 1) +#define SVGA3D_SURFACE_HINT_DYNAMIC (CONST64U(1) << 2) +#define SVGA3D_SURFACE_HINT_INDEXBUFFER (CONST64U(1) << 3) +#define SVGA3D_SURFACE_HINT_VERTEXBUFFER (CONST64U(1) << 4) +#define SVGA3D_SURFACE_HINT_TEXTURE (CONST64U(1) << 5) +#define SVGA3D_SURFACE_HINT_RENDERTARGET (CONST64U(1) << 6) +#define SVGA3D_SURFACE_HINT_DEPTHSTENCIL (CONST64U(1) << 7) +#define SVGA3D_SURFACE_HINT_WRITEONLY (CONST64U(1) << 8) +#define SVGA3D_SURFACE_MASKABLE_ANTIALIAS (CONST64U(1) << 9) +#define SVGA3D_SURFACE_AUTOGENMIPMAPS (CONST64U(1) << 10) + +#define SVGA3D_SURFACE_DECODE_RENDERTARGET (CONST64U(1) << 11) - /* - * Is this surface using a base-level pitch for it's mob backing? - * - * This flag is not intended to be set by guest-drivers, but is instead - * set by the device when the surface is bound to a mob with a specified - * pitch. - */ - SVGA3D_SURFACE_MOB_PITCH = (1 << 12), +/* + * Is this surface using a base-level pitch for it's mob backing? + * + * This flag is not intended to be set by guest-drivers, but is instead + * set by the device when the surface is bound to a mob with a specified + * pitch. + */ +#define SVGA3D_SURFACE_MOB_PITCH (CONST64U(1) << 12) - SVGA3D_SURFACE_INACTIVE = (1 << 13), - SVGA3D_SURFACE_HINT_RT_LOCKABLE = (1 << 14), - SVGA3D_SURFACE_VOLUME = (1 << 15), +#define SVGA3D_SURFACE_INACTIVE (CONST64U(1) << 13) +#define SVGA3D_SURFACE_HINT_RT_LOCKABLE (CONST64U(1) << 14) +#define SVGA3D_SURFACE_VOLUME (CONST64U(1) << 15) - /* - * Required to be set on a surface to bind it to a screen target. - */ - SVGA3D_SURFACE_SCREENTARGET = (1 << 16), +/* + * Required to be set on a surface to bind it to a screen target. + */ +#define SVGA3D_SURFACE_SCREENTARGET (CONST64U(1) << 16) - /* - * Align images in the guest-backing mob to 16-bytes. - */ - SVGA3D_SURFACE_ALIGN16 = (1 << 17), +/* + * Align images in the guest-backing mob to 16-bytes. + */ +#define SVGA3D_SURFACE_ALIGN16 (CONST64U(1) << 17) - SVGA3D_SURFACE_1D = (1 << 18), - SVGA3D_SURFACE_ARRAY = (1 << 19), +#define SVGA3D_SURFACE_1D (CONST64U(1) << 18) +#define SVGA3D_SURFACE_ARRAY (CONST64U(1) << 19) - /* - * Bind flags. - * These are enforced for any surface defined with DefineGBSurface_v2. - */ - SVGA3D_SURFACE_BIND_VERTEX_BUFFER = (1 << 20), - SVGA3D_SURFACE_BIND_INDEX_BUFFER = (1 << 21), - SVGA3D_SURFACE_BIND_CONSTANT_BUFFER = (1 << 22), - SVGA3D_SURFACE_BIND_SHADER_RESOURCE = (1 << 23), - SVGA3D_SURFACE_BIND_RENDER_TARGET = (1 << 24), - SVGA3D_SURFACE_BIND_DEPTH_STENCIL = (1 << 25), - SVGA3D_SURFACE_BIND_STREAM_OUTPUT = (1 << 26), +/* + * Bind flags. + * These are enforced for any surface defined with DefineGBSurface_v2. + */ +#define SVGA3D_SURFACE_BIND_VERTEX_BUFFER (CONST64U(1) << 20) +#define SVGA3D_SURFACE_BIND_INDEX_BUFFER (CONST64U(1) << 21) +#define SVGA3D_SURFACE_BIND_CONSTANT_BUFFER (CONST64U(1) << 22) +#define SVGA3D_SURFACE_BIND_SHADER_RESOURCE (CONST64U(1) << 23) +#define SVGA3D_SURFACE_BIND_RENDER_TARGET (CONST64U(1) << 24) +#define SVGA3D_SURFACE_BIND_DEPTH_STENCIL (CONST64U(1) << 25) +#define SVGA3D_SURFACE_BIND_STREAM_OUTPUT (CONST64U(1) << 26) - /* - * A note on staging flags: - * - * The STAGING flags notes that the surface will not be used directly by the - * drawing pipeline, i.e. that it will not be bound to any bind point. - * Staging surfaces may be used by copy operations to move data in and out - * of other surfaces. - * - * The HINT_INDIRECT_UPDATE flag suggests that the surface will receive - * updates indirectly, i.e. the surface will not be updated directly, but - * will receive copies from staging surfaces. - */ - SVGA3D_SURFACE_STAGING_UPLOAD = (1 << 27), - SVGA3D_SURFACE_STAGING_DOWNLOAD = (1 << 28), - SVGA3D_SURFACE_HINT_INDIRECT_UPDATE = (1 << 29), +/* + * The STAGING flags notes that the surface will not be used directly by the + * drawing pipeline, i.e. that it will not be bound to any bind point. + * Staging surfaces may be used by copy operations to move data in and out + * of other surfaces. No bind flags may be set on surfaces with this flag. + * + * The HINT_INDIRECT_UPDATE flag suggests that the surface will receive + * updates indirectly, i.e. the surface will not be updated directly, but + * will receive copies from staging surfaces. + */ +#define SVGA3D_SURFACE_STAGING_UPLOAD (CONST64U(1) << 27) +#define SVGA3D_SURFACE_STAGING_DOWNLOAD (CONST64U(1) << 28) +#define SVGA3D_SURFACE_HINT_INDIRECT_UPDATE (CONST64U(1) << 29) - /* - * Setting this flag allow this surface to be used with the - * SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command. It is only valid for - * buffer surfaces, an no bind flags are allowed to be set on surfaces - * with this flag. - */ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER = (1 << 30), +/* + * Setting this flag allow this surface to be used with the + * SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command. It is only valid for + * buffer surfaces, and no bind flags are allowed to be set on surfaces + * with this flag. + */ +#define SVGA3D_SURFACE_TRANSFER_FROM_BUFFER (CONST64U(1) << 30) - /* - * Marker for the last defined bit. - */ - SVGA3D_SURFACE_FLAG_MAX = (1 << 31), -} SVGA3dSurfaceFlags; +/* + * Reserved for video operations. + */ +#define SVGA3D_SURFACE_RESERVED1 (CONST64U(1) << 31) + +/* + * Specifies that a surface is multisample, and therefore requires the full + * mob-backing to store all the samples. + */ +#define SVGA3D_SURFACE_MULTISAMPLE (CONST64U(1) << 32) + +#define SVGA3D_SURFACE_FLAG_MAX (CONST64U(1) << 33) + +/* + * Surface flags types: + * + * SVGA3dSurface1Flags: Lower 32-bits of flags. + * SVGA3dSurface2Flags: Upper 32-bits of flags. + * SVGA3dSurfaceAllFlags: Full 64-bits of flags. + */ +typedef uint32 SVGA3dSurface1Flags; +typedef uint32 SVGA3dSurface2Flags; +typedef uint64 SVGA3dSurfaceAllFlags; + +#define SVGA3D_SURFACE_FLAGS1_MASK ((uint64_t)MAX_UINT32) +#define SVGA3D_SURFACE_FLAGS2_MASK (MAX_UINT64 & ~SVGA3D_SURFACE_FLAGS1_MASK) #define SVGA3D_SURFACE_HB_DISALLOWED_MASK \ ( SVGA3D_SURFACE_MOB_PITCH | \ @@ -393,29 +427,41 @@ typedef enum SVGA3dSurfaceFlags { SVGA3D_SURFACE_STAGING_UPLOAD | \ SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_HINT_INDIRECT_UPDATE | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_HB_PRESENT_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MULTISAMPLE \ ) #define SVGA3D_SURFACE_2D_DISALLOWED_MASK \ ( SVGA3D_SURFACE_CUBEMAP | \ SVGA3D_SURFACE_MASKABLE_ANTIALIAS | \ SVGA3D_SURFACE_AUTOGENMIPMAPS | \ - SVGA3D_SURFACE_DECODE_RENDERTARGET | \ SVGA3D_SURFACE_VOLUME | \ SVGA3D_SURFACE_1D | \ - SVGA3D_SURFACE_ARRAY | \ SVGA3D_SURFACE_BIND_VERTEX_BUFFER | \ SVGA3D_SURFACE_BIND_INDEX_BUFFER | \ SVGA3D_SURFACE_BIND_CONSTANT_BUFFER | \ SVGA3D_SURFACE_BIND_DEPTH_STENCIL | \ SVGA3D_SURFACE_BIND_STREAM_OUTPUT | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_BASICOPS_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MULTISAMPLE \ ) #define SVGA3D_SURFACE_SCREENTARGET_DISALLOWED_MASK \ ( SVGA3D_SURFACE_CUBEMAP | \ SVGA3D_SURFACE_AUTOGENMIPMAPS | \ - SVGA3D_SURFACE_DECODE_RENDERTARGET | \ SVGA3D_SURFACE_VOLUME | \ SVGA3D_SURFACE_1D | \ SVGA3D_SURFACE_BIND_VERTEX_BUFFER | \ @@ -427,12 +473,36 @@ typedef enum SVGA3dSurfaceFlags { SVGA3D_SURFACE_STAGING_UPLOAD | \ SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_HINT_INDIRECT_UPDATE | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_BUFFER_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MASKABLE_ANTIALIAS | \ + SVGA3D_SURFACE_ARRAY | \ + SVGA3D_SURFACE_MULTISAMPLE | \ + SVGA3D_SURFACE_MOB_PITCH \ + ) + +#define SVGA3D_SURFACE_MULTISAMPLE_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_SCREENTARGET | \ + SVGA3D_SURFACE_MOB_PITCH \ ) #define SVGA3D_SURFACE_DX_ONLY_MASK \ ( SVGA3D_SURFACE_BIND_STREAM_OUTPUT | \ + SVGA3D_SURFACE_STAGING_UPLOAD | \ + SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + ) #define SVGA3D_SURFACE_STAGING_MASK \ ( SVGA3D_SURFACE_STAGING_UPLOAD | \ @@ -488,7 +558,7 @@ typedef enum { /* * Indicates that this format can be converted to any RGB format for which - * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified + * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified. */ SVGA3DFORMAT_OP_CONVERT_TO_ARGB = 0x00002000, @@ -499,22 +569,22 @@ typedef enum { /* * Indicated that this format can be read as an SRGB texture (meaning that the - * sampler will linearize the looked up data) + * sampler will linearize the looked up data). */ SVGA3DFORMAT_OP_SRGBREAD = 0x00008000, /* - * Indicates that this format can be used in the bumpmap instructions + * Indicates that this format can be used in the bumpmap instructions. */ SVGA3DFORMAT_OP_BUMPMAP = 0x00010000, /* - * Indicates that this format can be sampled by the displacement map sampler + * Indicates that this format can be sampled by the displacement map sampler. */ SVGA3DFORMAT_OP_DMAP = 0x00020000, /* - * Indicates that this format cannot be used with texture filtering + * Indicates that this format cannot be used with texture filtering. */ SVGA3DFORMAT_OP_NOFILTER = 0x00040000, @@ -531,18 +601,18 @@ typedef enum { SVGA3DFORMAT_OP_SRGBWRITE = 0x00100000, /* - * Indicates that this format cannot be used with alpha blending + * Indicates that this format cannot be used with alpha blending. */ SVGA3DFORMAT_OP_NOALPHABLEND = 0x00200000, /* * Indicates that the device can auto-generated sublevels for resources - * of this format + * of this format. */ SVGA3DFORMAT_OP_AUTOGENMIPMAP = 0x00400000, /* - * Indicates that this format can be used by vertex texture sampler + * Indicates that this format can be used by vertex texture sampler. */ SVGA3DFORMAT_OP_VERTEXTEXTURE = 0x00800000, @@ -1502,7 +1572,6 @@ union SVGADXQueryResultUnion { #include "vmware_pack_end.h" SVGADXQueryResultUnion; - typedef enum { SVGA3D_QUERYSTATE_PENDING = 0, /* Query is not finished yet */ SVGA3D_QUERYSTATE_SUCCEEDED = 1, /* Completed successfully */ @@ -1534,9 +1603,9 @@ typedef struct { union { struct { - uint16 function; /* SVGA3dFogFunction */ - uint8 type; /* SVGA3dFogType */ - uint8 base; /* SVGA3dFogBase */ + uint16 function; /* SVGA3dFogFunction */ + uint8 type; /* SVGA3dFogType */ + uint8 base; /* SVGA3dFogBase */ }; uint32 uintValue; }; @@ -1548,19 +1617,27 @@ SVGA3dFogMode; * Uniquely identify one image (a 1D/2D/3D array) from a surface. This * is a surface ID as well as face/mipmap indices. */ - typedef #include "vmware_pack_begin.h" struct SVGA3dSurfaceImageId { - uint32 sid; - uint32 face; - uint32 mipmap; + uint32 sid; + uint32 face; + uint32 mipmap; } #include "vmware_pack_end.h" SVGA3dSurfaceImageId; typedef #include "vmware_pack_begin.h" +struct SVGA3dSubSurfaceId { + uint32 sid; + uint32 subResourceId; +} +#include "vmware_pack_end.h" +SVGA3dSubSurfaceId; + +typedef +#include "vmware_pack_begin.h" struct { uint32 width; uint32 height; @@ -1583,13 +1660,18 @@ typedef enum { SVGA_OTABLE_DX9_MAX = 5, SVGA_OTABLE_DXCONTEXT = 5, - SVGA_OTABLE_MAX = 6 -} SVGAOTableType; + SVGA_OTABLE_DX_MAX = 6, -/* - * Deprecated. - */ -#define SVGA_OTABLE_COUNT 4 + SVGA_OTABLE_RESERVED1 = 6, + SVGA_OTABLE_RESERVED2 = 7, + + /* + * Additions to this table need to be tied to HW-version features and + * checkpointed accordingly. + */ + SVGA_OTABLE_DEVEL_MAX = 8, + SVGA_OTABLE_MAX = 8 +} SVGAOTableType; typedef enum { SVGA_COTABLE_MIN = 0, @@ -1606,7 +1688,7 @@ typedef enum { SVGA_COTABLE_DXSHADER = 10, SVGA_COTABLE_DX10_MAX = 11, SVGA_COTABLE_UAVIEW = 11, - SVGA_COTABLE_MAX + SVGA_COTABLE_MAX = 12, } SVGACOTableType; /* @@ -1627,8 +1709,37 @@ typedef enum SVGAMobFormat { SVGA3D_MOBFMT_PREDX_MAX = 7, SVGA3D_MOBFMT_EMPTY = 7, SVGA3D_MOBFMT_MAX, + + /* + * This isn't actually used by the guest, but is a mob-format used + * internally by the SVGA device (and is therefore not binary compatible). + */ + SVGA3D_MOBFMT_HB, } SVGAMobFormat; #define SVGA3D_MOB_EMPTY_BASE 1 +/* + * Multisample pattern types. + */ + +typedef enum SVGA3dMSPattern { + SVGA3D_MS_PATTERN_NONE = 0, + SVGA3D_MS_PATTERN_MIN = 0, + SVGA3D_MS_PATTERN_STANDARD = 1, + SVGA3D_MS_PATTERN_CENTER = 2, + SVGA3D_MS_PATTERN_MAX = 3, +} SVGA3dMSPattern; + +/* + * Precision settings for each sample. + */ + +typedef enum SVGA3dMSQualityLevel { + SVGA3D_MS_QUALITY_NONE = 0, + SVGA3D_MS_QUALITY_MIN = 0, + SVGA3D_MS_QUALITY_FULL = 1, + SVGA3D_MS_QUALITY_MAX = 2, +} SVGA3dMSQualityLevel; + #endif /* _SVGA3D_TYPES_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 847e3301c478..056f54b35d73 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -64,16 +64,26 @@ typedef uint32 SVGAMobId; #define SVGA_MAX_BITS_PER_PIXEL 32 #define SVGA_MAX_DEPTH 24 #define SVGA_MAX_DISPLAYS 10 +#define SVGA_MAX_SCREEN_SIZE 8192 +#define SVGA_SCREEN_ROOT_LIMIT (SVGA_MAX_SCREEN_SIZE * SVGA_MAX_DISPLAYS) + /* * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned * cursor bypass mode. This is still supported, but no new guest * drivers should use it. */ -#define SVGA_CURSOR_ON_HIDE 0x0 /* Must be 0 to maintain backward compatibility */ -#define SVGA_CURSOR_ON_SHOW 0x1 /* Must be 1 to maintain backward compatibility */ -#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 /* Remove the cursor from the framebuffer because we need to see what's under it */ -#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* Put the cursor back in the framebuffer so the user can see it */ +#define SVGA_CURSOR_ON_HIDE 0x0 +#define SVGA_CURSOR_ON_SHOW 0x1 + +/* + * Remove the cursor from the framebuffer + * because we need to see what's under it + */ +#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 + +/* Put the cursor back in the framebuffer so the user can see it */ +#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* * The maximum framebuffer size that can traced for guests unless the @@ -102,7 +112,10 @@ typedef uint32 SVGAMobId; #define SVGA_VERSION_0 0 #define SVGA_ID_0 SVGA_MAKE_ID(SVGA_VERSION_0) -/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */ +/* + * "Invalid" value for all SVGA IDs. + * (Version ID, screen object ID, surface ID...) + */ #define SVGA_ID_INVALID 0xFFFFFFFF /* Port offsets, relative to BAR0 */ @@ -155,7 +168,7 @@ enum { SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */ SVGA_REG_SYNC = 21, /* See "FIFO Synchronization Registers" */ SVGA_REG_BUSY = 22, /* See "FIFO Synchronization Registers" */ - SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */ + SVGA_REG_GUEST_ID = 23, /* (Deprecated) */ SVGA_REG_CURSOR_ID = 24, /* (Deprecated) */ SVGA_REG_CURSOR_X = 25, /* (Deprecated) */ SVGA_REG_CURSOR_Y = 26, /* (Deprecated) */ @@ -187,7 +200,14 @@ enum { SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */ SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */ - SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */ + + /* + * Max primary memory. + * See SVGA_CAP_NO_BB_RESTRICTION. + */ + SVGA_REG_MAX_PRIMARY_MEM = 50, + SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, + SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Sugested limit on mob mem */ SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */ SVGA_REG_CMD_PREPEND_LOW = 53, @@ -195,7 +215,10 @@ enum { SVGA_REG_SCREENTARGET_MAX_WIDTH = 55, SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56, SVGA_REG_MOB_MAX_SIZE = 57, - SVGA_REG_TOP = 58, /* Must be 1 more than the last register */ + SVGA_REG_BLANK_SCREEN_TARGETS = 58, + SVGA_REG_CAP2 = 59, + SVGA_REG_DEVEL_CAP = 60, + SVGA_REG_TOP = 61, /* Must be 1 more than the last register */ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ @@ -393,6 +416,7 @@ typedef enum { SVGA_CB_CONTEXT_0 = 0x0, SVGA_CB_CONTEXT_1 = 0x1, /* Supported with SVGA_CAP_HP_CMD_QUEUE */ SVGA_CB_CONTEXT_MAX = 0x2, + SVGA_CB_CONTEXT_HP_MAX = 0x2, } SVGACBContext; @@ -449,6 +473,18 @@ typedef enum { * due to an error. No IRQ is raised. */ SVGA_CB_STATUS_SUBMISSION_ERROR = 6, + + /* + * Written by the host when the host finished a + * SVGA_DC_CMD_ASYNC_STOP_QUEUE request for this command buffer + * queue. The offset of the first byte not processed is stored in + * the errorOffset field of the command buffer header. All guest + * visible side effects of commands till that point are guaranteed + * to be finished before this is written. The + * SVGA_IRQFLAG_COMMAND_BUFFER IRQ is raised as long as the + * SVGA_CB_FLAG_NO_IRQ is not set. + */ + SVGA_CB_STATUS_PARTIAL_COMPLETE = 7, } SVGACBStatus; typedef enum { @@ -461,8 +497,8 @@ typedef enum { typedef #include "vmware_pack_begin.h" struct { - volatile SVGACBStatus status; - volatile uint32 errorOffset; + volatile SVGACBStatus status; /* Modified by device. */ + volatile uint32 errorOffset; /* Modified by device. */ uint64 id; SVGACBFlags flags; uint32 length; @@ -473,7 +509,9 @@ struct { uint32 mobOffset; } mob; } ptr; - uint32 offset; /* Valid if CMD_BUFFERS_2 cap set, must be zero otherwise */ + uint32 offset; /* Valid if CMD_BUFFERS_2 cap set, must be zero otherwise, + * modified by device. + */ uint32 dxContext; /* Valid if DX_CONTEXT flag set, must be zero otherwise */ uint32 mustBeZero[6]; } @@ -484,20 +522,26 @@ typedef enum { SVGA_DC_CMD_NOP = 0, SVGA_DC_CMD_START_STOP_CONTEXT = 1, SVGA_DC_CMD_PREEMPT = 2, - SVGA_DC_CMD_MAX = 3, - SVGA_DC_CMD_FORCE_UINT = MAX_UINT32, + SVGA_DC_CMD_START_QUEUE = 3, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_ASYNC_STOP_QUEUE = 4, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_EMPTY_CONTEXT_QUEUE = 5, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_MAX = 6, } SVGADeviceContextCmdId; -typedef struct { +/* + * Starts or stops both SVGA_CB_CONTEXT_0 and SVGA_CB_CONTEXT_1. + */ + +typedef struct SVGADCCmdStartStop { uint32 enable; - SVGACBContext context; + SVGACBContext context; /* Must be zero */ } SVGADCCmdStartStop; /* * SVGADCCmdPreempt -- * * This command allows the guest to request that all command buffers - * on the specified context be preempted that can be. After execution + * on SVGA_CB_CONTEXT_0 be preempted that can be. After execution * of this command all command buffers that were preempted will * already have SVGA_CB_STATUS_PREEMPTED written into the status * field. The device might still be processing a command buffer, @@ -507,12 +551,69 @@ typedef struct { * command buffer header set to zero. */ -typedef struct { - SVGACBContext context; +typedef struct SVGADCCmdPreempt { + SVGACBContext context; /* Must be zero */ uint32 ignoreIDZero; } SVGADCCmdPreempt; /* + * Starts the requested command buffer processing queue. Valid only + * if the SVGA_CAP_HP_CMD_QUEUE cap is set. + * + * For a command queue to be considered runnable it must be enabled + * and any corresponding higher priority queues must also be enabled. + * For example in order for command buffers to be processed on + * SVGA_CB_CONTEXT_0 both SVGA_CB_CONTEXT_0 and SVGA_CB_CONTEXT_1 must + * be enabled. But for commands to be runnable on SVGA_CB_CONTEXT_1 + * only that queue must be enabled. + */ + +typedef struct SVGADCCmdStartQueue { + SVGACBContext context; +} SVGADCCmdStartQueue; + +/* + * Requests the SVGA device to stop processing the requested command + * buffer queue as soon as possible. The guest knows the stop has + * completed when one of the following happens. + * + * 1) A command buffer status of SVGA_CB_STATUS_PARTIAL_COMPLETE is returned + * 2) A command buffer error is encountered with would stop the queue + * regardless of the async stop request. + * 3) All command buffers that have been submitted complete successfully. + * 4) The stop completes synchronously if no command buffers are + * active on the queue when it is issued. + * + * If the command queue is not in a runnable state there is no + * guarentee this async stop will finish. For instance if the high + * priority queue is not enabled and a stop is requested on the low + * priority queue, the high priority queue must be reenabled to + * guarantee that the async stop will finish. + * + * This command along with SVGA_DC_CMD_EMPTY_CONTEXT_QUEUE can be used + * to implement mid command buffer preemption. + * + * Valid only if the SVGA_CAP_HP_CMD_QUEUE cap is set. + */ + +typedef struct SVGADCCmdAsyncStopQueue { + SVGACBContext context; +} SVGADCCmdAsyncStopQueue; + +/* + * Requests the SVGA device to throw away any full command buffers on + * the requested command queue that have not been started. For a + * driver to know which command buffers were thrown away a driver + * should only issue this command when the queue is stopped, for + * whatever reason. + */ + +typedef struct SVGADCCmdEmptyQueue { + SVGACBContext context; +} SVGADCCmdEmptyQueue; + + +/* * SVGAGMRImageFormat -- * * This is a packed representation of the source 2D image format @@ -537,7 +638,7 @@ typedef struct SVGAGMRImageFormat { struct { uint32 bitsPerPixel : 8; uint32 colorDepth : 8; - uint32 reserved : 16; /* Must be zero */ + uint32 reserved : 16; /* Must be zero */ }; uint32 value; @@ -673,8 +774,36 @@ SVGASignedPoint; * SVGA_CAP_GBOBJECTS -- * Enable guest-backed objects and surfaces. * - * SVGA_CAP_CMD_BUFFERS_3 -- - * Enable support for command buffers in a mob. + * SVGA_CAP_DX -- + * Enable support for DX commands, and command buffers in a mob. + * + * SVGA_CAP_HP_CMD_QUEUE -- + * Enable support for the high priority command queue, and the + * ScreenCopy command. + * + * SVGA_CAP_NO_BB_RESTRICTION -- + * Allow ScreenTargets to be defined without regard to the 32-bpp + * bounding-box memory restrictions. ie: + * + * The summed memory usage of all screens (assuming they were defined as + * 32-bpp) must always be less than the value of the + * SVGA_REG_MAX_PRIMARY_MEM register. + * + * If this cap is not present, the 32-bpp bounding box around all screens + * must additionally be under the value of the SVGA_REG_MAX_PRIMARY_MEM + * register. + * + * If the cap is present, the bounding box restriction is lifted (and only + * the screen-sum limit applies). + * + * (Note that this is a slight lie... there is still a sanity limit on any + * dimension of the topology to be less than SVGA_SCREEN_ROOT_LIMIT, even + * when SVGA_CAP_NO_BB_RESTRICTION is present, but that should be + * large enough to express any possible topology without holes between + * monitors.) + * + * SVGA_CAP_CAP2_REGISTER -- + * If this cap is present, the SVGA_REG_CAP2 register is supported. */ #define SVGA_CAP_NONE 0x00000000 @@ -700,8 +829,30 @@ SVGASignedPoint; #define SVGA_CAP_GBOBJECTS 0x08000000 #define SVGA_CAP_DX 0x10000000 #define SVGA_CAP_HP_CMD_QUEUE 0x20000000 +#define SVGA_CAP_NO_BB_RESTRICTION 0x40000000 +#define SVGA_CAP_CAP2_REGISTER 0x80000000 -#define SVGA_CAP_CMD_RESERVED 0x80000000 +/* + * The SVGA_REG_CAP2 register is an additional set of SVGA capability bits. + * + * SVGA_CAP2_GROW_OTABLE -- + * Allow the GrowOTable/DXGrowCOTable commands. + * + * SVGA_CAP2_INTRA_SURFACE_COPY -- + * Allow the IntraSurfaceCopy command. + * + * SVGA_CAP2_DX2 -- + * Allow the DefineGBSurface_v3, WholeSurfaceCopy. + * + * SVGA_CAP2_RESERVED -- + * Reserve the last bit for extending the SVGA capabilities to some + * future mechanisms. + */ +#define SVGA_CAP2_NONE 0x00000000 +#define SVGA_CAP2_GROW_OTABLE 0x00000001 +#define SVGA_CAP2_INTRA_SURFACE_COPY 0x00000002 +#define SVGA_CAP2_DX2 0x00000004 +#define SVGA_CAP2_RESERVED 0x80000000 /* @@ -723,7 +874,8 @@ typedef enum { SVGABackdoorCapDeviceCaps = 0, SVGABackdoorCapFifoCaps = 1, SVGABackdoorCap3dHWVersion = 2, - SVGABackdoorCapMax = 3, + SVGABackdoorCapDeviceCaps2 = 3, + SVGABackdoorCapMax = 4, } SVGABackdoorCapType; @@ -1915,16 +2067,6 @@ SVGAFifoCmdRemapGMR2; #define SVGA_VRAM_SIZE_W2K (64 * 1024 * 1024) /* 64 MB */ -/* - * To simplify autoDetect display configuration, support a minimum of - * two 1920x1200 monitors, 32bpp, side-by-side, optionally rotated: - * numDisplays = 2 - * maxWidth = numDisplay * 1920 = 3840 - * maxHeight = rotated width of single monitor = 1920 - * vramSize = maxWidth * maxHeight * 4 = 29491200 - */ -#define SVGA_VRAM_SIZE_AUTODETECT (32 * 1024 * 1024) - #if defined(VMX86_SERVER) #define SVGA_VRAM_SIZE (4 * 1024 * 1024) #define SVGA_VRAM_SIZE_3D (64 * 1024 * 1024) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h index 53602a4e7957..350bbc6fab02 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h @@ -41,7 +41,10 @@ typedef uint64 PPN64; typedef bool Bool; +#define MAX_UINT64 U64_MAX #define MAX_UINT32 U32_MAX #define MAX_UINT16 U16_MAX +#define CONST64U(x) x##ULL + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c new file mode 100644 index 000000000000..2dda03345761 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -0,0 +1,1123 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/************************************************************************** + * + * Copyright © 2011-2018 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <drm/ttm/ttm_placement.h> + +#include <drm/drmP.h> +#include "vmwgfx_drv.h" +#include "drm/ttm/ttm_object.h" + + +/** + * struct vmw_user_buffer_object - User-space-visible buffer object + * + * @prime: The prime object providing user visibility. + * @vbo: The struct vmw_buffer_object + */ +struct vmw_user_buffer_object { + struct ttm_prime_object prime; + struct vmw_buffer_object vbo; +}; + + +/** + * vmw_buffer_object - Convert a struct ttm_buffer_object to a struct + * vmw_buffer_object. + * + * @bo: Pointer to the TTM buffer object. + * Return: Pointer to the struct vmw_buffer_object embedding the + * TTM buffer object. + */ +static struct vmw_buffer_object * +vmw_buffer_object(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct vmw_buffer_object, base); +} + + +/** + * vmw_user_buffer_object - Convert a struct ttm_buffer_object to a struct + * vmw_user_buffer_object. + * + * @bo: Pointer to the TTM buffer object. + * Return: Pointer to the struct vmw_buffer_object embedding the TTM buffer + * object. + */ +static struct vmw_user_buffer_object * +vmw_user_buffer_object(struct ttm_buffer_object *bo) +{ + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); + + return container_of(vmw_bo, struct vmw_user_buffer_object, vbo); +} + + +/** + * vmw_bo_pin_in_placement - Validate a buffer to placement. + * + * @dev_priv: Driver private. + * @buf: DMA buffer to move. + * @placement: The placement to pin it. + * @interruptible: Use interruptible wait. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal + */ +int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + struct ttm_placement *placement, + bool interruptible) +{ + struct ttm_operation_ctx ctx = {interruptible, false }; + struct ttm_buffer_object *bo = &buf->base; + int ret; + uint32_t new_flags; + + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); + if (unlikely(ret != 0)) + return ret; + + vmw_execbuf_release_pinned_bo(dev_priv); + + ret = ttm_bo_reserve(bo, interruptible, false, NULL); + if (unlikely(ret != 0)) + goto err; + + if (buf->pin_count > 0) + ret = ttm_bo_mem_compat(placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + else + ret = ttm_bo_validate(bo, placement, &ctx); + + if (!ret) + vmw_bo_pin_reserved(buf, true); + + ttm_bo_unreserve(bo); + +err: + ttm_write_unlock(&dev_priv->reservation_sem); + return ret; +} + + +/** + * vmw_bo_pin_in_vram_or_gmr - Move a buffer to vram or gmr. + * + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. + * + * @dev_priv: Driver private. + * @buf: DMA buffer to move. + * @pin: Pin buffer if true. + * @interruptible: Use interruptible wait. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal + */ +int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) +{ + struct ttm_operation_ctx ctx = {interruptible, false }; + struct ttm_buffer_object *bo = &buf->base; + int ret; + uint32_t new_flags; + + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); + if (unlikely(ret != 0)) + return ret; + + vmw_execbuf_release_pinned_bo(dev_priv); + + ret = ttm_bo_reserve(bo, interruptible, false, NULL); + if (unlikely(ret != 0)) + goto err; + + if (buf->pin_count > 0) { + ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + goto out_unreserve; + } + + ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, &ctx); + if (likely(ret == 0) || ret == -ERESTARTSYS) + goto out_unreserve; + + ret = ttm_bo_validate(bo, &vmw_vram_placement, &ctx); + +out_unreserve: + if (!ret) + vmw_bo_pin_reserved(buf, true); + + ttm_bo_unreserve(bo); +err: + ttm_write_unlock(&dev_priv->reservation_sem); + return ret; +} + + +/** + * vmw_bo_pin_in_vram - Move a buffer to vram. + * + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. + * + * @dev_priv: Driver private. + * @buf: DMA buffer to move. + * @interruptible: Use interruptible wait. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal + */ +int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) +{ + return vmw_bo_pin_in_placement(dev_priv, buf, &vmw_vram_placement, + interruptible); +} + + +/** + * vmw_bo_pin_in_start_of_vram - Move a buffer to start of vram. + * + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. + * + * @dev_priv: Driver private. + * @buf: DMA buffer to pin. + * @interruptible: Use interruptible wait. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal + */ +int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) +{ + struct ttm_operation_ctx ctx = {interruptible, false }; + struct ttm_buffer_object *bo = &buf->base; + struct ttm_placement placement; + struct ttm_place place; + int ret = 0; + uint32_t new_flags; + + place = vmw_vram_placement.placement[0]; + place.lpfn = bo->num_pages; + placement.num_placement = 1; + placement.placement = &place; + placement.num_busy_placement = 1; + placement.busy_placement = &place; + + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); + if (unlikely(ret != 0)) + return ret; + + vmw_execbuf_release_pinned_bo(dev_priv); + ret = ttm_bo_reserve(bo, interruptible, false, NULL); + if (unlikely(ret != 0)) + goto err_unlock; + + /* + * Is this buffer already in vram but not at the start of it? + * In that case, evict it first because TTM isn't good at handling + * that situation. + */ + if (bo->mem.mem_type == TTM_PL_VRAM && + bo->mem.start < bo->num_pages && + bo->mem.start > 0 && + buf->pin_count == 0) { + ctx.interruptible = false; + (void) ttm_bo_validate(bo, &vmw_sys_placement, &ctx); + } + + if (buf->pin_count > 0) + ret = ttm_bo_mem_compat(&placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + else + ret = ttm_bo_validate(bo, &placement, &ctx); + + /* For some reason we didn't end up at the start of vram */ + WARN_ON(ret == 0 && bo->offset != 0); + if (!ret) + vmw_bo_pin_reserved(buf, true); + + ttm_bo_unreserve(bo); +err_unlock: + ttm_write_unlock(&dev_priv->reservation_sem); + + return ret; +} + + +/** + * vmw_bo_unpin - Unpin the buffer given buffer, does not move the buffer. + * + * This function takes the reservation_sem in write mode. + * + * @dev_priv: Driver private. + * @buf: DMA buffer to unpin. + * @interruptible: Use interruptible wait. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal + */ +int vmw_bo_unpin(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) +{ + struct ttm_buffer_object *bo = &buf->base; + int ret; + + ret = ttm_read_lock(&dev_priv->reservation_sem, interruptible); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_bo_reserve(bo, interruptible, false, NULL); + if (unlikely(ret != 0)) + goto err; + + vmw_bo_pin_reserved(buf, false); + + ttm_bo_unreserve(bo); + +err: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + +/** + * vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement + * of a buffer. + * + * @bo: Pointer to a struct ttm_buffer_object. Must be pinned or reserved. + * @ptr: SVGAGuestPtr returning the result. + */ +void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo, + SVGAGuestPtr *ptr) +{ + if (bo->mem.mem_type == TTM_PL_VRAM) { + ptr->gmrId = SVGA_GMR_FRAMEBUFFER; + ptr->offset = bo->offset; + } else { + ptr->gmrId = bo->mem.start; + ptr->offset = 0; + } +} + + +/** + * vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it. + * + * @vbo: The buffer object. Must be reserved. + * @pin: Whether to pin or unpin. + * + */ +void vmw_bo_pin_reserved(struct vmw_buffer_object *vbo, bool pin) +{ + struct ttm_operation_ctx ctx = { false, true }; + struct ttm_place pl; + struct ttm_placement placement; + struct ttm_buffer_object *bo = &vbo->base; + uint32_t old_mem_type = bo->mem.mem_type; + int ret; + + lockdep_assert_held(&bo->resv->lock.base); + + if (pin) { + if (vbo->pin_count++ > 0) + return; + } else { + WARN_ON(vbo->pin_count <= 0); + if (--vbo->pin_count > 0) + return; + } + + pl.fpfn = 0; + pl.lpfn = 0; + pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB + | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; + if (pin) + pl.flags |= TTM_PL_FLAG_NO_EVICT; + + memset(&placement, 0, sizeof(placement)); + placement.num_placement = 1; + placement.placement = &pl; + + ret = ttm_bo_validate(bo, &placement, &ctx); + + BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type); +} + + +/** + * vmw_bo_map_and_cache - Map a buffer object and cache the map + * + * @vbo: The buffer object to map + * Return: A kernel virtual address or NULL if mapping failed. + * + * This function maps a buffer object into the kernel address space, or + * returns the virtual kernel address of an already existing map. The virtual + * address remains valid as long as the buffer object is pinned or reserved. + * The cached map is torn down on either + * 1) Buffer object move + * 2) Buffer object swapout + * 3) Buffer object destruction + * + */ +void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo) +{ + struct ttm_buffer_object *bo = &vbo->base; + bool not_used; + void *virtual; + int ret; + + virtual = ttm_kmap_obj_virtual(&vbo->map, ¬_used); + if (virtual) + return virtual; + + ret = ttm_bo_kmap(bo, 0, bo->num_pages, &vbo->map); + if (ret) + DRM_ERROR("Buffer object map failed: %d.\n", ret); + + return ttm_kmap_obj_virtual(&vbo->map, ¬_used); +} + + +/** + * vmw_bo_unmap - Tear down a cached buffer object map. + * + * @vbo: The buffer object whose map we are tearing down. + * + * This function tears down a cached map set up using + * vmw_buffer_object_map_and_cache(). + */ +void vmw_bo_unmap(struct vmw_buffer_object *vbo) +{ + if (vbo->map.bo == NULL) + return; + + ttm_bo_kunmap(&vbo->map); +} + + +/** + * vmw_bo_acc_size - Calculate the pinned memory usage of buffers + * + * @dev_priv: Pointer to a struct vmw_private identifying the device. + * @size: The requested buffer size. + * @user: Whether this is an ordinary dma buffer or a user dma buffer. + */ +static size_t vmw_bo_acc_size(struct vmw_private *dev_priv, size_t size, + bool user) +{ + static size_t struct_size, user_struct_size; + size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *)); + + if (unlikely(struct_size == 0)) { + size_t backend_size = ttm_round_pot(vmw_tt_size); + + struct_size = backend_size + + ttm_round_pot(sizeof(struct vmw_buffer_object)); + user_struct_size = backend_size + + ttm_round_pot(sizeof(struct vmw_user_buffer_object)); + } + + if (dev_priv->map_mode == vmw_dma_alloc_coherent) + page_array_size += + ttm_round_pot(num_pages * sizeof(dma_addr_t)); + + return ((user) ? user_struct_size : struct_size) + + page_array_size; +} + + +/** + * vmw_bo_bo_free - vmw buffer object destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +void vmw_bo_bo_free(struct ttm_buffer_object *bo) +{ + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); + + vmw_bo_unmap(vmw_bo); + kfree(vmw_bo); +} + + +/** + * vmw_user_bo_destroy - vmw buffer object destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +static void vmw_user_bo_destroy(struct ttm_buffer_object *bo) +{ + struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo); + + vmw_bo_unmap(&vmw_user_bo->vbo); + ttm_prime_object_kfree(vmw_user_bo, prime); +} + + +/** + * vmw_bo_init - Initialize a vmw buffer object + * + * @dev_priv: Pointer to the device private struct + * @vmw_bo: Pointer to the struct vmw_buffer_object to initialize. + * @size: Buffer object size in bytes. + * @placement: Initial placement. + * @interruptible: Whether waits should be performed interruptible. + * @bo_free: The buffer object destructor. + * Returns: Zero on success, negative error code on error. + * + * Note that on error, the code will free the buffer object. + */ +int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interruptible, + void (*bo_free)(struct ttm_buffer_object *bo)) +{ + struct ttm_bo_device *bdev = &dev_priv->bdev; + size_t acc_size; + int ret; + bool user = (bo_free == &vmw_user_bo_destroy); + + WARN_ON_ONCE(!bo_free && (!user && (bo_free != vmw_bo_bo_free))); + + acc_size = vmw_bo_acc_size(dev_priv, size, user); + memset(vmw_bo, 0, sizeof(*vmw_bo)); + + INIT_LIST_HEAD(&vmw_bo->res_list); + + ret = ttm_bo_init(bdev, &vmw_bo->base, size, + ttm_bo_type_device, placement, + 0, interruptible, acc_size, + NULL, NULL, bo_free); + return ret; +} + + +/** + * vmw_user_bo_release - TTM reference base object release callback for + * vmw user buffer objects + * + * @p_base: The TTM base object pointer about to be unreferenced. + * + * Clears the TTM base object pointer and drops the reference the + * base object has on the underlying struct vmw_buffer_object. + */ +static void vmw_user_bo_release(struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *vmw_user_bo; + struct ttm_base_object *base = *p_base; + struct ttm_buffer_object *bo; + + *p_base = NULL; + + if (unlikely(base == NULL)) + return; + + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, + prime.base); + bo = &vmw_user_bo->vbo.base; + ttm_bo_unref(&bo); +} + + +/** + * vmw_user_bo_ref_obj-release - TTM synccpu reference object release callback + * for vmw user buffer objects + * + * @base: Pointer to the TTM base object + * @ref_type: Reference type of the reference reaching zero. + * + * Called when user-space drops its last synccpu reference on the buffer + * object, Either explicitly or as part of a cleanup file close. + */ +static void vmw_user_bo_ref_obj_release(struct ttm_base_object *base, + enum ttm_ref_type ref_type) +{ + struct vmw_user_buffer_object *user_bo; + + user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); + + switch (ref_type) { + case TTM_REF_SYNCCPU_WRITE: + ttm_bo_synccpu_write_release(&user_bo->vbo.base); + break; + default: + WARN_ONCE(true, "Undefined buffer object reference release.\n"); + } +} + + +/** + * vmw_user_bo_alloc - Allocate a user buffer object + * + * @dev_priv: Pointer to a struct device private. + * @tfile: Pointer to a struct ttm_object_file on which to register the user + * object. + * @size: Size of the buffer object. + * @shareable: Boolean whether the buffer is shareable with other open files. + * @handle: Pointer to where the handle value should be assigned. + * @p_vbo: Pointer to where the refcounted struct vmw_buffer_object pointer + * should be assigned. + * Return: Zero on success, negative error code on error. + */ +int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_vbo, + struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *user_bo; + struct ttm_buffer_object *tmp; + int ret; + + user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); + if (unlikely(!user_bo)) { + DRM_ERROR("Failed to allocate a buffer.\n"); + return -ENOMEM; + } + + ret = vmw_bo_init(dev_priv, &user_bo->vbo, size, + (dev_priv->has_mob) ? + &vmw_sys_placement : + &vmw_vram_sys_placement, true, + &vmw_user_bo_destroy); + if (unlikely(ret != 0)) + return ret; + + tmp = ttm_bo_reference(&user_bo->vbo.base); + ret = ttm_prime_object_init(tfile, + size, + &user_bo->prime, + shareable, + ttm_buffer_type, + &vmw_user_bo_release, + &vmw_user_bo_ref_obj_release); + if (unlikely(ret != 0)) { + ttm_bo_unref(&tmp); + goto out_no_base_object; + } + + *p_vbo = &user_bo->vbo; + if (p_base) { + *p_base = &user_bo->prime.base; + kref_get(&(*p_base)->refcount); + } + *handle = user_bo->prime.base.hash.key; + +out_no_base_object: + return ret; +} + + +/** + * vmw_user_bo_verify_access - verify access permissions on this + * buffer object. + * + * @bo: Pointer to the buffer object being accessed + * @tfile: Identifying the caller. + */ +int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, + struct ttm_object_file *tfile) +{ + struct vmw_user_buffer_object *vmw_user_bo; + + if (unlikely(bo->destroy != vmw_user_bo_destroy)) + return -EPERM; + + vmw_user_bo = vmw_user_buffer_object(bo); + + /* Check that the caller has opened the object. */ + if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) + return 0; + + DRM_ERROR("Could not grant buffer access.\n"); + return -EPERM; +} + + +/** + * vmw_user_bo_synccpu_grab - Grab a struct vmw_user_buffer_object for cpu + * access, idling previous GPU operations on the buffer and optionally + * blocking it for further command submissions. + * + * @user_bo: Pointer to the buffer object being grabbed for CPU access + * @tfile: Identifying the caller. + * @flags: Flags indicating how the grab should be performed. + * Return: Zero on success, Negative error code on error. In particular, + * -EBUSY will be returned if a dontblock operation is requested and the + * buffer object is busy, and -ERESTARTSYS will be returned if a wait is + * interrupted by a signal. + * + * A blocking grab will be automatically released when @tfile is closed. + */ +static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, + struct ttm_object_file *tfile, + uint32_t flags) +{ + struct ttm_buffer_object *bo = &user_bo->vbo.base; + bool existed; + int ret; + + if (flags & drm_vmw_synccpu_allow_cs) { + bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); + long lret; + + lret = reservation_object_wait_timeout_rcu + (bo->resv, true, true, + nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); + if (!lret) + return -EBUSY; + else if (lret < 0) + return lret; + return 0; + } + + ret = ttm_bo_synccpu_write_grab + (bo, !!(flags & drm_vmw_synccpu_dontblock)); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_ref_object_add(tfile, &user_bo->prime.base, + TTM_REF_SYNCCPU_WRITE, &existed, false); + if (ret != 0 || existed) + ttm_bo_synccpu_write_release(&user_bo->vbo.base); + + return ret; +} + +/** + * vmw_user_bo_synccpu_release - Release a previous grab for CPU access, + * and unblock command submission on the buffer if blocked. + * + * @handle: Handle identifying the buffer object. + * @tfile: Identifying the caller. + * @flags: Flags indicating the type of release. + */ +static int vmw_user_bo_synccpu_release(uint32_t handle, + struct ttm_object_file *tfile, + uint32_t flags) +{ + if (!(flags & drm_vmw_synccpu_allow_cs)) + return ttm_ref_object_base_unref(tfile, handle, + TTM_REF_SYNCCPU_WRITE); + + return 0; +} + + +/** + * vmw_user_bo_synccpu_ioctl - ioctl function implementing the synccpu + * functionality. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and calls the + * relevant synccpu functions. + */ +int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_synccpu_arg *arg = + (struct drm_vmw_synccpu_arg *) data; + struct vmw_buffer_object *vbo; + struct vmw_user_buffer_object *user_bo; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct ttm_base_object *buffer_base; + int ret; + + if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 + || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write | + drm_vmw_synccpu_dontblock | + drm_vmw_synccpu_allow_cs)) != 0) { + DRM_ERROR("Illegal synccpu flags.\n"); + return -EINVAL; + } + + switch (arg->op) { + case drm_vmw_synccpu_grab: + ret = vmw_user_bo_lookup(tfile, arg->handle, &vbo, + &buffer_base); + if (unlikely(ret != 0)) + return ret; + + user_bo = container_of(vbo, struct vmw_user_buffer_object, + vbo); + ret = vmw_user_bo_synccpu_grab(user_bo, tfile, arg->flags); + vmw_bo_unreference(&vbo); + ttm_base_object_unref(&buffer_base); + if (unlikely(ret != 0 && ret != -ERESTARTSYS && + ret != -EBUSY)) { + DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + case drm_vmw_synccpu_release: + ret = vmw_user_bo_synccpu_release(arg->handle, tfile, + arg->flags); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + default: + DRM_ERROR("Invalid synccpu operation.\n"); + return -EINVAL; + } + + return 0; +} + + +/** + * vmw_bo_alloc_ioctl - ioctl function implementing the buffer object + * allocation functionality. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and allocates a + * struct vmw_user_buffer_object bo. + */ +int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + union drm_vmw_alloc_dmabuf_arg *arg = + (union drm_vmw_alloc_dmabuf_arg *)data; + struct drm_vmw_alloc_dmabuf_req *req = &arg->req; + struct drm_vmw_dmabuf_rep *rep = &arg->rep; + struct vmw_buffer_object *vbo; + uint32_t handle; + int ret; + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + req->size, false, &handle, &vbo, + NULL); + if (unlikely(ret != 0)) + goto out_no_bo; + + rep->handle = handle; + rep->map_handle = drm_vma_node_offset_addr(&vbo->base.vma_node); + rep->cur_gmr_id = handle; + rep->cur_gmr_offset = 0; + + vmw_bo_unreference(&vbo); + +out_no_bo: + ttm_read_unlock(&dev_priv->reservation_sem); + + return ret; +} + + +/** + * vmw_bo_unref_ioctl - Generic handle close ioctl. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and closes a + * handle to a TTM base object, optionally freeing the object. + */ +int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_unref_dmabuf_arg *arg = + (struct drm_vmw_unref_dmabuf_arg *)data; + + return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + arg->handle, + TTM_REF_USAGE); +} + + +/** + * vmw_user_bo_lookup - Look up a vmw user buffer object from a handle. + * + * @tfile: The TTM object file the handle is registered with. + * @handle: The user buffer object handle + * @out: Pointer to a where a pointer to the embedded + * struct vmw_buffer_object should be placed. + * @p_base: Pointer to where a pointer to the TTM base object should be + * placed, or NULL if no such pointer is required. + * Return: Zero on success, Negative error code on error. + * + * Both the output base object pointer and the vmw buffer object pointer + * will be refcounted. + */ +int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t handle, struct vmw_buffer_object **out, + struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *vmw_user_bo; + struct ttm_base_object *base; + + base = ttm_base_object_lookup(tfile, handle); + if (unlikely(base == NULL)) { + DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", + (unsigned long)handle); + return -ESRCH; + } + + if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { + ttm_base_object_unref(&base); + DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", + (unsigned long)handle); + return -EINVAL; + } + + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, + prime.base); + (void)ttm_bo_reference(&vmw_user_bo->vbo.base); + if (p_base) + *p_base = base; + else + ttm_base_object_unref(&base); + *out = &vmw_user_bo->vbo; + + return 0; +} + + +/** + * vmw_user_bo_reference - Open a handle to a vmw user buffer object. + * + * @tfile: The TTM object file to register the handle with. + * @vbo: The embedded vmw buffer object. + * @handle: Pointer to where the new handle should be placed. + * Return: Zero on success, Negative error code on error. + */ +int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *vbo, + uint32_t *handle) +{ + struct vmw_user_buffer_object *user_bo; + + if (vbo->base.destroy != vmw_user_bo_destroy) + return -EINVAL; + + user_bo = container_of(vbo, struct vmw_user_buffer_object, vbo); + + *handle = user_bo->prime.base.hash.key; + return ttm_ref_object_add(tfile, &user_bo->prime.base, + TTM_REF_USAGE, NULL, false); +} + + +/** + * vmw_bo_fence_single - Utility function to fence a single TTM buffer + * object without unreserving it. + * + * @bo: Pointer to the struct ttm_buffer_object to fence. + * @fence: Pointer to the fence. If NULL, this function will + * insert a fence into the command stream.. + * + * Contrary to the ttm_eu version of this function, it takes only + * a single buffer object instead of a list, and it also doesn't + * unreserve the buffer object, which needs to be done separately. + */ +void vmw_bo_fence_single(struct ttm_buffer_object *bo, + struct vmw_fence_obj *fence) +{ + struct ttm_bo_device *bdev = bo->bdev; + + struct vmw_private *dev_priv = + container_of(bdev, struct vmw_private, bdev); + + if (fence == NULL) { + vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); + reservation_object_add_excl_fence(bo->resv, &fence->base); + dma_fence_put(&fence->base); + } else + reservation_object_add_excl_fence(bo->resv, &fence->base); +} + + +/** + * vmw_dumb_create - Create a dumb kms buffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @args: Pointer to a struct drm_mode_create_dumb structure + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm create_dumb functionality. + * Note that this is very similar to the vmw_bo_alloc ioctl, except + * that the arguments have a different format. + */ +int vmw_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_buffer_object *vbo; + int ret; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + args->size, false, &args->handle, + &vbo, NULL); + if (unlikely(ret != 0)) + goto out_no_bo; + + vmw_bo_unreference(&vbo); +out_no_bo: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + + +/** + * vmw_dumb_map_offset - Return the address space offset of a dumb buffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @handle: Handle identifying the dumb buffer. + * @offset: The address space offset returned. + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm dumb_map_offset functionality. + */ +int vmw_dumb_map_offset(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset) +{ + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_buffer_object *out_buf; + int ret; + + ret = vmw_user_bo_lookup(tfile, handle, &out_buf, NULL); + if (ret != 0) + return -EINVAL; + + *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node); + vmw_bo_unreference(&out_buf); + return 0; +} + + +/** + * vmw_dumb_destroy - Destroy a dumb boffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @handle: Handle identifying the dumb buffer. + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm dumb_destroy functionality. + */ +int vmw_dumb_destroy(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle) +{ + return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + handle, TTM_REF_USAGE); +} + + +/** + * vmw_bo_swap_notify - swapout notify callback. + * + * @bo: The buffer object to be swapped out. + */ +void vmw_bo_swap_notify(struct ttm_buffer_object *bo) +{ + /* Is @bo embedded in a struct vmw_buffer_object? */ + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) + return; + + /* Kill any cached kernel maps before swapout */ + vmw_bo_unmap(vmw_buffer_object(bo)); +} + + +/** + * vmw_bo_move_notify - TTM move_notify_callback + * + * @bo: The TTM buffer object about to move. + * @mem: The struct ttm_mem_reg indicating to what memory + * region the move is taking place. + * + * Detaches cached maps and device bindings that require that the + * buffer doesn't move. + */ +void vmw_bo_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem) +{ + struct vmw_buffer_object *vbo; + + if (mem == NULL) + return; + + /* Make sure @bo is embedded in a struct vmw_buffer_object? */ + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) + return; + + vbo = container_of(bo, struct vmw_buffer_object, base); + + /* + * Kill any cached kernel maps before move to or from VRAM. + * With other types of moves, the underlying pages stay the same, + * and the map can be kept. + */ + if (mem->mem_type == TTM_PL_VRAM || bo->mem.mem_type == TTM_PL_VRAM) + vmw_bo_unmap(vbo); + + /* + * If we're moving a backup MOB out of MOB placement, then make sure we + * read back all resource content first, and unbind the MOB from + * the resource. + */ + if (mem->mem_type != VMW_PL_MOB && bo->mem.mem_type == VMW_PL_MOB) + vmw_resource_unbind_list(vbo); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 750319d95458..7c3cb8efd11a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -38,7 +38,7 @@ struct vmw_user_context { struct vmw_cmdbuf_res_manager *man; struct vmw_resource *cotables[SVGA_COTABLE_DX10_MAX]; spinlock_t cotable_lock; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; }; static void vmw_user_context_free(struct vmw_resource *res); @@ -424,7 +424,7 @@ static int vmw_gb_context_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -648,7 +648,7 @@ static int vmw_dx_context_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -900,7 +900,7 @@ vmw_context_binding_state(struct vmw_resource *ctx) * specified in the parameter. 0 otherwise. */ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, - struct vmw_dma_buffer *mob) + struct vmw_buffer_object *mob) { struct vmw_user_context *uctx = container_of(ctx_res, struct vmw_user_context, res); @@ -908,7 +908,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, if (mob == NULL) { if (uctx->dx_query_mob) { uctx->dx_query_mob->dx_query_ctx = NULL; - vmw_dmabuf_unreference(&uctx->dx_query_mob); + vmw_bo_unreference(&uctx->dx_query_mob); uctx->dx_query_mob = NULL; } @@ -922,7 +922,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, mob->dx_query_ctx = ctx_res; if (!uctx->dx_query_mob) - uctx->dx_query_mob = vmw_dmabuf_reference(mob); + uctx->dx_query_mob = vmw_bo_reference(mob); return 0; } @@ -932,7 +932,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, * * @ctx_res: The context resource */ -struct vmw_dma_buffer * +struct vmw_buffer_object * vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res) { struct vmw_user_context *uctx = diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index df55e7d8b4cf..1d45714e1d5a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -324,7 +324,7 @@ static int vmw_cotable_unbind(struct vmw_resource *res, vmw_dx_context_scrub_cotables(vcotbl->ctx, readback); mutex_unlock(&dev_priv->binding_mutex); (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -367,7 +367,7 @@ static int vmw_cotable_readback(struct vmw_resource *res) } (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(&res->backup->base, fence); + vmw_bo_fence_single(&res->backup->base, fence); vmw_fence_obj_unreference(&fence); return 0; @@ -390,7 +390,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) struct ttm_operation_ctx ctx = { false, false }; struct vmw_private *dev_priv = res->dev_priv; struct vmw_cotable *vcotbl = vmw_cotable(res); - struct vmw_dma_buffer *buf, *old_buf = res->backup; + struct vmw_buffer_object *buf, *old_buf = res->backup; struct ttm_buffer_object *bo, *old_bo = &res->backup->base; size_t old_size = res->backup_size; size_t old_size_read_back = vcotbl->size_read_back; @@ -415,8 +415,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) if (!buf) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, - true, vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, + true, vmw_bo_bo_free); if (ret) { DRM_ERROR("Failed initializing new cotable MOB.\n"); return ret; @@ -482,7 +482,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) /* Let go of the old mob. */ list_del(&res->mob_head); list_add_tail(&res->mob_head, &buf->res_list); - vmw_dmabuf_unreference(&old_buf); + vmw_bo_unreference(&old_buf); res->id = vcotbl->type; return 0; @@ -491,7 +491,7 @@ out_map_new: ttm_bo_kunmap(&old_map); out_wait: ttm_bo_unreserve(bo); - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c deleted file mode 100644 index df7d1c97eb82..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/************************************************************************** - * - * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <drm/ttm/ttm_placement.h> - -#include <drm/drmP.h> -#include "vmwgfx_drv.h" - - -/** - * vmw_dmabuf_pin_in_placement - Validate a buffer to placement. - * - * @dev_priv: Driver private. - * @buf: DMA buffer to move. - * @placement: The placement to pin it. - * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - struct ttm_placement *placement, - bool interruptible) -{ - struct ttm_operation_ctx ctx = {interruptible, false }; - struct ttm_buffer_object *bo = &buf->base; - int ret; - uint32_t new_flags; - - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - - vmw_execbuf_release_pinned_bo(dev_priv); - - ret = ttm_bo_reserve(bo, interruptible, false, NULL); - if (unlikely(ret != 0)) - goto err; - - if (buf->pin_count > 0) - ret = ttm_bo_mem_compat(placement, &bo->mem, - &new_flags) == true ? 0 : -EINVAL; - else - ret = ttm_bo_validate(bo, placement, &ctx); - - if (!ret) - vmw_bo_pin_reserved(buf, true); - - ttm_bo_unreserve(bo); - -err: - ttm_write_unlock(&dev_priv->reservation_sem); - return ret; -} - -/** - * vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr. - * - * This function takes the reservation_sem in write mode. - * Flushes and unpins the query bo to avoid failures. - * - * @dev_priv: Driver private. - * @buf: DMA buffer to move. - * @pin: Pin buffer if true. - * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) -{ - struct ttm_operation_ctx ctx = {interruptible, false }; - struct ttm_buffer_object *bo = &buf->base; - int ret; - uint32_t new_flags; - - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - - vmw_execbuf_release_pinned_bo(dev_priv); - - ret = ttm_bo_reserve(bo, interruptible, false, NULL); - if (unlikely(ret != 0)) - goto err; - - if (buf->pin_count > 0) { - ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem, - &new_flags) == true ? 0 : -EINVAL; - goto out_unreserve; - } - - ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, &ctx); - if (likely(ret == 0) || ret == -ERESTARTSYS) - goto out_unreserve; - - ret = ttm_bo_validate(bo, &vmw_vram_placement, &ctx); - -out_unreserve: - if (!ret) - vmw_bo_pin_reserved(buf, true); - - ttm_bo_unreserve(bo); -err: - ttm_write_unlock(&dev_priv->reservation_sem); - return ret; -} - -/** - * vmw_dmabuf_pin_in_vram - Move a buffer to vram. - * - * This function takes the reservation_sem in write mode. - * Flushes and unpins the query bo to avoid failures. - * - * @dev_priv: Driver private. - * @buf: DMA buffer to move. - * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) -{ - return vmw_dmabuf_pin_in_placement(dev_priv, buf, &vmw_vram_placement, - interruptible); -} - -/** - * vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram. - * - * This function takes the reservation_sem in write mode. - * Flushes and unpins the query bo to avoid failures. - * - * @dev_priv: Driver private. - * @buf: DMA buffer to pin. - * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) -{ - struct ttm_operation_ctx ctx = {interruptible, false }; - struct ttm_buffer_object *bo = &buf->base; - struct ttm_placement placement; - struct ttm_place place; - int ret = 0; - uint32_t new_flags; - - place = vmw_vram_placement.placement[0]; - place.lpfn = bo->num_pages; - placement.num_placement = 1; - placement.placement = &place; - placement.num_busy_placement = 1; - placement.busy_placement = &place; - - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - - vmw_execbuf_release_pinned_bo(dev_priv); - ret = ttm_bo_reserve(bo, interruptible, false, NULL); - if (unlikely(ret != 0)) - goto err_unlock; - - /* - * Is this buffer already in vram but not at the start of it? - * In that case, evict it first because TTM isn't good at handling - * that situation. - */ - if (bo->mem.mem_type == TTM_PL_VRAM && - bo->mem.start < bo->num_pages && - bo->mem.start > 0 && - buf->pin_count == 0) { - ctx.interruptible = false; - (void) ttm_bo_validate(bo, &vmw_sys_placement, &ctx); - } - - if (buf->pin_count > 0) - ret = ttm_bo_mem_compat(&placement, &bo->mem, - &new_flags) == true ? 0 : -EINVAL; - else - ret = ttm_bo_validate(bo, &placement, &ctx); - - /* For some reason we didn't end up at the start of vram */ - WARN_ON(ret == 0 && bo->offset != 0); - if (!ret) - vmw_bo_pin_reserved(buf, true); - - ttm_bo_unreserve(bo); -err_unlock: - ttm_write_unlock(&dev_priv->reservation_sem); - - return ret; -} - -/** - * vmw_dmabuf_unpin - Unpin the buffer given buffer, does not move the buffer. - * - * This function takes the reservation_sem in write mode. - * - * @dev_priv: Driver private. - * @buf: DMA buffer to unpin. - * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -int vmw_dmabuf_unpin(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) -{ - struct ttm_buffer_object *bo = &buf->base; - int ret; - - ret = ttm_read_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - - ret = ttm_bo_reserve(bo, interruptible, false, NULL); - if (unlikely(ret != 0)) - goto err; - - vmw_bo_pin_reserved(buf, false); - - ttm_bo_unreserve(bo); - -err: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; -} - -/** - * vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement - * of a buffer. - * - * @bo: Pointer to a struct ttm_buffer_object. Must be pinned or reserved. - * @ptr: SVGAGuestPtr returning the result. - */ -void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo, - SVGAGuestPtr *ptr) -{ - if (bo->mem.mem_type == TTM_PL_VRAM) { - ptr->gmrId = SVGA_GMR_FRAMEBUFFER; - ptr->offset = bo->offset; - } else { - ptr->gmrId = bo->mem.start; - ptr->offset = 0; - } -} - - -/** - * vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it. - * - * @vbo: The buffer object. Must be reserved. - * @pin: Whether to pin or unpin. - * - */ -void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) -{ - struct ttm_operation_ctx ctx = { false, true }; - struct ttm_place pl; - struct ttm_placement placement; - struct ttm_buffer_object *bo = &vbo->base; - uint32_t old_mem_type = bo->mem.mem_type; - int ret; - - lockdep_assert_held(&bo->resv->lock.base); - - if (pin) { - if (vbo->pin_count++ > 0) - return; - } else { - WARN_ON(vbo->pin_count <= 0); - if (--vbo->pin_count > 0) - return; - } - - pl.fpfn = 0; - pl.lpfn = 0; - pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB - | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; - if (pin) - pl.flags |= TTM_PL_FLAG_NO_EVICT; - - memset(&placement, 0, sizeof(placement)); - placement.num_placement = 1; - placement.placement = &pl; - - ret = ttm_bo_validate(bo, &placement, &ctx); - - BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type); -} - - -/* - * vmw_dma_buffer_unmap - Tear down a cached buffer object map. - * - * @vbo: The buffer object whose map we are tearing down. - * - * This function tears down a cached map set up using - * vmw_dma_buffer_map_and_cache(). - */ -void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) -{ - if (vbo->map.bo == NULL) - return; - - ttm_bo_kunmap(&vbo->map); -} - - -/* - * vmw_dma_buffer_map_and_cache - Map a buffer object and cache the map - * - * @vbo: The buffer object to map - * Return: A kernel virtual address or NULL if mapping failed. - * - * This function maps a buffer object into the kernel address space, or - * returns the virtual kernel address of an already existing map. The virtual - * address remains valid as long as the buffer object is pinned or reserved. - * The cached map is torn down on either - * 1) Buffer object move - * 2) Buffer object swapout - * 3) Buffer object destruction - * - */ -void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo) -{ - struct ttm_buffer_object *bo = &vbo->base; - bool not_used; - void *virtual; - int ret; - - virtual = ttm_kmap_obj_virtual(&vbo->map, ¬_used); - if (virtual) - return virtual; - - ret = ttm_bo_kmap(bo, 0, bo->num_pages, &vbo->map); - if (ret) - DRM_ERROR("Buffer object map failed: %d.\n", ret); - - return ttm_kmap_obj_virtual(&vbo->map, ¬_used); -} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index af88cb737be3..bb6dbbe18835 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -137,6 +137,12 @@ #define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ struct drm_vmw_context_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \ + union drm_vmw_gb_surface_create_ext_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ + union drm_vmw_gb_surface_reference_ext_arg) /** * The core DRM version of this macro doesn't account for @@ -153,9 +159,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, + VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, @@ -219,11 +225,17 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { vmw_gb_surface_reference_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_SYNCCPU, - vmw_user_dmabuf_synccpu_ioctl, + vmw_user_bo_synccpu_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, + vmw_gb_surface_define_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, + vmw_gb_surface_reference_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { @@ -258,6 +270,15 @@ MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); +static void vmw_print_capabilities2(uint32_t capabilities2) +{ + DRM_INFO("Capabilities2:\n"); + if (capabilities2 & SVGA_CAP2_GROW_OTABLE) + DRM_INFO(" Grow oTable.\n"); + if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) + DRM_INFO(" IntraSurface copy.\n"); +} + static void vmw_print_capabilities(uint32_t capabilities) { DRM_INFO("Capabilities:\n"); @@ -321,7 +342,7 @@ static void vmw_print_capabilities(uint32_t capabilities) static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { int ret; - struct vmw_dma_buffer *vbo; + struct vmw_buffer_object *vbo; struct ttm_bo_kmap_obj map; volatile SVGA3dQueryResult *result; bool dummy; @@ -335,9 +356,9 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) if (!vbo) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, vbo, PAGE_SIZE, - &vmw_sys_ne_placement, false, - &vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, vbo, PAGE_SIZE, + &vmw_sys_ne_placement, false, + &vmw_bo_bo_free); if (unlikely(ret != 0)) return ret; @@ -358,7 +379,7 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) if (unlikely(ret != 0)) { DRM_ERROR("Dummy query buffer map failed.\n"); - vmw_dmabuf_unreference(&vbo); + vmw_bo_unreference(&vbo); } else dev_priv->dummy_query_bo = vbo; @@ -460,7 +481,7 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) BUG_ON(dev_priv->pinned_bo != NULL); - vmw_dmabuf_unreference(&dev_priv->dummy_query_bo); + vmw_bo_unreference(&dev_priv->dummy_query_bo); if (dev_priv->cman) vmw_cmdbuf_remove_pool(dev_priv->cman); @@ -644,6 +665,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); + mutex_init(&dev_priv->requested_layout_mutex); mutex_init(&dev_priv->global_kms_state_mutex); rwlock_init(&dev_priv->resource_lock); ttm_lock_init(&dev_priv->reservation_sem); @@ -683,6 +705,12 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); + + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) { + dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2); + } + + ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { DRM_INFO("Restricting capabilities due to IOMMU setup.\n"); @@ -751,6 +779,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } vmw_print_capabilities(dev_priv->capabilities); + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) + vmw_print_capabilities2(dev_priv->capabilities2); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) @@ -883,7 +913,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv->has_mob) { spin_lock(&dev_priv->cap_lock); - vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX); + vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DXCONTEXT); dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP); spin_unlock(&dev_priv->cap_lock); } @@ -898,9 +928,23 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) goto out_no_fifo; + if (dev_priv->has_dx) { + /* + * SVGA_CAP2_DX2 (DefineGBSurface_v3) is needed for SM4_1 + * support + */ + if ((dev_priv->capabilities2 & SVGA_CAP2_DX2) != 0) { + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_SM41); + dev_priv->has_sm4_1 = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); + } + } + DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no."); - DRM_INFO("Atomic: %s\n", - (dev->driver->driver_features & DRIVER_ATOMIC) ? "yes" : "no"); + DRM_INFO("Atomic: %s\n", (dev->driver->driver_features & DRIVER_ATOMIC) + ? "yes." : "no."); + DRM_INFO("SM4_1: %s\n", dev_priv->has_sm4_1 ? "yes." : "no."); snprintf(host_log, sizeof(host_log), "vmwgfx: %s-%s", VMWGFX_REPO, VMWGFX_GIT_VERSION); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 422eef114b98..1abe21758b0d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,10 +43,10 @@ #include <linux/sync_file.h> #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20180322" +#define VMWGFX_DRIVER_DATE "20180704" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 14 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 15 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 @@ -83,10 +83,10 @@ struct vmw_fpriv { struct drm_master *locked_master; struct ttm_object_file *tfile; - bool gb_aware; + bool gb_aware; /* user-space is guest-backed aware */ }; -struct vmw_dma_buffer { +struct vmw_buffer_object { struct ttm_buffer_object base; struct list_head res_list; s32 pin_count; @@ -120,7 +120,7 @@ struct vmw_resource { unsigned long backup_size; bool res_dirty; /* Protected by backup buffer reserved */ bool backup_dirty; /* Protected by backup buffer reserved */ - struct vmw_dma_buffer *backup; + struct vmw_buffer_object *backup; unsigned long backup_offset; unsigned long pin_count; /* Protected by resource reserved */ const struct vmw_res_func *func; @@ -166,7 +166,7 @@ struct vmw_surface_offset; struct vmw_surface { struct vmw_resource res; - uint32_t flags; + SVGA3dSurfaceAllFlags flags; uint32_t format; uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES]; struct drm_vmw_size base_size; @@ -180,6 +180,8 @@ struct vmw_surface { SVGA3dTextureFilter autogen_filter; uint32_t multisample_count; struct list_head view_list; + SVGA3dMSPattern multisample_pattern; + SVGA3dMSQualityLevel quality_level; }; struct vmw_marker_queue { @@ -304,7 +306,7 @@ struct vmw_sw_context{ uint32_t cmd_bounce_size; struct list_head resource_list; struct list_head ctx_resource_list; /* For contexts and cotables */ - struct vmw_dma_buffer *cur_query_bo; + struct vmw_buffer_object *cur_query_bo; struct list_head res_relocations; uint32_t *buf_start; struct vmw_res_cache_entry res_cache[vmw_res_max]; @@ -315,7 +317,7 @@ struct vmw_sw_context{ bool staged_bindings_inuse; struct list_head staged_cmd_res; struct vmw_resource_val_node *dx_ctx_node; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct vmw_resource *dx_query_ctx; struct vmw_cmdbuf_res_manager *man; }; @@ -386,6 +388,7 @@ struct vmw_private { uint32_t initial_height; u32 *mmio_virt; uint32_t capabilities; + uint32_t capabilities2; uint32_t max_gmr_ids; uint32_t max_gmr_pages; uint32_t max_mob_pages; @@ -397,6 +400,7 @@ struct vmw_private { spinlock_t cap_lock; bool has_dx; bool assume_16bpp; + bool has_sm4_1; /* * VGA registers. @@ -412,6 +416,15 @@ struct vmw_private { uint32_t num_displays; /* + * Currently requested_layout_mutex is used to protect the gui + * positionig state in display unit. With that use case currently this + * mutex is only taken during layout ioctl and atomic check_modeset. + * Other display unit state can be protected with this mutex but that + * needs careful consideration. + */ + struct mutex requested_layout_mutex; + + /* * Framebuffer info. */ @@ -513,8 +526,8 @@ struct vmw_private { * are protected by the cmdbuf mutex. */ - struct vmw_dma_buffer *dummy_query_bo; - struct vmw_dma_buffer *pinned_bo; + struct vmw_buffer_object *dummy_query_bo; + struct vmw_buffer_object *pinned_bo; uint32_t query_cid; uint32_t query_cid_valid; bool dummy_query_bo_pinned; @@ -623,43 +636,13 @@ extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, struct vmw_surface **out_surf, - struct vmw_dma_buffer **out_buf); + struct vmw_buffer_object **out_buf); extern int vmw_user_resource_lookup_handle( struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, const struct vmw_user_resource_conv *converter, struct vmw_resource **p_res); -extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); -extern int vmw_dmabuf_init(struct vmw_private *dev_priv, - struct vmw_dma_buffer *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interuptable, - void (*bo_free) (struct ttm_buffer_object *bo)); -extern int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile); -extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf, - struct ttm_base_object **p_base); -extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, - struct vmw_dma_buffer *dma_buf, - uint32_t *handle); -extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo, - uint32_t cur_validate_node); -extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo); -extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile, - uint32_t id, struct vmw_dma_buffer **out, - struct ttm_base_object **base); extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, @@ -670,43 +653,70 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv, struct vmw_resource **out); extern void vmw_resource_unreserve(struct vmw_resource *res, bool switch_backup, - struct vmw_dma_buffer *new_backup, + struct vmw_buffer_object *new_backup, unsigned long new_backup_offset); -extern void vmw_resource_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem); extern void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); -extern void vmw_resource_swap_notify(struct ttm_buffer_object *bo); -extern int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob); -extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, - struct vmw_fence_obj *fence); +extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); extern void vmw_resource_evict_all(struct vmw_private *dev_priv); - +extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo); /** - * DMA buffer helper routines - vmwgfx_dmabuf.c + * Buffer object helper functions - vmwgfx_bo.c */ -extern int vmw_dmabuf_pin_in_placement(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - struct ttm_placement *placement, +extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, + struct ttm_placement *placement, + bool interruptible); +extern int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible); +extern int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible); +extern int vmw_bo_pin_in_start_of_vram(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, bool interruptible); -extern int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible); -extern int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible); -extern int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - bool interruptible); -extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - bool interruptible); +extern int vmw_bo_unpin(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, + bool interruptible); extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, SVGAGuestPtr *ptr); -extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); -extern void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo); -extern void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo); +extern void vmw_bo_pin_reserved(struct vmw_buffer_object *bo, bool pin); +extern void vmw_bo_bo_free(struct ttm_buffer_object *bo); +extern int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interuptable, + void (*bo_free)(struct ttm_buffer_object *bo)); +extern int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, + struct ttm_object_file *tfile); +extern int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_dma_buf, + struct ttm_base_object **p_base); +extern int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *dma_buf, + uint32_t *handle); +extern int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t id, struct vmw_buffer_object **out, + struct ttm_base_object **base); +extern void vmw_bo_fence_single(struct ttm_buffer_object *bo, + struct vmw_fence_obj *fence); +extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); +extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); +extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem); +extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); /** * Misc Ioctl functionality - vmwgfx_ioctl.c @@ -758,7 +768,7 @@ extern void vmw_ttm_global_release(struct vmw_private *dev_priv); extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma); /** - * TTM buffer object driver - vmwgfx_buffer.c + * TTM buffer object driver - vmwgfx_ttm_buffer.c */ extern const size_t vmw_tt_size; @@ -1041,8 +1051,8 @@ vmw_context_binding_state(struct vmw_resource *ctx); extern void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx, bool readback); extern int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, - struct vmw_dma_buffer *mob); -extern struct vmw_dma_buffer * + struct vmw_buffer_object *mob); +extern struct vmw_buffer_object * vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res); @@ -1070,14 +1080,22 @@ extern int vmw_surface_validate(struct vmw_private *dev_priv, struct vmw_surface *srf); int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t user_accounting_size, - uint32_t svga3d_flags, + SVGA3dSurfaceAllFlags svga3d_flags, SVGA3dSurfaceFormat format, bool for_scanout, uint32_t num_mip_levels, uint32_t multisample_count, uint32_t array_size, struct drm_vmw_size size, + SVGA3dMSPattern multisample_pattern, + SVGA3dMSQualityLevel quality_level, struct vmw_surface **srf_out); +extern int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); +extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); /* * Shader management - vmwgfx_shader.c @@ -1224,6 +1242,11 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, u32 w, u32 h, struct vmw_diff_cpy *diff); +/* Host messaging -vmwgfx_msg.c: */ +int vmw_host_get_guestinfo(const char *guest_info_param, + char *buffer, size_t *length); +int vmw_host_log(const char *log); + /** * Inline helper functions */ @@ -1243,9 +1266,9 @@ static inline struct vmw_surface *vmw_surface_reference(struct vmw_surface *srf) return srf; } -static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf) +static inline void vmw_bo_unreference(struct vmw_buffer_object **buf) { - struct vmw_dma_buffer *tmp_buf = *buf; + struct vmw_buffer_object *tmp_buf = *buf; *buf = NULL; if (tmp_buf != NULL) { @@ -1255,7 +1278,8 @@ static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf) } } -static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer *buf) +static inline struct vmw_buffer_object * +vmw_bo_reference(struct vmw_buffer_object *buf) { if (ttm_bo_reference(&buf->base)) return buf; @@ -1302,10 +1326,4 @@ static inline void vmw_mmio_write(u32 value, u32 *addr) { WRITE_ONCE(*addr, value); } - -/** - * Add vmw_msg module function - */ -extern int vmw_host_log(const char *log); - #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 47bb7e58a368..1f134570b759 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -92,7 +92,7 @@ struct vmw_resource_val_node { struct list_head head; struct drm_hash_item hash; struct vmw_resource *res; - struct vmw_dma_buffer *new_backup; + struct vmw_buffer_object *new_backup; struct vmw_ctx_binding_state *staged_bindings; unsigned long new_backup_offset; u32 first_usage : 1; @@ -126,9 +126,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAMobId *id, - struct vmw_dma_buffer **vmw_bo_p); + struct vmw_buffer_object **vmw_bo_p); static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, - struct vmw_dma_buffer *vbo, + struct vmw_buffer_object *vbo, bool validate_as_mob, uint32_t *p_val_node); /** @@ -185,7 +185,7 @@ static void vmw_resources_unreserve(struct vmw_sw_context *sw_context, } vmw_resource_unreserve(res, switch_backup, val->new_backup, val->new_backup_offset); - vmw_dmabuf_unreference(&val->new_backup); + vmw_bo_unreference(&val->new_backup); } } @@ -423,7 +423,7 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, } if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) { - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; dx_query_mob = vmw_context_get_dx_query_mob(ctx); if (dx_query_mob) @@ -544,7 +544,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv, * submission is reached. */ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, - struct vmw_dma_buffer *vbo, + struct vmw_buffer_object *vbo, bool validate_as_mob, uint32_t *p_val_node) { @@ -616,7 +616,7 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) return ret; if (res->backup) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; ret = vmw_bo_to_validate_list (sw_context, vbo, @@ -628,7 +628,7 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) } if (sw_context->dx_query_mob) { - struct vmw_dma_buffer *expected_dx_query_mob; + struct vmw_buffer_object *expected_dx_query_mob; expected_dx_query_mob = vmw_context_get_dx_query_mob(sw_context->dx_query_ctx); @@ -657,7 +657,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) list_for_each_entry(val, &sw_context->resource_list, head) { struct vmw_resource *res = val->res; - struct vmw_dma_buffer *backup = res->backup; + struct vmw_buffer_object *backup = res->backup; ret = vmw_resource_validate(res); if (unlikely(ret != 0)) { @@ -668,7 +668,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) /* Check if the resource switched backup buffer */ if (backup && res->backup && (backup != res->backup)) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; ret = vmw_bo_to_validate_list (sw_context, vbo, @@ -821,7 +821,7 @@ out_no_reloc: static int vmw_rebind_all_dx_query(struct vmw_resource *ctx_res) { struct vmw_private *dev_priv = ctx_res->dev_priv; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct { SVGA3dCmdHeader header; SVGA3dCmdDXBindAllQuery body; @@ -1152,7 +1152,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv, * command batch. */ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *new_query_bo, + struct vmw_buffer_object *new_query_bo, struct vmw_sw_context *sw_context) { struct vmw_res_cache_entry *ctx_entry = @@ -1234,7 +1234,7 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, if (dev_priv->pinned_bo != sw_context->cur_query_bo) { if (dev_priv->pinned_bo) { vmw_bo_pin_reserved(dev_priv->pinned_bo, false); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); } if (!sw_context->needs_post_query_barrier) { @@ -1256,7 +1256,7 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, dev_priv->query_cid = sw_context->last_query_ctx->id; dev_priv->query_cid_valid = true; dev_priv->pinned_bo = - vmw_dmabuf_reference(sw_context->cur_query_bo); + vmw_bo_reference(sw_context->cur_query_bo); } } } @@ -1282,15 +1282,14 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAMobId *id, - struct vmw_dma_buffer **vmw_bo_p) + struct vmw_buffer_object **vmw_bo_p) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; uint32_t handle = *id; struct vmw_relocation *reloc; int ret; - ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo, - NULL); + ret = vmw_user_bo_lookup(sw_context->fp->tfile, handle, &vmw_bo, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use MOB buffer.\n"); ret = -EINVAL; @@ -1316,7 +1315,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, return 0; out_no_reloc: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); *vmw_bo_p = NULL; return ret; } @@ -1343,15 +1342,14 @@ out_no_reloc: static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAGuestPtr *ptr, - struct vmw_dma_buffer **vmw_bo_p) + struct vmw_buffer_object **vmw_bo_p) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; uint32_t handle = ptr->gmrId; struct vmw_relocation *reloc; int ret; - ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo, - NULL); + ret = vmw_user_bo_lookup(sw_context->fp->tfile, handle, &vmw_bo, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use GMR region.\n"); ret = -EINVAL; @@ -1376,7 +1374,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, return 0; out_no_reloc: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); *vmw_bo_p = NULL; return ret; } @@ -1447,7 +1445,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv, SVGA3dCmdDXBindQuery q; } *cmd; - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; @@ -1466,7 +1464,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv, sw_context->dx_query_mob = vmw_bo; sw_context->dx_query_ctx = sw_context->dx_ctx_node->res; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1549,7 +1547,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdEndGBQuery q; @@ -1569,7 +1567,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1584,7 +1582,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdEndQuery q; @@ -1623,7 +1621,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv, ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1638,7 +1636,7 @@ static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdWaitForGBQuery q; @@ -1656,7 +1654,7 @@ static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return 0; } @@ -1671,7 +1669,7 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdWaitForQuery q; @@ -1708,7 +1706,7 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return 0; } @@ -1716,7 +1714,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; struct vmw_surface *srf = NULL; struct vmw_dma_cmd { SVGA3dCmdHeader header; @@ -1768,7 +1766,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, header); out_no_surface: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1887,7 +1885,7 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; struct { @@ -1901,7 +1899,7 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1928,7 +1926,7 @@ static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv, uint32_t *buf_id, unsigned long backup_offset) { - struct vmw_dma_buffer *dma_buf; + struct vmw_buffer_object *dma_buf; int ret; ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf); @@ -1939,7 +1937,7 @@ static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv, if (val_node->first_usage) val_node->no_buffer_needed = true; - vmw_dmabuf_unreference(&val_node->new_backup); + vmw_bo_unreference(&val_node->new_backup); val_node->new_backup = dma_buf; val_node->new_backup_offset = backup_offset; @@ -3118,6 +3116,32 @@ static int vmw_cmd_dx_transfer_from_buffer(struct vmw_private *dev_priv, &cmd->body.destSid, NULL); } +/** + * vmw_cmd_intra_surface_copy - + * Validate an SVGA_3D_CMD_INTRA_SURFACE_COPY command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_intra_surface_copy(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdIntraSurfaceCopy body; + } *cmd = container_of(header, typeof(*cmd), header); + + if (!(dev_priv->capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY)) + return -EINVAL; + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.surface.sid, NULL); +} + + static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf, uint32_t *size) @@ -3232,9 +3256,9 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { false, false, false), VMW_CMD_DEF(SVGA_3D_CMD_SCREEN_DMA, &vmw_cmd_invalid, false, false, false), - VMW_CMD_DEF(SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE, &vmw_cmd_invalid, + VMW_CMD_DEF(SVGA_3D_CMD_DEAD1, &vmw_cmd_invalid, false, false, false), - VMW_CMD_DEF(SVGA_3D_CMD_OPEN_CONTEXT_SURFACE, &vmw_cmd_invalid, + VMW_CMD_DEF(SVGA_3D_CMD_DEAD2, &vmw_cmd_invalid, false, false, false), VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_BITBLT, &vmw_cmd_invalid, false, false, false), @@ -3473,6 +3497,8 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER, &vmw_cmd_dx_transfer_from_buffer, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INTRA_SURFACE_COPY, &vmw_cmd_intra_surface_copy, + true, false, true), }; bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd) @@ -3701,8 +3727,8 @@ int vmw_validate_single_buffer(struct vmw_private *dev_priv, bool interruptible, bool validate_as_mob) { - struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer, - base); + struct vmw_buffer_object *vbo = + container_of(bo, struct vmw_buffer_object, base); struct ttm_operation_ctx ctx = { interruptible, true }; int ret; @@ -4423,7 +4449,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); out_unlock: return; @@ -4432,7 +4458,7 @@ out_no_emit: out_no_reserve: ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 9b7e0aca5f84..b913a56f3426 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -42,7 +42,7 @@ struct vmw_fb_par { void *vmalloc; struct mutex bo_mutex; - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; unsigned bo_size; struct drm_framebuffer *set_fb; struct drm_display_mode *set_mode; @@ -184,7 +184,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) struct drm_clip_rect clip; struct drm_framebuffer *cur_fb; u8 *src_ptr, *dst_ptr; - struct vmw_dma_buffer *vbo = par->vmw_bo; + struct vmw_buffer_object *vbo = par->vmw_bo; void *virtual; if (!READ_ONCE(par->dirty.active)) @@ -197,7 +197,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) (void) ttm_read_lock(&vmw_priv->reservation_sem, false); (void) ttm_bo_reserve(&vbo->base, false, false, NULL); - virtual = vmw_dma_buffer_map_and_cache(vbo); + virtual = vmw_bo_map_and_cache(vbo); if (!virtual) goto out_unreserve; @@ -391,9 +391,9 @@ static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) */ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, - size_t size, struct vmw_dma_buffer **out) + size_t size, struct vmw_buffer_object **out) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; (void) ttm_write_lock(&vmw_priv->reservation_sem, false); @@ -404,10 +404,10 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, goto err_unlock; } - ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size, + ret = vmw_bo_init(vmw_priv, vmw_bo, size, &vmw_sys_placement, false, - &vmw_dmabuf_bo_free); + &vmw_bo_bo_free); if (unlikely(ret != 0)) goto err_unlock; /* init frees the buffer on failure */ @@ -491,7 +491,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, } if (par->vmw_bo && detach_bo && unref_bo) - vmw_dmabuf_unreference(&par->vmw_bo); + vmw_bo_unreference(&par->vmw_bo); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index c2eeb677cdfc..3d546d409334 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -175,7 +175,6 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) struct vmw_private *dev_priv = fman->dev_priv; struct vmwgfx_wait_cb cb; long ret = timeout; - unsigned long irq_flags; if (likely(vmw_fence_obj_signaled(fence))) return timeout; @@ -183,7 +182,7 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); vmw_seqno_waiter_add(dev_priv); - spin_lock_irqsave(f->lock, irq_flags); + spin_lock(f->lock); if (intr && signal_pending(current)) { ret = -ERESTARTSYS; @@ -194,30 +193,45 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) cb.task = current; list_add(&cb.base.node, &f->cb_list); - while (ret > 0) { + for (;;) { __vmw_fences_update(fman); - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) - break; + /* + * We can use the barrier free __set_current_state() since + * DMA_FENCE_FLAG_SIGNALED_BIT + wakeup is protected by the + * fence spinlock. + */ if (intr) __set_current_state(TASK_INTERRUPTIBLE); else __set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock_irqrestore(f->lock, irq_flags); - ret = schedule_timeout(ret); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) { + if (ret == 0 && timeout > 0) + ret = 1; + break; + } - spin_lock_irqsave(f->lock, irq_flags); - if (ret > 0 && intr && signal_pending(current)) + if (intr && signal_pending(current)) { ret = -ERESTARTSYS; - } + break; + } + if (ret == 0) + break; + + spin_unlock(f->lock); + + ret = schedule_timeout(ret); + + spin_lock(f->lock); + } + __set_current_state(TASK_RUNNING); if (!list_empty(&cb.base.node)) list_del(&cb.base.node); - __set_current_state(TASK_RUNNING); out: - spin_unlock_irqrestore(f->lock, irq_flags); + spin_unlock(f->lock); vmw_seqno_waiter_remove(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 78fce406e1d4..172a6ba6539c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -56,6 +56,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_HW_CAPS: param->value = dev_priv->capabilities; break; + case DRM_VMW_PARAM_HW_CAPS2: + param->value = dev_priv->capabilities2; + break; case DRM_VMW_PARAM_FIFO_CAPS: param->value = dev_priv->fifo.capabilities; break; @@ -113,6 +116,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_DX: param->value = dev_priv->has_dx; break; + case DRM_VMW_PARAM_SM4_1: + param->value = dev_priv->has_sm4_1; + break; default: return -EINVAL; } @@ -122,15 +128,12 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, static u32 vmw_mask_multisample(unsigned int cap, u32 fmt_value) { - /* If the header is updated, update the format test as well! */ - BUILD_BUG_ON(SVGA3D_DEVCAP_DXFMT_BC5_UNORM + 1 != SVGA3D_DEVCAP_MAX); - - if (cap >= SVGA3D_DEVCAP_DXFMT_X8R8G8B8 && - cap <= SVGA3D_DEVCAP_DXFMT_BC5_UNORM) - fmt_value &= ~(SVGADX_DXFMT_MULTISAMPLE_2 | - SVGADX_DXFMT_MULTISAMPLE_4 | - SVGADX_DXFMT_MULTISAMPLE_8); - else if (cap == SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES) + /* + * A version of user-space exists which use MULTISAMPLE_MASKABLESAMPLES + * to check the sample count supported by virtual device. Since there + * never was support for multisample count for backing MOB return 0. + */ + if (cap == SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES) return 0; return fmt_value; @@ -377,8 +380,8 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, } vfb = vmw_framebuffer_to_vfb(fb); - if (!vfb->dmabuf) { - DRM_ERROR("Framebuffer not dmabuf backed.\n"); + if (!vfb->bo) { + DRM_ERROR("Framebuffer not buffer backed.\n"); ret = -EINVAL; goto out_no_ttm_lock; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bc5fbd39cf9a..466336b34fff 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -85,10 +85,10 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv, return 0; } -static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, - u32 width, u32 height, - u32 hotspotX, u32 hotspotY) +static int vmw_cursor_update_bo(struct vmw_private *dev_priv, + struct vmw_buffer_object *bo, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY) { struct ttm_bo_kmap_obj map; unsigned long kmap_offset; @@ -100,13 +100,13 @@ static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, kmap_offset = 0; kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT; - ret = ttm_bo_reserve(&dmabuf->base, true, false, NULL); + ret = ttm_bo_reserve(&bo->base, true, false, NULL); if (unlikely(ret != 0)) { DRM_ERROR("reserve failed\n"); return -EINVAL; } - ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); + ret = ttm_bo_kmap(&bo->base, kmap_offset, kmap_num, &map); if (unlikely(ret != 0)) goto err_unreserve; @@ -116,7 +116,7 @@ static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, ttm_bo_kunmap(&map); err_unreserve: - ttm_bo_unreserve(&dmabuf->base); + ttm_bo_unreserve(&bo->base); return ret; } @@ -352,13 +352,13 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, if (vps->surf) vmw_surface_unreference(&vps->surf); - if (vps->dmabuf) - vmw_dmabuf_unreference(&vps->dmabuf); + if (vps->bo) + vmw_bo_unreference(&vps->bo); if (fb) { - if (vmw_framebuffer_to_vfb(fb)->dmabuf) { - vps->dmabuf = vmw_framebuffer_to_vfbd(fb)->buffer; - vmw_dmabuf_reference(vps->dmabuf); + if (vmw_framebuffer_to_vfb(fb)->bo) { + vps->bo = vmw_framebuffer_to_vfbd(fb)->buffer; + vmw_bo_reference(vps->bo); } else { vps->surf = vmw_framebuffer_to_vfbs(fb)->surface; vmw_surface_reference(vps->surf); @@ -390,7 +390,7 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, } du->cursor_surface = vps->surf; - du->cursor_dmabuf = vps->dmabuf; + du->cursor_bo = vps->bo; if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; @@ -399,11 +399,11 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, vps->surf->snooper.image, 64, 64, hotspot_x, hotspot_y); - } else if (vps->dmabuf) { - ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, - plane->state->crtc_w, - plane->state->crtc_h, - hotspot_x, hotspot_y); + } else if (vps->bo) { + ret = vmw_cursor_update_bo(dev_priv, vps->bo, + plane->state->crtc_w, + plane->state->crtc_h, + hotspot_x, hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); return; @@ -519,7 +519,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, ret = -EINVAL; } - if (!vmw_framebuffer_to_vfb(fb)->dmabuf) + if (!vmw_framebuffer_to_vfb(fb)->bo) surface = vmw_framebuffer_to_vfbs(fb)->surface; if (surface && !surface->snooper.image) { @@ -687,8 +687,8 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) if (vps->surf) (void) vmw_surface_reference(vps->surf); - if (vps->dmabuf) - (void) vmw_dmabuf_reference(vps->dmabuf); + if (vps->bo) + (void) vmw_bo_reference(vps->bo); state = &vps->base; @@ -745,8 +745,8 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, if (vps->surf) vmw_surface_unreference(&vps->surf); - if (vps->dmabuf) - vmw_dmabuf_unreference(&vps->dmabuf); + if (vps->bo) + vmw_bo_unreference(&vps->bo); drm_atomic_helper_plane_destroy_state(plane, state); } @@ -902,12 +902,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, /** * vmw_kms_readback - Perform a readback from the screen system to - * a dma-buffer backed framebuffer. + * a buffer-object backed framebuffer. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm_file identifying the caller. * Must be set to NULL if @user_fence_rep is NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @user_fence_rep: User-space provided structure for fence information. * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. @@ -951,7 +951,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, struct vmw_framebuffer **out, const struct drm_mode_fb_cmd2 *mode_cmd, - bool is_dmabuf_proxy) + bool is_bo_proxy) { struct drm_device *dev = dev_priv->dev; @@ -1019,7 +1019,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, drm_helper_mode_fill_fb_struct(dev, &vfbs->base.base, mode_cmd); vfbs->surface = vmw_surface_reference(surface); vfbs->base.user_handle = mode_cmd->handles[0]; - vfbs->is_dmabuf_proxy = is_dmabuf_proxy; + vfbs->is_bo_proxy = is_bo_proxy; *out = &vfbs->base; @@ -1038,30 +1038,30 @@ out_err1: } /* - * Dmabuf framebuffer code + * Buffer-object framebuffer code */ -static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_bo_destroy(struct drm_framebuffer *framebuffer) { - struct vmw_framebuffer_dmabuf *vfbd = + struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); drm_framebuffer_cleanup(framebuffer); - vmw_dmabuf_unreference(&vfbd->buffer); + vmw_bo_unreference(&vfbd->buffer); if (vfbd->base.user_obj) ttm_base_object_unref(&vfbd->base.user_obj); kfree(vfbd); } -static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips) +static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, + struct drm_file *file_priv, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips) { struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - struct vmw_framebuffer_dmabuf *vfbd = + struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); struct drm_clip_rect norect; int ret, increment = 1; @@ -1092,13 +1092,13 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, true, true, NULL); break; case vmw_du_screen_object: - ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, - clips, NULL, num_clips, - increment, true, NULL, NULL); + ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, + clips, NULL, num_clips, + increment, true, NULL, NULL); break; case vmw_du_legacy: - ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, - clips, num_clips, increment); + ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, + clips, num_clips, increment); break; default: ret = -EINVAL; @@ -1114,23 +1114,23 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, return ret; } -static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { - .destroy = vmw_framebuffer_dmabuf_destroy, - .dirty = vmw_framebuffer_dmabuf_dirty, +static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { + .destroy = vmw_framebuffer_bo_destroy, + .dirty = vmw_framebuffer_bo_dirty, }; /** - * Pin the dmabuffer in a location suitable for access by the + * Pin the bofer in a location suitable for access by the * display system. */ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct ttm_placement *placement; int ret; - buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; if (!buf) @@ -1139,12 +1139,12 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) switch (dev_priv->active_display_unit) { case vmw_du_legacy: vmw_overlay_pause_all(dev_priv); - ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, buf, false); + ret = vmw_bo_pin_in_start_of_vram(dev_priv, buf, false); vmw_overlay_resume_all(dev_priv); break; case vmw_du_screen_object: case vmw_du_screen_target: - if (vfb->dmabuf) { + if (vfb->bo) { if (dev_priv->capabilities & SVGA_CAP_3D) { /* * Use surface DMA to get content to @@ -1160,8 +1160,7 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) placement = &vmw_mob_placement; } - return vmw_dmabuf_pin_in_placement(dev_priv, buf, placement, - false); + return vmw_bo_pin_in_placement(dev_priv, buf, placement, false); default: return -EINVAL; } @@ -1172,36 +1171,36 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) static int vmw_framebuffer_unpin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; - buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; if (WARN_ON(!buf)) return 0; - return vmw_dmabuf_unpin(dev_priv, buf, false); + return vmw_bo_unpin(dev_priv, buf, false); } /** - * vmw_create_dmabuf_proxy - create a proxy surface for the DMA buf + * vmw_create_bo_proxy - create a proxy surface for the buffer object * * @dev: DRM device * @mode_cmd: parameters for the new surface - * @dmabuf_mob: MOB backing the DMA buf + * @bo_mob: MOB backing the buffer object * @srf_out: newly created surface * - * When the content FB is a DMA buf, we create a surface as a proxy to the + * When the content FB is a buffer object, we create a surface as a proxy to the * same buffer. This way we can do a surface copy rather than a surface DMA. * This is a more efficient approach * * RETURNS: * 0 on success, error code otherwise */ -static int vmw_create_dmabuf_proxy(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct vmw_dma_buffer *dmabuf_mob, - struct vmw_surface **srf_out) +static int vmw_create_bo_proxy(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct vmw_buffer_object *bo_mob, + struct vmw_surface **srf_out) { uint32_t format; struct drm_vmw_size content_base_size = {0}; @@ -1239,15 +1238,17 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, content_base_size.depth = 1; ret = vmw_surface_gb_priv_define(dev, - 0, /* kernel visible only */ - 0, /* flags */ - format, - true, /* can be a scanout buffer */ - 1, /* num of mip levels */ - 0, - 0, - content_base_size, - srf_out); + 0, /* kernel visible only */ + 0, /* flags */ + format, + true, /* can be a scanout buffer */ + 1, /* num of mip levels */ + 0, + 0, + content_base_size, + SVGA3D_MS_PATTERN_NONE, + SVGA3D_MS_QUALITY_NONE, + srf_out); if (ret) { DRM_ERROR("Failed to allocate proxy content buffer\n"); return ret; @@ -1258,8 +1259,8 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, /* Reserve and switch the backing mob. */ mutex_lock(&res->dev_priv->cmdbuf_mutex); (void) vmw_resource_reserve(res, false, true); - vmw_dmabuf_unreference(&res->backup); - res->backup = vmw_dmabuf_reference(dmabuf_mob); + vmw_bo_unreference(&res->backup); + res->backup = vmw_bo_reference(bo_mob); res->backup_offset = 0; vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); @@ -1269,21 +1270,21 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, -static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, - struct vmw_framebuffer **out, - const struct drm_mode_fb_cmd2 - *mode_cmd) +static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv, + struct vmw_buffer_object *bo, + struct vmw_framebuffer **out, + const struct drm_mode_fb_cmd2 + *mode_cmd) { struct drm_device *dev = dev_priv->dev; - struct vmw_framebuffer_dmabuf *vfbd; + struct vmw_framebuffer_bo *vfbd; unsigned int requested_size; struct drm_format_name_buf format_name; int ret; requested_size = mode_cmd->height * mode_cmd->pitches[0]; - if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) { + if (unlikely(requested_size > bo->base.num_pages * PAGE_SIZE)) { DRM_ERROR("Screen buffer object size is too small " "for requested mode.\n"); return -EINVAL; @@ -1312,20 +1313,20 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, } drm_helper_mode_fill_fb_struct(dev, &vfbd->base.base, mode_cmd); - vfbd->base.dmabuf = true; - vfbd->buffer = vmw_dmabuf_reference(dmabuf); + vfbd->base.bo = true; + vfbd->buffer = vmw_bo_reference(bo); vfbd->base.user_handle = mode_cmd->handles[0]; *out = &vfbd->base; ret = drm_framebuffer_init(dev, &vfbd->base.base, - &vmw_framebuffer_dmabuf_funcs); + &vmw_framebuffer_bo_funcs); if (ret) goto out_err2; return 0; out_err2: - vmw_dmabuf_unreference(&dmabuf); + vmw_bo_unreference(&bo); kfree(vfbd); out_err1: return ret; @@ -1354,57 +1355,57 @@ vmw_kms_srf_ok(struct vmw_private *dev_priv, uint32_t width, uint32_t height) * vmw_kms_new_framebuffer - Create a new framebuffer. * * @dev_priv: Pointer to device private struct. - * @dmabuf: Pointer to dma buffer to wrap the kms framebuffer around. - * Either @dmabuf or @surface must be NULL. + * @bo: Pointer to buffer object to wrap the kms framebuffer around. + * Either @bo or @surface must be NULL. * @surface: Pointer to a surface to wrap the kms framebuffer around. - * Either @dmabuf or @surface must be NULL. - * @only_2d: No presents will occur to this dma buffer based framebuffer. This - * Helps the code to do some important optimizations. + * Either @bo or @surface must be NULL. + * @only_2d: No presents will occur to this buffer object based framebuffer. + * This helps the code to do some important optimizations. * @mode_cmd: Frame-buffer metadata. */ struct vmw_framebuffer * vmw_kms_new_framebuffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, + struct vmw_buffer_object *bo, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd2 *mode_cmd) { struct vmw_framebuffer *vfb = NULL; - bool is_dmabuf_proxy = false; + bool is_bo_proxy = false; int ret; /* * We cannot use the SurfaceDMA command in an non-accelerated VM, - * therefore, wrap the DMA buf in a surface so we can use the + * therefore, wrap the buffer object in a surface so we can use the * SurfaceCopy command. */ if (vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height) && - dmabuf && only_2d && + bo && only_2d && mode_cmd->width > 64 && /* Don't create a proxy for cursor */ dev_priv->active_display_unit == vmw_du_screen_target) { - ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd, - dmabuf, &surface); + ret = vmw_create_bo_proxy(dev_priv->dev, mode_cmd, + bo, &surface); if (ret) return ERR_PTR(ret); - is_dmabuf_proxy = true; + is_bo_proxy = true; } /* Create the new framebuffer depending one what we have */ if (surface) { ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, mode_cmd, - is_dmabuf_proxy); + is_bo_proxy); /* - * vmw_create_dmabuf_proxy() adds a reference that is no longer + * vmw_create_bo_proxy() adds a reference that is no longer * needed */ - if (is_dmabuf_proxy) + if (is_bo_proxy) vmw_surface_unreference(&surface); - } else if (dmabuf) { - ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb, - mode_cmd); + } else if (bo) { + ret = vmw_kms_new_framebuffer_bo(dev_priv, bo, &vfb, + mode_cmd); } else { BUG(); } @@ -1430,23 +1431,10 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_framebuffer *vfb = NULL; struct vmw_surface *surface = NULL; - struct vmw_dma_buffer *bo = NULL; + struct vmw_buffer_object *bo = NULL; struct ttm_base_object *user_obj; int ret; - /** - * This code should be conditioned on Screen Objects not being used. - * If screen objects are used, we can allocate a GMR to hold the - * requested framebuffer. - */ - - if (!vmw_kms_validate_mode_vram(dev_priv, - mode_cmd->pitches[0], - mode_cmd->height)) { - DRM_ERROR("Requested mode exceed bounding box limit.\n"); - return ERR_PTR(-ENOMEM); - } - /* * Take a reference on the user object of the resource * backing the kms fb. This ensures that user-space handle @@ -1466,7 +1454,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, * End conditioned code. */ - /* returns either a dmabuf or surface */ + /* returns either a bo or surface */ ret = vmw_user_lookup_handle(dev_priv, tfile, mode_cmd->handles[0], &surface, &bo); @@ -1494,7 +1482,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ if (bo) - vmw_dmabuf_unreference(&bo); + vmw_bo_unreference(&bo); if (surface) vmw_surface_unreference(&surface); @@ -1508,7 +1496,168 @@ err_out: return &vfb->base; } +/** + * vmw_kms_check_display_memory - Validates display memory required for a + * topology + * @dev: DRM device + * @num_rects: number of drm_rect in rects + * @rects: array of drm_rect representing the topology to validate indexed by + * crtc index. + * + * Returns: + * 0 on success otherwise negative error code + */ +static int vmw_kms_check_display_memory(struct drm_device *dev, + uint32_t num_rects, + struct drm_rect *rects) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_rect bounding_box = {0}; + u64 total_pixels = 0, pixel_mem, bb_mem; + int i; + + for (i = 0; i < num_rects; i++) { + /* + * Currently this check is limiting the topology within max + * texture/screentarget size. This should change in future when + * user-space support multiple fb with topology. + */ + if (rects[i].x1 < 0 || rects[i].y1 < 0 || + rects[i].x2 > mode_config->max_width || + rects[i].y2 > mode_config->max_height) { + DRM_ERROR("Invalid GUI layout.\n"); + return -EINVAL; + } + + /* Bounding box upper left is at (0,0). */ + if (rects[i].x2 > bounding_box.x2) + bounding_box.x2 = rects[i].x2; + + if (rects[i].y2 > bounding_box.y2) + bounding_box.y2 = rects[i].y2; + + total_pixels += (u64) drm_rect_width(&rects[i]) * + (u64) drm_rect_height(&rects[i]); + } + + /* Virtual svga device primary limits are always in 32-bpp. */ + pixel_mem = total_pixels * 4; + + /* + * For HV10 and below prim_bb_mem is vram size. When + * SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM is not present vram size is + * limit on primary bounding box + */ + if (pixel_mem > dev_priv->prim_bb_mem) { + DRM_ERROR("Combined output size too large.\n"); + return -EINVAL; + } + + /* SVGA_CAP_NO_BB_RESTRICTION is available for STDU only. */ + if (dev_priv->active_display_unit != vmw_du_screen_target || + !(dev_priv->capabilities & SVGA_CAP_NO_BB_RESTRICTION)) { + bb_mem = (u64) bounding_box.x2 * bounding_box.y2 * 4; + + if (bb_mem > dev_priv->prim_bb_mem) { + DRM_ERROR("Topology is beyond supported limits.\n"); + return -EINVAL; + } + } + + return 0; +} + +/** + * vmw_kms_check_topology - Validates topology in drm_atomic_state + * @dev: DRM device + * @state: the driver state object + * + * Returns: + * 0 on success otherwise negative error code + */ +static int vmw_kms_check_topology(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_crtc_state *old_crtc_state, *new_crtc_state; + struct drm_rect *rects; + struct drm_crtc *crtc; + uint32_t i; + int ret = 0; + + rects = kcalloc(dev->mode_config.num_crtc, sizeof(struct drm_rect), + GFP_KERNEL); + if (!rects) + return -ENOMEM; + + mutex_lock(&dev_priv->requested_layout_mutex); + + drm_for_each_crtc(crtc, dev) { + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + struct drm_crtc_state *crtc_state = crtc->state; + + i = drm_crtc_index(crtc); + + if (crtc_state && crtc_state->enable) { + rects[i].x1 = du->gui_x; + rects[i].y1 = du->gui_y; + rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; + rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; + } + } + + /* Determine change to topology due to new atomic state */ + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, + new_crtc_state, i) { + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; + + if (!new_crtc_state->enable && old_crtc_state->enable) { + rects[i].x1 = 0; + rects[i].y1 = 0; + rects[i].x2 = 0; + rects[i].y2 = 0; + continue; + } + + if (!du->pref_active) { + ret = -EINVAL; + goto clean; + } + + /* + * For vmwgfx each crtc has only one connector attached and it + * is not changed so don't really need to check the + * crtc->connector_mask and iterate over it. + */ + connector = &du->connector; + conn_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + goto clean; + } + + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); + vmw_conn_state->gui_x = du->gui_x; + vmw_conn_state->gui_y = du->gui_y; + + rects[i].x1 = du->gui_x; + rects[i].y1 = du->gui_y; + rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; + rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; + } + + ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, + rects); +clean: + mutex_unlock(&dev_priv->requested_layout_mutex); + kfree(rects); + return ret; +} /** * vmw_kms_atomic_check_modeset- validate state object for modeset changes @@ -1520,40 +1669,39 @@ err_out: * us to assign a value to mode->crtc_clock so that * drm_calc_timestamping_constants() won't throw an error message * - * RETURNS + * Returns: * Zero for success or -errno */ static int vmw_kms_atomic_check_modeset(struct drm_device *dev, struct drm_atomic_state *state) { - struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; - struct vmw_private *dev_priv = vmw_priv(dev); - int i; - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - unsigned long requested_bb_mem = 0; - - if (dev_priv->active_display_unit == vmw_du_screen_target) { - struct drm_plane *plane = crtc->primary; - struct drm_plane_state *plane_state; - - plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *crtc_state; + bool need_modeset = false; + int i, ret; - if (plane_state && plane_state->fb) { - int cpp = plane_state->fb->format->cpp[0]; + ret = drm_atomic_helper_check(dev, state); + if (ret) + return ret; - requested_bb_mem += crtc->mode.hdisplay * cpp * - crtc->mode.vdisplay; - } + if (!state->allow_modeset) + return ret; - if (requested_bb_mem > dev_priv->prim_bb_mem) - return -EINVAL; - } + /* + * Legacy path do not set allow_modeset properly like + * @drm_atomic_helper_update_plane, This will result in unnecessary call + * to vmw_kms_check_topology. So extra set of check. + */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) + need_modeset = true; } - return drm_atomic_helper_check(dev, state); + if (need_modeset) + return vmw_kms_check_topology(dev, state); + + return ret; } static const struct drm_mode_config_funcs vmw_kms_funcs = { @@ -1845,40 +1993,49 @@ void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe) { } - -/* - * Small shared kms functions. +/** + * vmw_du_update_layout - Update the display unit with topology from resolution + * plugin and generate DRM uevent + * @dev_priv: device private + * @num_rects: number of drm_rect in rects + * @rects: toplogy to update */ - -static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, - struct drm_vmw_rect *rects) +static int vmw_du_update_layout(struct vmw_private *dev_priv, + unsigned int num_rects, struct drm_rect *rects) { struct drm_device *dev = dev_priv->dev; struct vmw_display_unit *du; struct drm_connector *con; + struct drm_connector_list_iter conn_iter; - mutex_lock(&dev->mode_config.mutex); - -#if 0 - { - unsigned int i; - - DRM_INFO("%s: new layout ", __func__); - for (i = 0; i < num; i++) - DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y, - rects[i].w, rects[i].h); - DRM_INFO("\n"); + /* + * Currently only gui_x/y is protected with requested_layout_mutex. + */ + mutex_lock(&dev_priv->requested_layout_mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(con, &conn_iter) { + du = vmw_connector_to_du(con); + if (num_rects > du->unit) { + du->pref_width = drm_rect_width(&rects[du->unit]); + du->pref_height = drm_rect_height(&rects[du->unit]); + du->pref_active = true; + du->gui_x = rects[du->unit].x1; + du->gui_y = rects[du->unit].y1; + } else { + du->pref_width = 800; + du->pref_height = 600; + du->pref_active = false; + du->gui_x = 0; + du->gui_y = 0; + } } -#endif + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev_priv->requested_layout_mutex); + mutex_lock(&dev->mode_config.mutex); list_for_each_entry(con, &dev->mode_config.connector_list, head) { du = vmw_connector_to_du(con); - if (num > du->unit) { - du->pref_width = rects[du->unit].w; - du->pref_height = rects[du->unit].h; - du->pref_active = true; - du->gui_x = rects[du->unit].x; - du->gui_y = rects[du->unit].y; + if (num_rects > du->unit) { drm_object_property_set_value (&con->base, dev->mode_config.suggested_x_property, du->gui_x); @@ -1886,9 +2043,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, (&con->base, dev->mode_config.suggested_y_property, du->gui_y); } else { - du->pref_width = 800; - du->pref_height = 600; - du->pref_active = false; drm_object_property_set_value (&con->base, dev->mode_config.suggested_x_property, 0); @@ -1898,8 +2052,8 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, } con->status = vmw_du_connector_detect(con, true); } - mutex_unlock(&dev->mode_config.mutex); + drm_sysfs_hotplug_event(dev); return 0; @@ -2199,7 +2353,25 @@ vmw_du_connector_atomic_get_property(struct drm_connector *connector, return 0; } - +/** + * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Update preferred topology of display unit as per ioctl request. The topology + * is expressed as array of drm_vmw_rect. + * e.g. + * [0 0 640 480] [640 0 800 600] [0 480 640 480] + * + * NOTE: + * The x and y offset (upper left) in drm_vmw_rect cannot be less than 0. Beside + * device limit on topology, x + w and y + h (lower right) cannot be greater + * than INT_MAX. So topology beyond these limits will return with error. + * + * Returns: + * Zero on success, negative errno on failure. + */ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2208,15 +2380,12 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, (struct drm_vmw_update_layout_arg *)data; void __user *user_rects; struct drm_vmw_rect *rects; + struct drm_rect *drm_rects; unsigned rects_size; - int ret; - int i; - u64 total_pixels = 0; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_vmw_rect bounding_box = {0}; + int ret, i; if (!arg->num_outputs) { - struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + struct drm_rect def_rect = {0, 0, 800, 600}; vmw_du_update_layout(dev_priv, 1, &def_rect); return 0; } @@ -2235,52 +2404,29 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, goto out_free; } - for (i = 0; i < arg->num_outputs; ++i) { - if (rects[i].x < 0 || - rects[i].y < 0 || - rects[i].x + rects[i].w > mode_config->max_width || - rects[i].y + rects[i].h > mode_config->max_height) { - DRM_ERROR("Invalid GUI layout.\n"); - ret = -EINVAL; - goto out_free; - } - - /* - * bounding_box.w and bunding_box.h are used as - * lower-right coordinates - */ - if (rects[i].x + rects[i].w > bounding_box.w) - bounding_box.w = rects[i].x + rects[i].w; - - if (rects[i].y + rects[i].h > bounding_box.h) - bounding_box.h = rects[i].y + rects[i].h; + drm_rects = (struct drm_rect *)rects; - total_pixels += (u64) rects[i].w * (u64) rects[i].h; - } + for (i = 0; i < arg->num_outputs; i++) { + struct drm_vmw_rect curr_rect; - if (dev_priv->active_display_unit == vmw_du_screen_target) { - /* - * For Screen Targets, the limits for a toplogy are: - * 1. Bounding box (assuming 32bpp) must be < prim_bb_mem - * 2. Total pixels (assuming 32bpp) must be < prim_bb_mem - */ - u64 bb_mem = (u64) bounding_box.w * bounding_box.h * 4; - u64 pixel_mem = total_pixels * 4; - - if (bb_mem > dev_priv->prim_bb_mem) { - DRM_ERROR("Topology is beyond supported limits.\n"); - ret = -EINVAL; + /* Verify user-space for overflow as kernel use drm_rect */ + if ((rects[i].x + rects[i].w > INT_MAX) || + (rects[i].y + rects[i].h > INT_MAX)) { + ret = -ERANGE; goto out_free; } - if (pixel_mem > dev_priv->prim_bb_mem) { - DRM_ERROR("Combined output size too large\n"); - ret = -EINVAL; - goto out_free; - } + curr_rect = rects[i]; + drm_rects[i].x1 = curr_rect.x; + drm_rects[i].y1 = curr_rect.y; + drm_rects[i].x2 = curr_rect.x + curr_rect.w; + drm_rects[i].y2 = curr_rect.y + curr_rect.h; } - vmw_du_update_layout(dev_priv, arg->num_outputs, rects); + ret = vmw_kms_check_display_memory(dev, arg->num_outputs, drm_rects); + + if (ret == 0) + vmw_du_update_layout(dev_priv, arg->num_outputs, drm_rects); out_free: kfree(rects); @@ -2427,7 +2573,7 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, * interrupted by a signal. */ int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool interruptible, bool validate_as_mob, bool for_cpu_blit) @@ -2459,7 +2605,7 @@ int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, * Helper to be used if an error forces the caller to undo the actions of * vmw_kms_helper_buffer_prepare. */ -void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) +void vmw_kms_helper_buffer_revert(struct vmw_buffer_object *buf) { if (buf) ttm_bo_unreserve(&buf->base); @@ -2482,7 +2628,7 @@ void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) */ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_file *file_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct vmw_fence_obj **out_fence, struct drm_vmw_fence_rep __user * user_fence_rep) @@ -2494,7 +2640,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, file_priv ? &handle : NULL); if (buf) - vmw_fence_single_bo(&buf->base, fence); + vmw_bo_fence_single(&buf->base, fence); if (file_priv) vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret, user_fence_rep, fence, @@ -2522,7 +2668,7 @@ void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx) struct vmw_resource *res = ctx->res; vmw_kms_helper_buffer_revert(ctx->buf); - vmw_dmabuf_unreference(&ctx->buf); + vmw_bo_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } @@ -2567,7 +2713,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, if (ret) goto out_unreserve; - ctx->buf = vmw_dmabuf_reference(res->backup); + ctx->buf = vmw_bo_reference(res->backup); } ret = vmw_resource_validate(res); if (ret) @@ -2600,7 +2746,7 @@ void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, out_fence, NULL); - vmw_dmabuf_unreference(&ctx->buf); + vmw_bo_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 27c41c227120..31311298ec0b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -90,7 +90,7 @@ struct vmw_kms_dirty { #define vmw_framebuffer_to_vfbs(x) \ container_of(x, struct vmw_framebuffer_surface, base.base) #define vmw_framebuffer_to_vfbd(x) \ - container_of(x, struct vmw_framebuffer_dmabuf, base.base) + container_of(x, struct vmw_framebuffer_bo, base.base) /** * Base class for framebuffers @@ -102,7 +102,7 @@ struct vmw_framebuffer { struct drm_framebuffer base; int (*pin)(struct vmw_framebuffer *fb); int (*unpin)(struct vmw_framebuffer *fb); - bool dmabuf; + bool bo; struct ttm_base_object *user_obj; uint32_t user_handle; }; @@ -117,15 +117,15 @@ struct vmw_clip_rect { struct vmw_framebuffer_surface { struct vmw_framebuffer base; struct vmw_surface *surface; - struct vmw_dma_buffer *buffer; + struct vmw_buffer_object *buffer; struct list_head head; - bool is_dmabuf_proxy; /* true if this is proxy surface for DMA buf */ + bool is_bo_proxy; /* true if this is proxy surface for DMA buf */ }; -struct vmw_framebuffer_dmabuf { +struct vmw_framebuffer_bo { struct vmw_framebuffer base; - struct vmw_dma_buffer *buffer; + struct vmw_buffer_object *buffer; }; @@ -161,18 +161,18 @@ struct vmw_crtc_state { * * @base DRM plane object * @surf Display surface for STDU - * @dmabuf display dmabuf for SOU + * @bo display bo for SOU * @content_fb_type Used by STDU. - * @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit + * @bo_size Size of the bo, used by Screen Object Display Unit * @pinned pin count for STDU display surface */ struct vmw_plane_state { struct drm_plane_state base; struct vmw_surface *surf; - struct vmw_dma_buffer *dmabuf; + struct vmw_buffer_object *bo; int content_fb_type; - unsigned long dmabuf_size; + unsigned long bo_size; int pinned; @@ -192,6 +192,24 @@ struct vmw_connector_state { struct drm_connector_state base; bool is_implicit; + + /** + * @gui_x: + * + * vmwgfx connector property representing the x position of this display + * unit (connector is synonymous to display unit) in overall topology. + * This is what the device expect as xRoot while creating screen. + */ + int gui_x; + + /** + * @gui_y: + * + * vmwgfx connector property representing the y position of this display + * unit (connector is synonymous to display unit) in overall topology. + * This is what the device expect as yRoot while creating screen. + */ + int gui_y; }; /** @@ -209,7 +227,7 @@ struct vmw_display_unit { struct drm_plane cursor; struct vmw_surface *cursor_surface; - struct vmw_dma_buffer *cursor_dmabuf; + struct vmw_buffer_object *cursor_bo; size_t cursor_age; int cursor_x; @@ -243,7 +261,7 @@ struct vmw_display_unit { struct vmw_validation_ctx { struct vmw_resource *res; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; }; #define vmw_crtc_to_du(x) \ @@ -291,14 +309,14 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, struct vmw_kms_dirty *dirty); int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool interruptible, bool validate_as_mob, bool for_cpu_blit); -void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); +void vmw_kms_helper_buffer_revert(struct vmw_buffer_object *buf); void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_file *file_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct vmw_fence_obj **out_fence, struct drm_vmw_fence_rep __user * user_fence_rep); @@ -316,7 +334,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, uint32_t num_clips); struct vmw_framebuffer * vmw_kms_new_framebuffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, + struct vmw_buffer_object *bo, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd2 *mode_cmd); @@ -384,11 +402,11 @@ void vmw_du_connector_destroy_state(struct drm_connector *connector, */ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv); int vmw_kms_ldu_close_display(struct vmw_private *dev_priv); -int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment); +int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips, int increment); int vmw_kms_update_proxy(struct vmw_resource *res, const struct drm_clip_rect *clips, unsigned num_clips, @@ -408,14 +426,14 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, unsigned num_clips, int inc, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc); -int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - struct drm_clip_rect *clips, - struct drm_vmw_rect *vclips, - unsigned num_clips, int increment, - bool interruptible, - struct vmw_fence_obj **out_fence, - struct drm_crtc *crtc); +int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + unsigned int num_clips, int increment, + bool interruptible, + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc); int vmw_kms_sou_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index dc0cfda26b1b..030d49c243e1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -547,11 +547,11 @@ int vmw_kms_ldu_close_display(struct vmw_private *dev_priv) } -int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment) +int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips, int increment) { size_t fifo_size; int i; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 0963d0438190..7ed179d30ec5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -225,7 +225,7 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, ret = ttm_bo_reserve(bo, false, true, NULL); BUG_ON(ret != 0); - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); } @@ -362,7 +362,7 @@ static void vmw_otable_batch_takedown(struct vmw_private *dev_priv, ret = ttm_bo_reserve(bo, false, true, NULL); BUG_ON(ret != 0); - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); ttm_bo_unref(&batch->otable_bo); @@ -620,7 +620,7 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, vmw_fifo_commit(dev_priv, sizeof(*cmd)); } if (bo) { - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); } vmw_fifo_resource_dec(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 4437c41c585a..8b9270f31409 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -31,6 +31,7 @@ #include <linux/frame.h> #include <asm/hypervisor.h> #include <drm/drmP.h> +#include "vmwgfx_drv.h" #include "vmwgfx_msg.h" @@ -234,7 +235,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { - DRM_ERROR("Failed to get reply size\n"); + DRM_ERROR("Failed to get reply size for host message.\n"); return -EINVAL; } @@ -245,7 +246,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, reply_len = ebx; reply = kzalloc(reply_len + 1, GFP_KERNEL); if (!reply) { - DRM_ERROR("Cannot allocate memory for reply\n"); + DRM_ERROR("Cannot allocate memory for host message reply.\n"); return -ENOMEM; } @@ -338,7 +339,8 @@ int vmw_host_get_guestinfo(const char *guest_info_param, msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); if (!msg) { - DRM_ERROR("Cannot allocate memory to get %s", guest_info_param); + DRM_ERROR("Cannot allocate memory to get guest info \"%s\".", + guest_info_param); return -ENOMEM; } @@ -374,7 +376,7 @@ out_msg: out_open: *length = 0; kfree(msg); - DRM_ERROR("Failed to get %s", guest_info_param); + DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param); return -EINVAL; } @@ -403,7 +405,7 @@ int vmw_host_log(const char *log) msg = kasprintf(GFP_KERNEL, "log %s", log); if (!msg) { - DRM_ERROR("Cannot allocate memory for log message\n"); + DRM_ERROR("Cannot allocate memory for host log message.\n"); return -ENOMEM; } @@ -422,7 +424,7 @@ out_msg: vmw_close_channel(&channel); out_open: kfree(msg); - DRM_ERROR("Failed to send log\n"); + DRM_ERROR("Failed to send host log message.\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 3ced89e70a64..9f1b9d289bec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -38,7 +38,7 @@ #define VMW_OVERLAY_CAP_MASK (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE) struct vmw_stream { - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; bool claimed; bool paused; struct drm_vmw_control_stream_arg saved; @@ -94,7 +94,7 @@ static inline void fill_flush(struct vmw_escape_video_flush *cmd, * -ERESTARTSYS if interrupted by a signal. */ static int vmw_overlay_send_put(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct drm_vmw_control_stream_arg *arg, bool interruptible) { @@ -225,16 +225,16 @@ static int vmw_overlay_send_stop(struct vmw_private *dev_priv, * used with GMRs instead of being locked to vram. */ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool pin, bool inter) { if (!pin) - return vmw_dmabuf_unpin(dev_priv, buf, inter); + return vmw_bo_unpin(dev_priv, buf, inter); if (dev_priv->active_display_unit == vmw_du_legacy) - return vmw_dmabuf_pin_in_vram(dev_priv, buf, inter); + return vmw_bo_pin_in_vram(dev_priv, buf, inter); - return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, inter); + return vmw_bo_pin_in_vram_or_gmr(dev_priv, buf, inter); } /** @@ -278,7 +278,7 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv, } if (!pause) { - vmw_dmabuf_unreference(&stream->buf); + vmw_bo_unreference(&stream->buf); stream->paused = false; } else { stream->paused = true; @@ -297,7 +297,7 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv, * -ERESTARTSYS if interrupted. */ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct drm_vmw_control_stream_arg *arg, bool interruptible) { @@ -347,7 +347,7 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, } if (stream->buf != buf) - stream->buf = vmw_dmabuf_reference(buf); + stream->buf = vmw_bo_reference(buf); stream->saved = *arg; /* stream is no longer stopped/paused */ stream->paused = false; @@ -466,7 +466,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, struct vmw_overlay *overlay = dev_priv->overlay_priv; struct drm_vmw_control_stream_arg *arg = (struct drm_vmw_control_stream_arg *)data; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct vmw_resource *res; int ret; @@ -484,13 +484,13 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, goto out_unlock; } - ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf, NULL); + ret = vmw_user_bo_lookup(tfile, arg->handle, &buf, NULL); if (ret) goto out_unlock; ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); out_unlock: mutex_unlock(&overlay->mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 3063a3e4bd40..92003ea5a219 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -27,7 +27,6 @@ #include "vmwgfx_drv.h" #include <drm/vmwgfx_drm.h> -#include <drm/ttm/ttm_object.h> #include <drm/ttm/ttm_placement.h> #include <drm/drmP.h> #include "vmwgfx_resource_priv.h" @@ -35,29 +34,6 @@ #define VMW_RES_EVICT_ERR_COUNT 10 -struct vmw_user_dma_buffer { - struct ttm_prime_object prime; - struct vmw_dma_buffer dma; -}; - -struct vmw_bo_user_rep { - uint32_t handle; - uint64_t map_handle; -}; - -static inline struct vmw_dma_buffer * -vmw_dma_buffer(struct ttm_buffer_object *bo) -{ - return container_of(bo, struct vmw_dma_buffer, base); -} - -static inline struct vmw_user_dma_buffer * -vmw_user_dma_buffer(struct ttm_buffer_object *bo) -{ - struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); - return container_of(vmw_bo, struct vmw_user_dma_buffer, dma); -} - struct vmw_resource *vmw_resource_reference(struct vmw_resource *res) { kref_get(&res->kref); @@ -116,7 +92,7 @@ static void vmw_resource_release(struct kref *kref) res->backup_dirty = false; list_del_init(&res->mob_head); ttm_bo_unreserve(bo); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } if (likely(res->hw_destroy != NULL)) { @@ -287,7 +263,7 @@ out_bad_resource: } /** - * Helper function that looks either a surface or dmabuf. + * Helper function that looks either a surface or bo. * * The pointer this pointed at by out_surf and out_buf needs to be null. */ @@ -295,7 +271,7 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, struct vmw_surface **out_surf, - struct vmw_dma_buffer **out_buf) + struct vmw_buffer_object **out_buf) { struct vmw_resource *res; int ret; @@ -311,513 +287,11 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, } *out_surf = NULL; - ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf, NULL); + ret = vmw_user_bo_lookup(tfile, handle, out_buf, NULL); return ret; } /** - * Buffer management. - */ - -/** - * vmw_dmabuf_acc_size - Calculate the pinned memory usage of buffers - * - * @dev_priv: Pointer to a struct vmw_private identifying the device. - * @size: The requested buffer size. - * @user: Whether this is an ordinary dma buffer or a user dma buffer. - */ -static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size, - bool user) -{ - static size_t struct_size, user_struct_size; - size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *)); - - if (unlikely(struct_size == 0)) { - size_t backend_size = ttm_round_pot(vmw_tt_size); - - struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_dma_buffer)); - user_struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_user_dma_buffer)); - } - - if (dev_priv->map_mode == vmw_dma_alloc_coherent) - page_array_size += - ttm_round_pot(num_pages * sizeof(dma_addr_t)); - - return ((user) ? user_struct_size : struct_size) + - page_array_size; -} - -void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) -{ - struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); - - vmw_dma_buffer_unmap(vmw_bo); - kfree(vmw_bo); -} - -static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) -{ - struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); - - vmw_dma_buffer_unmap(&vmw_user_bo->dma); - ttm_prime_object_kfree(vmw_user_bo, prime); -} - -int vmw_dmabuf_init(struct vmw_private *dev_priv, - struct vmw_dma_buffer *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interruptible, - void (*bo_free) (struct ttm_buffer_object *bo)) -{ - struct ttm_bo_device *bdev = &dev_priv->bdev; - size_t acc_size; - int ret; - bool user = (bo_free == &vmw_user_dmabuf_destroy); - - BUG_ON(!bo_free && (!user && (bo_free != vmw_dmabuf_bo_free))); - - acc_size = vmw_dmabuf_acc_size(dev_priv, size, user); - memset(vmw_bo, 0, sizeof(*vmw_bo)); - - INIT_LIST_HEAD(&vmw_bo->res_list); - - ret = ttm_bo_init(bdev, &vmw_bo->base, size, - ttm_bo_type_device, placement, - 0, interruptible, acc_size, - NULL, NULL, bo_free); - return ret; -} - -static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) -{ - struct vmw_user_dma_buffer *vmw_user_bo; - struct ttm_base_object *base = *p_base; - struct ttm_buffer_object *bo; - - *p_base = NULL; - - if (unlikely(base == NULL)) - return; - - vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, - prime.base); - bo = &vmw_user_bo->dma.base; - ttm_bo_unref(&bo); -} - -static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base, - enum ttm_ref_type ref_type) -{ - struct vmw_user_dma_buffer *user_bo; - user_bo = container_of(base, struct vmw_user_dma_buffer, prime.base); - - switch (ref_type) { - case TTM_REF_SYNCCPU_WRITE: - ttm_bo_synccpu_write_release(&user_bo->dma.base); - break; - default: - BUG(); - } -} - -/** - * vmw_user_dmabuf_alloc - Allocate a user dma buffer - * - * @dev_priv: Pointer to a struct device private. - * @tfile: Pointer to a struct ttm_object_file on which to register the user - * object. - * @size: Size of the dma buffer. - * @shareable: Boolean whether the buffer is shareable with other open files. - * @handle: Pointer to where the handle value should be assigned. - * @p_dma_buf: Pointer to where the refcounted struct vmw_dma_buffer pointer - * should be assigned. - */ -int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf, - struct ttm_base_object **p_base) -{ - struct vmw_user_dma_buffer *user_bo; - struct ttm_buffer_object *tmp; - int ret; - - user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); - if (unlikely(!user_bo)) { - DRM_ERROR("Failed to allocate a buffer.\n"); - return -ENOMEM; - } - - ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, - (dev_priv->has_mob) ? - &vmw_sys_placement : - &vmw_vram_sys_placement, true, - &vmw_user_dmabuf_destroy); - if (unlikely(ret != 0)) - return ret; - - tmp = ttm_bo_reference(&user_bo->dma.base); - ret = ttm_prime_object_init(tfile, - size, - &user_bo->prime, - shareable, - ttm_buffer_type, - &vmw_user_dmabuf_release, - &vmw_user_dmabuf_ref_obj_release); - if (unlikely(ret != 0)) { - ttm_bo_unref(&tmp); - goto out_no_base_object; - } - - *p_dma_buf = &user_bo->dma; - if (p_base) { - *p_base = &user_bo->prime.base; - kref_get(&(*p_base)->refcount); - } - *handle = user_bo->prime.base.hash.key; - -out_no_base_object: - return ret; -} - -/** - * vmw_user_dmabuf_verify_access - verify access permissions on this - * buffer object. - * - * @bo: Pointer to the buffer object being accessed - * @tfile: Identifying the caller. - */ -int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile) -{ - struct vmw_user_dma_buffer *vmw_user_bo; - - if (unlikely(bo->destroy != vmw_user_dmabuf_destroy)) - return -EPERM; - - vmw_user_bo = vmw_user_dma_buffer(bo); - - /* Check that the caller has opened the object. */ - if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) - return 0; - - DRM_ERROR("Could not grant buffer access.\n"); - return -EPERM; -} - -/** - * vmw_user_dmabuf_synccpu_grab - Grab a struct vmw_user_dma_buffer for cpu - * access, idling previous GPU operations on the buffer and optionally - * blocking it for further command submissions. - * - * @user_bo: Pointer to the buffer object being grabbed for CPU access - * @tfile: Identifying the caller. - * @flags: Flags indicating how the grab should be performed. - * - * A blocking grab will be automatically released when @tfile is closed. - */ -static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, - struct ttm_object_file *tfile, - uint32_t flags) -{ - struct ttm_buffer_object *bo = &user_bo->dma.base; - bool existed; - int ret; - - if (flags & drm_vmw_synccpu_allow_cs) { - bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); - long lret; - - lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, - nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); - if (!lret) - return -EBUSY; - else if (lret < 0) - return lret; - return 0; - } - - ret = ttm_bo_synccpu_write_grab - (bo, !!(flags & drm_vmw_synccpu_dontblock)); - if (unlikely(ret != 0)) - return ret; - - ret = ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_SYNCCPU_WRITE, &existed, false); - if (ret != 0 || existed) - ttm_bo_synccpu_write_release(&user_bo->dma.base); - - return ret; -} - -/** - * vmw_user_dmabuf_synccpu_release - Release a previous grab for CPU access, - * and unblock command submission on the buffer if blocked. - * - * @handle: Handle identifying the buffer object. - * @tfile: Identifying the caller. - * @flags: Flags indicating the type of release. - */ -static int vmw_user_dmabuf_synccpu_release(uint32_t handle, - struct ttm_object_file *tfile, - uint32_t flags) -{ - if (!(flags & drm_vmw_synccpu_allow_cs)) - return ttm_ref_object_base_unref(tfile, handle, - TTM_REF_SYNCCPU_WRITE); - - return 0; -} - -/** - * vmw_user_dmabuf_synccpu_release - ioctl function implementing the synccpu - * functionality. - * - * @dev: Identifies the drm device. - * @data: Pointer to the ioctl argument. - * @file_priv: Identifies the caller. - * - * This function checks the ioctl arguments for validity and calls the - * relevant synccpu functions. - */ -int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_vmw_synccpu_arg *arg = - (struct drm_vmw_synccpu_arg *) data; - struct vmw_dma_buffer *dma_buf; - struct vmw_user_dma_buffer *user_bo; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct ttm_base_object *buffer_base; - int ret; - - if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 - || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write | - drm_vmw_synccpu_dontblock | - drm_vmw_synccpu_allow_cs)) != 0) { - DRM_ERROR("Illegal synccpu flags.\n"); - return -EINVAL; - } - - switch (arg->op) { - case drm_vmw_synccpu_grab: - ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf, - &buffer_base); - if (unlikely(ret != 0)) - return ret; - - user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, - dma); - ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags); - vmw_dmabuf_unreference(&dma_buf); - ttm_base_object_unref(&buffer_base); - if (unlikely(ret != 0 && ret != -ERESTARTSYS && - ret != -EBUSY)) { - DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", - (unsigned int) arg->handle); - return ret; - } - break; - case drm_vmw_synccpu_release: - ret = vmw_user_dmabuf_synccpu_release(arg->handle, tfile, - arg->flags); - if (unlikely(ret != 0)) { - DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", - (unsigned int) arg->handle); - return ret; - } - break; - default: - DRM_ERROR("Invalid synccpu operation.\n"); - return -EINVAL; - } - - return 0; -} - -int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - union drm_vmw_alloc_dmabuf_arg *arg = - (union drm_vmw_alloc_dmabuf_arg *)data; - struct drm_vmw_alloc_dmabuf_req *req = &arg->req; - struct drm_vmw_dmabuf_rep *rep = &arg->rep; - struct vmw_dma_buffer *dma_buf; - uint32_t handle; - int ret; - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - req->size, false, &handle, &dma_buf, - NULL); - if (unlikely(ret != 0)) - goto out_no_dmabuf; - - rep->handle = handle; - rep->map_handle = drm_vma_node_offset_addr(&dma_buf->base.vma_node); - rep->cur_gmr_id = handle; - rep->cur_gmr_offset = 0; - - vmw_dmabuf_unreference(&dma_buf); - -out_no_dmabuf: - ttm_read_unlock(&dev_priv->reservation_sem); - - return ret; -} - -int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_vmw_unref_dmabuf_arg *arg = - (struct drm_vmw_unref_dmabuf_arg *)data; - - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - arg->handle, - TTM_REF_USAGE); -} - -int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile, - uint32_t handle, struct vmw_dma_buffer **out, - struct ttm_base_object **p_base) -{ - struct vmw_user_dma_buffer *vmw_user_bo; - struct ttm_base_object *base; - - base = ttm_base_object_lookup(tfile, handle); - if (unlikely(base == NULL)) { - pr_err("Invalid buffer object handle 0x%08lx\n", - (unsigned long)handle); - return -ESRCH; - } - - if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { - ttm_base_object_unref(&base); - pr_err("Invalid buffer object handle 0x%08lx\n", - (unsigned long)handle); - return -EINVAL; - } - - vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, - prime.base); - (void)ttm_bo_reference(&vmw_user_bo->dma.base); - if (p_base) - *p_base = base; - else - ttm_base_object_unref(&base); - *out = &vmw_user_bo->dma; - - return 0; -} - -int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, - struct vmw_dma_buffer *dma_buf, - uint32_t *handle) -{ - struct vmw_user_dma_buffer *user_bo; - - if (dma_buf->base.destroy != vmw_user_dmabuf_destroy) - return -EINVAL; - - user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma); - - *handle = user_bo->prime.base.hash.key; - return ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_USAGE, NULL, false); -} - -/** - * vmw_dumb_create - Create a dumb kms buffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @args: Pointer to a struct drm_mode_create_dumb structure - * - * This is a driver callback for the core drm create_dumb functionality. - * Note that this is very similar to the vmw_dmabuf_alloc ioctl, except - * that the arguments have a different format. - */ -int vmw_dumb_create(struct drm_file *file_priv, - struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_dma_buffer *dma_buf; - int ret; - - args->pitch = args->width * ((args->bpp + 7) / 8); - args->size = args->pitch * args->height; - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - args->size, false, &args->handle, - &dma_buf, NULL); - if (unlikely(ret != 0)) - goto out_no_dmabuf; - - vmw_dmabuf_unreference(&dma_buf); -out_no_dmabuf: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; -} - -/** - * vmw_dumb_map_offset - Return the address space offset of a dumb buffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * @offset: The address space offset returned. - * - * This is a driver callback for the core drm dumb_map_offset functionality. - */ -int vmw_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset) -{ - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_dma_buffer *out_buf; - int ret; - - ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf, NULL); - if (ret != 0) - return -EINVAL; - - *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node); - vmw_dmabuf_unreference(&out_buf); - return 0; -} - -/** - * vmw_dumb_destroy - Destroy a dumb boffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * - * This is a driver callback for the core drm dumb_destroy functionality. - */ -int vmw_dumb_destroy(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle) -{ - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - handle, TTM_REF_USAGE); -} - -/** * vmw_resource_buf_alloc - Allocate a backup buffer for a resource. * * @res: The resource for which to allocate a backup buffer. @@ -829,7 +303,7 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res, { unsigned long size = (res->backup_size + PAGE_SIZE - 1) & PAGE_MASK; - struct vmw_dma_buffer *backup; + struct vmw_buffer_object *backup; int ret; if (likely(res->backup)) { @@ -841,16 +315,16 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res, if (unlikely(!backup)) return -ENOMEM; - ret = vmw_dmabuf_init(res->dev_priv, backup, res->backup_size, + ret = vmw_bo_init(res->dev_priv, backup, res->backup_size, res->func->backup_placement, interruptible, - &vmw_dmabuf_bo_free); + &vmw_bo_bo_free); if (unlikely(ret != 0)) - goto out_no_dmabuf; + goto out_no_bo; res->backup = backup; -out_no_dmabuf: +out_no_bo: return ret; } @@ -919,7 +393,7 @@ out_bind_failed: */ void vmw_resource_unreserve(struct vmw_resource *res, bool switch_backup, - struct vmw_dma_buffer *new_backup, + struct vmw_buffer_object *new_backup, unsigned long new_backup_offset) { struct vmw_private *dev_priv = res->dev_priv; @@ -931,11 +405,11 @@ void vmw_resource_unreserve(struct vmw_resource *res, if (res->backup) { lockdep_assert_held(&res->backup->base.resv->lock.base); list_del_init(&res->mob_head); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } if (new_backup) { - res->backup = vmw_dmabuf_reference(new_backup); + res->backup = vmw_bo_reference(new_backup); lockdep_assert_held(&new_backup->base.resv->lock.base); list_add_tail(&res->mob_head, &new_backup->res_list); } else { @@ -959,6 +433,7 @@ void vmw_resource_unreserve(struct vmw_resource *res, * for a resource and in that case, allocate * one, reserve and validate it. * + * @ticket: The ww aqcquire context to use, or NULL if trylocking. * @res: The resource for which to allocate a backup buffer. * @interruptible: Whether any sleeps during allocation should be * performed while interruptible. @@ -966,7 +441,8 @@ void vmw_resource_unreserve(struct vmw_resource *res, * reserved and validated backup buffer. */ static int -vmw_resource_check_buffer(struct vmw_resource *res, +vmw_resource_check_buffer(struct ww_acquire_ctx *ticket, + struct vmw_resource *res, bool interruptible, struct ttm_validate_buffer *val_buf) { @@ -985,7 +461,7 @@ vmw_resource_check_buffer(struct vmw_resource *res, val_buf->bo = ttm_bo_reference(&res->backup->base); val_buf->shared = false; list_add_tail(&val_buf->head, &val_list); - ret = ttm_eu_reserve_buffers(NULL, &val_list, interruptible, NULL); + ret = ttm_eu_reserve_buffers(ticket, &val_list, interruptible, NULL); if (unlikely(ret != 0)) goto out_no_reserve; @@ -1003,11 +479,11 @@ vmw_resource_check_buffer(struct vmw_resource *res, return 0; out_no_validate: - ttm_eu_backoff_reservation(NULL, &val_list); + ttm_eu_backoff_reservation(ticket, &val_list); out_no_reserve: ttm_bo_unref(&val_buf->bo); if (backup_dirty) - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); return ret; } @@ -1050,10 +526,12 @@ int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, * vmw_resource_backoff_reservation - Unreserve and unreference a * backup buffer *. + * @ticket: The ww acquire ctx used for reservation. * @val_buf: Backup buffer information. */ static void -vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) +vmw_resource_backoff_reservation(struct ww_acquire_ctx *ticket, + struct ttm_validate_buffer *val_buf) { struct list_head val_list; @@ -1062,7 +540,7 @@ vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) INIT_LIST_HEAD(&val_list); list_add_tail(&val_buf->head, &val_list); - ttm_eu_backoff_reservation(NULL, &val_list); + ttm_eu_backoff_reservation(ticket, &val_list); ttm_bo_unref(&val_buf->bo); } @@ -1070,10 +548,12 @@ vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) * vmw_resource_do_evict - Evict a resource, and transfer its data * to a backup buffer. * + * @ticket: The ww acquire ticket to use, or NULL if trylocking. * @res: The resource to evict. * @interruptible: Whether to wait interruptible. */ -static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) +static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket, + struct vmw_resource *res, bool interruptible) { struct ttm_validate_buffer val_buf; const struct vmw_res_func *func = res->func; @@ -1083,7 +563,7 @@ static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) val_buf.bo = NULL; val_buf.shared = false; - ret = vmw_resource_check_buffer(res, interruptible, &val_buf); + ret = vmw_resource_check_buffer(ticket, res, interruptible, &val_buf); if (unlikely(ret != 0)) return ret; @@ -1098,7 +578,7 @@ static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) res->backup_dirty = true; res->res_dirty = false; out_no_unbind: - vmw_resource_backoff_reservation(&val_buf); + vmw_resource_backoff_reservation(ticket, &val_buf); return ret; } @@ -1152,7 +632,8 @@ int vmw_resource_validate(struct vmw_resource *res) write_unlock(&dev_priv->resource_lock); - ret = vmw_resource_do_evict(evict_res, true); + /* Trylock backup buffers with a NULL ticket. */ + ret = vmw_resource_do_evict(NULL, evict_res, true); if (unlikely(ret != 0)) { write_lock(&dev_priv->resource_lock); list_add_tail(&evict_res->lru_head, lru_list); @@ -1171,7 +652,7 @@ int vmw_resource_validate(struct vmw_resource *res) goto out_no_validate; else if (!res->func->needs_backup && res->backup) { list_del_init(&res->mob_head); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } return 0; @@ -1180,109 +661,39 @@ out_no_validate: return ret; } -/** - * vmw_fence_single_bo - Utility function to fence a single TTM buffer - * object without unreserving it. - * - * @bo: Pointer to the struct ttm_buffer_object to fence. - * @fence: Pointer to the fence. If NULL, this function will - * insert a fence into the command stream.. - * - * Contrary to the ttm_eu version of this function, it takes only - * a single buffer object instead of a list, and it also doesn't - * unreserve the buffer object, which needs to be done separately. - */ -void vmw_fence_single_bo(struct ttm_buffer_object *bo, - struct vmw_fence_obj *fence) -{ - struct ttm_bo_device *bdev = bo->bdev; - - struct vmw_private *dev_priv = - container_of(bdev, struct vmw_private, bdev); - - if (fence == NULL) { - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - reservation_object_add_excl_fence(bo->resv, &fence->base); - dma_fence_put(&fence->base); - } else - reservation_object_add_excl_fence(bo->resv, &fence->base); -} /** - * vmw_resource_move_notify - TTM move_notify_callback + * vmw_resource_unbind_list * - * @bo: The TTM buffer object about to move. - * @mem: The struct ttm_mem_reg indicating to what memory - * region the move is taking place. + * @vbo: Pointer to the current backing MOB. * * Evicts the Guest Backed hardware resource if the backup * buffer is being moved out of MOB memory. - * Note that this function should not race with the resource - * validation code as long as it accesses only members of struct - * resource that remain static while bo::res is !NULL and - * while we have @bo reserved. struct resource::backup is *not* a - * static member. The resource validation code will take care - * to set @bo::res to NULL, while having @bo reserved when the - * buffer is no longer bound to the resource, so @bo:res can be - * used to determine whether there is a need to unbind and whether - * it is safe to unbind. + * Note that this function will not race with the resource + * validation code, since resource validation and eviction + * both require the backup buffer to be reserved. */ -void vmw_resource_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem) +void vmw_resource_unbind_list(struct vmw_buffer_object *vbo) { - struct vmw_dma_buffer *dma_buf; - - if (mem == NULL) - return; - - if (bo->destroy != vmw_dmabuf_bo_free && - bo->destroy != vmw_user_dmabuf_destroy) - return; - - dma_buf = container_of(bo, struct vmw_dma_buffer, base); - - /* - * Kill any cached kernel maps before move. An optimization could - * be to do this iff source or destination memory type is VRAM. - */ - vmw_dma_buffer_unmap(dma_buf); - if (mem->mem_type != VMW_PL_MOB) { - struct vmw_resource *res, *n; - struct ttm_validate_buffer val_buf; + struct vmw_resource *res, *next; + struct ttm_validate_buffer val_buf = { + .bo = &vbo->base, + .shared = false + }; - val_buf.bo = bo; - val_buf.shared = false; + lockdep_assert_held(&vbo->base.resv->lock.base); + list_for_each_entry_safe(res, next, &vbo->res_list, mob_head) { + if (!res->func->unbind) + continue; - list_for_each_entry_safe(res, n, &dma_buf->res_list, mob_head) { - - if (unlikely(res->func->unbind == NULL)) - continue; - - (void) res->func->unbind(res, true, &val_buf); - res->backup_dirty = true; - res->res_dirty = false; - list_del_init(&res->mob_head); - } - - (void) ttm_bo_wait(bo, false, false); + (void) res->func->unbind(res, true, &val_buf); + res->backup_dirty = true; + res->res_dirty = false; + list_del_init(&res->mob_head); } -} - - -/** - * vmw_resource_swap_notify - swapout notify callback. - * - * @bo: The buffer object to be swapped out. - */ -void vmw_resource_swap_notify(struct ttm_buffer_object *bo) -{ - if (bo->destroy != vmw_dmabuf_bo_free && - bo->destroy != vmw_user_dmabuf_destroy) - return; - /* Kill any cached kernel maps before swapout */ - vmw_dma_buffer_unmap(vmw_dma_buffer(bo)); + (void) ttm_bo_wait(&vbo->base, false, false); } @@ -1294,7 +705,7 @@ void vmw_resource_swap_notify(struct ttm_buffer_object *bo) * Read back cached states from the device if they exist. This function * assumings binding_mutex is held. */ -int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob) +int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob) { struct vmw_resource *dx_query_ctx; struct vmw_private *dev_priv; @@ -1344,7 +755,7 @@ int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob) void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) { - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct ttm_bo_device *bdev = bo->bdev; struct vmw_private *dev_priv; @@ -1353,7 +764,7 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo, mutex_lock(&dev_priv->binding_mutex); - dx_query_mob = container_of(bo, struct vmw_dma_buffer, base); + dx_query_mob = container_of(bo, struct vmw_buffer_object, base); if (mem == NULL || !dx_query_mob || !dx_query_mob->dx_query_ctx) { mutex_unlock(&dev_priv->binding_mutex); return; @@ -1368,7 +779,7 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo, /* Create a fence and attach the BO to it */ (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (fence != NULL) vmw_fence_obj_unreference(&fence); @@ -1405,6 +816,7 @@ static void vmw_resource_evict_type(struct vmw_private *dev_priv, struct vmw_resource *evict_res; unsigned err_count = 0; int ret; + struct ww_acquire_ctx ticket; do { write_lock(&dev_priv->resource_lock); @@ -1418,7 +830,8 @@ static void vmw_resource_evict_type(struct vmw_private *dev_priv, list_del_init(&evict_res->lru_head); write_unlock(&dev_priv->resource_lock); - ret = vmw_resource_do_evict(evict_res, false); + /* Wait lock backup buffers with a ticket. */ + ret = vmw_resource_do_evict(&ticket, evict_res, false); if (unlikely(ret != 0)) { write_lock(&dev_priv->resource_lock); list_add_tail(&evict_res->lru_head, lru_list); @@ -1481,7 +894,7 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible) goto out_no_reserve; if (res->pin_count == 0) { - struct vmw_dma_buffer *vbo = NULL; + struct vmw_buffer_object *vbo = NULL; if (res->backup) { vbo = res->backup; @@ -1539,7 +952,7 @@ void vmw_resource_unpin(struct vmw_resource *res) WARN_ON(res->pin_count == 0); if (--res->pin_count == 0 && res->backup) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; (void) ttm_bo_reserve(&vbo->base, false, false, NULL); vmw_bo_pin_reserved(vbo, false); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 73cf3c6e1591..4eea456b9d4e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -66,7 +66,7 @@ struct vmw_kms_sou_readback_blit { SVGAFifoCmdBlitScreenToGMRFB body; }; -struct vmw_kms_sou_dmabuf_blit { +struct vmw_kms_sou_bo_blit { uint32 header; SVGAFifoCmdBlitGMRFBToScreen body; }; @@ -83,7 +83,7 @@ struct vmw_screen_object_unit { struct vmw_display_unit base; unsigned long buffer_size; /**< Size of allocated buffer */ - struct vmw_dma_buffer *buffer; /**< Backing store buffer */ + struct vmw_buffer_object *buffer; /**< Backing store buffer */ bool defined; }; @@ -109,7 +109,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) */ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou, - uint32_t x, uint32_t y, + int x, int y, struct drm_display_mode *mode) { size_t fifo_size; @@ -139,13 +139,8 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); cmd->obj.size.width = mode->hdisplay; cmd->obj.size.height = mode->vdisplay; - if (sou->base.is_implicit) { - cmd->obj.root.x = x; - cmd->obj.root.y = y; - } else { - cmd->obj.root.x = sou->base.gui_x; - cmd->obj.root.y = sou->base.gui_y; - } + cmd->obj.root.x = x; + cmd->obj.root.y = y; sou->base.set_gui_x = cmd->obj.root.x; sou->base.set_gui_y = cmd->obj.root.y; @@ -222,12 +217,11 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) struct vmw_plane_state *vps; int ret; - - sou = vmw_crtc_to_sou(crtc); + sou = vmw_crtc_to_sou(crtc); dev_priv = vmw_priv(crtc->dev); - ps = crtc->primary->state; - fb = ps->fb; - vps = vmw_plane_state_to_vps(ps); + ps = crtc->primary->state; + fb = ps->fb; + vps = vmw_plane_state_to_vps(ps); vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; @@ -240,11 +234,25 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) } if (vfb) { - sou->buffer = vps->dmabuf; - sou->buffer_size = vps->dmabuf_size; + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; + int x, y; + + sou->buffer = vps->bo; + sou->buffer_size = vps->bo_size; + + if (sou->base.is_implicit) { + x = crtc->x; + y = crtc->y; + } else { + conn_state = sou->base.connector.state; + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); + + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; + } - ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y, - &crtc->mode); + ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); if (ret) DRM_ERROR("Failed to define Screen Object %dx%d\n", crtc->x, crtc->y); @@ -408,10 +416,10 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, struct drm_crtc *crtc = plane->state->crtc ? plane->state->crtc : old_state->crtc; - if (vps->dmabuf) - vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false); - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + if (vps->bo) + vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false); + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; vmw_du_plane_cleanup_fb(plane, old_state); } @@ -440,8 +448,8 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, if (!new_fb) { - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; return 0; } @@ -449,22 +457,22 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, size = new_state->crtc_w * new_state->crtc_h * 4; dev_priv = vmw_priv(crtc->dev); - if (vps->dmabuf) { - if (vps->dmabuf_size == size) { + if (vps->bo) { + if (vps->bo_size == size) { /* * Note that this might temporarily up the pin-count * to 2, until cleanup_fb() is called. */ - return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, + return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); } - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; } - vps->dmabuf = kzalloc(sizeof(*vps->dmabuf), GFP_KERNEL); - if (!vps->dmabuf) + vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL); + if (!vps->bo) return -ENOMEM; vmw_svga_enable(dev_priv); @@ -473,22 +481,22 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, * resume the overlays, this is preferred to failing to alloc. */ vmw_overlay_pause_all(dev_priv); - ret = vmw_dmabuf_init(dev_priv, vps->dmabuf, size, + ret = vmw_bo_init(dev_priv, vps->bo, size, &vmw_vram_ne_placement, - false, &vmw_dmabuf_bo_free); + false, &vmw_bo_bo_free); vmw_overlay_resume_all(dev_priv); if (ret) { - vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ + vps->bo = NULL; /* vmw_bo_init frees on error */ return ret; } - vps->dmabuf_size = size; + vps->bo_size = size; /* * TTM already thinks the buffer is pinned, but make sure the * pin_count is upped. */ - return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true); + return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); } @@ -512,10 +520,10 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, vclips.w = crtc->mode.hdisplay; vclips.h = crtc->mode.vdisplay; - if (vfb->dmabuf) - ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, NULL, - &vclips, 1, 1, true, - &fence, crtc); + if (vfb->bo) + ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, + &vclips, 1, 1, true, + &fence, crtc); else ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, &vclips, NULL, 0, 0, @@ -775,11 +783,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) return 0; } -static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv, +static int do_bo_define_gmrfb(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer) { - struct vmw_dma_buffer *buf = - container_of(framebuffer, struct vmw_framebuffer_dmabuf, + struct vmw_buffer_object *buf = + container_of(framebuffer, struct vmw_framebuffer_bo, base)->buffer; int depth = framebuffer->base.format->depth; struct { @@ -970,13 +978,13 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, } /** - * vmw_sou_dmabuf_fifo_commit - Callback to submit a set of readback clips. + * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips. * * @dirty: The closure structure. * * Commits a previously built command buffer of readback clips. */ -static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +static void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty) { if (!dirty->num_hits) { vmw_fifo_commit(dirty->dev_priv, 0); @@ -984,20 +992,20 @@ static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) } vmw_fifo_commit(dirty->dev_priv, - sizeof(struct vmw_kms_sou_dmabuf_blit) * + sizeof(struct vmw_kms_sou_bo_blit) * dirty->num_hits); } /** - * vmw_sou_dmabuf_clip - Callback to encode a readback cliprect. + * vmw_sou_bo_clip - Callback to encode a readback cliprect. * * @dirty: The closure structure * * Encodes a BLIT_GMRFB_TO_SCREEN cliprect. */ -static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) +static void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty) { - struct vmw_kms_sou_dmabuf_blit *blit = dirty->cmd; + struct vmw_kms_sou_bo_blit *blit = dirty->cmd; blit += dirty->num_hits; blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; @@ -1012,10 +1020,10 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_kms_do_dmabuf_dirty - Dirty part of a dma-buffer backed framebuffer + * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer * * @dev_priv: Pointer to the device private structure. - * @framebuffer: Pointer to the dma-buffer backed framebuffer. + * @framebuffer: Pointer to the buffer-object backed framebuffer. * @clips: Array of clip rects. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. @@ -1025,12 +1033,12 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. - * @crtc: If crtc is passed, perform dmabuf dirty on that crtc only. + * @crtc: If crtc is passed, perform bo dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ -int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, +int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, struct drm_vmw_rect *vclips, @@ -1039,8 +1047,8 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(framebuffer, struct vmw_framebuffer_dmabuf, + struct vmw_buffer_object *buf = + container_of(framebuffer, struct vmw_framebuffer_bo, base)->buffer; struct vmw_kms_dirty dirty; int ret; @@ -1050,14 +1058,14 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, if (ret) return ret; - ret = do_dmabuf_define_gmrfb(dev_priv, framebuffer); + ret = do_bo_define_gmrfb(dev_priv, framebuffer); if (unlikely(ret != 0)) goto out_revert; dirty.crtc = crtc; - dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; - dirty.clip = vmw_sou_dmabuf_clip; - dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * + dirty.fifo_commit = vmw_sou_bo_fifo_commit; + dirty.clip = vmw_sou_bo_clip; + dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) * num_clips; ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 0, 0, num_clips, increment, &dirty); @@ -1116,12 +1124,12 @@ static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) /** * vmw_kms_sou_readback - Perform a readback from the screen object system to - * a dma-buffer backed framebuffer. + * a buffer-object backed framebuffer. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm_file identifying the caller. * Must be set to NULL if @user_fence_rep is NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @user_fence_rep: User-space provided structure for fence information. * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. @@ -1139,8 +1147,8 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, uint32_t num_clips, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_buffer_object *buf = + container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_kms_dirty dirty; int ret; @@ -1149,7 +1157,7 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, if (ret) return ret; - ret = do_dmabuf_define_gmrfb(dev_priv, vfb); + ret = do_bo_define_gmrfb(dev_priv, vfb); if (unlikely(ret != 0)) goto out_revert; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index e3ba63da396d..fe4842ca3b6e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -159,7 +159,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv, SVGA3dShaderType type, uint8_t num_input_sig, uint8_t num_output_sig, - struct vmw_dma_buffer *byte_code, + struct vmw_buffer_object *byte_code, void (*res_free) (struct vmw_resource *res)) { struct vmw_shader *shader = vmw_res_to_shader(res); @@ -178,7 +178,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv, res->backup_size = size; if (byte_code) { - res->backup = vmw_dmabuf_reference(byte_code); + res->backup = vmw_bo_reference(byte_code); res->backup_offset = offset; } shader->size = size; @@ -306,7 +306,7 @@ static int vmw_gb_shader_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -537,7 +537,7 @@ static int vmw_dx_shader_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -723,7 +723,7 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, } static int vmw_user_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, + struct vmw_buffer_object *buffer, size_t shader_size, size_t offset, SVGA3dShaderType shader_type, @@ -801,7 +801,7 @@ out: static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, + struct vmw_buffer_object *buffer, size_t shader_size, size_t offset, SVGA3dShaderType shader_type) @@ -862,12 +862,12 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, { struct vmw_private *dev_priv = vmw_priv(dev); struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_dma_buffer *buffer = NULL; + struct vmw_buffer_object *buffer = NULL; SVGA3dShaderType shader_type; int ret; if (buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_dmabuf_lookup(tfile, buffer_handle, + ret = vmw_user_bo_lookup(tfile, buffer_handle, &buffer, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find buffer for shader " @@ -906,7 +906,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, ttm_read_unlock(&dev_priv->reservation_sem); out_bad_arg: - vmw_dmabuf_unreference(&buffer); + vmw_bo_unreference(&buffer); return ret; } @@ -983,7 +983,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, struct list_head *list) { struct ttm_operation_ctx ctx = { false, true }; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct ttm_bo_kmap_obj map; bool is_iomem; int ret; @@ -997,8 +997,8 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, if (unlikely(!buf)) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement, - true, vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement, + true, vmw_bo_bo_free); if (unlikely(ret != 0)) goto out; @@ -1031,7 +1031,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, res, list); vmw_resource_unreference(&res); no_reserve: - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); out: return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index a474d87b1af3..8d13628e8a86 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -44,7 +44,7 @@ enum stdu_content_type { SAME_AS_DISPLAY = 0, SEPARATE_SURFACE, - SEPARATE_DMA + SEPARATE_BO }; /** @@ -58,7 +58,7 @@ enum stdu_content_type { * @bottom: Bottom side of bounding box. * @fb_left: Left side of the framebuffer/content bounding box * @fb_top: Top of the framebuffer/content bounding box - * @buf: DMA buffer when DMA-ing between buffer and screen targets. + * @buf: buffer object when DMA-ing between buffer and screen targets. * @sid: Surface ID when copying between surface and screen targets. */ struct vmw_stdu_dirty { @@ -68,7 +68,7 @@ struct vmw_stdu_dirty { s32 fb_left, fb_top; u32 pitch; union { - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; u32 sid; }; }; @@ -178,13 +178,9 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, cmd->body.height = mode->vdisplay; cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; cmd->body.dpi = 0; - if (stdu->base.is_implicit) { - cmd->body.xRoot = crtc_x; - cmd->body.yRoot = crtc_y; - } else { - cmd->body.xRoot = stdu->base.gui_x; - cmd->body.yRoot = stdu->base.gui_y; - } + cmd->body.xRoot = crtc_x; + cmd->body.yRoot = crtc_y; + stdu->base.set_gui_x = cmd->body.xRoot; stdu->base.set_gui_y = cmd->body.yRoot; @@ -374,11 +370,14 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct vmw_private *dev_priv; struct vmw_screen_target_display_unit *stdu; - int ret; - + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; + int x, y, ret; - stdu = vmw_crtc_to_stdu(crtc); + stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); + conn_state = stdu->base.connector.state; + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); if (stdu->defined) { ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); @@ -397,8 +396,16 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) if (!crtc->state->enable) return; + if (stdu->base.is_implicit) { + x = crtc->x; + y = crtc->y; + } else { + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; + } + vmw_svga_enable(dev_priv); - ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y); + ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); if (ret) DRM_ERROR("Failed to define Screen Target of size %dx%d\n", @@ -508,14 +515,14 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, /** - * vmw_stdu_dmabuf_clip - Callback to encode a suface DMA command cliprect + * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect * * @dirty: The closure structure. * * Encodes a surface DMA command cliprect and updates the bounding box * for the DMA. */ -static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_clip(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -543,14 +550,14 @@ static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_stdu_dmabuf_fifo_commit - Callback to fill in and submit a DMA command. + * vmw_stdu_bo_fifo_commit - Callback to fill in and submit a DMA command. * * @dirty: The closure structure. * * Fills in the missing fields in a DMA command, and optionally encodes * a screen target update command, depending on transfer direction. */ -static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_fifo_commit(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -594,13 +601,13 @@ static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) /** - * vmw_stdu_dmabuf_cpu_clip - Callback to encode a CPU blit + * vmw_stdu_bo_cpu_clip - Callback to encode a CPU blit * * @dirty: The closure structure. * * This function calculates the bounding box for all the incoming clips. */ -static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_cpu_clip(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -624,14 +631,14 @@ static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty) /** - * vmw_stdu_dmabuf_cpu_commit - Callback to do a CPU blit from DMAbuf + * vmw_stdu_bo_cpu_commit - Callback to do a CPU blit from buffer object * * @dirty: The closure structure. * * For the special case when we cannot create a proxy surface in a * 2D VM, we have to do a CPU blit ourselves. */ -static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -652,7 +659,7 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) if (width == 0 || height == 0) return; - /* Assume we are blitting from Guest (dmabuf) to Host (display_srf) */ + /* Assume we are blitting from Guest (bo) to Host (display_srf) */ dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; dst_bo = &stdu->display_srf->res.backup->base; dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; @@ -712,13 +719,13 @@ out_cleanup: } /** - * vmw_kms_stdu_dma - Perform a DMA transfer between a dma-buffer backed + * vmw_kms_stdu_dma - Perform a DMA transfer between a buffer-object backed * framebuffer and the screen target system. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm-file identifying the caller. May be * set to NULL, but then @user_fence_rep must also be set to NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @clips: Array of clip rects. Either @clips or @vclips must be NULL. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. @@ -747,8 +754,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, bool interruptible, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_buffer_object *buf = + container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_stdu_dirty ddirty; int ret; bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); @@ -770,8 +777,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, ddirty.fb_left = ddirty.fb_top = S32_MAX; ddirty.pitch = vfb->base.pitches[0]; ddirty.buf = buf; - ddirty.base.fifo_commit = vmw_stdu_dmabuf_fifo_commit; - ddirty.base.clip = vmw_stdu_dmabuf_clip; + ddirty.base.fifo_commit = vmw_stdu_bo_fifo_commit; + ddirty.base.clip = vmw_stdu_bo_clip; ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) + num_clips * sizeof(SVGA3dCopyBox) + sizeof(SVGA3dCmdSurfaceDMASuffix); @@ -780,8 +787,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, if (cpu_blit) { - ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; - ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; + ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit; + ddirty.base.clip = vmw_stdu_bo_cpu_clip; ddirty.base.fifo_reserve_size = 0; } @@ -927,7 +934,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, if (ret) return ret; - if (vfbs->is_dmabuf_proxy) { + if (vfbs->is_bo_proxy) { ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); if (ret) goto out_finish; @@ -1075,7 +1082,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, * @new_state: info on the new plane state, including the FB * * This function allocates a new display surface if the content is - * backed by a DMA. The display surface is pinned here, and it'll + * backed by a buffer object. The display surface is pinned here, and it'll * be unpinned in .cleanup_fb() * * Returns 0 on success @@ -1105,13 +1112,13 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, } vfb = vmw_framebuffer_to_vfb(new_fb); - new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb); + new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay && new_vfbs->surface->base_size.height == vdisplay) new_content_type = SAME_AS_DISPLAY; - else if (vfb->dmabuf) - new_content_type = SEPARATE_DMA; + else if (vfb->bo) + new_content_type = SEPARATE_BO; else new_content_type = SEPARATE_SURFACE; @@ -1124,10 +1131,10 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, display_base_size.depth = 1; /* - * If content buffer is a DMA buf, then we have to construct - * surface info + * If content buffer is a buffer object, then we have to + * construct surface info */ - if (new_content_type == SEPARATE_DMA) { + if (new_content_type == SEPARATE_BO) { switch (new_fb->format->cpp[0]*8) { case 32: @@ -1150,6 +1157,9 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, content_srf.flags = 0; content_srf.mip_levels[0] = 1; content_srf.multisample_count = 0; + content_srf.multisample_pattern = + SVGA3D_MS_PATTERN_NONE; + content_srf.quality_level = SVGA3D_MS_QUALITY_NONE; } else { content_srf = *new_vfbs->surface; } @@ -1178,6 +1188,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, content_srf.multisample_count, 0, display_base_size, + content_srf.multisample_pattern, + content_srf.quality_level, &vps->surf); if (ret != 0) { DRM_ERROR("Couldn't allocate STDU surface.\n"); @@ -1212,12 +1224,12 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, vps->content_fb_type = new_content_type; /* - * This should only happen if the DMA buf is too large to create a + * This should only happen if the buffer object is too large to create a * proxy surface for. - * If we are a 2D VM with a DMA buffer then we have to use CPU blit + * If we are a 2D VM with a buffer object then we have to use CPU blit * so cache these mappings */ - if (vps->content_fb_type == SEPARATE_DMA && + if (vps->content_fb_type == SEPARATE_BO && !(dev_priv->capabilities & SVGA_CAP_3D)) vps->cpp = new_fb->pitches[0] / new_fb->width; @@ -1276,7 +1288,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, if (ret) DRM_ERROR("Failed to bind surface to STDU.\n"); - if (vfb->dmabuf) + if (vfb->bo) ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, 1, 1, true, false, crtc); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 40a439797ae2..e125233e074b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -33,6 +33,10 @@ #include "vmwgfx_binding.h" #include "device_include/svga3d_surfacedefs.h" +#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) +#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) +#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ + (svga3d_flags & ((uint64_t)U32_MAX)) /** * struct vmw_user_surface - User-space visible surface resource @@ -81,7 +85,16 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, bool readback, struct ttm_validate_buffer *val_buf); static int vmw_gb_surface_destroy(struct vmw_resource *res); - +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv); +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + struct drm_file *file_priv); static const struct vmw_user_resource_conv user_surface_conv = { .object_type = VMW_RES_SURFACE, @@ -224,7 +237,12 @@ static void vmw_surface_define_encode(const struct vmw_surface *srf, cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE; cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; - cmd->body.surfaceFlags = srf->flags; + /* + * Downcast of surfaceFlags, was upcasted when received from user-space, + * since driver internally stores as 64 bit. + * For legacy surface define only 32 bit flag is supported. + */ + cmd->body.surfaceFlags = (SVGA3dSurface1Flags)srf->flags; cmd->body.format = srf->format; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) cmd->body.face[i].numMipLevels = srf->mip_levels[i]; @@ -468,7 +486,7 @@ static int vmw_legacy_srf_dma(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -760,7 +778,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf = &user_srf->srf; res = &srf->res; - srf->flags = req->flags; + /* Driver internally stores as 64-bit flags */ + srf->flags = (SVGA3dSurfaceAllFlags)req->flags; srf->format = req->format; srf->scanout = req->scanout; @@ -785,6 +804,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf->base_size = *srf->sizes; srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->multisample_count = 0; + srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; + srf->quality_level = SVGA3D_MS_QUALITY_NONE; cur_bo_offset = 0; cur_offset = srf->offsets; @@ -842,12 +863,12 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (dev_priv->has_mob && req->shareable) { uint32_t backup_handle; - ret = vmw_user_dmabuf_alloc(dev_priv, tfile, - res->backup_size, - true, - &backup_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_alloc(dev_priv, tfile, + res->backup_size, + true, + &backup_handle, + &res->backup, + &user_srf->backup_base); if (unlikely(ret != 0)) { vmw_resource_unreference(&res); goto out_unlock; @@ -990,7 +1011,8 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; - rep->flags = srf->flags; + /* Downcast of flags when sending back to user space */ + rep->flags = (uint32_t)srf->flags; rep->format = srf->format; memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); user_sizes = (struct drm_vmw_size __user *)(unsigned long) @@ -1031,6 +1053,10 @@ static int vmw_gb_surface_create(struct vmw_resource *res) SVGA3dCmdHeader header; SVGA3dCmdDefineGBSurface_v2 body; } *cmd2; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBSurface_v3 body; + } *cmd3; if (likely(res->id != -1)) return 0; @@ -1047,7 +1073,11 @@ static int vmw_gb_surface_create(struct vmw_resource *res) goto out_no_fifo; } - if (srf->array_size > 0) { + if (dev_priv->has_sm4_1 && srf->array_size > 0) { + cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V3; + cmd_len = sizeof(cmd3->body); + submit_len = sizeof(*cmd3); + } else if (srf->array_size > 0) { /* has_dx checked on creation time. */ cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2; cmd_len = sizeof(cmd2->body); @@ -1060,6 +1090,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd = vmw_fifo_reserve(dev_priv, submit_len); cmd2 = (typeof(cmd2))cmd; + cmd3 = (typeof(cmd3))cmd; if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "creation.\n"); @@ -1067,12 +1098,27 @@ static int vmw_gb_surface_create(struct vmw_resource *res) goto out_no_fifo; } - if (srf->array_size > 0) { + if (dev_priv->has_sm4_1 && srf->array_size > 0) { + cmd3->header.id = cmd_id; + cmd3->header.size = cmd_len; + cmd3->body.sid = srf->res.id; + cmd3->body.surfaceFlags = srf->flags; + cmd3->body.format = srf->format; + cmd3->body.numMipLevels = srf->mip_levels[0]; + cmd3->body.multisampleCount = srf->multisample_count; + cmd3->body.multisamplePattern = srf->multisample_pattern; + cmd3->body.qualityLevel = srf->quality_level; + cmd3->body.autogenFilter = srf->autogen_filter; + cmd3->body.size.width = srf->base_size.width; + cmd3->body.size.height = srf->base_size.height; + cmd3->body.size.depth = srf->base_size.depth; + cmd3->body.arraySize = srf->array_size; + } else if (srf->array_size > 0) { cmd2->header.id = cmd_id; cmd2->header.size = cmd_len; cmd2->body.sid = srf->res.id; cmd2->body.surfaceFlags = srf->flags; - cmd2->body.format = cpu_to_le32(srf->format); + cmd2->body.format = srf->format; cmd2->body.numMipLevels = srf->mip_levels[0]; cmd2->body.multisampleCount = srf->multisample_count; cmd2->body.autogenFilter = srf->autogen_filter; @@ -1085,7 +1131,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; cmd->body.surfaceFlags = srf->flags; - cmd->body.format = cpu_to_le32(srf->format); + cmd->body.format = srf->format; cmd->body.numMipLevels = srf->mip_levels[0]; cmd->body.multisampleCount = srf->multisample_count; cmd->body.autogenFilter = srf->autogen_filter; @@ -1210,7 +1256,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -1256,194 +1302,55 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) /** * vmw_gb_surface_define_ioctl - Ioctl function implementing - * the user surface define functionality. + * the user surface define functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_user_surface *user_srf; - struct vmw_surface *srf; - struct vmw_resource *res; - struct vmw_resource *tmp; union drm_vmw_gb_surface_create_arg *arg = (union drm_vmw_gb_surface_create_arg *)data; - struct drm_vmw_gb_surface_create_req *req = &arg->req; struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - int ret; - uint32_t size; - uint32_t backup_handle = 0; - - if (req->multisample_count != 0) - return -EINVAL; - - if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS) - return -EINVAL; + struct drm_vmw_gb_surface_create_ext_req req_ext; - if (unlikely(vmw_user_surface_size == 0)) - vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + - 128; - - size = vmw_user_surface_size + 128; - - /* Define a surface based on the parameters. */ - ret = vmw_surface_gb_priv_define(dev, - size, - req->svga3d_flags, - req->format, - req->drm_surface_flags & drm_vmw_surface_flag_scanout, - req->mip_levels, - req->multisample_count, - req->array_size, - req->base_size, - &srf); - if (unlikely(ret != 0)) - return ret; - - user_srf = container_of(srf, struct vmw_user_surface, srf); - if (drm_is_primary_client(file_priv)) - user_srf->master = drm_master_get(file_priv->master); + req_ext.base = arg->req; + req_ext.version = drm_vmw_gb_surface_v1; + req_ext.svga3d_flags_upper_32_bits = 0; + req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; + req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; + req_ext.must_be_zero = 0; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - res = &user_srf->srf.res; - - - if (req->buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, - &res->backup, - &user_srf->backup_base); - if (ret == 0) { - if (res->backup->base.num_pages * PAGE_SIZE < - res->backup_size) { - DRM_ERROR("Surface backup buffer is too small.\n"); - vmw_dmabuf_unreference(&res->backup); - ret = -EINVAL; - goto out_unlock; - } else { - backup_handle = req->buffer_handle; - } - } - } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) - ret = vmw_user_dmabuf_alloc(dev_priv, tfile, - res->backup_size, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); - - if (unlikely(ret != 0)) { - vmw_resource_unreference(&res); - goto out_unlock; - } - - tmp = vmw_resource_reference(res); - ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); - - if (unlikely(ret != 0)) { - vmw_resource_unreference(&tmp); - vmw_resource_unreference(&res); - goto out_unlock; - } - - rep->handle = user_srf->prime.base.hash.key; - rep->backup_size = res->backup_size; - if (res->backup) { - rep->buffer_map_handle = - drm_vma_node_offset_addr(&res->backup->base.vma_node); - rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; - rep->buffer_handle = backup_handle; - } else { - rep->buffer_map_handle = 0; - rep->buffer_size = 0; - rep->buffer_handle = SVGA3D_INVALID_ID; - } - - vmw_resource_unreference(&res); - -out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; + return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); } /** * vmw_gb_surface_reference_ioctl - Ioctl function implementing - * the user surface reference functionality. + * the user surface reference functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_gb_surface_reference_arg *arg = (union drm_vmw_gb_surface_reference_arg *)data; struct drm_vmw_surface_arg *req = &arg->req; struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_surface *srf; - struct vmw_user_surface *user_srf; - struct ttm_base_object *base; - uint32_t backup_handle; - int ret = -EINVAL; + struct drm_vmw_gb_surface_ref_ext_rep rep_ext; + int ret; + + ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); - ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, - req->handle_type, &base); if (unlikely(ret != 0)) return ret; - user_srf = container_of(base, struct vmw_user_surface, prime.base); - srf = &user_srf->srf; - if (!srf->res.backup) { - DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); - goto out_bad_resource; - } - - mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, - &backup_handle); - mutex_unlock(&dev_priv->cmdbuf_mutex); - - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a GB surface " - "backup buffer.\n"); - (void) ttm_ref_object_base_unref(tfile, base->hash.key, - TTM_REF_USAGE); - goto out_bad_resource; - } - - rep->creq.svga3d_flags = srf->flags; - rep->creq.format = srf->format; - rep->creq.mip_levels = srf->mip_levels[0]; - rep->creq.drm_surface_flags = 0; - rep->creq.multisample_count = srf->multisample_count; - rep->creq.autogen_filter = srf->autogen_filter; - rep->creq.array_size = srf->array_size; - rep->creq.buffer_handle = backup_handle; - rep->creq.base_size = srf->base_size; - rep->crep.handle = user_srf->prime.base.hash.key; - rep->crep.backup_size = srf->res.backup_size; - rep->crep.buffer_handle = backup_handle; - rep->crep.buffer_map_handle = - drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); - rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; - -out_bad_resource: - ttm_base_object_unref(&base); + rep->creq = rep_ext.creq.base; + rep->crep = rep_ext.crep; return ret; } @@ -1461,6 +1368,8 @@ out_bad_resource: * @multisample_count: * @array_size: Surface array size. * @size: width, heigh, depth of the surface requested + * @multisample_pattern: Multisampling pattern when msaa is supported + * @quality_level: Precision settings * @user_srf_out: allocated user_srf. Set to NULL on failure. * * GB surfaces allocated by this function will not have a user mode handle, and @@ -1470,13 +1379,15 @@ out_bad_resource: */ int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t user_accounting_size, - uint32_t svga3d_flags, + SVGA3dSurfaceAllFlags svga3d_flags, SVGA3dSurfaceFormat format, bool for_scanout, uint32_t num_mip_levels, uint32_t multisample_count, uint32_t array_size, struct drm_vmw_size size, + SVGA3dMSPattern multisample_pattern, + SVGA3dMSQualityLevel quality_level, struct vmw_surface **srf_out) { struct vmw_private *dev_priv = vmw_priv(dev); @@ -1487,7 +1398,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, }; struct vmw_surface *srf; int ret; - u32 num_layers; + u32 num_layers = 1; + u32 sample_count = 1; *srf_out = NULL; @@ -1562,19 +1474,23 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->array_size = array_size; srf->multisample_count = multisample_count; + srf->multisample_pattern = multisample_pattern; + srf->quality_level = quality_level; if (array_size) num_layers = array_size; else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) num_layers = SVGA3D_MAX_SURFACE_FACES; - else - num_layers = 1; + + if (srf->flags & SVGA3D_SURFACE_MULTISAMPLE) + sample_count = srf->multisample_count; srf->res.backup_size = - svga3dsurface_get_serialized_size(srf->format, - srf->base_size, - srf->mip_levels[0], - num_layers); + svga3dsurface_get_serialized_size_extended(srf->format, + srf->base_size, + srf->mip_levels[0], + num_layers, + sample_count); if (srf->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) srf->res.backup_size += sizeof(SVGA3dDXSOState); @@ -1599,3 +1515,266 @@ out_unlock: ttm_read_unlock(&dev_priv->reservation_sem); return ret; } + +/** + * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_create_ext_arg *arg = + (union drm_vmw_gb_surface_create_ext_arg *)data; + struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; + struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; + + return vmw_gb_surface_define_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_reference_ext_arg *arg = + (union drm_vmw_gb_surface_reference_ext_arg *)data; + struct drm_vmw_surface_arg *req = &arg->req; + struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; + + return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_define_internal - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Request argument from user-space. + * @rep: Response argument to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_user_surface *user_srf; + struct vmw_surface *srf; + struct vmw_resource *res; + struct vmw_resource *tmp; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + int ret; + uint32_t size; + uint32_t backup_handle = 0; + SVGA3dSurfaceAllFlags svga3d_flags_64 = + SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, + req->base.svga3d_flags); + + if (!dev_priv->has_sm4_1) { + /* + * If SM4_1 is not support then cannot send 64-bit flag to + * device. + */ + if (req->svga3d_flags_upper_32_bits != 0) + return -EINVAL; + + if (req->base.multisample_count != 0) + return -EINVAL; + + if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) + return -EINVAL; + + if (req->quality_level != SVGA3D_MS_QUALITY_NONE) + return -EINVAL; + } + + if ((svga3d_flags_64 & SVGA3D_SURFACE_MULTISAMPLE) && + req->base.multisample_count == 0) + return -EINVAL; + + if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) + return -EINVAL; + + if (unlikely(vmw_user_surface_size == 0)) + vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + + 128; + + size = vmw_user_surface_size + 128; + + /* Define a surface based on the parameters. */ + ret = vmw_surface_gb_priv_define(dev, + size, + svga3d_flags_64, + req->base.format, + req->base.drm_surface_flags & + drm_vmw_surface_flag_scanout, + req->base.mip_levels, + req->base.multisample_count, + req->base.array_size, + req->base.base_size, + req->multisample_pattern, + req->quality_level, + &srf); + if (unlikely(ret != 0)) + return ret; + + user_srf = container_of(srf, struct vmw_user_surface, srf); + if (drm_is_primary_client(file_priv)) + user_srf->master = drm_master_get(file_priv->master); + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + res = &user_srf->srf.res; + + if (req->base.buffer_handle != SVGA3D_INVALID_ID) { + ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, + &res->backup, + &user_srf->backup_base); + if (ret == 0) { + if (res->backup->base.num_pages * PAGE_SIZE < + res->backup_size) { + DRM_ERROR("Surface backup buffer too small.\n"); + vmw_bo_unreference(&res->backup); + ret = -EINVAL; + goto out_unlock; + } else { + backup_handle = req->base.buffer_handle; + } + } + } else if (req->base.drm_surface_flags & + drm_vmw_surface_flag_create_buffer) + ret = vmw_user_bo_alloc(dev_priv, tfile, + res->backup_size, + req->base.drm_surface_flags & + drm_vmw_surface_flag_shareable, + &backup_handle, + &res->backup, + &user_srf->backup_base); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + + tmp = vmw_resource_reference(res); + ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, + req->base.drm_surface_flags & + drm_vmw_surface_flag_shareable, + VMW_RES_SURFACE, + &vmw_user_surface_base_release, NULL); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&tmp); + vmw_resource_unreference(&res); + goto out_unlock; + } + + rep->handle = user_srf->prime.base.hash.key; + rep->backup_size = res->backup_size; + if (res->backup) { + rep->buffer_map_handle = + drm_vma_node_offset_addr(&res->backup->base.vma_node); + rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; + rep->buffer_handle = backup_handle; + } else { + rep->buffer_map_handle = 0; + rep->buffer_size = 0; + rep->buffer_handle = SVGA3D_INVALID_ID; + } + + vmw_resource_unreference(&res); + +out_unlock: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + +/** + * vmw_gb_surface_reference_internal - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Pointer to user-space request surface arg. + * @rep: Pointer to response to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_surface *srf; + struct vmw_user_surface *user_srf; + struct ttm_base_object *base; + uint32_t backup_handle; + int ret = -EINVAL; + + ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, + req->handle_type, &base); + if (unlikely(ret != 0)) + return ret; + + user_srf = container_of(base, struct vmw_user_surface, prime.base); + srf = &user_srf->srf; + if (!srf->res.backup) { + DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); + goto out_bad_resource; + } + + mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ + ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); + mutex_unlock(&dev_priv->cmdbuf_mutex); + + if (unlikely(ret != 0)) { + DRM_ERROR("Could not add a reference to a GB surface " + "backup buffer.\n"); + (void) ttm_ref_object_base_unref(tfile, base->hash.key, + TTM_REF_USAGE); + goto out_bad_resource; + } + + rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(srf->flags); + rep->creq.base.format = srf->format; + rep->creq.base.mip_levels = srf->mip_levels[0]; + rep->creq.base.drm_surface_flags = 0; + rep->creq.base.multisample_count = srf->multisample_count; + rep->creq.base.autogen_filter = srf->autogen_filter; + rep->creq.base.array_size = srf->array_size; + rep->creq.base.buffer_handle = backup_handle; + rep->creq.base.base_size = srf->base_size; + rep->crep.handle = user_srf->prime.base.hash.key; + rep->crep.backup_size = srf->res.backup_size; + rep->crep.buffer_handle = backup_handle; + rep->crep.buffer_map_handle = + drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); + rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; + + rep->creq.version = drm_vmw_gb_surface_v1; + rep->creq.svga3d_flags_upper_32_bits = + SVGA3D_FLAGS_UPPER_32(srf->flags); + rep->creq.multisample_pattern = srf->multisample_pattern; + rep->creq.quality_level = srf->quality_level; + rep->creq.must_be_zero = 0; + +out_bad_resource: + ttm_base_object_unref(&base); + + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 02de216d55a1..31786b200afc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -798,7 +798,7 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) struct ttm_object_file *tfile = vmw_fpriv((struct drm_file *)filp->private_data)->tfile; - return vmw_user_dmabuf_verify_access(bo, tfile); + return vmw_user_bo_verify_access(bo, tfile); } static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) @@ -852,7 +852,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, bool evict, struct ttm_mem_reg *mem) { - vmw_resource_move_notify(bo, mem); + vmw_bo_move_notify(bo, mem); vmw_query_move_notify(bo, mem); } @@ -864,7 +864,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, */ static void vmw_swap_notify(struct ttm_buffer_object *bo) { - vmw_resource_swap_notify(bo); + vmw_bo_swap_notify(bo); (void) ttm_bo_wait(bo, false, false); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 97acba712e4e..22adaf35b136 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5222,6 +5222,7 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev) return PCI_SPEED_UNKNOWN; } +EXPORT_SYMBOL(pcie_get_speed_cap); /** * pcie_get_width_cap - query for the PCI device's link width capability @@ -5240,6 +5241,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev) return PCIE_LNK_WIDTH_UNKNOWN; } +EXPORT_SYMBOL(pcie_get_width_cap); /** * pcie_bandwidth_capable - calculate a PCI device's link bandwidth capability diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h index 674599025d7d..8181e9e7cf1d 100644 --- a/include/drm/drm_pci.h +++ b/include/drm/drm_pci.h @@ -58,11 +58,4 @@ static inline int drm_get_pci_dev(struct pci_dev *pdev, } #endif -#define DRM_PCIE_SPEED_25 1 -#define DRM_PCIE_SPEED_50 2 -#define DRM_PCIE_SPEED_80 4 - -int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); -int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); - #endif /* _DRM_PCI_H_ */ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 7c2dfd6cc1af..4214ceb71c05 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -284,12 +284,12 @@ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, struct drm_sched_rq *rq, atomic_t *guilty); -long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, +long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, long timeout); -void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity); void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity); +void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity); void drm_sched_entity_push_job(struct drm_sched_job *sched_job, struct drm_sched_entity *entity); void drm_sched_entity_set_rq(struct drm_sched_entity *entity, diff --git a/include/linux/pci.h b/include/linux/pci.h index 340029b2fb38..6e0c0803b241 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -261,6 +261,9 @@ enum pci_bus_speed { PCI_SPEED_UNKNOWN = 0xff, }; +enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev); +enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); + struct pci_cap_saved_data { u16 cap_nr; bool cap_extended; diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 0bc784f5e0db..399f58317cff 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -40,6 +40,7 @@ extern "C" { #define DRM_VMW_GET_PARAM 0 #define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_ALLOC_BO 1 #define DRM_VMW_UNREF_DMABUF 2 #define DRM_VMW_HANDLE_CLOSE 2 #define DRM_VMW_CURSOR_BYPASS 3 @@ -68,6 +69,8 @@ extern "C" { #define DRM_VMW_GB_SURFACE_REF 24 #define DRM_VMW_SYNCCPU 25 #define DRM_VMW_CREATE_EXTENDED_CONTEXT 26 +#define DRM_VMW_GB_SURFACE_CREATE_EXT 27 +#define DRM_VMW_GB_SURFACE_REF_EXT 28 /*************************************************************************/ /** @@ -79,6 +82,9 @@ extern "C" { * * DRM_VMW_PARAM_OVERLAY_IOCTL: * Does the driver support the overlay ioctl. + * + * DRM_VMW_PARAM_SM4_1 + * SM4_1 support is enabled. */ #define DRM_VMW_PARAM_NUM_STREAMS 0 @@ -94,6 +100,8 @@ extern "C" { #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 #define DRM_VMW_PARAM_SCREEN_TARGET 11 #define DRM_VMW_PARAM_DX 12 +#define DRM_VMW_PARAM_HW_CAPS2 13 +#define DRM_VMW_PARAM_SM4_1 14 /** * enum drm_vmw_handle_type - handle type for ref ioctls @@ -356,9 +364,9 @@ struct drm_vmw_fence_rep { /*************************************************************************/ /** - * DRM_VMW_ALLOC_DMABUF + * DRM_VMW_ALLOC_BO * - * Allocate a DMA buffer that is visible also to the host. + * Allocate a buffer object that is visible also to the host. * NOTE: The buffer is * identified by a handle and an offset, which are private to the guest, but * useable in the command stream. The guest kernel may translate these @@ -366,27 +374,28 @@ struct drm_vmw_fence_rep { * be zero at all times, or it may disappear from the interface before it is * fixed. * - * The DMA buffer may stay user-space mapped in the guest at all times, + * The buffer object may stay user-space mapped in the guest at all times, * and is thus suitable for sub-allocation. * - * DMA buffers are mapped using the mmap() syscall on the drm device. + * Buffer objects are mapped using the mmap() syscall on the drm device. */ /** - * struct drm_vmw_alloc_dmabuf_req + * struct drm_vmw_alloc_bo_req * * @size: Required minimum size of the buffer. * - * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Input data to the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_alloc_dmabuf_req { +struct drm_vmw_alloc_bo_req { __u32 size; __u32 pad64; }; +#define drm_vmw_alloc_dmabuf_req drm_vmw_alloc_bo_req /** - * struct drm_vmw_dmabuf_rep + * struct drm_vmw_bo_rep * * @map_handle: Offset to use in the mmap() call used to map the buffer. * @handle: Handle unique to this buffer. Used for unreferencing. @@ -395,50 +404,32 @@ struct drm_vmw_alloc_dmabuf_req { * @cur_gmr_offset: Offset to use in the command stream when this buffer is * referenced. See note above. * - * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + * Output data from the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_dmabuf_rep { +struct drm_vmw_bo_rep { __u64 map_handle; __u32 handle; __u32 cur_gmr_id; __u32 cur_gmr_offset; __u32 pad64; }; +#define drm_vmw_dmabuf_rep drm_vmw_bo_rep /** - * union drm_vmw_dmabuf_arg + * union drm_vmw_alloc_bo_arg * * @req: Input data as described above. * @rep: Output data as described above. * - * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Argument to the DRM_VMW_ALLOC_BO Ioctl. */ -union drm_vmw_alloc_dmabuf_arg { - struct drm_vmw_alloc_dmabuf_req req; - struct drm_vmw_dmabuf_rep rep; -}; - -/*************************************************************************/ -/** - * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. - * - */ - -/** - * struct drm_vmw_unref_dmabuf_arg - * - * @handle: Handle indicating what buffer to free. Obtained from the - * DRM_VMW_ALLOC_DMABUF Ioctl. - * - * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. - */ - -struct drm_vmw_unref_dmabuf_arg { - __u32 handle; - __u32 pad64; +union drm_vmw_alloc_bo_arg { + struct drm_vmw_alloc_bo_req req; + struct drm_vmw_bo_rep rep; }; +#define drm_vmw_alloc_dmabuf_arg drm_vmw_alloc_bo_arg /*************************************************************************/ /** @@ -1103,9 +1094,8 @@ union drm_vmw_extended_context_arg { * DRM_VMW_HANDLE_CLOSE - Close a user-space handle and release its * underlying resource. * - * Note that this ioctl is overlaid on the DRM_VMW_UNREF_DMABUF Ioctl. - * The ioctl arguments therefore need to be identical in layout. - * + * Note that this ioctl is overlaid on the deprecated DRM_VMW_UNREF_DMABUF + * Ioctl. */ /** @@ -1119,7 +1109,107 @@ struct drm_vmw_handle_close_arg { __u32 handle; __u32 pad64; }; +#define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_CREATE_EXT - Create a host guest-backed surface. + * + * Allocates a surface handle and queues a create surface command + * for the host on the first use of the surface. The surface ID can + * be used as the surface ID in commands referencing the surface. + * + * This new command extends DRM_VMW_GB_SURFACE_CREATE by adding version + * parameter and 64 bit svga flag. + */ + +/** + * enum drm_vmw_surface_version + * + * @drm_vmw_surface_gb_v1: Corresponds to current gb surface format with + * svga3d surface flags split into 2, upper half and lower half. + */ +enum drm_vmw_surface_version { + drm_vmw_gb_surface_v1 +}; + +/** + * struct drm_vmw_gb_surface_create_ext_req + * + * @base: Surface create parameters. + * @version: Version of surface create ioctl. + * @svga3d_flags_upper_32_bits: Upper 32 bits of svga3d flags. + * @multisample_pattern: Multisampling pattern when msaa is supported. + * @quality_level: Precision settings for each sample. + * @must_be_zero: Reserved for future usage. + * + * Input argument to the DRM_VMW_GB_SURFACE_CREATE_EXT Ioctl. + * Part of output argument for the DRM_VMW_GB_SURFACE_REF_EXT Ioctl. + */ +struct drm_vmw_gb_surface_create_ext_req { + struct drm_vmw_gb_surface_create_req base; + enum drm_vmw_surface_version version; + uint32_t svga3d_flags_upper_32_bits; + SVGA3dMSPattern multisample_pattern; + SVGA3dMSQualityLevel quality_level; + uint64_t must_be_zero; +}; + +/** + * union drm_vmw_gb_surface_create_ext_arg + * + * @req: Input argument as described above. + * @rep: Output argument as described above. + * + * Argument to the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ +union drm_vmw_gb_surface_create_ext_arg { + struct drm_vmw_gb_surface_create_rep rep; + struct drm_vmw_gb_surface_create_ext_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_REF_EXT - Reference a host surface. + * + * Puts a reference on a host surface with a given handle, as previously + * returned by the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface handle in + * the command stream. + * + * On successful return, the Ioctl returns the surface information given + * to and returned from the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ +/** + * struct drm_vmw_gb_surface_ref_ext_rep + * + * @creq: The data used as input when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_ext_req" + * @crep: Additional data output when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_rep" + * + * Output Argument to the DRM_VMW_GB_SURFACE_REF_EXT ioctl. + */ +struct drm_vmw_gb_surface_ref_ext_rep { + struct drm_vmw_gb_surface_create_ext_req creq; + struct drm_vmw_gb_surface_create_rep crep; +}; + +/** + * union drm_vmw_gb_surface_reference_ext_arg + * + * @req: Input data as described above at "struct drm_vmw_surface_arg" + * @rep: Output data as described above at + * "struct drm_vmw_gb_surface_ref_ext_rep" + * + * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +union drm_vmw_gb_surface_reference_ext_arg { + struct drm_vmw_gb_surface_ref_ext_rep rep; + struct drm_vmw_surface_arg req; +}; #if defined(__cplusplus) } |