/* * Copyright 2014 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. * */ #include <linux/firmware.h>#include <linux/pm_runtime.h> #include "amdgpu.h"#include "amdgpu_gfx.h"#include "amdgpu_rlc.h"#include "amdgpu_ras.h"#include "amdgpu_reset.h"#include "amdgpu_xcp.h"#include "amdgpu_xgmi.h"#include "amdgpu_mes.h"#include "amdgpu_userq.h"#include "mes_userqueue.h"#include "nvd.h" /* delay 0.1 second to enable gfx off feature */#define GFX_OFF_DELAY_ENABLE msecs_to_jiffies(100) #define GFX_OFF_NO_DELAY 0 /* * GPU GFX IP block helpers function. */ int amdgpu_gfx_mec_queue_to_bit(struct amdgpu_device *adev, int mec, int pipe, int queue){ int bit = 0; bit += mec * adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe; bit += pipe * adev->gfx.mec.num_queue_per_pipe; bit += queue; return bit;} void amdgpu_queue_mask_bit_to_mec_queue(struct amdgpu_device *adev, int bit, int *mec, int *pipe, int *queue){ *queue = bit % adev->gfx.mec.num_queue_per_pipe; *pipe = (bit / adev->gfx.mec.num_queue_per_pipe) % adev->gfx.mec.num_pipe_per_mec; *mec = (bit / adev->gfx.mec.num_queue_per_pipe) / adev->gfx.mec.num_pipe_per_mec; } bool amdgpu_gfx_is_mec_queue_enabled(struct amdgpu_device *adev, int xcc_id, int mec, int pipe, int queue){ return test_bit(amdgpu_gfx_mec_queue_to_bit(adev, mec, pipe, queue), adev->gfx.mec_bitmap[xcc_id].queue_bitmap);} static int amdgpu_gfx_me_queue_to_bit(struct amdgpu_device *adev, int me, int pipe, int queue){ int num_queue_per_pipe = 1; /* we only enable 1 KGQ per pipe */ int bit = 0; bit += me * adev->gfx.me.num_pipe_per_me * num_queue_per_pipe; bit += pipe * num_queue_per_pipe; bit += queue; return bit;} bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me, int pipe, int queue){ return test_bit(amdgpu_gfx_me_queue_to_bit(adev, me, pipe, queue), adev->gfx.me.queue_bitmap);} /** * amdgpu_gfx_parse_disable_cu - Parse the disable_cu module parameter * * @adev: amdgpu device pointer * @mask: array in which the per-shader array disable masks will be stored * @max_se: number of SEs * @max_sh: number of SHs * * The bitmask of CUs to be disabled in the shader array determined by se and * sh is stored in mask[se * max_sh + sh]. */void amdgpu_gfx_parse_disable_cu(struct amdgpu_device *adev, unsigned int *mask, unsigned int max_se, unsigned int max_sh){ unsigned int se, sh, cu; const char *p; memset(mask, 0, sizeof(*mask) * max_se * max_sh); if (!amdgpu_disable_cu || !*amdgpu_disable_cu) return; p = amdgpu_disable_cu; for (;;) { char *next; int ret = sscanf(p, "%u.%u.%u", &se, &sh, &cu); if (ret < 3) { drm_err(adev_to_drm(adev), "could not parse disable_cu\n"); return; } if (se < max_se && sh < max_sh && cu < 16) { drm_info(adev_to_drm(adev), "Disabling CU %u.%u.%u\n", se, sh, cu); mask[se * max_sh + sh] |= 1u << cu; } else { drm_err(adev_to_drm(adev), "disable_cu %u.%u.%u is out of range\n", se, sh, cu); } next = strchr(p, ','); if (!next) break; p = next + 1; }} static bool amdgpu_gfx_is_graphics_multipipe_capable(struct amdgpu_device *adev){ return amdgpu_async_gfx_ring && adev->gfx.me.num_pipe_per_me > 1;} static bool amdgpu_gfx_is_compute_multipipe_capable(struct amdgpu_device *adev){ if (amdgpu_compute_multipipe != -1) { dev_info(adev->dev, " forcing compute pipe policy %d\n", amdgpu_compute_multipipe); return amdgpu_compute_multipipe == 1; } if (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) return true; /* FIXME: spreading the queues across pipes causes perf regressions * on POLARIS11 compute workloads */ if (adev->asic_type == CHIP_POLARIS11) return false; return adev->gfx.mec.num_mec > 1;} bool amdgpu_gfx_is_high_priority_graphics_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring){ int queue = ring->queue; int pipe = ring->pipe; /* Policy: use pipe1 queue0 as high priority graphics queue if we * have more than one gfx pipe. */ if (amdgpu_gfx_is_graphics_multipipe_capable(adev) && adev->gfx.num_gfx_rings > 1 && pipe == 1 && queue == 0) { int me = ring->me; int bit; bit = amdgpu_gfx_me_queue_to_bit(adev, me, pipe, queue); if (ring == &adev->gfx.gfx_ring[bit]) return true; } return false;} bool amdgpu_gfx_is_high_priority_compute_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring){ /* Policy: use 1st queue as high priority compute queue if we * have more than one compute queue. */ if (adev->gfx.num_compute_rings > 1 && ring == &adev->gfx.compute_ring[0]) return true; return false;} void amdgpu_gfx_compute_queue_acquire(struct amdgpu_device *adev){ int i, j, queue, pipe; bool multipipe_policy = amdgpu_gfx_is_compute_multipipe_capable(adev); int max_queues_per_mec = min(adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe, adev->gfx.num_compute_rings); int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1; if (multipipe_policy) { /* policy: make queues evenly cross all pipes on MEC1 only * for multiple xcc, just use the original policy for simplicity */ for (j = 0; j < num_xcc; j++) { for (i = 0; i < max_queues_per_mec; i++) { pipe = i % adev->gfx.mec.num_pipe_per_mec; queue = (i / adev->gfx.mec.num_pipe_per_mec) % adev->gfx.mec.num_queue_per_pipe; set_bit(pipe * adev->gfx.mec.num_queue_per_pipe + queue, adev->gfx.mec_bitmap[j].queue_bitmap); } } } else { /* policy: amdgpu owns all queues in the given pipe */ for (j = 0; j < num_xcc; j++) { for (i = 0; i < max_queues_per_mec; ++i) set_bit(i, adev->gfx.mec_bitmap[j].queue_bitmap); } } for (j = 0; j < num_xcc; j++) { dev_dbg(adev->dev, "mec queue bitmap weight=%d\n", bitmap_weight(adev->gfx.mec_bitmap[j].queue_bitmap, AMDGPU_MAX_COMPUTE_QUEUES)); }} void amdgpu_gfx_graphics_queue_acquire(struct amdgpu_device *adev){ int i, queue, pipe; bool multipipe_policy = amdgpu_gfx_is_graphics_multipipe_capable(adev); int num_queue_per_pipe = 1; /* we only enable 1 KGQ per pipe */ int max_queues_per_me = adev->gfx.me.num_pipe_per_me * num_queue_per_pipe; if (multipipe_policy) { /* policy: amdgpu owns the first queue per pipe at this stage * will extend to mulitple queues per pipe later */ for (i = 0; i < max_queues_per_me; i++) { pipe = i % adev->gfx.me.num_pipe_per_me; queue = (i / adev->gfx.me.num_pipe_per_me) % num_queue_per_pipe; set_bit(pipe * num_queue_per_pipe + queue, adev->gfx.me.queue_bitmap); } } else { for (i = 0; i < max_queues_per_me; ++i) set_bit(i, adev->gfx.me.queue_bitmap); } /* update the number of active graphics rings */ if (adev->gfx.num_gfx_rings) adev->gfx.num_gfx_rings = bitmap_weight(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES);} static int amdgpu_gfx_kiq_acquire(struct amdgpu_device *adev, struct amdgpu_ring *ring, int xcc_id){ int queue_bit; int mec, pipe, queue; queue_bit = adev->gfx.mec.num_mec * adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe; while (--queue_bit >= 0) { if (test_bit(queue_bit, adev->gfx.mec_bitmap[xcc_id].queue_bitmap)) continue; amdgpu_queue_mask_bit_to_mec_queue(adev, queue_bit, &mec, &pipe, &queue); /* * 1. Using pipes 2/3 from MEC 2 seems cause problems. * 2. It must use queue id 0, because CGPG_IDLE/SAVE/LOAD/RUN * only can be issued on queue 0. */ if ((mec == 1 && pipe > 1) || queue != 0) continue; ring->me = mec + 1; ring->pipe = pipe; ring->queue = queue; return 0; } dev_err(adev->dev, "Failed to find a queue for KIQ\n"); return -EINVAL;} int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev, int xcc_id){ struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; struct amdgpu_irq_src *irq = &kiq->irq; struct amdgpu_ring *ring = &kiq->ring; int r = 0; spin_lock_init(&kiq->ring_lock); ring->adev = NULL; ring->ring_obj = NULL; ring->use_doorbell = true; ring->xcc_id = xcc_id; ring->vm_hub = AMDGPU_GFXHUB(xcc_id); ring->doorbell_index = (adev->doorbell_index.kiq + xcc_id * adev->doorbell_index.xcc_doorbell_range) << 1; r = amdgpu_gfx_kiq_acquire(adev, ring, xcc_id); if (r) return r; ring->eop_gpu_addr = kiq->eop_gpu_addr; ring->no_scheduler = true; snprintf(ring->name, sizeof(ring->name), "kiq_%hhu.%hhu.%hhu.%hhu", (unsigned char)xcc_id, (unsigned char)ring->me, (unsigned char)ring->pipe, (unsigned char)ring->queue); r = amdgpu_ring_init(adev, ring, 1024, irq, AMDGPU_CP_KIQ_IRQ_DRIVER0, AMDGPU_RING_PRIO_DEFAULT, NULL); if (r) dev_warn(adev->dev, "(%d) failed to init kiq ring\n", r); return r;} void amdgpu_gfx_kiq_free_ring(struct amdgpu_ring *ring){ amdgpu_ring_fini(ring);} void amdgpu_gfx_kiq_fini(struct amdgpu_device *adev, int xcc_id){ struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; amdgpu_bo_free_kernel(&kiq->eop_obj, &kiq->eop_gpu_addr, NULL);} int amdgpu_gfx_kiq_init(struct amdgpu_device *adev, unsigned int hpd_size, int xcc_id){ int r; u32 *hpd; struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; r = amdgpu_bo_create_kernel(adev, hpd_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, &kiq->eop_obj, &kiq->eop_gpu_addr, (void **)&hpd); if (r) { dev_warn(adev->dev, "failed to create KIQ bo (%d).\n", r); return r; } memset(hpd, 0, hpd_size); r = amdgpu_bo_reserve(kiq->eop_obj, true); if (unlikely(r != 0)) dev_warn(adev->dev, "(%d) reserve kiq eop bo failed\n", r); amdgpu_bo_kunmap(kiq->eop_obj); amdgpu_bo_unreserve(kiq->eop_obj); return 0;} static void amdgpu_gfx_mqd_reset_restore(struct amdgpu_ring *ring){ struct amdgpu_device *adev = ring->adev; int mqd_idx, mqd_size; /* restore mqd with the backup copy */ if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) { mqd_idx = ring - &adev->gfx.compute_ring[0]; mqd_size = adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size; if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy_toio(ring->mqd_ptr, adev->gfx.mec.mqd_backup[mqd_idx], mqd_size); } else if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) { mqd_size = adev->mqds[AMDGPU_HW_IP_GFX].mqd_size; mqd_idx = ring - &adev->gfx.gfx_ring[0]; if (adev->gfx.me.mqd_backup[mqd_idx]) memcpy_toio(ring->mqd_ptr, adev->gfx.me.mqd_backup[mqd_idx], mqd_size); } /* reset the ring */ ring->wptr = 0; atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); amdgpu_ring_clear_ring(ring);} /* create MQD for each compute/gfx queue */int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, unsigned int mqd_size, int xcc_id){ int r, i, j; struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; struct amdgpu_ring *ring = &kiq->ring; u32 domain = AMDGPU_GEM_DOMAIN_GTT; u32 gfx_mqd_size = max(adev->mqds[AMDGPU_HW_IP_GFX].mqd_size, mqd_size); u32 compute_mqd_size = max(adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size, mqd_size); #if !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) /* Only enable on gfx10 and 11 for now to avoid changing behavior on older chips */ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 0, 0)) domain |= AMDGPU_GEM_DOMAIN_VRAM;#endif /* create MQD for KIQ (on GFX8+ where we use KIQ) */ if (adev->asic_type >= CHIP_TOPAZ && !adev->enable_mes_kiq && !ring->mqd_obj) { /* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must * otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD * deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for * KIQ MQD no matter SRIOV or Bare-metal */ r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd ob (%d)", r); return r; } /* prepare MQD backup */ kiq->mqd_backup = kzalloc(mqd_size, GFP_KERNEL); if (!kiq->mqd_backup) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } if (adev->asic_type >= CHIP_NAVI10 && amdgpu_async_gfx_ring) { /* create MQD for each KGQ */ for (i = 0; i < adev->gfx.num_gfx_rings; i++) { ring = &adev->gfx.gfx_ring[i]; if (!ring->mqd_obj) { r = amdgpu_bo_create_kernel(adev, AMDGPU_MQD_SIZE_ALIGN(gfx_mqd_size), PAGE_SIZE, domain, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd bo (%d)", r); return r; } ring->mqd_size = gfx_mqd_size; /* prepare MQD backup */ adev->gfx.me.mqd_backup[i] = kzalloc(gfx_mqd_size, GFP_KERNEL); if (!adev->gfx.me.mqd_backup[i]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } } } /* create MQD for each KCQ */ for (i = 0; i < adev->gfx.num_compute_rings; i++) { j = i + xcc_id * adev->gfx.num_compute_rings; ring = &adev->gfx.compute_ring[j]; if (!ring->mqd_obj) { r = amdgpu_bo_create_kernel(adev, AMDGPU_MQD_SIZE_ALIGN(compute_mqd_size), PAGE_SIZE, domain, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd bo (%d)", r); return r; } ring->mqd_size = compute_mqd_size; /* prepare MQD backup */ adev->gfx.mec.mqd_backup[j] = kzalloc(compute_mqd_size, GFP_KERNEL); if (!adev->gfx.mec.mqd_backup[j]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } } return 0;} void amdgpu_gfx_mqd_sw_fini(struct amdgpu_device *adev, int xcc_id)Lines 1–500 of 3098. Load more
/* * Copyright 2014 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. * */ #include <linux/firmware.h> #include <linux/pm_runtime.h> #include "amdgpu.h" #include "amdgpu_gfx.h" #include "amdgpu_rlc.h" #include "amdgpu_ras.h" #include "amdgpu_reset.h" #include "amdgpu_xcp.h" #include "amdgpu_xgmi.h" #include "amdgpu_mes.h" #include "amdgpu_userq.h" #include "mes_userqueue.h" #include "nvd.h" /* delay 0.1 second to enable gfx off feature */ #define GFX_OFF_DELAY_ENABLE msecs_to_jiffies(100) #define GFX_OFF_NO_DELAY 0 /* * GPU GFX IP block helpers function. */ int amdgpu_gfx_mec_queue_to_bit(struct amdgpu_device *adev, int mec, int pipe, int queue) { int bit = 0; bit += mec * adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe; bit += pipe * adev->gfx.mec.num_queue_per_pipe; bit += queue; return bit; } void amdgpu_queue_mask_bit_to_mec_queue(struct amdgpu_device *adev, int bit, int *mec, int *pipe, int *queue) { *queue = bit % adev->gfx.mec.num_queue_per_pipe; *pipe = (bit / adev->gfx.mec.num_queue_per_pipe) % adev->gfx.mec.num_pipe_per_mec; *mec = (bit / adev->gfx.mec.num_queue_per_pipe) / adev->gfx.mec.num_pipe_per_mec; } bool amdgpu_gfx_is_mec_queue_enabled(struct amdgpu_device *adev, int xcc_id, int mec, int pipe, int queue) { return test_bit(amdgpu_gfx_mec_queue_to_bit(adev, mec, pipe, queue), adev->gfx.mec_bitmap[xcc_id].queue_bitmap); } static int amdgpu_gfx_me_queue_to_bit(struct amdgpu_device *adev, int me, int pipe, int queue) { int num_queue_per_pipe = 1; /* we only enable 1 KGQ per pipe */ int bit = 0; bit += me * adev->gfx.me.num_pipe_per_me * num_queue_per_pipe; bit += pipe * num_queue_per_pipe; bit += queue; return bit; } bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me, int pipe, int queue) { return test_bit(amdgpu_gfx_me_queue_to_bit(adev, me, pipe, queue), adev->gfx.me.queue_bitmap); } /** * amdgpu_gfx_parse_disable_cu - Parse the disable_cu module parameter * * @adev: amdgpu device pointer * @mask: array in which the per-shader array disable masks will be stored * @max_se: number of SEs * @max_sh: number of SHs * * The bitmask of CUs to be disabled in the shader array determined by se and * sh is stored in mask[se * max_sh + sh]. */ void amdgpu_gfx_parse_disable_cu(struct amdgpu_device *adev, unsigned int *mask, unsigned int max_se, unsigned int max_sh) { unsigned int se, sh, cu; const char *p; memset(mask, 0, sizeof(*mask) * max_se * max_sh); if (!amdgpu_disable_cu || !*amdgpu_disable_cu) return; p = amdgpu_disable_cu; for (;;) { char *next; int ret = sscanf(p, "%u.%u.%u", &se, &sh, &cu); if (ret < 3) { drm_err(adev_to_drm(adev), "could not parse disable_cu\n"); return; } if (se < max_se && sh < max_sh && cu < 16) { drm_info(adev_to_drm(adev), "Disabling CU %u.%u.%u\n", se, sh, cu); mask[se * max_sh + sh] |= 1u << cu; } else { drm_err(adev_to_drm(adev), "disable_cu %u.%u.%u is out of range\n", se, sh, cu); } next = strchr(p, ','); if (!next) break; p = next + 1; } } static bool amdgpu_gfx_is_graphics_multipipe_capable(struct amdgpu_device *adev) { return amdgpu_async_gfx_ring && adev->gfx.me.num_pipe_per_me > 1; } static bool amdgpu_gfx_is_compute_multipipe_capable(struct amdgpu_device *adev) { if (amdgpu_compute_multipipe != -1) { dev_info(adev->dev, " forcing compute pipe policy %d\n", amdgpu_compute_multipipe); return amdgpu_compute_multipipe == 1; } if (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) return true; /* FIXME: spreading the queues across pipes causes perf regressions * on POLARIS11 compute workloads */ if (adev->asic_type == CHIP_POLARIS11) return false; return adev->gfx.mec.num_mec > 1; } bool amdgpu_gfx_is_high_priority_graphics_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring) { int queue = ring->queue; int pipe = ring->pipe; /* Policy: use pipe1 queue0 as high priority graphics queue if we * have more than one gfx pipe. */ if (amdgpu_gfx_is_graphics_multipipe_capable(adev) && adev->gfx.num_gfx_rings > 1 && pipe == 1 && queue == 0) { int me = ring->me; int bit; bit = amdgpu_gfx_me_queue_to_bit(adev, me, pipe, queue); if (ring == &adev->gfx.gfx_ring[bit]) return true; } return false; } bool amdgpu_gfx_is_high_priority_compute_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring) { /* Policy: use 1st queue as high priority compute queue if we * have more than one compute queue. */ if (adev->gfx.num_compute_rings > 1 && ring == &adev->gfx.compute_ring[0]) return true; return false; } void amdgpu_gfx_compute_queue_acquire(struct amdgpu_device *adev) { int i, j, queue, pipe; bool multipipe_policy = amdgpu_gfx_is_compute_multipipe_capable(adev); int max_queues_per_mec = min(adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe, adev->gfx.num_compute_rings); int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1; if (multipipe_policy) { /* policy: make queues evenly cross all pipes on MEC1 only * for multiple xcc, just use the original policy for simplicity */ for (j = 0; j < num_xcc; j++) { for (i = 0; i < max_queues_per_mec; i++) { pipe = i % adev->gfx.mec.num_pipe_per_mec; queue = (i / adev->gfx.mec.num_pipe_per_mec) % adev->gfx.mec.num_queue_per_pipe; set_bit(pipe * adev->gfx.mec.num_queue_per_pipe + queue, adev->gfx.mec_bitmap[j].queue_bitmap); } } } else { /* policy: amdgpu owns all queues in the given pipe */ for (j = 0; j < num_xcc; j++) { for (i = 0; i < max_queues_per_mec; ++i) set_bit(i, adev->gfx.mec_bitmap[j].queue_bitmap); } } for (j = 0; j < num_xcc; j++) { dev_dbg(adev->dev, "mec queue bitmap weight=%d\n", bitmap_weight(adev->gfx.mec_bitmap[j].queue_bitmap, AMDGPU_MAX_COMPUTE_QUEUES)); } } void amdgpu_gfx_graphics_queue_acquire(struct amdgpu_device *adev) { int i, queue, pipe; bool multipipe_policy = amdgpu_gfx_is_graphics_multipipe_capable(adev); int num_queue_per_pipe = 1; /* we only enable 1 KGQ per pipe */ int max_queues_per_me = adev->gfx.me.num_pipe_per_me * num_queue_per_pipe; if (multipipe_policy) { /* policy: amdgpu owns the first queue per pipe at this stage * will extend to mulitple queues per pipe later */ for (i = 0; i < max_queues_per_me; i++) { pipe = i % adev->gfx.me.num_pipe_per_me; queue = (i / adev->gfx.me.num_pipe_per_me) % num_queue_per_pipe; set_bit(pipe * num_queue_per_pipe + queue, adev->gfx.me.queue_bitmap); } } else { for (i = 0; i < max_queues_per_me; ++i) set_bit(i, adev->gfx.me.queue_bitmap); } /* update the number of active graphics rings */ if (adev->gfx.num_gfx_rings) adev->gfx.num_gfx_rings = bitmap_weight(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES); } static int amdgpu_gfx_kiq_acquire(struct amdgpu_device *adev, struct amdgpu_ring *ring, int xcc_id) { int queue_bit; int mec, pipe, queue; queue_bit = adev->gfx.mec.num_mec * adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe; while (--queue_bit >= 0) { if (test_bit(queue_bit, adev->gfx.mec_bitmap[xcc_id].queue_bitmap)) continue; amdgpu_queue_mask_bit_to_mec_queue(adev, queue_bit, &mec, &pipe, &queue); /* * 1. Using pipes 2/3 from MEC 2 seems cause problems. * 2. It must use queue id 0, because CGPG_IDLE/SAVE/LOAD/RUN * only can be issued on queue 0. */ if ((mec == 1 && pipe > 1) || queue != 0) continue; ring->me = mec + 1; ring->pipe = pipe; ring->queue = queue; return 0; } dev_err(adev->dev, "Failed to find a queue for KIQ\n"); return -EINVAL; } int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev, int xcc_id) { struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; struct amdgpu_irq_src *irq = &kiq->irq; struct amdgpu_ring *ring = &kiq->ring; int r = 0; spin_lock_init(&kiq->ring_lock); ring->adev = NULL; ring->ring_obj = NULL; ring->use_doorbell = true; ring->xcc_id = xcc_id; ring->vm_hub = AMDGPU_GFXHUB(xcc_id); ring->doorbell_index = (adev->doorbell_index.kiq + xcc_id * adev->doorbell_index.xcc_doorbell_range) << 1; r = amdgpu_gfx_kiq_acquire(adev, ring, xcc_id); if (r) return r; ring->eop_gpu_addr = kiq->eop_gpu_addr; ring->no_scheduler = true; snprintf(ring->name, sizeof(ring->name), "kiq_%hhu.%hhu.%hhu.%hhu", (unsigned char)xcc_id, (unsigned char)ring->me, (unsigned char)ring->pipe, (unsigned char)ring->queue); r = amdgpu_ring_init(adev, ring, 1024, irq, AMDGPU_CP_KIQ_IRQ_DRIVER0, AMDGPU_RING_PRIO_DEFAULT, NULL); if (r) dev_warn(adev->dev, "(%d) failed to init kiq ring\n", r); return r; } void amdgpu_gfx_kiq_free_ring(struct amdgpu_ring *ring) { amdgpu_ring_fini(ring); } void amdgpu_gfx_kiq_fini(struct amdgpu_device *adev, int xcc_id) { struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; amdgpu_bo_free_kernel(&kiq->eop_obj, &kiq->eop_gpu_addr, NULL); } int amdgpu_gfx_kiq_init(struct amdgpu_device *adev, unsigned int hpd_size, int xcc_id) { int r; u32 *hpd; struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; r = amdgpu_bo_create_kernel(adev, hpd_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, &kiq->eop_obj, &kiq->eop_gpu_addr, (void **)&hpd); if (r) { dev_warn(adev->dev, "failed to create KIQ bo (%d).\n", r); return r; } memset(hpd, 0, hpd_size); r = amdgpu_bo_reserve(kiq->eop_obj, true); if (unlikely(r != 0)) dev_warn(adev->dev, "(%d) reserve kiq eop bo failed\n", r); amdgpu_bo_kunmap(kiq->eop_obj); amdgpu_bo_unreserve(kiq->eop_obj); return 0; } static void amdgpu_gfx_mqd_reset_restore(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; int mqd_idx, mqd_size; /* restore mqd with the backup copy */ if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) { mqd_idx = ring - &adev->gfx.compute_ring[0]; mqd_size = adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size; if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy_toio(ring->mqd_ptr, adev->gfx.mec.mqd_backup[mqd_idx], mqd_size); } else if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) { mqd_size = adev->mqds[AMDGPU_HW_IP_GFX].mqd_size; mqd_idx = ring - &adev->gfx.gfx_ring[0]; if (adev->gfx.me.mqd_backup[mqd_idx]) memcpy_toio(ring->mqd_ptr, adev->gfx.me.mqd_backup[mqd_idx], mqd_size); } /* reset the ring */ ring->wptr = 0; atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); amdgpu_ring_clear_ring(ring); } /* create MQD for each compute/gfx queue */ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, unsigned int mqd_size, int xcc_id) { int r, i, j; struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id]; struct amdgpu_ring *ring = &kiq->ring; u32 domain = AMDGPU_GEM_DOMAIN_GTT; u32 gfx_mqd_size = max(adev->mqds[AMDGPU_HW_IP_GFX].mqd_size, mqd_size); u32 compute_mqd_size = max(adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size, mqd_size); #if !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) /* Only enable on gfx10 and 11 for now to avoid changing behavior on older chips */ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 0, 0)) domain |= AMDGPU_GEM_DOMAIN_VRAM; #endif /* create MQD for KIQ (on GFX8+ where we use KIQ) */ if (adev->asic_type >= CHIP_TOPAZ && !adev->enable_mes_kiq && !ring->mqd_obj) { /* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must * otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD * deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for * KIQ MQD no matter SRIOV or Bare-metal */ r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd ob (%d)", r); return r; } /* prepare MQD backup */ kiq->mqd_backup = kzalloc(mqd_size, GFP_KERNEL); if (!kiq->mqd_backup) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } if (adev->asic_type >= CHIP_NAVI10 && amdgpu_async_gfx_ring) { /* create MQD for each KGQ */ for (i = 0; i < adev->gfx.num_gfx_rings; i++) { ring = &adev->gfx.gfx_ring[i]; if (!ring->mqd_obj) { r = amdgpu_bo_create_kernel(adev, AMDGPU_MQD_SIZE_ALIGN(gfx_mqd_size), PAGE_SIZE, domain, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd bo (%d)", r); return r; } ring->mqd_size = gfx_mqd_size; /* prepare MQD backup */ adev->gfx.me.mqd_backup[i] = kzalloc(gfx_mqd_size, GFP_KERNEL); if (!adev->gfx.me.mqd_backup[i]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } } } /* create MQD for each KCQ */ for (i = 0; i < adev->gfx.num_compute_rings; i++) { j = i + xcc_id * adev->gfx.num_compute_rings; ring = &adev->gfx.compute_ring[j]; if (!ring->mqd_obj) { r = amdgpu_bo_create_kernel(adev, AMDGPU_MQD_SIZE_ALIGN(compute_mqd_size), PAGE_SIZE, domain, &ring->mqd_obj, &ring->mqd_gpu_addr, &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd bo (%d)", r); return r; } ring->mqd_size = compute_mqd_size; /* prepare MQD backup */ adev->gfx.mec.mqd_backup[j] = kzalloc(compute_mqd_size, GFP_KERNEL); if (!adev->gfx.mec.mqd_backup[j]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; } } } return 0; } void amdgpu_gfx_mqd_sw_fini(struct amdgpu_device *adev, int xcc_id)