Commit 280cf1a9 authored by Lyude Paul's avatar Lyude Paul Committed by Alex Deucher

drm/amdgpu: Dynamically probe for ATIF handle (v2)

The other day I was testing one of the HP laptops at my office with an
i915/amdgpu hybrid setup and noticed that hotplugging was non-functional
on almost all of the display outputs. I eventually discovered that all
of the external outputs were connected to the amdgpu device instead of
i915, and that the hotplugs weren't being detected so long as the GPU
was in runtime suspend. After some talking with folks at AMD, I learned
that amdgpu is actually supposed to support hotplug detection in runtime
suspend so long as the OEM has implemented it properly in the firmware.

On this HP ZBook 15 G4 (the machine in question), amdgpu wasn't managing
to find the ATIF handle at all despite the fact that I could see acpi
events being sent in response to any hotplugging. After going through
dumps of the firmware, I discovered that this machine did in fact
support ATIF, but that it's ATIF method lived in an entirely different
namespace than this device's handle (the device handle was
\_SB_.PCI0.PEG0.PEGP, but ATIF lives in ATPX's handle at
\_SB_.PCI0.GFX0).

So, fix this by probing ATPX's ACPI parent's namespace if we can't find
ATIF elsewhere, along with storing a pointer to the proper handle to use
for ATIF and using that instead of the device's handle.

This fixes HPD detection while in runtime suspend for this ZBook!

v2: Update the comment to reflect how the namespaces are arranged
based on the system configuration. (Alex)
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 24aeefcd
...@@ -65,6 +65,8 @@ struct amdgpu_atif_functions { ...@@ -65,6 +65,8 @@ struct amdgpu_atif_functions {
}; };
struct amdgpu_atif { struct amdgpu_atif {
acpi_handle handle;
struct amdgpu_atif_notifications notifications; struct amdgpu_atif_notifications notifications;
struct amdgpu_atif_functions functions; struct amdgpu_atif_functions functions;
struct amdgpu_atif_notification_cfg notification_cfg; struct amdgpu_atif_notification_cfg notification_cfg;
...@@ -83,7 +85,8 @@ struct amdgpu_atif { ...@@ -83,7 +85,8 @@ struct amdgpu_atif {
* Executes the requested ATIF function (all asics). * Executes the requested ATIF function (all asics).
* Returns a pointer to the acpi output buffer. * Returns a pointer to the acpi output buffer.
*/ */
static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
int function,
struct acpi_buffer *params) struct acpi_buffer *params)
{ {
acpi_status status; acpi_status status;
...@@ -107,7 +110,8 @@ static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, ...@@ -107,7 +110,8 @@ static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function,
atif_arg_elements[1].integer.value = 0; 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 */ /* Fail only if calling the method fails and ATIF is supported */
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
...@@ -178,15 +182,14 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas ...@@ -178,15 +182,14 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas
* (all asics). * (all asics).
* returns 0 on success, error on failure. * returns 0 on success, error on failure.
*/ */
static int amdgpu_atif_verify_interface(acpi_handle handle, static int amdgpu_atif_verify_interface(struct amdgpu_atif *atif)
struct amdgpu_atif *atif)
{ {
union acpi_object *info; union acpi_object *info;
struct atif_verify_interface output; struct atif_verify_interface output;
size_t size; size_t size;
int err = 0; 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) if (!info)
return -EIO; return -EIO;
...@@ -213,6 +216,35 @@ static int amdgpu_atif_verify_interface(acpi_handle handle, ...@@ -213,6 +216,35 @@ static int amdgpu_atif_verify_interface(acpi_handle handle,
return err; 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 * amdgpu_atif_get_notification_params - determine notify configuration
* *
...@@ -225,15 +257,16 @@ static int amdgpu_atif_verify_interface(acpi_handle handle, ...@@ -225,15 +257,16 @@ static int amdgpu_atif_verify_interface(acpi_handle handle,
* where n is specified in the result if a notifier is used. * where n is specified in the result if a notifier is used.
* Returns 0 on success, error on failure. * Returns 0 on success, error on failure.
*/ */
static int amdgpu_atif_get_notification_params(acpi_handle handle, static int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif)
struct amdgpu_atif_notification_cfg *n)
{ {
union acpi_object *info; union acpi_object *info;
struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg;
struct atif_system_params params; struct atif_system_params params;
size_t size; size_t size;
int err = 0; 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) { if (!info) {
err = -EIO; err = -EIO;
goto out; goto out;
...@@ -287,14 +320,15 @@ static int amdgpu_atif_get_notification_params(acpi_handle handle, ...@@ -287,14 +320,15 @@ static int amdgpu_atif_get_notification_params(acpi_handle handle,
* (all asics). * (all asics).
* Returns 0 on success, error on failure. * Returns 0 on success, error on failure.
*/ */
static int amdgpu_atif_get_sbios_requests(acpi_handle handle, static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif,
struct atif_sbios_requests *req) struct atif_sbios_requests *req)
{ {
union acpi_object *info; union acpi_object *info;
size_t size; size_t size;
int count = 0; 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) if (!info)
return -EIO; return -EIO;
...@@ -331,7 +365,6 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, ...@@ -331,7 +365,6 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev,
{ {
struct amdgpu_atif *atif = adev->atif; struct amdgpu_atif *atif = adev->atif;
struct atif_sbios_requests req; struct atif_sbios_requests req;
acpi_handle handle;
int count; int count;
DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n",
...@@ -347,8 +380,7 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, ...@@ -347,8 +380,7 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev,
return NOTIFY_DONE; return NOTIFY_DONE;
/* Check pending SBIOS requests */ /* Check pending SBIOS requests */
handle = ACPI_HANDLE(&adev->pdev->dev); count = amdgpu_atif_get_sbios_requests(atif, &req);
count = amdgpu_atif_get_sbios_requests(handle, &req);
if (count <= 0) if (count <= 0)
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -679,7 +711,7 @@ static int amdgpu_acpi_event(struct notifier_block *nb, ...@@ -679,7 +711,7 @@ static int amdgpu_acpi_event(struct notifier_block *nb,
*/ */
int amdgpu_acpi_init(struct amdgpu_device *adev) int amdgpu_acpi_init(struct amdgpu_device *adev)
{ {
acpi_handle handle; acpi_handle handle, atif_handle;
struct amdgpu_atif *atif; struct amdgpu_atif *atif;
struct amdgpu_atcs *atcs = &adev->atcs; struct amdgpu_atcs *atcs = &adev->atcs;
int ret; int ret;
...@@ -696,14 +728,20 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) ...@@ -696,14 +728,20 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret);
} }
/* Call the ATIF method */ /* 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); atif = kzalloc(sizeof(*atif), GFP_KERNEL);
if (!atif) { if (!atif) {
DRM_WARN("Not enough memory to initialize ATIF\n"); DRM_WARN("Not enough memory to initialize ATIF\n");
goto out; goto out;
} }
atif->handle = atif_handle;
ret = amdgpu_atif_verify_interface(handle, atif); /* Call the ATIF method */
ret = amdgpu_atif_verify_interface(atif);
if (ret) { if (ret) {
DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret);
kfree(atif); kfree(atif);
...@@ -739,8 +777,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) ...@@ -739,8 +777,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
} }
if (atif->functions.system_params) { if (atif->functions.system_params) {
ret = amdgpu_atif_get_notification_params(handle, ret = amdgpu_atif_get_notification_params(atif);
&atif->notification_cfg);
if (ret) { if (ret) {
DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
ret); ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment