[PATCH V1 2/6] accel/amdxdna: Add basic support for AIE4 devices

Lizhi Hou
2026-03-30T16:37:31Z

From: David Zhang <yidong.zhang@amd.com>

Add initial support for AIE4 devices (PCI device IDs 0x17F2 and 0x1B0B),
including:
Device initialization
Basic mailbox communication
SR-IOV enablement

This lays the groundwork for full AIE4 support.

Co-developed-by: Hayden Laccabue <Hayden.Laccabue@amd.com>
Signed-off-by: Hayden Laccabue <Hayden.Laccabue@amd.com>
Signed-off-by: David Zhang <yidong.zhang@amd.com>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
---
drivers/accel/amdxdna/Makefile | 5 +
drivers/accel/amdxdna/aie.h | 3 +
drivers/accel/amdxdna/aie2_pci.c | 2 +-
drivers/accel/amdxdna/aie2_pci.h | 3 -
drivers/accel/amdxdna/aie2_smu.c | 2 +-
drivers/accel/amdxdna/aie4_message.c | 27 ++
drivers/accel/amdxdna/aie4_msg_priv.h | 49 ++++
drivers/accel/amdxdna/aie4_pci.c | 364 ++++++++++++++++++++++++
drivers/accel/amdxdna/aie4_pci.h | 48 ++++
drivers/accel/amdxdna/aie4_sriov.c | 88 ++++++
drivers/accel/amdxdna/amdxdna_mailbox.c | 19 +-
drivers/accel/amdxdna/amdxdna_mailbox.h | 8 +-
drivers/accel/amdxdna/amdxdna_pci_drv.c | 19 +-
drivers/accel/amdxdna/amdxdna_pci_drv.h | 2 +
drivers/accel/amdxdna/npu3_regs.c | 39 +++
include/uapi/drm/amdxdna_accel.h | 3 +-
16 files changed, 666 insertions(+), 15 deletions(-)
create mode 100644 drivers/accel/amdxdna/aie4_message.c
create mode 100644 drivers/accel/amdxdna/aie4_msg_priv.h
create mode 100644 drivers/accel/amdxdna/aie4_pci.c
create mode 100644 drivers/accel/amdxdna/aie4_pci.h
create mode 100644 drivers/accel/amdxdna/aie4_sriov.c
create mode 100644 drivers/accel/amdxdna/npu3_regs.c

diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile
index 5c7911554c46..a61cd6c0db30 100644
--- a/drivers/accel/amdxdna/Makefile
+++ b/drivers/accel/amdxdna/Makefile
@@ -10,6 +10,8 @@ amdxdna-y := \
aie2_psp.o \
aie2_smu.o \
aie2_solver.o \
+ aie4_message.o \
+ aie4_pci.o \
amdxdna_ctx.o \
amdxdna_gem.o \
amdxdna_iommu.o \
@@ -20,7 +22,10 @@ amdxdna-y := \
amdxdna_sysfs.o \
amdxdna_ubuf.o \
npu1_regs.o \
+ npu3_regs.o \
npu4_regs.o \
npu5_regs.o \
npu6_regs.o
+
+amdxdna-$(CONFIG_PCI_IOV) += aie4_sriov.o
obj-$(CONFIG_DRM_ACCEL_AMDXDNA) = amdxdna.o
diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h
index 1bea14b79c7c..6c53870d0098 100644
--- a/drivers/accel/amdxdna/aie.h
+++ b/drivers/accel/amdxdna/aie.h
@@ -8,6 +8,9 @@
#include "amdxdna_pci_drv.h"
#include "amdxdna_mailbox.h"

+#define AIE_INTERVAL 20000 /* us */
+#define AIE_TIMEOUT 1000000 /* us */
+
struct aie_device {
struct amdxdna_dev *xdna;
struct mailbox_channel *mgmt_chann;
diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c
index 03bac963516d..708d0b7fd2e3 100644
--- a/drivers/accel/amdxdna/aie2_pci.c
+++ b/drivers/accel/amdxdna/aie2_pci.c
@@ -79,7 +79,7 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev)
* is alive.
*/
ret = readx_poll_timeout(readl, SRAM_GET_ADDR(ndev, FW_ALIVE_OFF),
- addr, addr, AIE2_INTERVAL, AIE2_TIMEOUT);
+ addr, addr, AIE_INTERVAL, AIE_TIMEOUT);
if (ret || !addr)
return -ETIME;

diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h
index 90fb0aafaf40..96960a2219a4 100644
--- a/drivers/accel/amdxdna/aie2_pci.h
+++ b/drivers/accel/amdxdna/aie2_pci.h
@@ -14,9 +14,6 @@
#include "aie2_msg_priv.h"
#include "amdxdna_mailbox.h"

-#define AIE2_INTERVAL 20000 /* us */
-#define AIE2_TIMEOUT 1000000 /* us */
-
/* Firmware determines device memory base address and size */
#define AIE2_DEVM_BASE 0x4000000
#define AIE2_DEVM_SIZE SZ_64M
diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c
index 727637dac3a8..1b966bbef2e5 100644
--- a/drivers/accel/amdxdna/aie2_smu.c
+++ b/drivers/accel/amdxdna/aie2_smu.c
@@ -44,7 +44,7 @@ static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd,
writel(1, SMU_REG(ndev, SMU_INTR_REG));

ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp,
- resp, AIE2_INTERVAL, AIE2_TIMEOUT);
+ resp, AIE_INTERVAL, AIE_TIMEOUT);
if (ret) {
XDNA_ERR(ndev->aie.xdna, "smu cmd %d timed out", reg_cmd);
return ret;
diff --git a/drivers/accel/amdxdna/aie4_message.c b/drivers/accel/amdxdna/aie4_message.c
new file mode 100644
index 000000000000..d621dd32ac40
--- /dev/null
+++ b/drivers/accel/amdxdna/aie4_message.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <drm/amdxdna_accel.h>
+#include <drm/drm_print.h>
+#include <linux/mutex.h>
+
+#include "aie.h"
+#include "aie4_msg_priv.h"
+#include "aie4_pci.h"
+#include "amdxdna_mailbox.h"
+#include "amdxdna_mailbox_helper.h"
+#include "amdxdna_pci_drv.h"
+
+int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev)
+{
+ DECLARE_AIE_MSG(aie4_msg_suspend, AIE4_MSG_OP_SUSPEND);
+ int ret;
+
+ ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
+ if (ret)
+ XDNA_ERR(ndev->aie.xdna, "Failed to suspend fw, ret %d", ret);
+
+ return ret;
+}
diff --git a/drivers/accel/amdxdna/aie4_msg_priv.h b/drivers/accel/amdxdna/aie4_msg_priv.h
new file mode 100644
index 000000000000..88463cc3a98a
--- /dev/null
+++ b/drivers/accel/amdxdna/aie4_msg_priv.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#ifndef _AIE4_MSG_PRIV_H_
+#define _AIE4_MSG_PRIV_H_
+
+#include <linux/types.h>
+
+enum aie4_msg_opcode {
+ AIE4_MSG_OP_SUSPEND = 0x10003,
+
+ AIE4_MSG_OP_CREATE_VFS = 0x20001,
+ AIE4_MSG_OP_DESTROY_VFS = 0x20002,
+};
+
+enum aie4_msg_status {
+ AIE4_MSG_STATUS_SUCCESS = 0x0,
+ AIE4_MSG_STATUS_ERROR = 0x1,
+ AIE4_MSG_STATUS_NOTSUPP = 0x2,
+ MAX_AIE4_MSG_STATUS_CODE = 0x4,
+};
+
+struct aie4_msg_suspend_req {
+ __u32 rsvd;
+} __packed;
+
+struct aie4_msg_suspend_resp {
+ enum aie4_msg_status status;
+} __packed;
+
+struct aie4_msg_create_vfs_req {
+ __u32 vf_cnt;
+} __packed;
+
+struct aie4_msg_create_vfs_resp {
+ enum aie4_msg_status status;
+} __packed;
+
+struct aie4_msg_destroy_vfs_req {
+ __u32 rsvd;
+} __packed;
+
+struct aie4_msg_destroy_vfs_resp {
+ enum aie4_msg_status status;
+} __packed;
+
+#endif /* _AIE4_MSG_PRIV_H_ */
diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c
new file mode 100644
index 000000000000..0f360c1ccebd
--- /dev/null
+++ b/drivers/accel/amdxdna/aie4_pci.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <drm/amdxdna_accel.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_print.h>
+
+#include "aie4_pci.h"
+#include "amdxdna_pci_drv.h"
+
+#define NO_IOHUB 0
+
+/*
+ * The management mailbox channel is allocated by firmware.
+ * The related register and ring buffer information is on SRAM BAR.
+ * This struct is the register layout.
+ */
+struct mailbox_info {
+ __u32 valid;
+ __u32 protocol_major;
+ __u32 protocol_minor;
+ __u32 x2i_tail_offset;
+ __u32 x2i_head_offset;
+ __u32 x2i_buffer_addr;
+ __u32 x2i_buffer_size;
+ __u32 i2x_tail_offset;
+ __u32 i2x_head_offset;
+ __u32 i2x_buffer_addr;
+ __u32 i2x_buffer_size;
+ __u32 i2x_msi_idx;
+ __u32 reserved[4];
+};
+
+static int aie4_fw_is_alive(struct amdxdna_dev *xdna)
+{
+ const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+ u32 __iomem *src;
+ u32 fw_is_valid;
+ int ret;
+
+ src = ndev->rbuf_base + npriv->mbox_info_off;
+
+ ret = readx_poll_timeout(readl, src + offsetof(struct mailbox_info, valid),
+ fw_is_valid, (fw_is_valid == 0x1),
+ AIE_INTERVAL, AIE_TIMEOUT);
+ if (ret)
+ XDNA_ERR(xdna, "fw_is_valid=%d after %d ms",
+ fw_is_valid, DIV_ROUND_CLOSEST(AIE_TIMEOUT, 1000000));
+
+ return ret;
+}
+
+static void aie4_read_mbox_info(struct amdxdna_dev *xdna,
+ struct mailbox_info *mbox_info)
+{
+ const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+ u32 *dst = (u32 *)mbox_info;
+ u32 __iomem *src;
+ int i;
+
+ src = ndev->rbuf_base + npriv->mbox_info_off;
+
+ for (i = 0; i < sizeof(*mbox_info) / sizeof(u32); i++)
+ dst[i] = readl(&src[i]);
+}
+
+static int aie4_mailbox_info(struct amdxdna_dev *xdna,
+ struct mailbox_info *mbox_info)
+{
+ int ret;
+
+ ret = aie4_fw_is_alive(xdna);
+ if (ret)
+ return ret;
+
+ aie4_read_mbox_info(xdna, mbox_info);
+
+ ret = aie_check_protocol(&xdna->dev_handle->aie,
+ mbox_info->protocol_major,
+ mbox_info->protocol_minor);
+ if (ret)
+ XDNA_ERR(xdna, "mailbox major.minor %d.%d is not supported",
+ mbox_info->protocol_major, mbox_info->protocol_minor);
+
+ return ret;
+}
+
+static void aie4_mailbox_fini(struct amdxdna_dev_hdl *ndev)
+{
+ struct amdxdna_dev *xdna = ndev->aie.xdna;
+
+ aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann);
+ drmm_kfree(&xdna->ddev, ndev->mbox);
+ ndev->mbox = NULL;
+}
+
+static int aie4_irq_init(struct amdxdna_dev *xdna)
+{
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+ int ret, nvec;
+
+ nvec = pci_msix_vec_count(pdev);
+ XDNA_DBG(xdna, "irq vectors:%d", nvec);
+ if (nvec <= 0) {
+ XDNA_ERR(xdna, "does not get number of interrupt vector");
+ return -EINVAL;
+ }
+
+ ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
+ if (ret < 0) {
+ XDNA_ERR(xdna, "failed to alloc irq vector, ret: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aie4_mailbox_start(struct amdxdna_dev *xdna,
+ struct mailbox_info *mbi)
+{
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+ const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
+ struct xdna_mailbox_chann_res *i2x;
+ struct xdna_mailbox_chann_res *x2i;
+ int mgmt_mb_irq;
+ int ret;
+
+ struct xdna_mailbox_res mbox_res = {
+ .ringbuf_base = ndev->rbuf_base,
+ .ringbuf_size = pci_resource_len(pdev, npriv->mbox_rbuf_bar),
+ .mbox_base = ndev->mbox_base,
+ .mbox_size = pci_resource_len(pdev, npriv->mbox_bar),
+ .name = "xdna_aie4_mailbox",
+ };
+
+ i2x = &ndev->aie.mgmt_i2x;
+ x2i = &ndev->aie.mgmt_x2i;
+
+ x2i->mb_head_ptr_reg = mbi->x2i_head_offset;
+ x2i->mb_tail_ptr_reg = mbi->x2i_tail_offset;
+ x2i->rb_start_addr = mbi->x2i_buffer_addr;
+ x2i->rb_size = mbi->x2i_buffer_size;
+
+ i2x->rb_start_addr = mbi->i2x_buffer_addr;
+ i2x->rb_size = mbi->i2x_buffer_size;
+ i2x->mb_head_ptr_reg = mbi->i2x_head_offset;
+ i2x->mb_tail_ptr_reg = mbi->i2x_tail_offset;
+
+ ndev->aie.mgmt_chan_idx = mbi->i2x_msi_idx;
+ aie_dump_mgmt_chann_debug(&ndev->aie);
+
+ ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
+ if (!ndev->mbox) {
+ XDNA_ERR(xdna, "failed to create mailbox device");
+ return -ENODEV;
+ }
+
+ ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
+ if (!ndev->aie.mgmt_chann) {
+ XDNA_ERR(xdna, "failed to alloc mailbox channel");
+ return -ENODEV;
+ }
+
+ mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx);
+ if (mgmt_mb_irq < 0) {
+ XDNA_ERR(xdna, "failed to alloc irq vector, return %d", mgmt_mb_irq);
+ ret = mgmt_mb_irq;
+ goto free_channel;
+ }
+
+ ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
+ &ndev->aie.mgmt_x2i,
+ &ndev->aie.mgmt_i2x,
+ NO_IOHUB,
+ mgmt_mb_irq);
+ if (ret) {
+ XDNA_ERR(xdna, "failed to start management mailbox channel");
+ ret = -EINVAL;
+ goto free_channel;
+ }
+
+ XDNA_DBG(xdna, "Mailbox management channel created");
+ return 0;
+
+free_channel:
+ xdna_mailbox_free_channel(ndev->aie.mgmt_chann);
+ ndev->aie.mgmt_chann = NULL;
+ return ret;
+}
+
+static int aie4_mailbox_init(struct amdxdna_dev *xdna)
+{
+ struct mailbox_info mbox_info;
+ int ret;
+
+ ret = aie4_mailbox_info(xdna, &mbox_info);
+ if (ret)
+ return ret;
+
+ return aie4_mailbox_start(xdna, &mbox_info);
+}
+
+static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev)
+{
+ /* TODO */
+}
+
+static int aie4_fw_load(struct amdxdna_dev_hdl *ndev)
+{
+ /* TODO */
+ return 0;
+}
+
+static int aie4_hw_start(struct amdxdna_dev *xdna)
+{
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+ int ret;
+
+ ret = aie4_fw_load(ndev);
+ if (ret)
+ return ret;
+
+ ret = aie4_mailbox_init(xdna);
+ if (ret)
+ goto fw_unload;
+
+ return 0;
+
+fw_unload:
+ aie4_fw_unload(ndev);
+
+ return ret;
+}
+
+static void aie4_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev)
+{
+ int ret;
+
+ /* No paired resume needed, fw is stateless */
+ ret = aie4_suspend_fw(ndev);
+ if (ret)
+ XDNA_ERR(ndev->aie.xdna, "suspend_fw failed, ret %d", ret);
+ else
+ XDNA_DBG(ndev->aie.xdna, "npu firmware suspended");
+}
+
+static void aie4_hw_stop(struct amdxdna_dev *xdna)
+{
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+
+ drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
+
+ aie4_mgmt_fw_fini(ndev);
+ aie4_mailbox_fini(ndev);
+
+ aie4_fw_unload(ndev);
+}
+
+static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev)
+{
+ struct amdxdna_dev *xdna = ndev->aie.xdna;
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+ void __iomem *tbl[PCI_NUM_RESOURCES] = {0};
+ unsigned long bars = 0;
+ int ret, i;
+
+ /* Enable managed PCI device */
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ XDNA_ERR(xdna, "pcim enable device failed, ret %d", ret);
+ return ret;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ XDNA_ERR(xdna, "failed to set DMA mask to 64:%d", ret);
+ return ret;
+ }
+
+ set_bit(xdna->dev_info->mbox_bar, &bars);
+ set_bit(xdna->dev_info->sram_bar, &bars);
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (!test_bit(i, &bars))
+ continue;
+ tbl[i] = pcim_iomap(pdev, i, 0);
+ if (!tbl[i]) {
+ XDNA_ERR(xdna, "map bar %d failed", i);
+ return -ENOMEM;
+ }
+ }
+
+ ndev->mbox_base = tbl[xdna->dev_info->mbox_bar];
+ ndev->rbuf_base = tbl[xdna->dev_info->sram_bar];
+
+ pci_set_master(pdev);
+
+ ret = aie4_irq_init(xdna);
+ if (ret)
+ goto clear_master;
+
+ ret = aie4_hw_start(xdna);
+ if (ret)
+ goto clear_master;
+
+ return 0;
+
+clear_master:
+ pci_clear_master(pdev);
+
+ return ret;
+}
+
+static void aie4_pcidev_fini(struct amdxdna_dev_hdl *ndev)
+{
+ struct amdxdna_dev *xdna = ndev->aie.xdna;
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+
+ aie4_hw_stop(xdna);
+
+ pci_clear_master(pdev);
+}
+
+static void aie4_fini(struct amdxdna_dev *xdna)
+{
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+
+ aie4_sriov_stop(ndev);
+ aie4_pcidev_fini(ndev);
+}
+
+static int aie4_init(struct amdxdna_dev *xdna)
+{
+ struct amdxdna_dev_hdl *ndev;
+ int ret;
+
+ ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL);
+ if (!ndev)
+ return -ENOMEM;
+
+ ndev->priv = xdna->dev_info->dev_priv;
+ ndev->aie.xdna = xdna;
+ xdna->dev_handle = ndev;
+
+ ret = aie4_pcidev_init(ndev);
+ if (ret) {
+ XDNA_ERR(xdna, "Setup PCI device failed, ret %d", ret);
+ return ret;
+ }
+
+ XDNA_DBG(xdna, "aie4 init finished");
+ return 0;
+}
+
+const struct amdxdna_dev_ops aie4_ops = {
+ .init = aie4_init,
+ .fini = aie4_fini,
+ .sriov_configure = aie4_sriov_configure,
+};
diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h
new file mode 100644
index 000000000000..f3810a969431
--- /dev/null
+++ b/drivers/accel/amdxdna/aie4_pci.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#ifndef _AIE4_PCI_H_
+#define _AIE4_PCI_H_
+
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/pci.h>
+
+#include "aie.h"
+#include "amdxdna_mailbox.h"
+
+struct amdxdna_dev_priv {
+ u32 mbox_bar;
+ u32 mbox_rbuf_bar;
+ u64 mbox_info_off;
+};
+
+struct amdxdna_dev_hdl {
+ struct aie_device aie;
+ const struct amdxdna_dev_priv *priv;
+ void __iomem *mbox_base;
+ void __iomem *rbuf_base;
+
+ struct mailbox *mbox;
+};
+
+/* aie4_message.c */
+int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev);
+
+/* aie4_sriov.c */
+#if IS_ENABLED(CONFIG_PCI_IOV)
+int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs);
+int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev);
+#else
+#define aie4_sriov_configure NULL
+static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev)
+{
+ return 0;
+}
+#endif
+
+extern const struct amdxdna_dev_ops aie4_ops;
+
+#endif /* _AIE4_PCI_H_ */
diff --git a/drivers/accel/amdxdna/aie4_sriov.c b/drivers/accel/amdxdna/aie4_sriov.c
new file mode 100644
index 000000000000..e1ce633768a5
--- /dev/null
+++ b/drivers/accel/amdxdna/aie4_sriov.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <drm/amdxdna_accel.h>
+#include <drm/drm_print.h>
+#include <linux/pci.h>
+
+#include "aie.h"
+#include "aie4_msg_priv.h"
+#include "aie4_pci.h"
+#include "amdxdna_mailbox.h"
+#include "amdxdna_mailbox_helper.h"
+#include "amdxdna_pci_drv.h"
+
+static int aie4_destroy_vfs(struct amdxdna_dev_hdl *ndev)
+{
+ DECLARE_AIE_MSG(aie4_msg_destroy_vfs, AIE4_MSG_OP_DESTROY_VFS);
+ int ret;
+
+ ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
+ if (ret)
+ XDNA_ERR(ndev->aie.xdna, "destroy vfs op failed: %d", ret);
+
+ return ret;
+}
+
+static int aie4_create_vfs(struct amdxdna_dev_hdl *ndev, int num_vfs)
+{
+ DECLARE_AIE_MSG(aie4_msg_create_vfs, AIE4_MSG_OP_CREATE_VFS);
+ int ret;
+
+ req.vf_cnt = num_vfs;
+ ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
+ if (ret)
+ XDNA_ERR(ndev->aie.xdna, "create vfs op failed: %d", ret);
+
+ return ret;
+}
+
+int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev)
+{
+ struct amdxdna_dev *xdna = ndev->aie.xdna;
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+ int ret;
+
+ if (!pci_num_vf(pdev))
+ return 0;
+
+ ret = pci_vfs_assigned(pdev);
+ if (ret) {
+ XDNA_ERR(xdna, "VFs are still assigned to VMs");
+ return -EPERM;
+ }
+
+ pci_disable_sriov(pdev);
+ return aie4_destroy_vfs(ndev);
+}
+
+static int aie4_sriov_start(struct amdxdna_dev_hdl *ndev, int num_vfs)
+{
+ struct amdxdna_dev *xdna = ndev->aie.xdna;
+ struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+ int ret;
+
+ ret = aie4_create_vfs(ndev, num_vfs);
+ if (ret)
+ return ret;
+
+ ret = pci_enable_sriov(pdev, num_vfs);
+ if (ret) {
+ XDNA_ERR(xdna, "configure VFs failed, ret: %d", ret);
+ aie4_destroy_vfs(ndev);
+ return ret;
+ }
+
+ return num_vfs;
+}
+
+int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs)
+{
+ struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+
+ drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
+
+ return (num_vfs) ? aie4_sriov_start(ndev, num_vfs) : aie4_sriov_stop(ndev);
+}
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index e681a090752d..84a7e92562ad 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -112,6 +112,18 @@ static u32 mailbox_reg_read(struct mailbox_channel *mb_chann, u32 mbox_reg)
return readl(ringbuf_addr);
}

+static inline void mailbox_irq_acknowledge(struct mailbox_channel *mb_chann)
+{
+ if (mb_chann->iohub_int_addr)
+ mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
+}
+
+static inline u32 mailbox_irq_status(struct mailbox_channel *mb_chann)
+{
+ return (mb_chann->iohub_int_addr) ?
+ mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr) : 0;
+}
+
static inline void
mailbox_set_headptr(struct mailbox_channel *mb_chann, u32 headptr_val)
{
@@ -199,7 +211,6 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg)
start_addr = mb_chann->res[CHAN_RES_X2I].rb_start_addr;
tmp_tail = tail + mb_msg->pkg_size;

-
check_again:
if (tail >= head && tmp_tail > ringbuf_size) {
write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail;
@@ -357,7 +368,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
}

again:
- mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
+ mailbox_irq_acknowledge(mb_chann);

while (1) {
/*
@@ -382,7 +393,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
* the interrupt register to make sure there is not any new response
* before exiting.
*/
- if (mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr))
+ if (mailbox_irq_status(mb_chann))
goto again;
}

@@ -520,7 +531,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
}

mb_chann->bad_state = false;
- mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
+ mailbox_irq_acknowledge(mb_chann);

MB_DBG(mb_chann, "Mailbox channel started (irq: %d)", mb_chann->msix_irq);
return 0;
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.h b/drivers/accel/amdxdna/amdxdna_mailbox.h
index 8b1e00945da4..2908404303ae 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.h
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.h
@@ -1,10 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
+ * Copyright (C) 2022-2026, Advanced Micro Devices, Inc.
*/

-#ifndef _AIE2_MAILBOX_H_
-#define _AIE2_MAILBOX_H_
+#ifndef _AIE_MAILBOX_H_
+#define _AIE_MAILBOX_H_

struct mailbox;
struct mailbox_channel;
@@ -124,4 +124,4 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
int xdna_mailbox_send_msg(struct mailbox_channel *mailbox_chann,
const struct xdna_mailbox_msg *msg, u64 tx_timeout);

-#endif /* _AIE2_MAILBOX_ */
+#endif /* _AIE_MAILBOX_ */
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c
index b50a7d1f8a11..09d7d88bb6f1 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c
@@ -37,9 +37,10 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin");
* 0.6: Support preemption
* 0.7: Support getting power and utilization data
* 0.8: Support BO usage query
+ * 0.9: Add new device type AMDXDNA_DEV_TYPE_PF
*/
#define AMDXDNA_DRIVER_MAJOR 0
-#define AMDXDNA_DRIVER_MINOR 8
+#define AMDXDNA_DRIVER_MINOR 9

/*
* Bind the driver base on (vendor_id, device_id) pair and later use the
@@ -49,6 +50,8 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin");
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0B) },
{0}
};

@@ -59,6 +62,8 @@ static const struct amdxdna_device_id amdxdna_ids[] = {
{ 0x17f0, 0x10, &dev_npu4_info },
{ 0x17f0, 0x11, &dev_npu5_info },
{ 0x17f0, 0x20, &dev_npu6_info },
+ { 0x17f2, 0x10, &dev_npu3_pf_info },
+ { 0x1B0B, 0x10, &dev_npu3_pf_info },
{0}
};

@@ -365,12 +370,24 @@ static const struct dev_pm_ops amdxdna_pm_ops = {
RUNTIME_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume, NULL)
};

+static int amdxdna_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
+
+ guard(mutex)(&xdna->dev_lock);
+ if (xdna->dev_info->ops->sriov_configure)
+ return xdna->dev_info->ops->sriov_configure(xdna, num_vfs);
+
+ return -ENOENT;
+}
+
static struct pci_driver amdxdna_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = pci_ids,
.probe = amdxdna_probe,
.remove = amdxdna_remove,
.driver.pm = &amdxdna_pm_ops,
+ .sriov_configure = amdxdna_sriov_configure,
};

module_pci_driver(amdxdna_pci_driver);
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h
index 5e0bf565a1ae..eabbf57f2b38 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h
@@ -55,6 +55,7 @@ struct amdxdna_dev_ops {
void (*fini)(struct amdxdna_dev *xdna);
int (*resume)(struct amdxdna_dev *xdna);
int (*suspend)(struct amdxdna_dev *xdna);
+ int (*sriov_configure)(struct amdxdna_dev *xdna, int num_vfs);
int (*hwctx_init)(struct amdxdna_hwctx *hwctx);
void (*hwctx_fini)(struct amdxdna_hwctx *hwctx);
int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
@@ -157,6 +158,7 @@ struct amdxdna_client {

/* Add device info below */
extern const struct amdxdna_dev_info dev_npu1_info;
+extern const struct amdxdna_dev_info dev_npu3_pf_info;
extern const struct amdxdna_dev_info dev_npu4_info;
extern const struct amdxdna_dev_info dev_npu5_info;
extern const struct amdxdna_dev_info dev_npu6_info;
diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c
new file mode 100644
index 000000000000..f6e20f4858db
--- /dev/null
+++ b/drivers/accel/amdxdna/npu3_regs.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <drm/amdxdna_accel.h>
+#include <drm/drm_device.h>
+
+#include "aie4_pci.h"
+#include "amdxdna_pci_drv.h"
+
+#define NPU3_MBOX_BAR 0
+
+#define NPU3_MBOX_BUFFER_BAR 2
+#define NPU3_MBOX_INFO_OFF 0x0
+
+/* PCIe BAR Index for NPU3 */
+#define NPU3_REG_BAR_INDEX 0
+
+static const struct amdxdna_fw_feature_tbl npu3_fw_feature_table[] = {
+ { .major = 5, .min_minor = 10 },
+ { 0 }
+};
+
+static const struct amdxdna_dev_priv npu3_dev_priv = {
+ .mbox_bar = NPU3_MBOX_BAR,
+ .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR,
+ .mbox_info_off = NPU3_MBOX_INFO_OFF,
+};
+
+const struct amdxdna_dev_info dev_npu3_pf_info = {
+ .mbox_bar = NPU3_MBOX_BAR,
+ .sram_bar = NPU3_MBOX_BUFFER_BAR,
+ .vbnv = "RyzenAI-npu3-pf",
+ .device_type = AMDXDNA_DEV_TYPE_PF,
+ .dev_priv = &npu3_dev_priv,
+ .fw_feature_tbl = npu3_fw_feature_table,
+ .ops = &aie4_ops,
+};
diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h
index 61d3686fa3b1..0b11e8e3ea5d 100644
--- a/include/uapi/drm/amdxdna_accel.h
+++ b/include/uapi/drm/amdxdna_accel.h
@@ -29,7 +29,8 @@ extern "C" {

enum amdxdna_device_type {
AMDXDNA_DEV_TYPE_UNKNOWN = -1,
- AMDXDNA_DEV_TYPE_KMQ,
+ AMDXDNA_DEV_TYPE_KMQ = 0,
+ AMDXDNA_DEV_TYPE_PF = 2,
};

enum amdxdna_drm_ioctl_id {
--
2.34.1