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
					
				| @ -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 @@ out: | ||||
| 	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 New Issue
	
	Block a user