/* * 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/power_supply.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/console.h>#include <linux/slab.h> #include <drm/drm_atomic_helper.h>#include <drm/drm_probe_helper.h>#include <drm/amdgpu_drm.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/pci.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 <linux/suspend.h>#include <drm/task_barrier.h>#include <linux/pm_runtime.h> 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/renoir_gpu_info.bin");MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin");MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_RESUME_MS 2000 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", "NAVI10", "NAVI14", "NAVI12", "LAST",}; /** * 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 = ddev->dev_private; uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev); return snprintf(buf, PAGE_SIZE, "%llu\n", cnt);} static DEVICE_ATTR(pcie_replay_count, S_IRUGO, amdgpu_device_get_pcie_replay_count, NULL); static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); /** * DOC: product_name * * The amdgpu driver provides a sysfs API for reporting the product name * for the device * The file serial_number is used for this and returns the product name * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_product_name(struct device *dev, struct device_attribute *attr, char *buf){ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_name);} static DEVICE_ATTR(product_name, S_IRUGO, amdgpu_device_get_product_name, NULL); /** * DOC: product_number * * The amdgpu driver provides a sysfs API for reporting the part number * for the device * The file serial_number is used for this and returns the part number * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_product_number(struct device *dev, struct device_attribute *attr, char *buf){ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_number);} static DEVICE_ATTR(product_number, S_IRUGO, amdgpu_device_get_product_number, NULL); /** * DOC: serial_number * * The amdgpu driver provides a sysfs API for reporting the serial number * for the device * The file serial_number is used for this and returns the serial number * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_serial_number(struct device *dev, struct device_attribute *attr, char *buf){ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->serial);} static DEVICE_ATTR(serial_number, S_IRUGO, amdgpu_device_get_serial_number, NULL); /** * amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control * * @dev: drm_device pointer * * Returns true if the device is a dGPU with HG/PX power control, * otherwise return false. */bool amdgpu_device_supports_boco(struct drm_device *dev){ struct amdgpu_device *adev = dev->dev_private; if (adev->flags & AMD_IS_PX) return true; return false;} /** * amdgpu_device_supports_baco - Does the device support BACO * * @dev: drm_device pointer * * Returns true if the device supporte BACO, * otherwise return false. */bool amdgpu_device_supports_baco(struct drm_device *dev){ struct amdgpu_device *adev = dev->dev_private; return amdgpu_asic_supports_baco(adev);} /** * VRAM access helper functions. * * amdgpu_device_vram_access - read/write a buffer in vram * * @adev: amdgpu_device pointer * @pos: offset of the buffer in vram * @buf: virtual address of the buffer in system memory * @size: read/write size, sizeof(@buf) must > @size * @write: true - write to vram, otherwise - read from vram */void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, uint32_t *buf, size_t size, bool write){ unsigned long flags; uint32_t hi = ~0; uint64_t last; #ifdef CONFIG_64BIT last = min(pos + size, adev->gmc.visible_vram_size); if (last > pos) { void __iomem *addr = adev->mman.aper_base_kaddr + pos; size_t count = last - pos; if (write) { memcpy_toio(addr, buf, count); mb(); amdgpu_asic_flush_hdp(adev, NULL); } else { amdgpu_asic_invalidate_hdp(adev, NULL); mb(); memcpy_fromio(buf, addr, count); } if (count == size) return; pos += count; buf += count / 4; size -= count; }#endif spin_lock_irqsave(&adev->mmio_idx_lock, flags); for (last = pos + size; pos < last; pos += 4) { uint32_t tmp = pos >> 31; WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)pos) | 0x80000000); if (tmp != hi) { WREG32_NO_KIQ(mmMM_INDEX_HI, tmp); hi = tmp; } if (write) WREG32_NO_KIQ(mmMM_DATA, *buf++); else *buf++ = RREG32_NO_KIQ(mmMM_DATA); } spin_unlock_irqrestore(&adev->mmio_idx_lock, flags);} /* * device register access helper functions. *//** * amdgpu_device_rreg - read a register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @acc_flags: access flags which require special behavior * * Returns the 32 bit value from the offset specified. */uint32_t amdgpu_device_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t acc_flags){ uint32_t ret; if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) return amdgpu_kiq_rreg(adev, reg); if ((reg * 4) < adev->rmmio_size) ret = readl(((void __iomem *)adev->rmmio) + (reg * 4)); else ret = adev->pcie_rreg(adev, (reg * 4)); trace_amdgpu_device_rreg(adev->pdev->device, reg, ret); return ret;} /* * MMIO register read with bytes helper functions * @offset:bytes offset from MMIO start **/ /** * amdgpu_mm_rreg8 - read a memory mapped IO register * * @adev: amdgpu_device pointer * @offset: byte aligned register offset * * Returns the 8 bit value from the offset specified. */uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset) { if (offset < adev->rmmio_size) return (readb(adev->rmmio + offset)); BUG();} /* * MMIO register write with bytes helper functions * @offset:bytes offset from MMIO start * @value: the value want to be written to the register **//** * amdgpu_mm_wreg8 - read a memory mapped IO register * * @adev: amdgpu_device pointer * @offset: byte aligned register offset * @value: 8 bit value to write * * Writes the value specified to the offset specified. */void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value) { if (offset < adev->rmmio_size) writeb(value, adev->rmmio + offset); else BUG();} void static inline amdgpu_device_wreg_no_kiq(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags){ trace_amdgpu_device_wreg(adev->pdev->device, reg, v); if ((reg * 4) < adev->rmmio_size) writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); else adev->pcie_wreg(adev, (reg * 4), v);} /** * amdgpu_device_wreg - write to a register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * @acc_flags: access flags which require special behavior * * Writes the value specified to the offset specified. */void amdgpu_device_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags){ if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) return amdgpu_kiq_wreg(adev, reg, v); amdgpu_device_wreg_no_kiq(adev, reg, v, acc_flags);} /* * amdgpu_mm_wreg_mmio_rlc - write register either with mmio or with RLC path if in range * * this function is invoked only the debugfs register access * */void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags){ if (amdgpu_sriov_fullaccess(adev) && adev->gfx.rlc.funcs && adev->gfx.rlc.funcs->is_rlcg_access_range) { if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) return adev->gfx.rlc.funcs->rlcg_wreg(adev, reg, v); } amdgpu_device_wreg_no_kiq(adev, reg, v, acc_flags);} /** * amdgpu_io_rreg - read an IO register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * * Returns the 32 bit value from the offset specified. */u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg){ if ((reg * 4) < adev->rio_mem_size) return ioread32(adev->rio_mem + (reg * 4)); else { iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); return ioread32(adev->rio_mem + (mmMM_DATA * 4)); }} /** * amdgpu_io_wreg - write to an IO register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * * Writes the value specified to the offset specified. */void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v){ if ((reg * 4) < adev->rio_mem_size) iowrite32(v, adev->rio_mem + (reg * 4)); else { iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); iowrite32(v, adev->rio_mem + (mmMM_DATA * 4)); }} /** * amdgpu_mm_rdoorbell - read a doorbell dword * * @adev: amdgpu_device pointer * @index: doorbell index * * Returns the value in the doorbell aperture at the * requested doorbell index (CIK). */u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index){ if (index < adev->doorbell.num_doorbells) { return readl(adev->doorbell.ptr + index); } else { DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); return 0; }} /** * amdgpu_mm_wdoorbell - write a doorbell dword * * @adev: amdgpu_device pointer * @index: doorbell index * @v: value to write * * Writes @v to the doorbell aperture at the * requested doorbell index (CIK). */void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v){ if (index < adev->doorbell.num_doorbells) { writel(v, adev->doorbell.ptr + index); } else { DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); }} /** * amdgpu_mm_rdoorbell64 - read a doorbell Qword * * @adev: amdgpu_device pointer * @index: doorbell index *Lines 1–500 of 4582. 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/power_supply.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/console.h> #include <linux/slab.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_probe_helper.h> #include <drm/amdgpu_drm.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/pci.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 <linux/suspend.h> #include <drm/task_barrier.h> #include <linux/pm_runtime.h> 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/renoir_gpu_info.bin"); MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin"); MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin"); MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_RESUME_MS 2000 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", "NAVI10", "NAVI14", "NAVI12", "LAST", }; /** * 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 = ddev->dev_private; uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev); return snprintf(buf, PAGE_SIZE, "%llu\n", cnt); } static DEVICE_ATTR(pcie_replay_count, S_IRUGO, amdgpu_device_get_pcie_replay_count, NULL); static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); /** * DOC: product_name * * The amdgpu driver provides a sysfs API for reporting the product name * for the device * The file serial_number is used for this and returns the product name * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_product_name(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_name); } static DEVICE_ATTR(product_name, S_IRUGO, amdgpu_device_get_product_name, NULL); /** * DOC: product_number * * The amdgpu driver provides a sysfs API for reporting the part number * for the device * The file serial_number is used for this and returns the part number * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_product_number(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_number); } static DEVICE_ATTR(product_number, S_IRUGO, amdgpu_device_get_product_number, NULL); /** * DOC: serial_number * * The amdgpu driver provides a sysfs API for reporting the serial number * for the device * The file serial_number is used for this and returns the serial number * as returned from the FRU. * NOTE: This is only available for certain server cards */ static ssize_t amdgpu_device_get_serial_number(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; return snprintf(buf, PAGE_SIZE, "%s\n", adev->serial); } static DEVICE_ATTR(serial_number, S_IRUGO, amdgpu_device_get_serial_number, NULL); /** * amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control * * @dev: drm_device pointer * * Returns true if the device is a dGPU with HG/PX power control, * otherwise return false. */ bool amdgpu_device_supports_boco(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private; if (adev->flags & AMD_IS_PX) return true; return false; } /** * amdgpu_device_supports_baco - Does the device support BACO * * @dev: drm_device pointer * * Returns true if the device supporte BACO, * otherwise return false. */ bool amdgpu_device_supports_baco(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private; return amdgpu_asic_supports_baco(adev); } /** * VRAM access helper functions. * * amdgpu_device_vram_access - read/write a buffer in vram * * @adev: amdgpu_device pointer * @pos: offset of the buffer in vram * @buf: virtual address of the buffer in system memory * @size: read/write size, sizeof(@buf) must > @size * @write: true - write to vram, otherwise - read from vram */ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, uint32_t *buf, size_t size, bool write) { unsigned long flags; uint32_t hi = ~0; uint64_t last; #ifdef CONFIG_64BIT last = min(pos + size, adev->gmc.visible_vram_size); if (last > pos) { void __iomem *addr = adev->mman.aper_base_kaddr + pos; size_t count = last - pos; if (write) { memcpy_toio(addr, buf, count); mb(); amdgpu_asic_flush_hdp(adev, NULL); } else { amdgpu_asic_invalidate_hdp(adev, NULL); mb(); memcpy_fromio(buf, addr, count); } if (count == size) return; pos += count; buf += count / 4; size -= count; } #endif spin_lock_irqsave(&adev->mmio_idx_lock, flags); for (last = pos + size; pos < last; pos += 4) { uint32_t tmp = pos >> 31; WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)pos) | 0x80000000); if (tmp != hi) { WREG32_NO_KIQ(mmMM_INDEX_HI, tmp); hi = tmp; } if (write) WREG32_NO_KIQ(mmMM_DATA, *buf++); else *buf++ = RREG32_NO_KIQ(mmMM_DATA); } spin_unlock_irqrestore(&adev->mmio_idx_lock, flags); } /* * device register access helper functions. */ /** * amdgpu_device_rreg - read a register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @acc_flags: access flags which require special behavior * * Returns the 32 bit value from the offset specified. */ uint32_t amdgpu_device_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t acc_flags) { uint32_t ret; if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) return amdgpu_kiq_rreg(adev, reg); if ((reg * 4) < adev->rmmio_size) ret = readl(((void __iomem *)adev->rmmio) + (reg * 4)); else ret = adev->pcie_rreg(adev, (reg * 4)); trace_amdgpu_device_rreg(adev->pdev->device, reg, ret); return ret; } /* * MMIO register read with bytes helper functions * @offset:bytes offset from MMIO start * */ /** * amdgpu_mm_rreg8 - read a memory mapped IO register * * @adev: amdgpu_device pointer * @offset: byte aligned register offset * * Returns the 8 bit value from the offset specified. */ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset) { if (offset < adev->rmmio_size) return (readb(adev->rmmio + offset)); BUG(); } /* * MMIO register write with bytes helper functions * @offset:bytes offset from MMIO start * @value: the value want to be written to the register * */ /** * amdgpu_mm_wreg8 - read a memory mapped IO register * * @adev: amdgpu_device pointer * @offset: byte aligned register offset * @value: 8 bit value to write * * Writes the value specified to the offset specified. */ void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value) { if (offset < adev->rmmio_size) writeb(value, adev->rmmio + offset); else BUG(); } void static inline amdgpu_device_wreg_no_kiq(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) { trace_amdgpu_device_wreg(adev->pdev->device, reg, v); if ((reg * 4) < adev->rmmio_size) writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); else adev->pcie_wreg(adev, (reg * 4), v); } /** * amdgpu_device_wreg - write to a register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * @acc_flags: access flags which require special behavior * * Writes the value specified to the offset specified. */ void amdgpu_device_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) { if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) return amdgpu_kiq_wreg(adev, reg, v); amdgpu_device_wreg_no_kiq(adev, reg, v, acc_flags); } /* * amdgpu_mm_wreg_mmio_rlc - write register either with mmio or with RLC path if in range * * this function is invoked only the debugfs register access * */ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) { if (amdgpu_sriov_fullaccess(adev) && adev->gfx.rlc.funcs && adev->gfx.rlc.funcs->is_rlcg_access_range) { if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) return adev->gfx.rlc.funcs->rlcg_wreg(adev, reg, v); } amdgpu_device_wreg_no_kiq(adev, reg, v, acc_flags); } /** * amdgpu_io_rreg - read an IO register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * * Returns the 32 bit value from the offset specified. */ u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg) { if ((reg * 4) < adev->rio_mem_size) return ioread32(adev->rio_mem + (reg * 4)); else { iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); return ioread32(adev->rio_mem + (mmMM_DATA * 4)); } } /** * amdgpu_io_wreg - write to an IO register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * * Writes the value specified to the offset specified. */ void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v) { if ((reg * 4) < adev->rio_mem_size) iowrite32(v, adev->rio_mem + (reg * 4)); else { iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); iowrite32(v, adev->rio_mem + (mmMM_DATA * 4)); } } /** * amdgpu_mm_rdoorbell - read a doorbell dword * * @adev: amdgpu_device pointer * @index: doorbell index * * Returns the value in the doorbell aperture at the * requested doorbell index (CIK). */ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index) { if (index < adev->doorbell.num_doorbells) { return readl(adev->doorbell.ptr + index); } else { DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); return 0; } } /** * amdgpu_mm_wdoorbell - write a doorbell dword * * @adev: amdgpu_device pointer * @index: doorbell index * @v: value to write * * Writes @v to the doorbell aperture at the * requested doorbell index (CIK). */ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v) { if (index < adev->doorbell.num_doorbells) { writel(v, adev->doorbell.ptr + index); } else { DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); } } /** * amdgpu_mm_rdoorbell64 - read a doorbell Qword * * @adev: amdgpu_device pointer * @index: doorbell index *