はじめに
このブログでも何度か取り上げた、AMD XDNA (Xilinx AI Engine) 。その Linux の driver が github に公開されました。
今回は、github の中をさっくり、覗いてみます。
どんな構成
Introduction に下記のような記載があります。
This repository is for supporting XRT on AMD XDNA devices. From this repository, you can build a XRT plugin DEB package. On a machine with XDNA device, with both XRT and XRT plugin packages installed, user can start using XDNA device on Linux.
そう、XRT、って、Xilinx の XRT です。つまり、Xilinx Runtime を使うわけです。
- OSは、Ubuntu 22.04
- Kernel は v6.7 with IOMMU SVA
- v6.7 with IOMMU SVA は、iommu_sva_v4_v6.7-rc8 branch on https://github.com/AMDESE/linux を使わないといけなさそうなので注意
- XRT は、https://github.com/Xilinx/XRT を使う
amdxdna
ドライバの本体は、amdxdna です。
amdxdna_drv.c の中を覗いてみたら、どうやら、PCIデバイスとなっています。
static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502), .class = PCI_CLASS_SP_OTHER << 8, /* Signal Processing */ .class_mask = 0xFFFF00, .driver_data = DEV_INFO_TO_DATA(1502), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0), .class = PCI_CLASS_SP_OTHER << 8, /* Signal Processing */ .class_mask = 0xFFFF00, .driver_data = DEV_INFO_TO_DATA(17f0), }, {0} }; MODULE_DEVICE_TABLE(pci, pci_ids);
デバイスIDが 0x1502 って、
で出てきた、IPU_device ですね。
で、0x17f0 は?
下記のように、PCI Driver になっていますね。
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, }; module_pci_driver(amdxdna_pci_driver);
IPU の初期化
XDNA は、IPUなので、IPUの初期化の部分(ipu_init)をみてみます。
ret = amdxdna_iommu_mode_setup(xdna); ret = iommu_dev_enable_feature(&xdna->pdev->dev, IOMMU_DEV_FEAT_SVA);
で、IOMMUを使っています。
ret = ipu_setup_pcidev(idev);
が IPU の初期化の部分ですかね。後で中をみてみます。
tbl = pcim_iomap_table(pdev);
idev->sram_base = tbl[xdna->dev_info->sram_bar];
idev->smu_base = tbl[xdna->dev_info->smu_bar];
SRAM と SMU の BAR の設定
ret = ipu_smu_init(idev);
SMU の初期化。。後で中をみてみます。
idev->psp_hdl = amdxdna_psp_create(&pdev->dev, &psp_conf);
PSP って何だろうか?あとでみてみます
ret = ipu_get_mgmt_chann_info(idev);
FIrmware 関連っぽいです。
mbox_res.ringbuf_base = (u64)idev->sram_base; mbox_res.ringbuf_size = pci_resource_len(xdna->pdev, xdna->dev_info->sram_bar); mbox_res.mbox_base = (u64)tbl[xdna->dev_info->mbox_bar]; mbox_res.mbox_size = MBOX_SIZE(idev); mbox_res.name = "xdna_mailbox"; xdna->mbox = xdna_mailbox_create(&mbox_res);
SRAMのBARを使って、Message Boxを使っています。
mgmt_mb_irq = pci_irq_vector(xdna->pdev, idev->mgmt_chan_idx);
割り込み
xdna_mailbox_intr_reg = idev->mgmt_i2x.mb_head_ptr_reg + 4; xdna->mgmt_chann = xdna_mailbox_create_channel(xdna->mbox, &idev->mgmt_x2i, &idev->mgmt_i2x, xdna_mailbox_intr_reg, mgmt_mb_irq);
Message Box の生成
ret = ipu_mgmt_fw_init(idev);
Firmware の初期化
xrs_cfg.clk_list.num_levels = 3; xrs_cfg.clk_list.cu_clk_list[0] = 0; xrs_cfg.clk_list.cu_clk_list[1] = 800; xrs_cfg.clk_list.cu_clk_list[2] = 1000; xrs_cfg.sys_eff_factor = 1; xrs_cfg.actions = &ipu_xrs_actions; xrs_cfg.total_col = idev->metadata.cols; xrs_cfg.mode = XRS_MODE_TEMPORAL_BEST; idev->xrs_hdl = xrs_init(&xrs_cfg);
xrs って、何だろうか?後でみてみます。
xdna->async_msgd = kthread_run(ipu_error_async_msg_thread, xdna, "async_msgd");
Firmwareからの非同期エラーを処理するkthreadの立ち上げ
iipu_setup_pcidev
ret = dma_set_mask_and_coherent(&xdna->pdev->dev, DMA_BIT_MASK(64));
64ビットのDMA
ret = pcim_enable_device(xdna->pdev); pci_set_master(xdna->pdev);
PCI Device & Master Device
bar_mask = pci_select_bars(xdna->pdev, IORESOURCE_MEM); ret = pcim_iomap_regions(xdna->pdev, bar_mask, "amdxdna-ipu");
BARの設定
nvec = pci_msix_vec_count(xdna->pdev); ret = pci_alloc_irq_vectors(xdna->pdev, nvec, nvec, PCI_IRQ_MSIX);
MSIX の設定
ipu_smu_init
ret = ipu_smu_set_power_on(idev); ret = ipu_smu_set_mpipu_clock_freq(idev, SMU_MPIPUCLK_FREQ_MAX); ret = ipu_smu_set_hclock_freq(idev, SMU_HCLK_FREQ_MAX);
どうやら、電力とクロックの設定のようです。
amdxdna_psp_create
ret = psp_load_firmware(psp);
reg_vals[0] = PSP_VALIDATE; reg_vals[1] = lower_32_bits(psp->fw_paddr); reg_vals[2] = upper_32_bits(psp->fw_paddr); reg_vals[3] = psp->fw_buf_sz; ret = psp_exec(psp, reg_vals); memset(reg_vals, 0, sizeof(reg_vals)); reg_vals[0] = PSP_START; reg_vals[1] = PSP_START_COPY_FW; ret = psp_exec(psp, reg_vals);
PSPを起動!
xrs_init
void *xrs_init(struct init_config *cfg) { struct solver_rgroup *rgp; struct solver_state *xrs; xrs = kzalloc(sizeof(*xrs), GFP_KERNEL); if (!xrs) return NULL; memcpy(&xrs->cfg, cfg, sizeof(struct init_config)); rgp = &xrs->rgp; INIT_LIST_HEAD(&rgp->node_list); INIT_LIST_HEAD(&rgp->pt_node_list); return xrs; }
特に何もしていません。
xrs.h によると、
/* * xrs_init() - Register resource solver. Resource solver client needs * to call this function to register itself. * * @cfg: The system metrics for resource solver to use * * Return: A resource solver handle * * Note: We should only create one handle per AIE array to be managed. */ void *xrs_init(struct init_config *cfg);
とありました。
おわり
AMD XDNAが PCI Device となっていることがわかりました。
関連ブログ