cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

amdgpu_atpx_handler.c (17550B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2010 Red Hat Inc.
      4 * Author : Dave Airlie <airlied@redhat.com>
      5 *
      6 * ATPX support for both Intel/ATI
      7 */
      8#include <linux/vga_switcheroo.h>
      9#include <linux/slab.h>
     10#include <linux/acpi.h>
     11#include <linux/pci.h>
     12#include <linux/delay.h>
     13
     14#include "amdgpu.h"
     15#include "amd_acpi.h"
     16
     17#define AMDGPU_PX_QUIRK_FORCE_ATPX  (1 << 0)
     18
     19struct amdgpu_px_quirk {
     20	u32 chip_vendor;
     21	u32 chip_device;
     22	u32 subsys_vendor;
     23	u32 subsys_device;
     24	u32 px_quirk_flags;
     25};
     26
     27struct amdgpu_atpx_functions {
     28	bool px_params;
     29	bool power_cntl;
     30	bool disp_mux_cntl;
     31	bool i2c_mux_cntl;
     32	bool switch_start;
     33	bool switch_end;
     34	bool disp_connectors_mapping;
     35	bool disp_detection_ports;
     36};
     37
     38struct amdgpu_atpx {
     39	acpi_handle handle;
     40	struct amdgpu_atpx_functions functions;
     41	bool is_hybrid;
     42	bool dgpu_req_power_for_displays;
     43};
     44
     45static struct amdgpu_atpx_priv {
     46	bool atpx_detected;
     47	bool bridge_pm_usable;
     48	unsigned int quirks;
     49	/* handle for device - and atpx */
     50	acpi_handle dhandle;
     51	acpi_handle other_handle;
     52	struct amdgpu_atpx atpx;
     53} amdgpu_atpx_priv;
     54
     55struct atpx_verify_interface {
     56	u16 size;		/* structure size in bytes (includes size field) */
     57	u16 version;		/* version */
     58	u32 function_bits;	/* supported functions bit vector */
     59} __packed;
     60
     61struct atpx_px_params {
     62	u16 size;		/* structure size in bytes (includes size field) */
     63	u32 valid_flags;	/* which flags are valid */
     64	u32 flags;		/* flags */
     65} __packed;
     66
     67struct atpx_power_control {
     68	u16 size;
     69	u8 dgpu_state;
     70} __packed;
     71
     72struct atpx_mux {
     73	u16 size;
     74	u16 mux;
     75} __packed;
     76
     77bool amdgpu_has_atpx(void) {
     78	return amdgpu_atpx_priv.atpx_detected;
     79}
     80
     81bool amdgpu_has_atpx_dgpu_power_cntl(void) {
     82	return amdgpu_atpx_priv.atpx.functions.power_cntl;
     83}
     84
     85bool amdgpu_is_atpx_hybrid(void) {
     86	return amdgpu_atpx_priv.atpx.is_hybrid;
     87}
     88
     89bool amdgpu_atpx_dgpu_req_power_for_displays(void) {
     90	return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays;
     91}
     92
     93#if defined(CONFIG_ACPI)
     94void *amdgpu_atpx_get_dhandle(void) {
     95	return amdgpu_atpx_priv.dhandle;
     96}
     97#endif
     98
     99/**
    100 * amdgpu_atpx_call - call an ATPX method
    101 *
    102 * @handle: acpi handle
    103 * @function: the ATPX function to execute
    104 * @params: ATPX function params
    105 *
    106 * Executes the requested ATPX function (all asics).
    107 * Returns a pointer to the acpi output buffer.
    108 */
    109static union acpi_object *amdgpu_atpx_call(acpi_handle handle, int function,
    110					   struct acpi_buffer *params)
    111{
    112	acpi_status status;
    113	union acpi_object atpx_arg_elements[2];
    114	struct acpi_object_list atpx_arg;
    115	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
    116
    117	atpx_arg.count = 2;
    118	atpx_arg.pointer = &atpx_arg_elements[0];
    119
    120	atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
    121	atpx_arg_elements[0].integer.value = function;
    122
    123	if (params) {
    124		atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
    125		atpx_arg_elements[1].buffer.length = params->length;
    126		atpx_arg_elements[1].buffer.pointer = params->pointer;
    127	} else {
    128		/* We need a second fake parameter */
    129		atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
    130		atpx_arg_elements[1].integer.value = 0;
    131	}
    132
    133	status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
    134
    135	/* Fail only if calling the method fails and ATPX is supported */
    136	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
    137		printk("failed to evaluate ATPX got %s\n",
    138		       acpi_format_exception(status));
    139		kfree(buffer.pointer);
    140		return NULL;
    141	}
    142
    143	return buffer.pointer;
    144}
    145
    146/**
    147 * amdgpu_atpx_parse_functions - parse supported functions
    148 *
    149 * @f: supported functions struct
    150 * @mask: supported functions mask from ATPX
    151 *
    152 * Use the supported functions mask from ATPX function
    153 * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions
    154 * are supported (all asics).
    155 */
    156static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mask)
    157{
    158	f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED;
    159	f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED;
    160	f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED;
    161	f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED;
    162	f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED;
    163	f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED;
    164	f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED;
    165	f->disp_detection_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
    166}
    167
    168/**
    169 * amdgpu_atpx_validate - validate ATPX functions
    170 *
    171 * @atpx: amdgpu atpx struct
    172 *
    173 * Validate that required functions are enabled (all asics).
    174 * returns 0 on success, error on failure.
    175 */
    176static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
    177{
    178	u32 valid_bits = 0;
    179
    180	if (atpx->functions.px_params) {
    181		union acpi_object *info;
    182		struct atpx_px_params output;
    183		size_t size;
    184
    185		info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
    186		if (!info)
    187			return -EIO;
    188
    189		memset(&output, 0, sizeof(output));
    190
    191		size = *(u16 *) info->buffer.pointer;
    192		if (size < 10) {
    193			printk("ATPX buffer is too small: %zu\n", size);
    194			kfree(info);
    195			return -EINVAL;
    196		}
    197		size = min(sizeof(output), size);
    198
    199		memcpy(&output, info->buffer.pointer, size);
    200
    201		valid_bits = output.flags & output.valid_flags;
    202
    203		kfree(info);
    204	}
    205
    206	/* if separate mux flag is set, mux controls are required */
    207	if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
    208		atpx->functions.i2c_mux_cntl = true;
    209		atpx->functions.disp_mux_cntl = true;
    210	}
    211	/* if any outputs are muxed, mux controls are required */
    212	if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
    213			  ATPX_TV_SIGNAL_MUXED |
    214			  ATPX_DFP_SIGNAL_MUXED))
    215		atpx->functions.disp_mux_cntl = true;
    216
    217
    218	/* some bioses set these bits rather than flagging power_cntl as supported */
    219	if (valid_bits & (ATPX_DYNAMIC_PX_SUPPORTED |
    220			  ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED))
    221		atpx->functions.power_cntl = true;
    222
    223	atpx->is_hybrid = false;
    224	if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
    225		if (amdgpu_atpx_priv.quirks & AMDGPU_PX_QUIRK_FORCE_ATPX) {
    226			printk("ATPX Hybrid Graphics, forcing to ATPX\n");
    227			atpx->functions.power_cntl = true;
    228			atpx->is_hybrid = false;
    229		} else {
    230			printk("ATPX Hybrid Graphics\n");
    231			/*
    232			 * Disable legacy PM methods only when pcie port PM is usable,
    233			 * otherwise the device might fail to power off or power on.
    234			 */
    235			atpx->functions.power_cntl = !amdgpu_atpx_priv.bridge_pm_usable;
    236			atpx->is_hybrid = true;
    237		}
    238	}
    239
    240	atpx->dgpu_req_power_for_displays = false;
    241	if (valid_bits & ATPX_DGPU_REQ_POWER_FOR_DISPLAYS)
    242		atpx->dgpu_req_power_for_displays = true;
    243
    244	return 0;
    245}
    246
    247/**
    248 * amdgpu_atpx_verify_interface - verify ATPX
    249 *
    250 * @atpx: amdgpu atpx struct
    251 *
    252 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
    253 * to initialize ATPX and determine what features are supported
    254 * (all asics).
    255 * returns 0 on success, error on failure.
    256 */
    257static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx)
    258{
    259	union acpi_object *info;
    260	struct atpx_verify_interface output;
    261	size_t size;
    262	int err = 0;
    263
    264	info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
    265	if (!info)
    266		return -EIO;
    267
    268	memset(&output, 0, sizeof(output));
    269
    270	size = *(u16 *) info->buffer.pointer;
    271	if (size < 8) {
    272		printk("ATPX buffer is too small: %zu\n", size);
    273		err = -EINVAL;
    274		goto out;
    275	}
    276	size = min(sizeof(output), size);
    277
    278	memcpy(&output, info->buffer.pointer, size);
    279
    280	/* TODO: check version? */
    281	printk("ATPX version %u, functions 0x%08x\n",
    282	       output.version, output.function_bits);
    283
    284	amdgpu_atpx_parse_functions(&atpx->functions, output.function_bits);
    285
    286out:
    287	kfree(info);
    288	return err;
    289}
    290
    291/**
    292 * amdgpu_atpx_set_discrete_state - power up/down discrete GPU
    293 *
    294 * @atpx: atpx info struct
    295 * @state: discrete GPU state (0 = power down, 1 = power up)
    296 *
    297 * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to
    298 * power down/up the discrete GPU (all asics).
    299 * Returns 0 on success, error on failure.
    300 */
    301static int amdgpu_atpx_set_discrete_state(struct amdgpu_atpx *atpx, u8 state)
    302{
    303	struct acpi_buffer params;
    304	union acpi_object *info;
    305	struct atpx_power_control input;
    306
    307	if (atpx->functions.power_cntl) {
    308		input.size = 3;
    309		input.dgpu_state = state;
    310		params.length = input.size;
    311		params.pointer = &input;
    312		info = amdgpu_atpx_call(atpx->handle,
    313					ATPX_FUNCTION_POWER_CONTROL,
    314					&params);
    315		if (!info)
    316			return -EIO;
    317		kfree(info);
    318
    319		/* 200ms delay is required after off */
    320		if (state == 0)
    321			msleep(200);
    322	}
    323	return 0;
    324}
    325
    326/**
    327 * amdgpu_atpx_switch_disp_mux - switch display mux
    328 *
    329 * @atpx: atpx info struct
    330 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
    331 *
    332 * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to
    333 * switch the display mux between the discrete GPU and integrated GPU
    334 * (all asics).
    335 * Returns 0 on success, error on failure.
    336 */
    337static int amdgpu_atpx_switch_disp_mux(struct amdgpu_atpx *atpx, u16 mux_id)
    338{
    339	struct acpi_buffer params;
    340	union acpi_object *info;
    341	struct atpx_mux input;
    342
    343	if (atpx->functions.disp_mux_cntl) {
    344		input.size = 4;
    345		input.mux = mux_id;
    346		params.length = input.size;
    347		params.pointer = &input;
    348		info = amdgpu_atpx_call(atpx->handle,
    349					ATPX_FUNCTION_DISPLAY_MUX_CONTROL,
    350					&params);
    351		if (!info)
    352			return -EIO;
    353		kfree(info);
    354	}
    355	return 0;
    356}
    357
    358/**
    359 * amdgpu_atpx_switch_i2c_mux - switch i2c/hpd mux
    360 *
    361 * @atpx: atpx info struct
    362 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
    363 *
    364 * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to
    365 * switch the i2c/hpd mux between the discrete GPU and integrated GPU
    366 * (all asics).
    367 * Returns 0 on success, error on failure.
    368 */
    369static int amdgpu_atpx_switch_i2c_mux(struct amdgpu_atpx *atpx, u16 mux_id)
    370{
    371	struct acpi_buffer params;
    372	union acpi_object *info;
    373	struct atpx_mux input;
    374
    375	if (atpx->functions.i2c_mux_cntl) {
    376		input.size = 4;
    377		input.mux = mux_id;
    378		params.length = input.size;
    379		params.pointer = &input;
    380		info = amdgpu_atpx_call(atpx->handle,
    381					ATPX_FUNCTION_I2C_MUX_CONTROL,
    382					&params);
    383		if (!info)
    384			return -EIO;
    385		kfree(info);
    386	}
    387	return 0;
    388}
    389
    390/**
    391 * amdgpu_atpx_switch_start - notify the sbios of a GPU switch
    392 *
    393 * @atpx: atpx info struct
    394 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
    395 *
    396 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX
    397 * function to notify the sbios that a switch between the discrete GPU and
    398 * integrated GPU has begun (all asics).
    399 * Returns 0 on success, error on failure.
    400 */
    401static int amdgpu_atpx_switch_start(struct amdgpu_atpx *atpx, u16 mux_id)
    402{
    403	struct acpi_buffer params;
    404	union acpi_object *info;
    405	struct atpx_mux input;
    406
    407	if (atpx->functions.switch_start) {
    408		input.size = 4;
    409		input.mux = mux_id;
    410		params.length = input.size;
    411		params.pointer = &input;
    412		info = amdgpu_atpx_call(atpx->handle,
    413					ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION,
    414					&params);
    415		if (!info)
    416			return -EIO;
    417		kfree(info);
    418	}
    419	return 0;
    420}
    421
    422/**
    423 * amdgpu_atpx_switch_end - notify the sbios of a GPU switch
    424 *
    425 * @atpx: atpx info struct
    426 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
    427 *
    428 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX
    429 * function to notify the sbios that a switch between the discrete GPU and
    430 * integrated GPU has ended (all asics).
    431 * Returns 0 on success, error on failure.
    432 */
    433static int amdgpu_atpx_switch_end(struct amdgpu_atpx *atpx, u16 mux_id)
    434{
    435	struct acpi_buffer params;
    436	union acpi_object *info;
    437	struct atpx_mux input;
    438
    439	if (atpx->functions.switch_end) {
    440		input.size = 4;
    441		input.mux = mux_id;
    442		params.length = input.size;
    443		params.pointer = &input;
    444		info = amdgpu_atpx_call(atpx->handle,
    445					ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION,
    446					&params);
    447		if (!info)
    448			return -EIO;
    449		kfree(info);
    450	}
    451	return 0;
    452}
    453
    454/**
    455 * amdgpu_atpx_switchto - switch to the requested GPU
    456 *
    457 * @id: GPU to switch to
    458 *
    459 * Execute the necessary ATPX functions to switch between the discrete GPU and
    460 * integrated GPU (all asics).
    461 * Returns 0 on success, error on failure.
    462 */
    463static int amdgpu_atpx_switchto(enum vga_switcheroo_client_id id)
    464{
    465	u16 gpu_id;
    466
    467	if (id == VGA_SWITCHEROO_IGD)
    468		gpu_id = ATPX_INTEGRATED_GPU;
    469	else
    470		gpu_id = ATPX_DISCRETE_GPU;
    471
    472	amdgpu_atpx_switch_start(&amdgpu_atpx_priv.atpx, gpu_id);
    473	amdgpu_atpx_switch_disp_mux(&amdgpu_atpx_priv.atpx, gpu_id);
    474	amdgpu_atpx_switch_i2c_mux(&amdgpu_atpx_priv.atpx, gpu_id);
    475	amdgpu_atpx_switch_end(&amdgpu_atpx_priv.atpx, gpu_id);
    476
    477	return 0;
    478}
    479
    480/**
    481 * amdgpu_atpx_power_state - power down/up the requested GPU
    482 *
    483 * @id: GPU to power down/up
    484 * @state: requested power state (0 = off, 1 = on)
    485 *
    486 * Execute the necessary ATPX function to power down/up the discrete GPU
    487 * (all asics).
    488 * Returns 0 on success, error on failure.
    489 */
    490static int amdgpu_atpx_power_state(enum vga_switcheroo_client_id id,
    491				   enum vga_switcheroo_state state)
    492{
    493	/* on w500 ACPI can't change intel gpu state */
    494	if (id == VGA_SWITCHEROO_IGD)
    495		return 0;
    496
    497	amdgpu_atpx_set_discrete_state(&amdgpu_atpx_priv.atpx, state);
    498	return 0;
    499}
    500
    501/**
    502 * amdgpu_atpx_pci_probe_handle - look up the ATPX handle
    503 *
    504 * @pdev: pci device
    505 *
    506 * Look up the ATPX handles (all asics).
    507 * Returns true if the handles are found, false if not.
    508 */
    509static bool amdgpu_atpx_pci_probe_handle(struct pci_dev *pdev)
    510{
    511	acpi_handle dhandle, atpx_handle;
    512	acpi_status status;
    513
    514	dhandle = ACPI_HANDLE(&pdev->dev);
    515	if (!dhandle)
    516		return false;
    517
    518	status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
    519	if (ACPI_FAILURE(status)) {
    520		amdgpu_atpx_priv.other_handle = dhandle;
    521		return false;
    522	}
    523	amdgpu_atpx_priv.dhandle = dhandle;
    524	amdgpu_atpx_priv.atpx.handle = atpx_handle;
    525	return true;
    526}
    527
    528/**
    529 * amdgpu_atpx_init - verify the ATPX interface
    530 *
    531 * Verify the ATPX interface (all asics).
    532 * Returns 0 on success, error on failure.
    533 */
    534static int amdgpu_atpx_init(void)
    535{
    536	int r;
    537
    538	/* set up the ATPX handle */
    539	r = amdgpu_atpx_verify_interface(&amdgpu_atpx_priv.atpx);
    540	if (r)
    541		return r;
    542
    543	/* validate the atpx setup */
    544	r = amdgpu_atpx_validate(&amdgpu_atpx_priv.atpx);
    545	if (r)
    546		return r;
    547
    548	return 0;
    549}
    550
    551/**
    552 * amdgpu_atpx_get_client_id - get the client id
    553 *
    554 * @pdev: pci device
    555 *
    556 * look up whether we are the integrated or discrete GPU (all asics).
    557 * Returns the client id.
    558 */
    559static enum vga_switcheroo_client_id amdgpu_atpx_get_client_id(struct pci_dev *pdev)
    560{
    561	if (amdgpu_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))
    562		return VGA_SWITCHEROO_IGD;
    563	else
    564		return VGA_SWITCHEROO_DIS;
    565}
    566
    567static const struct vga_switcheroo_handler amdgpu_atpx_handler = {
    568	.switchto = amdgpu_atpx_switchto,
    569	.power_state = amdgpu_atpx_power_state,
    570	.get_client_id = amdgpu_atpx_get_client_id,
    571};
    572
    573static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
    574	/* HG _PR3 doesn't seem to work on this A+A weston board */
    575	{ 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
    576	{ 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
    577	{ 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
    578	{ 0x1002, 0x699f, 0x1028, 0x0814, AMDGPU_PX_QUIRK_FORCE_ATPX },
    579	{ 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX },
    580	{ 0x1002, 0x6900, 0x17AA, 0x3806, AMDGPU_PX_QUIRK_FORCE_ATPX },
    581	{ 0, 0, 0, 0, 0 },
    582};
    583
    584static void amdgpu_atpx_get_quirks(struct pci_dev *pdev)
    585{
    586	const struct amdgpu_px_quirk *p = amdgpu_px_quirk_list;
    587
    588	/* Apply PX quirks */
    589	while (p && p->chip_device != 0) {
    590		if (pdev->vendor == p->chip_vendor &&
    591		    pdev->device == p->chip_device &&
    592		    pdev->subsystem_vendor == p->subsys_vendor &&
    593		    pdev->subsystem_device == p->subsys_device) {
    594			amdgpu_atpx_priv.quirks |= p->px_quirk_flags;
    595			break;
    596		}
    597		++p;
    598	}
    599}
    600
    601/**
    602 * amdgpu_atpx_detect - detect whether we have PX
    603 *
    604 * Check if we have a PX system (all asics).
    605 * Returns true if we have a PX system, false if not.
    606 */
    607static bool amdgpu_atpx_detect(void)
    608{
    609	char acpi_method_name[255] = { 0 };
    610	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
    611	struct pci_dev *pdev = NULL;
    612	bool has_atpx = false;
    613	int vga_count = 0;
    614	bool d3_supported = false;
    615	struct pci_dev *parent_pdev;
    616
    617	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
    618		vga_count++;
    619
    620		has_atpx |= amdgpu_atpx_pci_probe_handle(pdev);
    621
    622		parent_pdev = pci_upstream_bridge(pdev);
    623		d3_supported |= parent_pdev && parent_pdev->bridge_d3;
    624		amdgpu_atpx_get_quirks(pdev);
    625	}
    626
    627	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
    628		vga_count++;
    629
    630		has_atpx |= amdgpu_atpx_pci_probe_handle(pdev);
    631
    632		parent_pdev = pci_upstream_bridge(pdev);
    633		d3_supported |= parent_pdev && parent_pdev->bridge_d3;
    634		amdgpu_atpx_get_quirks(pdev);
    635	}
    636
    637	if (has_atpx && vga_count == 2) {
    638		acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
    639		pr_info("vga_switcheroo: detected switching method %s handle\n",
    640			acpi_method_name);
    641		amdgpu_atpx_priv.atpx_detected = true;
    642		amdgpu_atpx_priv.bridge_pm_usable = d3_supported;
    643		amdgpu_atpx_init();
    644		return true;
    645	}
    646	return false;
    647}
    648
    649/**
    650 * amdgpu_register_atpx_handler - register with vga_switcheroo
    651 *
    652 * Register the PX callbacks with vga_switcheroo (all asics).
    653 */
    654void amdgpu_register_atpx_handler(void)
    655{
    656	bool r;
    657	enum vga_switcheroo_handler_flags_t handler_flags = 0;
    658
    659	/* detect if we have any ATPX + 2 VGA in the system */
    660	r = amdgpu_atpx_detect();
    661	if (!r)
    662		return;
    663
    664	vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags);
    665}
    666
    667/**
    668 * amdgpu_unregister_atpx_handler - unregister with vga_switcheroo
    669 *
    670 * Unregister the PX callbacks with vga_switcheroo (all asics).
    671 */
    672void amdgpu_unregister_atpx_handler(void)
    673{
    674	vga_switcheroo_unregister_handler();
    675}