6830 lines · 183.8 KB · C
RawDownload
/* * Copyright 2008 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * Copyright 2009 Jerome Glisse. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie *          Alex Deucher *          Jerome Glisse */ #include <linux/aperture.h>#include <linux/power_supply.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/console.h>#include <linux/slab.h>#include <linux/iommu.h>#include <linux/pci.h>#include <linux/pci-p2pdma.h>#include <linux/apple-gmux.h> #include <drm/drm_atomic_helper.h>#include <drm/drm_client_event.h>#include <drm/drm_crtc_helper.h>#include <drm/drm_probe_helper.h>#include <drm/amdgpu_drm.h>#include <linux/device.h>#include <linux/vgaarb.h>#include <linux/vga_switcheroo.h>#include <linux/efi.h>#include "amdgpu.h"#include "amdgpu_trace.h"#include "amdgpu_i2c.h"#include "atom.h"#include "amdgpu_atombios.h"#include "amdgpu_atomfirmware.h"#include "amd_pcie.h"#ifdef CONFIG_DRM_AMDGPU_SI#include "si.h"#endif#ifdef CONFIG_DRM_AMDGPU_CIK#include "cik.h"#endif#include "vi.h"#include "soc15.h"#include "nv.h"#include "bif/bif_4_1_d.h"#include <linux/firmware.h>#include "amdgpu_vf_error.h" #include "amdgpu_amdkfd.h"#include "amdgpu_pm.h" #include "amdgpu_xgmi.h"#include "amdgpu_ras.h"#include "amdgpu_pmu.h"#include "amdgpu_fru_eeprom.h"#include "amdgpu_reset.h"#include "amdgpu_virt.h"#include "amdgpu_dev_coredump.h" #include <linux/suspend.h>#include <drm/task_barrier.h>#include <linux/pm_runtime.h> #include <drm/drm_drv.h> #if IS_ENABLED(CONFIG_X86)#include <asm/intel-family.h>#endif MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin");MODULE_FIRMWARE("amdgpu/raven2_gpu_info.bin");MODULE_FIRMWARE("amdgpu/arcturus_gpu_info.bin");MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_RESUME_MS		2000#define AMDGPU_MAX_RETRY_LIMIT		2#define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL)#define AMDGPU_PCIE_INDEX_FALLBACK (0x38 >> 2)#define AMDGPU_PCIE_INDEX_HI_FALLBACK (0x44 >> 2)#define AMDGPU_PCIE_DATA_FALLBACK (0x3C >> 2) static const struct drm_driver amdgpu_kms_driver; const char *amdgpu_asic_name[] = {	"TAHITI",	"PITCAIRN",	"VERDE",	"OLAND",	"HAINAN",	"BONAIRE",	"KAVERI",	"KABINI",	"HAWAII",	"MULLINS",	"TOPAZ",	"TONGA",	"FIJI",	"CARRIZO",	"STONEY",	"POLARIS10",	"POLARIS11",	"POLARIS12",	"VEGAM",	"VEGA10",	"VEGA12",	"VEGA20",	"RAVEN",	"ARCTURUS",	"RENOIR",	"ALDEBARAN",	"NAVI10",	"CYAN_SKILLFISH",	"NAVI14",	"NAVI12",	"SIENNA_CICHLID",	"NAVY_FLOUNDER",	"VANGOGH",	"DIMGREY_CAVEFISH",	"BEIGE_GOBY",	"YELLOW_CARP",	"IP DISCOVERY",	"LAST",}; #define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMD_IP_BLOCK_TYPE_NUM  - 1, 0)/* * Default init level where all blocks are expected to be initialized. This is * the level of initialization expected by default and also after a full reset * of the device. */struct amdgpu_init_level amdgpu_init_default = {	.level = AMDGPU_INIT_LEVEL_DEFAULT,	.hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL,}; struct amdgpu_init_level amdgpu_init_recovery = {	.level = AMDGPU_INIT_LEVEL_RESET_RECOVERY,	.hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL,}; /* * Minimal blocks needed to be initialized before a XGMI hive can be reset. This * is used for cases like reset on initialization where the entire hive needs to * be reset before first use. */struct amdgpu_init_level amdgpu_init_minimal_xgmi = {	.level = AMDGPU_INIT_LEVEL_MINIMAL_XGMI,	.hwini_ip_block_mask =		BIT(AMD_IP_BLOCK_TYPE_GMC) | BIT(AMD_IP_BLOCK_TYPE_SMC) |		BIT(AMD_IP_BLOCK_TYPE_COMMON) | BIT(AMD_IP_BLOCK_TYPE_IH) |		BIT(AMD_IP_BLOCK_TYPE_PSP)}; static inline bool amdgpu_ip_member_of_hwini(struct amdgpu_device *adev,					     enum amd_ip_block_type block){	return (adev->init_lvl->hwini_ip_block_mask & (1U << block)) != 0;} void amdgpu_set_init_level(struct amdgpu_device *adev,			   enum amdgpu_init_lvl_id lvl){	switch (lvl) {	case AMDGPU_INIT_LEVEL_MINIMAL_XGMI:		adev->init_lvl = &amdgpu_init_minimal_xgmi;		break;	case AMDGPU_INIT_LEVEL_RESET_RECOVERY:		adev->init_lvl = &amdgpu_init_recovery;		break;	case AMDGPU_INIT_LEVEL_DEFAULT:		fallthrough;	default:		adev->init_lvl = &amdgpu_init_default;		break;	}} static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev); /** * DOC: pcie_replay_count * * The amdgpu driver provides a sysfs API for reporting the total number * of PCIe replays (NAKs) * The file pcie_replay_count is used for this and returns the total * number of replays as a sum of the NAKs generated and NAKs received */ static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev,		struct device_attribute *attr, char *buf){	struct drm_device *ddev = dev_get_drvdata(dev);	struct amdgpu_device *adev = drm_to_adev(ddev);	uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev); 	return sysfs_emit(buf, "%llu\n", cnt);} static DEVICE_ATTR(pcie_replay_count, 0444,		amdgpu_device_get_pcie_replay_count, NULL); static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj,					  struct bin_attribute *attr, char *buf,					  loff_t ppos, size_t count){	struct device *dev = kobj_to_dev(kobj);	struct drm_device *ddev = dev_get_drvdata(dev);	struct amdgpu_device *adev = drm_to_adev(ddev);	ssize_t bytes_read; 	switch (ppos) {	case AMDGPU_SYS_REG_STATE_XGMI:		bytes_read = amdgpu_asic_get_reg_state(			adev, AMDGPU_REG_STATE_TYPE_XGMI, buf, count);		break;	case AMDGPU_SYS_REG_STATE_WAFL:		bytes_read = amdgpu_asic_get_reg_state(			adev, AMDGPU_REG_STATE_TYPE_WAFL, buf, count);		break;	case AMDGPU_SYS_REG_STATE_PCIE:		bytes_read = amdgpu_asic_get_reg_state(			adev, AMDGPU_REG_STATE_TYPE_PCIE, buf, count);		break;	case AMDGPU_SYS_REG_STATE_USR:		bytes_read = amdgpu_asic_get_reg_state(			adev, AMDGPU_REG_STATE_TYPE_USR, buf, count);		break;	case AMDGPU_SYS_REG_STATE_USR_1:		bytes_read = amdgpu_asic_get_reg_state(			adev, AMDGPU_REG_STATE_TYPE_USR_1, buf, count);		break;	default:		return -EINVAL;	} 	return bytes_read;} BIN_ATTR(reg_state, 0444, amdgpu_sysfs_reg_state_get, NULL,	 AMDGPU_SYS_REG_STATE_END); int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev){	int ret; 	if (!amdgpu_asic_get_reg_state_supported(adev))		return 0; 	ret = sysfs_create_bin_file(&adev->dev->kobj, &bin_attr_reg_state); 	return ret;} void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev){	if (!amdgpu_asic_get_reg_state_supported(adev))		return;	sysfs_remove_bin_file(&adev->dev->kobj, &bin_attr_reg_state);} int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block){	int r; 	if (ip_block->version->funcs->suspend) {		r = ip_block->version->funcs->suspend(ip_block);		if (r) {			dev_err(ip_block->adev->dev,				"suspend of IP block <%s> failed %d\n",				ip_block->version->funcs->name, r);			return r;		}	} 	ip_block->status.hw = false;	return 0;} int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block){	int r; 	if (ip_block->version->funcs->resume) {		r = ip_block->version->funcs->resume(ip_block);		if (r) {			dev_err(ip_block->adev->dev,				"resume of IP block <%s> failed %d\n",				ip_block->version->funcs->name, r);			return r;		}	} 	ip_block->status.hw = true;	return 0;} /** * DOC: board_info * * The amdgpu driver provides a sysfs API for giving board related information. * It provides the form factor information in the format * *   type : form factor * * Possible form factor values * * - "cem"		- PCIE CEM card * - "oam"		- Open Compute Accelerator Module * - "unknown"	- Not known * */ static ssize_t amdgpu_device_get_board_info(struct device *dev,					    struct device_attribute *attr,					    char *buf){	struct drm_device *ddev = dev_get_drvdata(dev);	struct amdgpu_device *adev = drm_to_adev(ddev);	enum amdgpu_pkg_type pkg_type = AMDGPU_PKG_TYPE_CEM;	const char *pkg; 	if (adev->smuio.funcs && adev->smuio.funcs->get_pkg_type)		pkg_type = adev->smuio.funcs->get_pkg_type(adev); 	switch (pkg_type) {	case AMDGPU_PKG_TYPE_CEM:		pkg = "cem";		break;	case AMDGPU_PKG_TYPE_OAM:		pkg = "oam";		break;	default:		pkg = "unknown";		break;	} 	return sysfs_emit(buf, "%s : %s\n", "type", pkg);} static DEVICE_ATTR(board_info, 0444, amdgpu_device_get_board_info, NULL); static struct attribute *amdgpu_board_attrs[] = {	&dev_attr_board_info.attr,	NULL,}; static umode_t amdgpu_board_attrs_is_visible(struct kobject *kobj,					     struct attribute *attr, int n){	struct device *dev = kobj_to_dev(kobj);	struct drm_device *ddev = dev_get_drvdata(dev);	struct amdgpu_device *adev = drm_to_adev(ddev); 	if (adev->flags & AMD_IS_APU)		return 0; 	return attr->mode;} static const struct attribute_group amdgpu_board_attrs_group = {	.attrs = amdgpu_board_attrs,	.is_visible = amdgpu_board_attrs_is_visible}; static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev);  /** * amdgpu_device_supports_px - Is the device a dGPU with ATPX power control * * @dev: drm_device pointer * * Returns true if the device is a dGPU with ATPX power control, * otherwise return false. */bool amdgpu_device_supports_px(struct drm_device *dev){	struct amdgpu_device *adev = drm_to_adev(dev); 	if ((adev->flags & AMD_IS_PX) && !amdgpu_is_atpx_hybrid())		return true;	return false;} /** * amdgpu_device_supports_boco - Is the device a dGPU with ACPI power resources * * @dev: drm_device pointer * * Returns true if the device is a dGPU with ACPI power control, * otherwise return false. */bool amdgpu_device_supports_boco(struct drm_device *dev){	struct amdgpu_device *adev = drm_to_adev(dev); 	if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))		return false; 	if (adev->has_pr3 ||	    ((adev->flags & AMD_IS_PX) && amdgpu_is_atpx_hybrid()))		return true;	return false;} /** * amdgpu_device_supports_baco - Does the device support BACO * * @dev: drm_device pointer * * Return: * 1 if the device supporte BACO; * 3 if the device support MACO (only works if BACO is supported) * otherwise return 0. */int amdgpu_device_supports_baco(struct drm_device *dev){	struct amdgpu_device *adev = drm_to_adev(dev); 	return amdgpu_asic_supports_baco(adev);} void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev){	struct drm_device *dev;	int bamaco_support; 	dev = adev_to_drm(adev); 	adev->pm.rpm_mode = AMDGPU_RUNPM_NONE;	bamaco_support = amdgpu_device_supports_baco(dev); 	switch (amdgpu_runtime_pm) {	case 2:		if (bamaco_support & MACO_SUPPORT) {			adev->pm.rpm_mode = AMDGPU_RUNPM_BAMACO;			dev_info(adev->dev, "Forcing BAMACO for runtime pm\n");		} else if (bamaco_support == BACO_SUPPORT) {			adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;			dev_info(adev->dev, "Requested mode BAMACO not available,fallback to use BACO\n");		}		break;	case 1:		if (bamaco_support & BACO_SUPPORT) {			adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;			dev_info(adev->dev, "Forcing BACO for runtime pm\n");		}		break;	case -1:	case -2:		if (amdgpu_device_supports_px(dev)) { /* enable PX as runtime mode */			adev->pm.rpm_mode = AMDGPU_RUNPM_PX;			dev_info(adev->dev, "Using ATPX for runtime pm\n");		} else if (amdgpu_device_supports_boco(dev)) { /* enable boco as runtime mode */			adev->pm.rpm_mode = AMDGPU_RUNPM_BOCO;			dev_info(adev->dev, "Using BOCO for runtime pm\n");		} else {			if (!bamaco_support)				goto no_runtime_pm; 			switch (adev->asic_type) {			case CHIP_VEGA20:			case CHIP_ARCTURUS:				/* BACO are not supported on vega20 and arctrus */				break;			case CHIP_VEGA10:				/* enable BACO as runpm mode if noretry=0 */				if (!adev->gmc.noretry)					adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;				break;			default:				/* enable BACO as runpm mode on CI+ */				adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;				break;			} 			if (adev->pm.rpm_mode == AMDGPU_RUNPM_BACO) {

Lines 1–500 of 6830.