/* * Copyright 2023 Advanced Micro Devices, Inc. * * 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. *
*/ #include <linux/firmware.h> #include <linux/pci.h>
staticint gmc_v12_0_vm_fault_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, enum amdgpu_interrupt_state state)
{ switch (state) { case AMDGPU_IRQ_STATE_DISABLE: /* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB0(0), false); /* GFX HUB */ /* This works because this interrupt is only * enabled at init/resume and disabled in * fini/suspend, so the overall state doesn't * change over the course of suspend/resume.
*/ if (!adev->in_s0ix)
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB(0), false); break; case AMDGPU_IRQ_STATE_ENABLE: /* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB0(0), true); /* GFX HUB */ /* This works because this interrupt is only * enabled at init/resume and disabled in * fini/suspend, so the overall state doesn't * change over the course of suspend/resume.
*/ if (!adev->in_s0ix)
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB(0), true); break; default: break;
}
if (!amdgpu_sriov_vf(adev)) { /* * Issue a dummy read to wait for the status register to * be updated to avoid reading an incorrect value due to * the new fast GRBM interface.
*/ if (entry->vmid_src == AMDGPU_GFXHUB(0))
RREG32(hub->vm_l2_pro_fault_status);
status = RREG32(hub->vm_l2_pro_fault_status);
WREG32_P(hub->vm_l2_pro_fault_cntl, 1, ~1);
dev_err(adev->dev, " in page starting at address 0x%016llx from client %d\n",
addr, entry->client_id);
/* Only print L2 fault status if the status register could be read and * contains useful information
*/ if (status != 0)
hub->vmhub_funcs->print_l2_protection_fault_status(adev, status);
}
/* * GART * VMID 0 is the physical GPU addresses as used by the kernel. * VMIDs 1-15 are used for userspace clients and are handled * by the amdgpu vm/hsa code.
*/
spin_lock(&adev->gmc.invalidate_lock); /* * It may lose gpuvm invalidate acknowldege state across power-gating * off cycle, add semaphore acquire before invalidation and semaphore * release after invalidation to avoid entering power gated state * to WA the Issue
*/
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ if (use_semaphore) { for (i = 0; i < adev->usec_timeout; i++) { /* a read return value of 1 means semaphore acuqire */
tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem +
hub->eng_distance * eng, hub_ip); if (tmp & 0x1) break;
udelay(1);
}
if (i >= adev->usec_timeout)
dev_err(adev->dev, "Timeout waiting for sem acquire in VM flush!\n");
}
/* Wait for ACK with a delay.*/ for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_ack +
hub->eng_distance * eng, hub_ip);
tmp &= 1 << vmid; if (tmp) break;
udelay(1);
}
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release
*/
WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem +
hub->eng_distance * eng, 0, hub_ip);
/* Issue additional private vm invalidation to MMHUB */ if ((vmhub != AMDGPU_GFXHUB(0)) &&
(hub->vm_l2_bank_select_reserved_cid2) &&
!amdgpu_sriov_vf(adev)) {
inv_req = RREG32_NO_KIQ(hub->vm_l2_bank_select_reserved_cid2); /* bit 25: RSERVED_CACHE_PRIVATE_INVALIDATION */
inv_req |= (1 << 25); /* Issue private invalidation */
WREG32_NO_KIQ(hub->vm_l2_bank_select_reserved_cid2, inv_req); /* Read back to ensure invalidation is done*/
RREG32_NO_KIQ(hub->vm_l2_bank_select_reserved_cid2);
}
spin_unlock(&adev->gmc.invalidate_lock);
if (i < adev->usec_timeout) return;
dev_err(adev->dev, "Timeout waiting for VM flush ACK!\n");
}
/** * gmc_v12_0_flush_gpu_tlb - gart tlb flush callback * * @adev: amdgpu_device pointer * @vmid: vm instance to flush * @vmhub: which hub to flush * @flush_type: the flush type * * Flush the TLB for the requested page table.
*/ staticvoid gmc_v12_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
uint32_t vmhub, uint32_t flush_type)
{ if ((vmhub == AMDGPU_GFXHUB(0)) && !adev->gfx.is_poweron) return;
/* This is necessary for SRIOV as well as for GFXOFF to function * properly under bare metal
*/ if ((adev->gfx.kiq[0].ring.sched.ready || adev->mes.ring[0].sched.ready) &&
(amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { struct amdgpu_vmhub *hub = &adev->vmhub[vmhub]; constunsigned eng = 17;
u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type);
u32 req = hub->vm_inv_eng0_req + hub->eng_distance * eng;
u32 ack = hub->vm_inv_eng0_ack + hub->eng_distance * eng;
/** * gmc_v12_0_flush_gpu_tlb_pasid - tlb flush via pasid * * @adev: amdgpu_device pointer * @pasid: pasid to be flush * @flush_type: the flush type * @all_hub: flush all hubs * @inst: is used to select which instance of KIQ to use for the invalidation * * Flush the TLB for the requested pasid.
*/ staticvoid gmc_v12_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
uint16_t pasid, uint32_t flush_type, bool all_hub, uint32_t inst)
{
uint16_t queried; int vmid, i;
/* * It may lose gpuvm invalidate acknowldege state across power-gating * off cycle, add semaphore acquire before invalidation and semaphore * release after invalidation to avoid entering power gated state * to WA the Issue
*/
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ if (use_semaphore) /* a read return value of 1 means semaphore acuqire */
amdgpu_ring_emit_reg_wait(ring,
hub->vm_inv_eng0_sem +
hub->eng_distance * eng, 0x1, 0x1);
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release
*/
amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem +
hub->eng_distance * eng, 0);
/* base offset of vram pages */ if (amdgpu_sriov_vf(adev))
adev->vm_manager.vram_base_offset = 0; else
adev->vm_manager.vram_base_offset = adev->mmhub.funcs->get_mc_fb_offset(adev);
}
/** * gmc_v12_0_mc_init - initialize the memory controller driver params * * @adev: amdgpu_device pointer * * Look up the amount of vram, vram width, and decide how to place * vram and gart within the GPU's physical address space. * Returns 0 for success.
*/ staticint gmc_v12_0_mc_init(struct amdgpu_device *adev)
{ int r;
/* size in MB on si */
adev->gmc.mc_vram_size =
adev->nbio.funcs->get_memsize(adev) * 1024ULL * 1024ULL;
adev->gmc.real_vram_size = adev->gmc.mc_vram_size;
if (!(adev->flags & AMD_IS_APU)) {
r = amdgpu_device_resize_fb_bar(adev); if (r) return r;
}
#ifdef CONFIG_X86_64 if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) {
adev->gmc.aper_base = adev->mmhub.funcs->get_mc_fb_offset(adev);
adev->gmc.aper_size = adev->gmc.real_vram_size;
} #endif /* In case the PCI BAR is larger than the actual amount of vram */
adev->gmc.visible_vram_size = adev->gmc.aper_size; if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size)
adev->gmc.visible_vram_size = adev->gmc.real_vram_size;
/* set the gart size */ if (amdgpu_gart_size == -1) {
adev->gmc.gart_size = 512ULL << 20;
} else
adev->gmc.gart_size = (u64)amdgpu_gart_size << 20;
gmc_v12_0_vram_gtt_location(adev, &adev->gmc);
return 0;
}
staticint gmc_v12_0_gart_init(struct amdgpu_device *adev)
{ int r;
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 1):
set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask);
set_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask); /* * To fulfill 4-level page support, * vm size is 256TB (48bit), maximum size, * block size 512 (9bit)
*/
amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48); break; default: break;
}
/* This interrupt is VMC page fault.*/
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_VMC,
VMC_1_0__SRCID__VM_FAULT,
&adev->gmc.vm_fault);
if (r) return r;
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX,
UTCL2_1_0__SRCID__FAULT,
&adev->gmc.vm_fault); if (r) return r;
if (!amdgpu_sriov_vf(adev)) { /* interrupt sent to DF. */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_DF, 0,
&adev->gmc.ecc_irq); if (r) return r;
}
/* * Set the internal MC address mask This is the max address of the GPU's * internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44)); if (r) {
printk(KERN_WARNING "amdgpu: No suitable DMA available.\n"); return r;
}
adev->need_swiotlb = drm_need_swiotlb(44);
r = gmc_v12_0_mc_init(adev); if (r) return r;
amdgpu_gmc_get_vbios_allocations(adev);
/* Memory manager */
r = amdgpu_bo_init(adev); if (r) return r;
r = gmc_v12_0_gart_init(adev); if (r) return r;
/* * number of VMs * VMID 0 is reserved for System * amdgpu graphics/compute will use VMIDs 1-7 * amdkfd will use VMIDs 8-15
*/
adev->vm_manager.first_kfd_vmid = adev->gfx.disable_kq ? 1 : 8;
amdgpu_vm_manager_init(adev);
r = amdgpu_gmc_ras_sw_init(adev); if (r) return r;
return 0;
}
/** * gmc_v12_0_gart_fini - vm fini callback * * @adev: amdgpu_device pointer * * Tears down the driver GART/VM setup (CIK).
*/ staticvoid gmc_v12_0_gart_fini(struct amdgpu_device *adev)
{
amdgpu_gart_table_vram_free(adev);
}
if (amdgpu_sriov_vf(adev)) { /* full access mode, so don't touch any GMC register */
DRM_DEBUG("For SRIOV client, shouldn't do anything.\n"); return 0;
}
amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0);
if (adev->gmc.ecc_irq.funcs &&
amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC))
amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.