Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c61e2775 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/radeon: split ATRM support out from the ATPX handler (v3)

There are systems that use ATRM, but not ATPX.

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=41265



V2: fix #ifdefs as per Greg's comments
V3: fix it harder

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent 7c3906d0
Loading
Loading
Loading
Loading
+0 −15
Original line number Diff line number Diff line
@@ -142,21 +142,6 @@ struct radeon_device;
/*
 * BIOS.
 */
#define ATRM_BIOS_PAGE 4096

#if defined(CONFIG_VGA_SWITCHEROO)
bool radeon_atrm_supported(struct pci_dev *pdev);
int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
#else
static inline bool radeon_atrm_supported(struct pci_dev *pdev)
{
	return false;
}

static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){
	return -EINVAL;
}
#endif
bool radeon_get_bios(struct radeon_device *rdev);

/*
+1 −55
Original line number Diff line number Diff line
@@ -30,57 +30,8 @@ static struct radeon_atpx_priv {
	/* handle for device - and atpx */
	acpi_handle dhandle;
	acpi_handle atpx_handle;
	acpi_handle atrm_handle;
} radeon_atpx_priv;

/* retrieve the ROM in 4k blocks */
static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
			    int offset, int len)
{
	acpi_status status;
	union acpi_object atrm_arg_elements[2], *obj;
	struct acpi_object_list atrm_arg;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};

	atrm_arg.count = 2;
	atrm_arg.pointer = &atrm_arg_elements[0];

	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
	atrm_arg_elements[0].integer.value = offset;

	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
	atrm_arg_elements[1].integer.value = len;

	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
	if (ACPI_FAILURE(status)) {
		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
		return -ENODEV;
	}

	obj = (union acpi_object *)buffer.pointer;
	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
	len = obj->buffer.length;
	kfree(buffer.pointer);
	return len;
}

bool radeon_atrm_supported(struct pci_dev *pdev)
{
	/* get the discrete ROM only via ATRM */
	if (!radeon_atpx_priv.atpx_detected)
		return false;

	if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
		return false;
	return true;
}


int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
{
	return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
}

static int radeon_atpx_get_version(acpi_handle handle)
{
	acpi_status status;
@@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,

static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
{
	acpi_handle dhandle, atpx_handle, atrm_handle;
	acpi_handle dhandle, atpx_handle;
	acpi_status status;

	dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
	if (ACPI_FAILURE(status))
		return false;

	status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
	if (ACPI_FAILURE(status))
		return false;

	radeon_atpx_priv.dhandle = dhandle;
	radeon_atpx_priv.atpx_handle = atpx_handle;
	radeon_atpx_priv.atrm_handle = atrm_handle;
	return true;
}

+76 −4
Original line number Diff line number Diff line
@@ -99,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev)
	return true;
}

#ifdef CONFIG_ACPI
/* ATRM is used to get the BIOS on the discrete cards in
 * dual-gpu systems.
 */
/* retrieve the ROM in 4k blocks */
#define ATRM_BIOS_PAGE 4096
/**
 * radeon_atrm_call - fetch a chunk of the vbios
 *
 * @atrm_handle: acpi ATRM handle
 * @bios: vbios image pointer
 * @offset: offset of vbios image data to fetch
 * @len: length of vbios image data to fetch
 *
 * Executes ATRM to fetch a chunk of the discrete
 * vbios image on PX systems (all asics).
 * Returns the length of the buffer fetched.
 */
static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
			    int offset, int len)
{
	acpi_status status;
	union acpi_object atrm_arg_elements[2], *obj;
	struct acpi_object_list atrm_arg;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};

	atrm_arg.count = 2;
	atrm_arg.pointer = &atrm_arg_elements[0];

	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
	atrm_arg_elements[0].integer.value = offset;

	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
	atrm_arg_elements[1].integer.value = len;

	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
	if (ACPI_FAILURE(status)) {
		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
		return -ENODEV;
	}

	obj = (union acpi_object *)buffer.pointer;
	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
	len = obj->buffer.length;
	kfree(buffer.pointer);
	return len;
}

static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
	int ret;
	int size = 256 * 1024;
	int i;
	struct pci_dev *pdev = NULL;
	acpi_handle dhandle, atrm_handle;
	acpi_status status;
	bool found = false;

	if (!radeon_atrm_supported(rdev->pdev))
	/* ATRM is for the discrete card only */
	if (rdev->flags & RADEON_IS_IGP)
		return false;

	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
		dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
		if (!dhandle)
			continue;

		status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
		if (!ACPI_FAILURE(status)) {
			found = true;
			break;
		}
	}

	if (!found)
		return false;

	rdev->bios = kmalloc(size, GFP_KERNEL);
@@ -118,7 +183,8 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
	}

	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
		ret = radeon_atrm_get_bios_chunk(rdev->bios,
		ret = radeon_atrm_call(atrm_handle,
				       rdev->bios,
				       (i * ATRM_BIOS_PAGE),
				       ATRM_BIOS_PAGE);
		if (ret < ATRM_BIOS_PAGE)
@@ -131,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
	}
	return true;
}
#else
static inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
	return false;
}
#endif

static bool ni_read_disabled_bios(struct radeon_device *rdev)
{