drm/radeon: implement apci perf request
These functions use acpi methods to adjust the pcie gen speed. Used by DPM. Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
9d45ad5aff
commit
e37e6a0e4f
2 changed files with 143 additions and 21 deletions
|
@ -2458,7 +2458,7 @@ extern int radeon_acpi_init(struct radeon_device *rdev);
|
|||
extern void radeon_acpi_fini(struct radeon_device *rdev);
|
||||
extern bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev);
|
||||
extern int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
|
||||
u8 ref_req, bool advertise);
|
||||
u8 perf_req, bool advertise);
|
||||
extern int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev);
|
||||
#else
|
||||
static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; }
|
||||
|
|
|
@ -78,28 +78,21 @@ struct atcs_verify_interface {
|
|||
u32 function_bits; /* supported functions bit vector */
|
||||
} __packed;
|
||||
|
||||
bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev)
|
||||
{
|
||||
/* XXX: query ATIF */
|
||||
#define ATCS_VALID_FLAGS_MASK 0x3
|
||||
|
||||
return false;
|
||||
}
|
||||
struct atcs_pref_req_input {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
|
||||
u16 valid_flags_mask; /* valid flags mask */
|
||||
u16 flags; /* flags */
|
||||
u8 req_type; /* request type */
|
||||
u8 perf_req; /* performance request */
|
||||
} __packed;
|
||||
|
||||
int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev)
|
||||
{
|
||||
/* XXX: call appropriate ATIF method */
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
|
||||
u8 ref_req, bool advertise)
|
||||
{
|
||||
/* XXX: call appropriate ATIF method */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
struct atcs_pref_req_output {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u8 ret_val; /* return value */
|
||||
} __packed;
|
||||
|
||||
/* Call the ATIF method
|
||||
*/
|
||||
|
@ -528,6 +521,135 @@ static int radeon_atcs_verify_interface(acpi_handle handle,
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_acpi_is_pcie_performance_request_supported
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
*
|
||||
* Check if the ATCS pcie_perf_req and pcie_dev_rdy methods
|
||||
* are supported (all asics).
|
||||
* returns true if supported, false if not.
|
||||
*/
|
||||
bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev)
|
||||
{
|
||||
struct radeon_atcs *atcs = &rdev->atcs;
|
||||
|
||||
if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_acpi_pcie_notify_device_ready
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
*
|
||||
* Executes the PCIE_DEVICE_READY_NOTIFICATION method
|
||||
* (all asics).
|
||||
* returns 0 on success, error on failure.
|
||||
*/
|
||||
int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *info;
|
||||
struct radeon_atcs *atcs = &rdev->atcs;
|
||||
|
||||
/* Get the device handle */
|
||||
handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
if (!atcs->functions.pcie_dev_rdy)
|
||||
return -EINVAL;
|
||||
|
||||
info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL);
|
||||
if (!info)
|
||||
return -EIO;
|
||||
|
||||
kfree(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_acpi_pcie_performance_request
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @perf_req: requested perf level (pcie gen speed)
|
||||
* @advertise: set advertise caps flag if set
|
||||
*
|
||||
* Executes the PCIE_PERFORMANCE_REQUEST method to
|
||||
* change the pcie gen speed (all asics).
|
||||
* returns 0 on success, error on failure.
|
||||
*/
|
||||
int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
|
||||
u8 perf_req, bool advertise)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *info;
|
||||
struct radeon_atcs *atcs = &rdev->atcs;
|
||||
struct atcs_pref_req_input atcs_input;
|
||||
struct atcs_pref_req_output atcs_output;
|
||||
struct acpi_buffer params;
|
||||
size_t size;
|
||||
u32 retry = 3;
|
||||
|
||||
/* Get the device handle */
|
||||
handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
if (!atcs->functions.pcie_perf_req)
|
||||
return -EINVAL;
|
||||
|
||||
atcs_input.size = sizeof(struct atcs_pref_req_input);
|
||||
/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
|
||||
atcs_input.client_id = rdev->pdev->devfn | (rdev->pdev->bus->number << 8);
|
||||
atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
|
||||
atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
|
||||
if (advertise)
|
||||
atcs_input.flags |= ATCS_ADVERTISE_CAPS;
|
||||
atcs_input.req_type = ATCS_PCIE_LINK_SPEED;
|
||||
atcs_input.perf_req = perf_req;
|
||||
|
||||
params.length = sizeof(struct atcs_pref_req_input);
|
||||
params.pointer = &atcs_input;
|
||||
|
||||
while (retry--) {
|
||||
info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms);
|
||||
if (!info)
|
||||
return -EIO;
|
||||
|
||||
memset(&atcs_output, 0, sizeof(atcs_output));
|
||||
|
||||
size = *(u16 *) info->buffer.pointer;
|
||||
if (size < 3) {
|
||||
DRM_INFO("ATCS buffer is too small: %zu\n", size);
|
||||
kfree(info);
|
||||
return -EINVAL;
|
||||
}
|
||||
size = min(sizeof(atcs_output), size);
|
||||
|
||||
memcpy(&atcs_output, info->buffer.pointer, size);
|
||||
|
||||
kfree(info);
|
||||
|
||||
switch (atcs_output.ret_val) {
|
||||
case ATCS_REQUEST_REFUSED:
|
||||
default:
|
||||
return -EINVAL;
|
||||
case ATCS_REQUEST_COMPLETE:
|
||||
return 0;
|
||||
case ATCS_REQUEST_IN_PROGRESS:
|
||||
udelay(10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_acpi_event - handle notify events
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue