/* * 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 <linux/nospec.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_ras_mgr.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>#include <asm/cpu_device_id.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");MODULE_FIRMWARE("amdgpu/cyan_skillfish_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) #define AMDGPU_VBIOS_SKIP (1U << 0)#define AMDGPU_VBIOS_OPTIONAL (1U << 1) 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 int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev);static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev);static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev); static void amdgpu_device_load_switch_state(struct amdgpu_device *adev); 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);static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, void *data); /** * 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 int amdgpu_device_attr_sysfs_init(struct amdgpu_device *adev){ int ret = 0; if (amdgpu_nbio_is_replay_cnt_supported(adev)) ret = sysfs_create_file(&adev->dev->kobj, &dev_attr_pcie_replay_count.attr); return ret;} static void amdgpu_device_attr_sysfs_fini(struct amdgpu_device *adev){ if (amdgpu_nbio_is_replay_cnt_supported(adev)) sysfs_remove_file(&adev->dev->kobj, &dev_attr_pcie_replay_count.attr);} static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj, const 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;} static const 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);} /** * 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}; /** * DOC: uma/carveout_options * * This is a read-only file that lists all available UMA allocation * options and their corresponding indices. Example output:: * * $ cat uma/carveout_options * 0: Minimum (512 MB) * 1: (1 GB) * 2: (2 GB) * 3: (4 GB) * 4: (6 GB) * 5: (8 GB) * 6: (12 GB) * 7: Medium (16 GB) * 8: (24 GB) * 9: High (32 GB) */static ssize_t carveout_options_show(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); struct amdgpu_uma_carveout_info *uma_info = &adev->uma_info; uint32_t memory_carved; ssize_t size = 0; if (!uma_info || !uma_info->num_entries) return -ENODEV; for (int i = 0; i < uma_info->num_entries; i++) { memory_carved = uma_info->entries[i].memory_carved_mb; if (memory_carved >= SZ_1G/SZ_1M) { size += sysfs_emit_at(buf, size, "%d: %s (%u GB)\n", i, uma_info->entries[i].name, memory_carved >> 10); } else { size += sysfs_emit_at(buf, size, "%d: %s (%u MB)\n", i, uma_info->entries[i].name, memory_carved); } } return size;}static DEVICE_ATTR_RO(carveout_options); /** * DOC: uma/carveout * * This file is both readable and writable. When read, it shows the * index of the current setting. Writing a valid index to this file * allows users to change the UMA carveout size to the selected option * on the next boot. * * The available options and their corresponding indices can be read * from the uma/carveout_options file. */static ssize_t carveout_show(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); return sysfs_emit(buf, "%u\n", adev->uma_info.uma_option_index);} static ssize_t carveout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); struct amdgpu_uma_carveout_info *uma_info = &adev->uma_info; struct amdgpu_uma_carveout_option *opt; unsigned long val; uint8_t flags; int r; r = kstrtoul(buf, 10, &val); if (r) return r; if (val >= uma_info->num_entries) return -EINVAL; val = array_index_nospec(val, uma_info->num_entries); opt = &uma_info->entries[val]; if (!(opt->flags & AMDGPU_UMA_FLAG_AUTO) && !(opt->flags & AMDGPU_UMA_FLAG_CUSTOM)) { drm_err_once(ddev, "Option %lu not supported due to lack of Custom/Auto flag", val); return -EINVAL; } flags = opt->flags; flags &= ~((flags & AMDGPU_UMA_FLAG_AUTO) >> 1); guard(mutex)(&uma_info->update_lock); r = amdgpu_acpi_set_uma_allocation_size(adev, val, flags); if (r) return r; uma_info->uma_option_index = val; return count;}static DEVICE_ATTR_RW(carveout); static struct attribute *amdgpu_uma_attrs[] = { &dev_attr_carveout.attr,Lines 1–500 of 7737. Load more
/* * 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 <linux/nospec.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_ras_mgr.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> #include <asm/cpu_device_id.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"); MODULE_FIRMWARE("amdgpu/cyan_skillfish_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) #define AMDGPU_VBIOS_SKIP (1U << 0) #define AMDGPU_VBIOS_OPTIONAL (1U << 1) 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 int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev); static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev); static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev); static void amdgpu_device_load_switch_state(struct amdgpu_device *adev); 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); static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, void *data); /** * 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 int amdgpu_device_attr_sysfs_init(struct amdgpu_device *adev) { int ret = 0; if (amdgpu_nbio_is_replay_cnt_supported(adev)) ret = sysfs_create_file(&adev->dev->kobj, &dev_attr_pcie_replay_count.attr); return ret; } static void amdgpu_device_attr_sysfs_fini(struct amdgpu_device *adev) { if (amdgpu_nbio_is_replay_cnt_supported(adev)) sysfs_remove_file(&adev->dev->kobj, &dev_attr_pcie_replay_count.attr); } static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj, const 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; } static const 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); } /** * 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 }; /** * DOC: uma/carveout_options * * This is a read-only file that lists all available UMA allocation * options and their corresponding indices. Example output:: * * $ cat uma/carveout_options * 0: Minimum (512 MB) * 1: (1 GB) * 2: (2 GB) * 3: (4 GB) * 4: (6 GB) * 5: (8 GB) * 6: (12 GB) * 7: Medium (16 GB) * 8: (24 GB) * 9: High (32 GB) */ static ssize_t carveout_options_show(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); struct amdgpu_uma_carveout_info *uma_info = &adev->uma_info; uint32_t memory_carved; ssize_t size = 0; if (!uma_info || !uma_info->num_entries) return -ENODEV; for (int i = 0; i < uma_info->num_entries; i++) { memory_carved = uma_info->entries[i].memory_carved_mb; if (memory_carved >= SZ_1G/SZ_1M) { size += sysfs_emit_at(buf, size, "%d: %s (%u GB)\n", i, uma_info->entries[i].name, memory_carved >> 10); } else { size += sysfs_emit_at(buf, size, "%d: %s (%u MB)\n", i, uma_info->entries[i].name, memory_carved); } } return size; } static DEVICE_ATTR_RO(carveout_options); /** * DOC: uma/carveout * * This file is both readable and writable. When read, it shows the * index of the current setting. Writing a valid index to this file * allows users to change the UMA carveout size to the selected option * on the next boot. * * The available options and their corresponding indices can be read * from the uma/carveout_options file. */ static ssize_t carveout_show(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); return sysfs_emit(buf, "%u\n", adev->uma_info.uma_option_index); } static ssize_t carveout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); struct amdgpu_uma_carveout_info *uma_info = &adev->uma_info; struct amdgpu_uma_carveout_option *opt; unsigned long val; uint8_t flags; int r; r = kstrtoul(buf, 10, &val); if (r) return r; if (val >= uma_info->num_entries) return -EINVAL; val = array_index_nospec(val, uma_info->num_entries); opt = &uma_info->entries[val]; if (!(opt->flags & AMDGPU_UMA_FLAG_AUTO) && !(opt->flags & AMDGPU_UMA_FLAG_CUSTOM)) { drm_err_once(ddev, "Option %lu not supported due to lack of Custom/Auto flag", val); return -EINVAL; } flags = opt->flags; flags &= ~((flags & AMDGPU_UMA_FLAG_AUTO) >> 1); guard(mutex)(&uma_info->update_lock); r = amdgpu_acpi_set_uma_allocation_size(adev, val, flags); if (r) return r; uma_info->uma_option_index = val; return count; } static DEVICE_ATTR_RW(carveout); static struct attribute *amdgpu_uma_attrs[] = { &dev_attr_carveout.attr,