mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
amd-drm-fixes-7.3-2026-09-17:
amdgpu: - SMU 14.x fix - DC IRQ fix - Runtime PM fix for P2P - RAS fix - PCIe reporting fix - DCN 6 fix - Device removal fix - DC MALL fix amdkfd: - GC 12.x fixes - Boundary checks - Mapping clear fix -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCaqxIpQAKCRC93/aFa7yZ 2HcZAP9ZA5cERbp6QfT0a1tT3kDoMP02BKev5/XUNWEJjdgOYAEAsCj7UFE4oKjb 0996gK/lJvqq9lOgFTJnwl/z2jwytA0= =Ye34 -----END PGP SIGNATURE----- Merge tag 'amd-drm-fixes-7.3-2026-09-17' of https://gitlab.freedesktop.org/drm/amdgpu/kernel into drm-fixes amd-drm-fixes-7.3-2026-09-17: amdgpu: - SMU 14.x fix - DC IRQ fix - Runtime PM fix for P2P - RAS fix - PCIe reporting fix - DCN 6 fix - Device removal fix - DC MALL fix amdkfd: - GC 12.x fixes - Boundary checks - Mapping clear fix Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20260917201213.3880863-1-alexander.deucher@amd.com
This commit is contained in:
commit
94f69bfa18
|
|
@ -621,6 +621,9 @@ enum amdgpu_enforce_isolation_mode {
|
|||
struct amdgpu_device {
|
||||
struct device *dev;
|
||||
struct pci_dev *pdev;
|
||||
/* The two ends of the physical PCIe link outside the device. */
|
||||
struct pci_dev *link_dev;
|
||||
struct pci_dev *link_partner;
|
||||
struct drm_device ddev;
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_ACP
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
|
|||
struct kfd_dev *kfd = adev->kfd.dev;
|
||||
unsigned int i;
|
||||
|
||||
if (!kfd)
|
||||
if (!kfd || !kfd->init_complete)
|
||||
return;
|
||||
|
||||
for (i = 0; i < kfd->num_nodes; i++) {
|
||||
|
|
|
|||
|
|
@ -1954,18 +1954,17 @@ static void amdgpu_uid_fini(struct amdgpu_device *adev)
|
|||
adev->uid_info = NULL;
|
||||
}
|
||||
|
||||
static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
|
||||
static void amdgpu_device_init_pcie_links(struct amdgpu_device *adev)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
adev->link_dev = adev->pdev;
|
||||
adev->link_partner = pci_upstream_bridge(adev->link_dev);
|
||||
|
||||
/* skip upstream/downstream switches internal to dGPU */
|
||||
while ((parent = pci_upstream_bridge(parent))) {
|
||||
if (parent->vendor == PCI_VENDOR_ID_ATI)
|
||||
continue;
|
||||
break;
|
||||
/* Skip upstream/downstream switches internal to the dGPU. */
|
||||
while (adev->link_partner &&
|
||||
adev->link_partner->vendor == PCI_VENDOR_ID_ATI) {
|
||||
adev->link_dev = adev->link_partner;
|
||||
adev->link_partner = pci_upstream_bridge(adev->link_dev);
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1981,7 +1980,6 @@ static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
|
|||
static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
struct pci_dev *parent;
|
||||
bool total, skip_bios, early_full_gpu_access = false;
|
||||
uint32_t bios_flags;
|
||||
int i, r;
|
||||
|
|
@ -2077,10 +2075,9 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
|||
!dev_is_removable(&adev->pdev->dev))
|
||||
adev->flags |= AMD_IS_PX;
|
||||
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
parent = amdgpu_device_find_parent(adev);
|
||||
adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
|
||||
}
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
adev->has_pr3 = adev->link_partner &&
|
||||
pci_pr3_present(adev->link_partner);
|
||||
|
||||
adev->pm.pp_feature = amdgpu_pp_feature_mask;
|
||||
if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS)
|
||||
|
|
@ -3776,6 +3773,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
|
||||
adev->shutdown = false;
|
||||
adev->flags = flags;
|
||||
amdgpu_device_init_pcie_links(adev);
|
||||
|
||||
if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST)
|
||||
adev->asic_type = amdgpu_force_asic_type;
|
||||
|
|
@ -4337,7 +4335,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
|||
|
||||
void amdgpu_device_fini_sw(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, idx;
|
||||
int i;
|
||||
bool px;
|
||||
|
||||
amdgpu_device_ip_fini(adev);
|
||||
|
|
@ -4379,11 +4377,9 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
|
|||
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
|
||||
vga_client_unregister(adev->pdev);
|
||||
|
||||
if (drm_dev_enter(adev_to_drm(adev), &idx)) {
|
||||
|
||||
if (adev->rmmio) {
|
||||
iounmap(adev->rmmio);
|
||||
adev->rmmio = NULL;
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PERF_EVENTS))
|
||||
|
|
@ -5872,11 +5868,9 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
|
|||
*width = PCIE_LNK_WIDTH_UNKNOWN;
|
||||
|
||||
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
|
||||
struct pci_dev *parent = amdgpu_device_find_parent(adev);
|
||||
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
if (adev->link_partner) {
|
||||
*speed = pcie_get_speed_cap(adev->link_partner);
|
||||
*width = pcie_get_width_cap(adev->link_partner);
|
||||
}
|
||||
} else {
|
||||
/* use the current speeds rather than max if switching is not supported */
|
||||
|
|
@ -5898,21 +5892,11 @@ static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
|
|||
enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
|
||||
if (!speed || !width)
|
||||
return;
|
||||
|
||||
/* use the device itself */
|
||||
*speed = pcie_get_speed_cap(adev->pdev);
|
||||
*width = pcie_get_width_cap(adev->pdev);
|
||||
|
||||
/* use the link outside the device */
|
||||
parent = amdgpu_device_find_parent(adev);
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
}
|
||||
*speed = pcie_get_speed_cap(adev->link_dev);
|
||||
*width = pcie_get_width_cap(adev->link_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <linux/pci-p2pdma.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops;
|
||||
|
||||
|
|
@ -100,15 +101,54 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
|
|||
pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0)
|
||||
attach->peer2peer = false;
|
||||
|
||||
/*
|
||||
* Only allow P2P while the exporter is active, and keep it active
|
||||
* until detach. With runtime PM disabled take a plain reference so
|
||||
* the put in detach stays balanced.
|
||||
*/
|
||||
if (attach->peer2peer) {
|
||||
struct device *dev = adev_to_drm(adev)->dev;
|
||||
int ret = pm_runtime_get_if_active(dev);
|
||||
|
||||
if (!ret)
|
||||
attach->peer2peer = false;
|
||||
else if (ret < 0)
|
||||
pm_runtime_get_noresume(dev);
|
||||
}
|
||||
|
||||
r = dma_resv_lock(bo->tbo.base.resv, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
goto err_pm_put;
|
||||
|
||||
amdgpu_vm_bo_update_shared(bo);
|
||||
|
||||
dma_resv_unlock(bo->tbo.base.resv);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_put:
|
||||
if (attach->peer2peer)
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dma_buf_detach - &dma_buf_ops.detach implementation
|
||||
*
|
||||
* @dmabuf: DMA-buf where we remove the attachment from
|
||||
* @attach: the attachment to remove
|
||||
*
|
||||
* Drop the runtime PM reference taken in amdgpu_dma_buf_attach().
|
||||
*/
|
||||
static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct drm_gem_object *obj = dmabuf->priv;
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
|
||||
if (attach->peer2peer)
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -350,6 +390,7 @@ static void amdgpu_dma_buf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map
|
|||
|
||||
const struct dma_buf_ops amdgpu_dmabuf_ops = {
|
||||
.attach = amdgpu_dma_buf_attach,
|
||||
.detach = amdgpu_dma_buf_detach,
|
||||
.pin = amdgpu_dma_buf_pin,
|
||||
.unpin = amdgpu_dma_buf_unpin,
|
||||
.map_dma_buf = amdgpu_dma_buf_map,
|
||||
|
|
|
|||
|
|
@ -535,7 +535,7 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device
|
|||
RAS_CNTLR_INTERRUPT_CLEAR, 1);
|
||||
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl);
|
||||
|
||||
if (!ras->disable_ras_err_cnt_harvest) {
|
||||
if (ras && !ras->disable_ras_err_cnt_harvest && obj) {
|
||||
/*
|
||||
* clear error status after ras_controller_intr
|
||||
* according to hw team and count ue number
|
||||
|
|
|
|||
|
|
@ -770,10 +770,12 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
|
|||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
pr_debug("restore_mqd not implemented for queue type %d\n",
|
||||
q->properties.type);
|
||||
retval = -EOPNOTSUPP;
|
||||
goto deallocate_vmid;
|
||||
}
|
||||
|
||||
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
|
||||
retval = allocate_hqd(dqm, q);
|
||||
if (retval)
|
||||
|
|
@ -2250,7 +2252,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
|
|||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
pr_debug("restore_mqd not implemented for queue type %d\n",
|
||||
q->properties.type);
|
||||
retval = -EOPNOTSUPP;
|
||||
goto out_deallocate_doorbell;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
@ -380,6 +380,63 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
|
|||
|
||||
#endif
|
||||
|
||||
static void restore_mqd(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp, const void *mqd_src,
|
||||
const void *ctl_stack_src, const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_compute_mqd *m;
|
||||
|
||||
m = (struct v12_compute_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
/* Update MQD base address to the newly allocated location */
|
||||
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
|
||||
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
|
||||
|
||||
m->cp_hqd_pq_doorbell_control &=
|
||||
~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
|
||||
m->cp_hqd_pq_doorbell_control |=
|
||||
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
const void *ctl_stack_src,
|
||||
const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_sdma_mqd *m;
|
||||
|
||||
m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
m->sdmax_rlcx_doorbell_offset =
|
||||
qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
||||
struct kfd_node *dev)
|
||||
{
|
||||
|
|
@ -407,6 +464,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
|||
mqd->mqd_size = sizeof(struct v12_compute_mqd);
|
||||
mqd->get_wave_state = get_wave_state;
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd;
|
||||
#endif
|
||||
|
|
@ -453,6 +511,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
|||
mqd->is_occupied = kfd_is_occupied_sdma;
|
||||
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_sdma;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
@ -641,6 +641,72 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
|
|||
|
||||
#endif
|
||||
|
||||
static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp, const void *mqd_src,
|
||||
const void *ctl_stack_src, const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_1_compute_mqd *m;
|
||||
|
||||
/*
|
||||
* GFX12.1 is multi-XCC capable but this restore handles XCC0 only.
|
||||
* Multi-XCC CRIU restore is currently unreachable because
|
||||
* kfd_criu_restore_queue() validates against unscaled mqd_size.
|
||||
*/
|
||||
if (NUM_XCC(mm->dev->xcc_mask) > 1)
|
||||
pr_warn_once("GFX12.1 multi-XCC CRIU restore not fully supported\n");
|
||||
|
||||
m = (struct v12_1_compute_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
|
||||
NUM_XCC(mm->dev->xcc_mask));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
/* Update MQD base address to the newly allocated location */
|
||||
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
|
||||
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
|
||||
|
||||
m->cp_hqd_pq_doorbell_control &=
|
||||
~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
|
||||
m->cp_hqd_pq_doorbell_control |=
|
||||
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void restore_mqd_sdma_v12_1(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
const void *ctl_stack_src,
|
||||
const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_sdma_mqd *m;
|
||||
|
||||
m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
m->sdmax_rlcx_doorbell_offset =
|
||||
qp->doorbell_off << SDMA0_SDMA_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
||||
struct kfd_node *dev)
|
||||
{
|
||||
|
|
@ -668,6 +734,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
|||
mqd->mqd_size = sizeof(struct v12_1_compute_mqd);
|
||||
mqd->get_wave_state = get_wave_state_v12_1;
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_v12_1;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd;
|
||||
#endif
|
||||
|
|
@ -714,6 +781,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
|||
mqd->is_occupied = kfd_is_occupied_sdma;
|
||||
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_sdma_v12_1;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -285,6 +285,10 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
1 << CP_HQD_IB_CONTROL__IB_EXE_DISABLE__SHIFT;
|
||||
|
||||
/*
|
||||
* The lowest 6 bits of eop_control store the EOP ring size. If
|
||||
* their value is X, the ring size is 2^(X + 1) dwords, or
|
||||
* 2^(X + 3) bytes.
|
||||
*
|
||||
* HW does not clamp this field correctly. Maximum EOP queue size
|
||||
* is constrained by per-SE EOP done signal count, which is 8-bit.
|
||||
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
|
||||
|
|
@ -296,7 +300,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
*
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ?
|
||||
min(0xA, order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
|
||||
min(0xA, order_base_2(q->eop_ring_buffer_size / 8)) : 0;
|
||||
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT;
|
||||
|
||||
/*
|
||||
* The lowest 6 bits of eop_control store the EOP ring size. If
|
||||
* their value is X, the ring size is 2^(X + 1) dwords, or
|
||||
* 2^(X + 3) bytes.
|
||||
* HW does not clamp this field correctly. Maximum EOP queue size
|
||||
* is constrained by per-SE EOP done signal count, which is 8-bit.
|
||||
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
|
||||
|
|
@ -215,7 +218,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control |= q->eop_ring_buffer_size ? min(0xA,
|
||||
order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
|
||||
order_base_2(q->eop_ring_buffer_size / 8)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -1420,7 +1420,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
|||
if (acrtc && state->stream_status[i].plane_count != 0 &&
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
|
||||
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
|
||||
if (rc)
|
||||
drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
|
@ -1444,7 +1444,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
|||
/* During gpu-reset we disable and then enable vblank irq, so
|
||||
* don't use amdgpu_irq_get/put() to avoid refcount change.
|
||||
*/
|
||||
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
|
||||
if (!amdgpu_dm_irq_set(adev, irq_source, enable))
|
||||
drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
|
||||
|
||||
} else if (acrtc && state->stream_status[i].plane_count != 0) {
|
||||
|
|
|
|||
|
|
@ -552,6 +552,18 @@ struct amdgpu_display_manager {
|
|||
struct common_irq_params
|
||||
vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
|
||||
|
||||
/**
|
||||
* @irq_reg_lock:
|
||||
*
|
||||
* Serializes the read-modify-writes of the HW interrupt control
|
||||
* registers. Several interrupt sources share one register - e.g. the
|
||||
* enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK
|
||||
* live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must
|
||||
* not race with acking another. Held only across amdgpu_dm_irq_set()
|
||||
* and amdgpu_dm_irq_ack().
|
||||
*/
|
||||
spinlock_t irq_reg_lock;
|
||||
|
||||
/**
|
||||
* @dmub_trace_params:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "amdgpu_dm_psr.h"
|
||||
#include "amdgpu_dm_replay.h"
|
||||
#include "amdgpu_dm_crtc.h"
|
||||
#include "amdgpu_dm_irq.h"
|
||||
#include "amdgpu_dm_plane.h"
|
||||
#include "amdgpu_dm_trace.h"
|
||||
#include "amdgpu_dm_debugfs.h"
|
||||
|
|
@ -91,7 +92,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
|
|||
|
||||
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
|
||||
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
|
||||
|
||||
DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
|
||||
acrtc->crtc_id, enable ? "en" : "dis", rc);
|
||||
|
|
|
|||
|
|
@ -1439,12 +1439,13 @@ void dm_helpers_free_gpu_mem(
|
|||
|
||||
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
|
||||
{
|
||||
struct amdgpu_device *adev = ctx->driver_context;
|
||||
enum dc_irq_source irq_source;
|
||||
bool ret;
|
||||
|
||||
irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
|
||||
|
||||
ret = dc_interrupt_set(ctx->dc, irq_source, enable);
|
||||
ret = amdgpu_dm_irq_set(adev, irq_source, enable);
|
||||
|
||||
DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
|
||||
enable ? "en" : "dis", ret);
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
|
|||
DRM_DEBUG_KMS("DM_IRQ\n");
|
||||
|
||||
spin_lock_init(&adev->dm.irq_handler_list_table_lock);
|
||||
spin_lock_init(&adev->dm.irq_reg_lock);
|
||||
|
||||
adev->dm.irq_wq = alloc_workqueue("amdgpu_dm_irq",
|
||||
WQ_UNBOUND | WQ_HIGHPRI, 0);
|
||||
|
|
@ -530,7 +531,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
|
|||
*/
|
||||
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
|
||||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
dc_interrupt_set(adev->dm.dc, src, false);
|
||||
amdgpu_dm_irq_set(adev, src, false);
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
||||
|
|
@ -568,7 +569,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
|
|||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
|
||||
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
|
||||
dc_interrupt_set(adev->dm.dc, src, true);
|
||||
amdgpu_dm_irq_set(adev, src, true);
|
||||
}
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
|
@ -594,7 +595,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
|
|||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
|
||||
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
|
||||
dc_interrupt_set(adev->dm.dc, src, true);
|
||||
amdgpu_dm_irq_set(adev, src, true);
|
||||
}
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
|
@ -690,6 +691,23 @@ STATIC_IFN_KUNIT void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
|
|||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_immediate_work);
|
||||
|
||||
bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
|
||||
bool enable)
|
||||
{
|
||||
guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
|
||||
|
||||
return dc_interrupt_set(adev->dm.dc, src, enable);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_set);
|
||||
|
||||
void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src)
|
||||
{
|
||||
guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
|
||||
|
||||
dc_interrupt_ack(adev->dm.dc, src);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_ack);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_handler - Generic DM IRQ handler
|
||||
* @adev: amdgpu base driver device containing the DM device
|
||||
|
|
@ -710,7 +728,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
|
|||
entry->src_id,
|
||||
entry->src_data[0]);
|
||||
|
||||
dc_interrupt_ack(adev->dm.dc, src);
|
||||
amdgpu_dm_irq_ack(adev, src);
|
||||
|
||||
/* Call high irq work immediately */
|
||||
amdgpu_dm_irq_immediate_work(adev, src);
|
||||
|
|
@ -750,7 +768,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev,
|
|||
enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type);
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, src, st);
|
||||
amdgpu_dm_irq_set(adev, src, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_hpd_irq_state);
|
||||
|
|
@ -785,7 +803,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
|
|||
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
|
||||
dc_allow_idle_optimizations(dc, false);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -842,7 +860,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *a
|
|||
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_outbox_irq_state);
|
||||
|
|
@ -870,7 +888,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_trace_irq_state(struct amdgpu_device *ad
|
|||
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0;
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_trace_irq_state);
|
||||
|
|
@ -937,9 +955,7 @@ EXPORT_IF_KUNIT(amdgpu_dm_set_irq_funcs);
|
|||
|
||||
void amdgpu_dm_outbox_init(struct amdgpu_device *adev)
|
||||
{
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
DC_IRQ_SOURCE_DMCUB_OUTBOX,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, DC_IRQ_SOURCE_DMCUB_OUTBOX, true);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_outbox_init);
|
||||
|
||||
|
|
@ -962,7 +978,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
|
||||
/* First, clear all hpd and hpdrx interrupts */
|
||||
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
|
||||
if (!dc_interrupt_set(adev->dm.dc, i, false))
|
||||
if (!amdgpu_dm_irq_set(adev, i, false))
|
||||
drm_err(dev, "Failed to clear hpd(rx) source=%d on init\n",
|
||||
i);
|
||||
}
|
||||
|
|
@ -991,7 +1007,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
* of dm. Note that only hpd interrupt types are registered with
|
||||
* base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
|
||||
* hpd_rx isn't available. DM currently controls hpd_rx
|
||||
* explicitly with dc_interrupt_set()
|
||||
* explicitly with amdgpu_dm_irq_set()
|
||||
*/
|
||||
if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
|
||||
irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
|
||||
|
|
@ -1000,23 +1016,21 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
* and what bios reports as the # of connectors with hpd
|
||||
* sources. Since the # of hpd source types registered
|
||||
* with base driver == mode_info.num_hpd, we have to
|
||||
* fallback to dc_interrupt_set for the remaining types.
|
||||
* fallback to amdgpu_dm_irq_set for the remaining types.
|
||||
*/
|
||||
if (irq_type < adev->mode_info.num_hpd) {
|
||||
if (amdgpu_irq_get(adev, &adev->hpd_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Failed get HPD for source=%d)!\n",
|
||||
dc_link->irq_source_hpd);
|
||||
} else {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd_rx,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
|
||||
true);
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&iter);
|
||||
|
|
@ -1061,16 +1075,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
|
|||
drm_err(dev, "DM_IRQ: Failed put HPD for source=%d!\n",
|
||||
dc_link->irq_source_hpd);
|
||||
} else {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd,
|
||||
false);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd_rx,
|
||||
false);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
|
||||
false);
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&iter);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
|
|||
enum dc_irq_source irq_source,
|
||||
void *ih_index);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_set - enable or disable a DC interrupt source.
|
||||
*
|
||||
* @adev: AMD DRM device
|
||||
* @src: DC interrupt source to toggle
|
||||
* @enable: true to enable the source, false to disable it
|
||||
*
|
||||
* DM-wide replacement for dc_interrupt_set(). As locking is DM's
|
||||
* responsibility, this is a thin wrapper serializes the underlying
|
||||
* read-modify-write against the other interrupt sources sharing HW control
|
||||
* registers with @src, so DM must never call dc_interrupt_set() directly.
|
||||
*
|
||||
* Returns: true if the source was toggled.
|
||||
*/
|
||||
bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
|
||||
bool enable);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_ack - acknowledge a DC interrupt source.
|
||||
*
|
||||
* @adev: AMD DRM device
|
||||
* @src: DC interrupt source to acknowledge
|
||||
*
|
||||
* DM-wide replacement for dc_interrupt_ack(), serialized the same way as
|
||||
* amdgpu_dm_irq_set().
|
||||
*/
|
||||
void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src);
|
||||
|
||||
void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test)
|
|||
* dm_test_crtc_set_vupdate_irq_dc_busy - Test vupdate irq when DC rejects request
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* With an OTG instance assigned but no DC attached, dc_interrupt_set() returns
|
||||
* With an OTG instance assigned but no DC attached, amdgpu_dm_irq_set() returns
|
||||
* false and the function must report the request as busy (-EBUSY).
|
||||
*/
|
||||
static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
|
||||
|
|
@ -453,12 +453,12 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
|
|||
acrtc->base.dev = &adev->ddev;
|
||||
acrtc->otg_inst = 0;
|
||||
|
||||
/* adev->dm.dc is NULL, so dc_interrupt_set() returns false. */
|
||||
/* adev->dm.dc is NULL, so amdgpu_dm_irq_set() returns false. */
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true), -EBUSY);
|
||||
}
|
||||
|
||||
/* Per-source funcs let dc_interrupt_set() succeed without register access. */
|
||||
/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
|
||||
static bool dm_test_vupdate_irq_src_set(struct irq_service *irq_service,
|
||||
const struct irq_source_info *info,
|
||||
bool enable)
|
||||
|
|
@ -477,7 +477,7 @@ static struct irq_source_info_funcs dm_test_vupdate_irq_src_funcs = {
|
|||
.ack = dm_test_vupdate_irq_src_ack,
|
||||
};
|
||||
|
||||
/* A .set that fails so dc_interrupt_set() reports the source as busy. */
|
||||
/* A .set that fails so amdgpu_dm_irq_set() reports the source as busy. */
|
||||
static bool dm_test_vupdate_irq_src_set_busy(struct irq_service *irq_service,
|
||||
const struct irq_source_info *info,
|
||||
bool enable)
|
||||
|
|
@ -519,7 +519,9 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test)
|
|||
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/* Populate the per-source info table so dc_interrupt_set() succeeds. */
|
||||
/*
|
||||
* Populate the per-source info table so amdgpu_dm_irq_set() succeeds.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
|
||||
|
|
@ -1018,7 +1020,9 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test)
|
|||
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/* Per-source .set fails so dc_interrupt_set() reports the source busy. */
|
||||
/*
|
||||
* Per-source .set fails so amdgpu_dm_irq_set() reports the source busy.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
|
||||
|
|
|
|||
|
|
@ -2442,17 +2442,21 @@ static void dm_test_is_dp_sink_present_null_priv(struct kunit *test)
|
|||
* dm_test_dmub_outbox_interrupt_control_null_dc - Test outbox irq control with NULL dc
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* dc_interrupt_set() is NULL-safe and returns false when dc is NULL, so the
|
||||
* amdgpu_dm_irq_set() is NULL-safe and returns false when dc is NULL, so the
|
||||
* helper returns false without touching real interrupt hardware.
|
||||
*/
|
||||
static void dm_test_dmub_outbox_interrupt_control_null_dc(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_device *adev;
|
||||
struct dc_context *ctx;
|
||||
|
||||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, adev);
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx);
|
||||
ctx->driver_context = adev;
|
||||
|
||||
/* ctx->dc is NULL → dc_interrupt_set returns false */
|
||||
/* adev->dm.dc is NULL → amdgpu_dm_irq_set returns false */
|
||||
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, true));
|
||||
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ static bool dm_test_irq_src_ack(struct irq_service *irq_service,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Per-source funcs let dc_interrupt_set() succeed without register access. */
|
||||
/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
|
||||
static struct irq_source_info_funcs dm_test_irq_src_funcs = {
|
||||
.set = dm_test_irq_src_set,
|
||||
.ack = dm_test_irq_src_ack,
|
||||
|
|
@ -290,7 +290,7 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
|
|||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/*
|
||||
* Populate the per-source info table so dc_interrupt_set()/_ack()
|
||||
* Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
|
||||
* succeed without touching hardware registers.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
|
|
@ -1227,7 +1227,7 @@ static void dm_test_irq_suspend_empty(struct kunit *test)
|
|||
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
|
||||
|
||||
/*
|
||||
* With no registered handlers the HW dc_interrupt_set() calls are
|
||||
* With no registered handlers the amdgpu_dm_irq_set() calls are
|
||||
* skipped, so suspend must complete without touching the (absent) DC.
|
||||
*/
|
||||
amdgpu_dm_irq_suspend(adev);
|
||||
|
|
@ -1275,11 +1275,11 @@ static void dm_test_irq_resume_late_empty(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_suspend_registered - Test suspend reaches the dc_interrupt_set path
|
||||
* dm_test_irq_suspend_registered - Test suspend reaches the irq set path
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD handler so the handler list is non-empty,
|
||||
* forcing amdgpu_dm_irq_suspend() to call dc_interrupt_set() (NULL-safe with
|
||||
* forcing amdgpu_dm_irq_suspend() to call amdgpu_dm_irq_set() (NULL-safe with
|
||||
* no DC) and flush_work() on the registered handler.
|
||||
*/
|
||||
static void dm_test_irq_suspend_registered(struct kunit *test)
|
||||
|
|
@ -1330,11 +1330,11 @@ static void dm_test_irq_suspend_disables_polling(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_resume_early_registered - Test early resume reaches dc_interrupt_set
|
||||
* dm_test_irq_resume_early_registered - Test early resume reaches irq set
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD RX handler so early resume calls
|
||||
* dc_interrupt_set() for the short-pulse interrupt source.
|
||||
* amdgpu_dm_irq_set() for the short-pulse interrupt source.
|
||||
*/
|
||||
static void dm_test_irq_resume_early_registered(struct kunit *test)
|
||||
{
|
||||
|
|
@ -1358,10 +1358,10 @@ static void dm_test_irq_resume_early_registered(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_resume_late_registered - Test late resume reaches dc_interrupt_set
|
||||
* dm_test_irq_resume_late_registered - Test late resume reaches irq set
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD handler so late resume calls dc_interrupt_set()
|
||||
* Registers a low-context HPD handler so late resume calls amdgpu_dm_irq_set()
|
||||
* for the HPD interrupt source.
|
||||
*/
|
||||
static void dm_test_irq_resume_late_registered(struct kunit *test)
|
||||
|
|
@ -1592,7 +1592,7 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
|
|||
|
||||
/*
|
||||
* otg_inst >= 0 computes the irq source and reaches the NULL-safe
|
||||
* dc_interrupt_set(); the ips_support branch is skipped (dc == NULL).
|
||||
* amdgpu_dm_irq_set(); the ips_support branch is skipped (dc == NULL).
|
||||
*/
|
||||
acrtc->otg_inst = 3;
|
||||
adev->mode_info.crtcs[0] = acrtc;
|
||||
|
|
@ -1671,8 +1671,8 @@ static void dm_test_set_vupdate_irq_state_enable(struct kunit *test)
|
|||
*
|
||||
* With a non-NULL DC that advertises IPS support and currently allows idle
|
||||
* optimizations, dm_irq_state() must call dc_allow_idle_optimizations() before
|
||||
* dc_interrupt_set(). disable_idle_power_optimizations makes that call a safe
|
||||
* early return, and per-source stub funcs let dc_interrupt_set() succeed.
|
||||
* amdgpu_dm_irq_set(). disable_idle_power_optimizations makes that call a safe
|
||||
* early return, and per-source stub funcs let amdgpu_dm_irq_set() succeed.
|
||||
*/
|
||||
static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
|
||||
{
|
||||
|
|
@ -1891,7 +1891,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
|
|||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
|
||||
|
||||
/* dc_interrupt_set() is a no-op when dc is NULL, so both states
|
||||
/* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
|
||||
* return 0 without dereferencing the (absent) DC.
|
||||
*/
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
|
||||
|
|
@ -1951,7 +1951,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test)
|
|||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
|
||||
|
||||
/* Single dc_interrupt_set() call must be skipped when dc is NULL. */
|
||||
/* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
|
||||
amdgpu_dm_outbox_init(adev);
|
||||
}
|
||||
|
||||
|
|
@ -1969,7 +1969,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test)
|
|||
|
||||
/*
|
||||
* With an empty connector list the per-connector loop is skipped and
|
||||
* the initial clear loop relies on dc_interrupt_set() being a no-op
|
||||
* the initial clear loop relies on amdgpu_dm_irq_set() being a no-op
|
||||
* for a NULL dc, so init must complete without touching the DC.
|
||||
*/
|
||||
amdgpu_dm_hpd_init(adev);
|
||||
|
|
@ -2004,7 +2004,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
|
|||
|
||||
/*
|
||||
* num_hpd = 0 forces irq_type >= num_hpd so the loop takes the HW
|
||||
* fallback (dc_interrupt_set()) instead of amdgpu_irq_get(); with a
|
||||
* fallback (amdgpu_dm_irq_set()) instead of amdgpu_irq_get(); with a
|
||||
* NULL dc that fallback is a safe no-op.
|
||||
*/
|
||||
adev->mode_info.num_hpd = 0;
|
||||
|
|
@ -2090,7 +2090,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
|
|||
/*
|
||||
* num_hpd >= 1 makes irq_type (0) < num_hpd, so the loop takes the
|
||||
* amdgpu_irq_get()/amdgpu_irq_put() branch instead of the
|
||||
* dc_interrupt_set() fallback. The mock device has irq.installed ==
|
||||
* amdgpu_dm_irq_set() fallback. The mock device has irq.installed ==
|
||||
* false, so both calls fail early with -ENOENT (logging an error)
|
||||
* without touching the base-driver irq state.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1064,10 +1064,12 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
|||
*/
|
||||
unsigned int denom = refresh_hz * 6528;
|
||||
unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
|
||||
uint64_t num = (1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent);
|
||||
uint64_t tmr_ticks;
|
||||
|
||||
tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
|
||||
denom) - 64LL);
|
||||
tmr_ticks = div_u64(num + denom - 1, denom);
|
||||
tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
|
||||
|
||||
/* In some cases the stutter period is really big (tiny modes) in these
|
||||
* cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
|
||||
|
|
@ -1089,9 +1091,8 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
|||
}
|
||||
|
||||
denom *= 2;
|
||||
tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
|
||||
denom) - 64LL);
|
||||
tmr_ticks = div_u64(num + denom - 1, denom);
|
||||
tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
|
||||
}
|
||||
|
||||
/* Copy HW cursor */
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ static void dcn50_initialize_min_clocks(struct dc *dc)
|
|||
* audio corruption. Read current DISPCLK from DENTIST and request the same
|
||||
* freq to ensure that the timing is valid and unchanged.
|
||||
*/
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
if (dc->clk_mgr->funcs->get_dispclk_from_dentist)
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
}
|
||||
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
|
||||
clocks->fclk_p_state_change_support = true;
|
||||
|
|
@ -639,7 +640,8 @@ void dcn50_init_hw(struct dc *dc)
|
|||
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
|
||||
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
|
||||
|
||||
dcn50_initialize_min_clocks(dc);
|
||||
if (dc->clk_mgr && dc->clk_mgr->funcs)
|
||||
dcn50_initialize_min_clocks(dc);
|
||||
|
||||
/* On HW init, allow idle optimizations after pipes have been turned off.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -643,7 +643,8 @@ void dcn60_init_hw(struct dc *dc)
|
|||
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
|
||||
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
|
||||
|
||||
dcn401_initialize_min_clocks(dc);
|
||||
if (dc->clk_mgr && dc->clk_mgr->funcs)
|
||||
dcn401_initialize_min_clocks(dc);
|
||||
|
||||
/* On HW init, allow idle optimizations after pipes have been turned off.
|
||||
*
|
||||
|
|
@ -1001,6 +1002,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
|
|||
/**
|
||||
* dcn60_update_probe_status - Set the valid flag on a latched probe result.
|
||||
* @status: result sink whose u was written by the GET BLS step during execute
|
||||
* @probe: current probe state used to determine measurement type and validity
|
||||
*/
|
||||
static void dcn60_update_probe_status(struct dc_probe_status *status)
|
||||
{
|
||||
|
|
@ -1024,6 +1026,7 @@ static void dcn60_update_probe_status(struct dc_probe_status *status)
|
|||
/**
|
||||
* is_probe_measurement_type_for_hubbub - Returns true if the probe type is
|
||||
* served by the hubbub perfmon block on DCN60.
|
||||
* @type: the probe measurement type to classify
|
||||
*/
|
||||
static bool is_probe_measurement_type_for_hubbub(enum dc_probe_type type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2142,6 +2142,7 @@ static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu)
|
|||
static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
||||
void **table)
|
||||
{
|
||||
uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
|
||||
struct gpu_metrics_v1_3 *gpu_metrics =
|
||||
(struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
|
||||
smu, SMU_DRIVER_TABLE_GPU_METRICS);
|
||||
|
|
@ -2171,6 +2172,8 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
if (mp1_ver == IP_VERSION(14, 0, 3) && smu->smc_fw_version >= 0x00685000)
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user