// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright 2014-2022 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"kfd_priv.h" #include <linux/mm.h> #include <linux/mman.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/idr.h>
/* * This extension supports a kernel level doorbells management for the * kernel queues using the first doorbell page reserved for the kernel.
*/
/* * Each device exposes a doorbell aperture, a PCI MMIO aperture that * receives 32-bit writes that are passed to queues as wptr values. * The doorbells are intended to be written by applications as part * of queueing work on user-mode queues. * We assign doorbells to applications in PAGE_SIZE-sized and aligned chunks. * We map the doorbell address space into user-mode when a process creates * its first queue on each device. * Although the mapping is done by KFD, it is equivalent to an mmap of * the /dev/kfd with the particular device encoded in the mmap offset. * There will be other uses for mmap of /dev/kfd, so only a range of * offsets (KFD_MMAP_DOORBELL_START-END) is used for doorbells.
*/
/* # of doorbell bytes allocated for each process. */
size_t kfd_doorbell_process_slice(struct kfd_dev *kfd)
{ if (!kfd->shared_resources.enable_mes) return roundup(kfd->device_info.doorbell_size *
KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
PAGE_SIZE); else return amdgpu_mes_doorbell_process_slice(
(struct amdgpu_device *)kfd->adev);
}
/* Doorbell calculations for device init. */ int kfd_doorbell_init(struct kfd_dev *kfd)
{ int size = PAGE_SIZE; int r;
/* * Todo: KFD kernel level operations need only one doorbell for * ring test/HWS. So instead of reserving a whole page here for * kernel, reserve and consume a doorbell from existing KGD kernel * doorbell page.
*/
/* Bitmap to dynamically allocate doorbells from kernel page */
kfd->doorbell_bitmap = bitmap_zalloc(size / sizeof(u32), GFP_KERNEL); if (!kfd->doorbell_bitmap) {
DRM_ERROR("Failed to allocate kernel doorbell bitmap\n"); return -ENOMEM;
}
/* Alloc a doorbell page for KFD kernel usages */
r = amdgpu_bo_create_kernel(kfd->adev,
size,
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_DOORBELL,
&kfd->doorbells,
NULL,
(void **)&kfd->doorbell_kernel_ptr); if (r) {
pr_err("failed to allocate kernel doorbells\n");
bitmap_free(kfd->doorbell_bitmap); return r;
}
/* * For simplicitly we only allow mapping of the entire doorbell * allocation of a single device & process.
*/ if (vma->vm_end - vma->vm_start != kfd_doorbell_process_slice(dev->kfd)) return -EINVAL;
pdd = kfd_get_process_device_data(dev, process); if (!pdd) return -EINVAL;
staticint init_doorbell_bitmap(struct qcm_process_device *qpd, struct kfd_dev *dev)
{ unsignedint i; int range_start = dev->shared_resources.non_cp_doorbells_start; int range_end = dev->shared_resources.non_cp_doorbells_end;
if (!KFD_IS_SOC15(dev)) return 0;
/* Mask out doorbells reserved for SDMA, IH, and VCN on SOC15. */
pr_debug("reserved doorbell 0x%03x - 0x%03x\n", range_start, range_end);
pr_debug("reserved doorbell 0x%03x - 0x%03x\n",
range_start + KFD_QUEUE_DOORBELL_MIRROR_OFFSET,
range_end + KFD_QUEUE_DOORBELL_MIRROR_OFFSET);
for (i = 0; i < KFD_MAX_NUM_OF_QUEUES_PER_PROCESS / 2; i++) { if (i >= range_start && i <= range_end) {
__set_bit(i, qpd->doorbell_bitmap);
__set_bit(i + KFD_QUEUE_DOORBELL_MIRROR_OFFSET,
qpd->doorbell_bitmap);
}
}
int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *pdd)
{ int r; struct qcm_process_device *qpd = &pdd->qpd;
/* Allocate bitmap for dynamic doorbell allocation */
qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
GFP_KERNEL); if (!qpd->doorbell_bitmap) {
DRM_ERROR("Failed to allocate process doorbell bitmap\n"); return -ENOMEM;
}
r = init_doorbell_bitmap(&pdd->qpd, kfd); if (r) {
DRM_ERROR("Failed to initialize process doorbells\n");
r = -ENOMEM; goto err;
}
/* Allocate doorbells for this process */
r = amdgpu_bo_create_kernel(kfd->adev,
kfd_doorbell_process_slice(kfd),
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_DOORBELL,
&qpd->proc_doorbells,
NULL,
NULL); if (r) {
DRM_ERROR("Failed to allocate process doorbells\n"); goto err;
} return 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.