15a55a5daSLizhi Hou // SPDX-License-Identifier: GPL-2.0 25a55a5daSLizhi Hou /* 35a55a5daSLizhi Hou * Copyright (C) 2026, Advanced Micro Devices, Inc. 45a55a5daSLizhi Hou */ 55a55a5daSLizhi Hou 65a55a5daSLizhi Hou #include <linux/errno.h> 75a55a5daSLizhi Hou 85a55a5daSLizhi Hou #include "aie.h" 95a55a5daSLizhi Hou #include "amdxdna_mailbox_helper.h" 105a55a5daSLizhi Hou #include "amdxdna_mailbox.h" 115a55a5daSLizhi Hou #include "amdxdna_pci_drv.h" 125a55a5daSLizhi Hou 135a55a5daSLizhi Hou void aie_dump_mgmt_chann_debug(struct aie_device *aie) 145a55a5daSLizhi Hou { 155a55a5daSLizhi Hou struct amdxdna_dev *xdna = aie->xdna; 165a55a5daSLizhi Hou 175a55a5daSLizhi Hou XDNA_DBG(xdna, "i2x tail 0x%x", aie->mgmt_i2x.mb_tail_ptr_reg); 185a55a5daSLizhi Hou XDNA_DBG(xdna, "i2x head 0x%x", aie->mgmt_i2x.mb_head_ptr_reg); 195a55a5daSLizhi Hou XDNA_DBG(xdna, "i2x ringbuf 0x%x", aie->mgmt_i2x.rb_start_addr); 205a55a5daSLizhi Hou XDNA_DBG(xdna, "i2x rsize 0x%x", aie->mgmt_i2x.rb_size); 215a55a5daSLizhi Hou XDNA_DBG(xdna, "x2i tail 0x%x", aie->mgmt_x2i.mb_tail_ptr_reg); 225a55a5daSLizhi Hou XDNA_DBG(xdna, "x2i head 0x%x", aie->mgmt_x2i.mb_head_ptr_reg); 235a55a5daSLizhi Hou XDNA_DBG(xdna, "x2i ringbuf 0x%x", aie->mgmt_x2i.rb_start_addr); 245a55a5daSLizhi Hou XDNA_DBG(xdna, "x2i rsize 0x%x", aie->mgmt_x2i.rb_size); 255a55a5daSLizhi Hou XDNA_DBG(xdna, "x2i chann index 0x%x", aie->mgmt_chan_idx); 265a55a5daSLizhi Hou XDNA_DBG(xdna, "mailbox protocol major 0x%x", aie->mgmt_prot_major); 275a55a5daSLizhi Hou XDNA_DBG(xdna, "mailbox protocol minor 0x%x", aie->mgmt_prot_minor); 285a55a5daSLizhi Hou } 295a55a5daSLizhi Hou 305a55a5daSLizhi Hou void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann) 315a55a5daSLizhi Hou { 325a55a5daSLizhi Hou struct amdxdna_dev *xdna = aie->xdna; 335a55a5daSLizhi Hou 345a55a5daSLizhi Hou drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); 355a55a5daSLizhi Hou 365a55a5daSLizhi Hou if (!*chann) 375a55a5daSLizhi Hou return; 385a55a5daSLizhi Hou 395a55a5daSLizhi Hou xdna_mailbox_stop_channel(*chann); 405a55a5daSLizhi Hou xdna_mailbox_free_channel(*chann); 415a55a5daSLizhi Hou *chann = NULL; 425a55a5daSLizhi Hou } 435a55a5daSLizhi Hou 445a55a5daSLizhi Hou int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg) 455a55a5daSLizhi Hou { 465a55a5daSLizhi Hou struct amdxdna_dev *xdna = aie->xdna; 475a55a5daSLizhi Hou struct xdna_notify *hdl = msg->handle; 485a55a5daSLizhi Hou int ret; 495a55a5daSLizhi Hou 505a55a5daSLizhi Hou drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); 515a55a5daSLizhi Hou 525a55a5daSLizhi Hou if (!aie->mgmt_chann) 535a55a5daSLizhi Hou return -ENODEV; 545a55a5daSLizhi Hou 555a55a5daSLizhi Hou ret = xdna_send_msg_wait(xdna, aie->mgmt_chann, msg); 565a55a5daSLizhi Hou if (ret == -ETIME) 575a55a5daSLizhi Hou aie_destroy_chann(aie, &aie->mgmt_chann); 585a55a5daSLizhi Hou 595a55a5daSLizhi Hou if (!ret && *hdl->status) { 605a55a5daSLizhi Hou XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x", 615a55a5daSLizhi Hou msg->opcode, *hdl->data); 625a55a5daSLizhi Hou ret = -EINVAL; 635a55a5daSLizhi Hou } 645a55a5daSLizhi Hou 655a55a5daSLizhi Hou return ret; 665a55a5daSLizhi Hou } 675a55a5daSLizhi Hou 685a55a5daSLizhi Hou int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor) 695a55a5daSLizhi Hou { 705a55a5daSLizhi Hou const struct amdxdna_fw_feature_tbl *feature; 715a55a5daSLizhi Hou bool found = false; 725a55a5daSLizhi Hou 735a55a5daSLizhi Hou for (feature = aie->xdna->dev_info->fw_feature_tbl; 745a55a5daSLizhi Hou feature->major; feature++) { 755a55a5daSLizhi Hou if (feature->major != fw_major) 765a55a5daSLizhi Hou continue; 775a55a5daSLizhi Hou if (fw_minor < feature->min_minor) 785a55a5daSLizhi Hou continue; 795a55a5daSLizhi Hou if (feature->max_minor > 0 && fw_minor > feature->max_minor) 805a55a5daSLizhi Hou continue; 815a55a5daSLizhi Hou 825a55a5daSLizhi Hou aie->feature_mask |= feature->features; 835a55a5daSLizhi Hou 845a55a5daSLizhi Hou /* firmware version matches one of the driver support entry */ 855a55a5daSLizhi Hou found = true; 865a55a5daSLizhi Hou } 875a55a5daSLizhi Hou 885a55a5daSLizhi Hou return found ? 0 : -EOPNOTSUPP; 895a55a5daSLizhi Hou } 90d8c33b9cSMax Zhen 91d8c33b9cSMax Zhen static void amdxdna_update_vbnv(struct amdxdna_dev *xdna, 92d8c33b9cSMax Zhen const struct amdxdna_rev_vbnv *tbl, 93d8c33b9cSMax Zhen u32 rev) 94d8c33b9cSMax Zhen { 95d8c33b9cSMax Zhen int i; 96d8c33b9cSMax Zhen 97d8c33b9cSMax Zhen for (i = 0; tbl[i].vbnv; i++) { 98d8c33b9cSMax Zhen if (tbl[i].revision == rev) { 99d8c33b9cSMax Zhen xdna->vbnv = tbl[i].vbnv; 100d8c33b9cSMax Zhen break; 101d8c33b9cSMax Zhen } 102d8c33b9cSMax Zhen } 103d8c33b9cSMax Zhen } 104d8c33b9cSMax Zhen 105d8c33b9cSMax Zhen void amdxdna_vbnv_init(struct amdxdna_dev *xdna) 106d8c33b9cSMax Zhen { 107d8c33b9cSMax Zhen const struct amdxdna_dev_info *info = xdna->dev_info; 108d8c33b9cSMax Zhen u32 rev; 109d8c33b9cSMax Zhen 110d8c33b9cSMax Zhen xdna->vbnv = info->default_vbnv; 111d8c33b9cSMax Zhen 112d8c33b9cSMax Zhen if (!info->ops->get_dev_revision || !info->rev_vbnv_tbl) 113d8c33b9cSMax Zhen return; 114d8c33b9cSMax Zhen 115d8c33b9cSMax Zhen if (info->ops->get_dev_revision(xdna, &rev)) 116d8c33b9cSMax Zhen return; 117d8c33b9cSMax Zhen 118d8c33b9cSMax Zhen amdxdna_update_vbnv(xdna, info->rev_vbnv_tbl, rev); 119d8c33b9cSMax Zhen } 1200b087e06SDavid Zhang 1210b087e06SDavid Zhang int amdxdna_get_metadata(struct aie_device *aie, 1220b087e06SDavid Zhang struct amdxdna_client *client, 1230b087e06SDavid Zhang struct amdxdna_drm_get_info *args) 1240b087e06SDavid Zhang { 1250b087e06SDavid Zhang int ret = 0; 1260b087e06SDavid Zhang u32 buf_sz; 1270b087e06SDavid Zhang 1280b087e06SDavid Zhang buf_sz = min(args->buffer_size, sizeof(aie->metadata)); 1290b087e06SDavid Zhang if (copy_to_user(u64_to_user_ptr(args->buffer), &aie->metadata, buf_sz)) 1300b087e06SDavid Zhang ret = -EFAULT; 1310b087e06SDavid Zhang 1320b087e06SDavid Zhang return ret; 1330b087e06SDavid Zhang } 134*c0069781SNishad Saraf 135*c0069781SNishad Saraf void *amdxdna_alloc_msg_buffer(struct amdxdna_dev *xdna, u32 *size, 136*c0069781SNishad Saraf dma_addr_t *dma_addr) 137*c0069781SNishad Saraf { 138*c0069781SNishad Saraf void *vaddr; 139*c0069781SNishad Saraf int order; 140*c0069781SNishad Saraf 141*c0069781SNishad Saraf *size = max_t(u32, *size, SZ_8K); 142*c0069781SNishad Saraf order = get_order(*size); 143*c0069781SNishad Saraf if (order > MAX_PAGE_ORDER) 144*c0069781SNishad Saraf return ERR_PTR(-EINVAL); 145*c0069781SNishad Saraf *size = PAGE_SIZE << order; 146*c0069781SNishad Saraf 147*c0069781SNishad Saraf if (amdxdna_iova_on(xdna)) 148*c0069781SNishad Saraf return amdxdna_iommu_alloc(xdna, *size, dma_addr); 149*c0069781SNishad Saraf 150*c0069781SNishad Saraf vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, 151*c0069781SNishad Saraf DMA_FROM_DEVICE, GFP_KERNEL); 152*c0069781SNishad Saraf if (!vaddr) 153*c0069781SNishad Saraf return ERR_PTR(-ENOMEM); 154*c0069781SNishad Saraf 155*c0069781SNishad Saraf return vaddr; 156*c0069781SNishad Saraf } 157*c0069781SNishad Saraf 158*c0069781SNishad Saraf void amdxdna_free_msg_buffer(struct amdxdna_dev *xdna, size_t size, 159*c0069781SNishad Saraf void *cpu_addr, dma_addr_t dma_addr) 160*c0069781SNishad Saraf { 161*c0069781SNishad Saraf if (amdxdna_iova_on(xdna)) { 162*c0069781SNishad Saraf amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr); 163*c0069781SNishad Saraf return; 164*c0069781SNishad Saraf } 165*c0069781SNishad Saraf 166*c0069781SNishad Saraf dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE); 167*c0069781SNishad Saraf } 168