【百度大脑AI计算盒FZ5C】firmware pcap 驱动代码分析
# 设备树:
- zynqmp_pcap: pcap {
- compatible = "xlnx,zynqmp-pcap-fpga";
- clock-names = "ref_clk";
- };
复制代码# pcap 驱动 match table
- static const struct of_device_id zynqmp_fpga_of_match[] = {
- { .compatible = "xlnx,zynqmp-pcap-fpga", },
- {},
- };
- MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
复制代码# platform_driver 驱动
- static struct platform_driver zynqmp_fpga_driver = {
- .probe = zynqmp_fpga_probe,
- .remove = zynqmp_fpga_remove,
- .driver = {
- .name = "zynqmp_fpga_manager",
- .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
- },
- };
- module_platform_driver(zynqmp_fpga_driver);
复制代码# probe:创建 mgr,注册 mgr
- static int zynqmp_fpga_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct zynqmp_fpga_priv *priv;
- struct fpga_manager *mgr;
- int ret;
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->dev = dev;
- mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
- &zynqmp_fpga_ops, priv);
- if (!mgr)
- return -ENOMEM;
- platform_set_drvdata(pdev, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret) {
- dev_err(dev, "unable to register FPGA manager");
- return ret;
- }
- return 0;
- }
复制代码# mrg 方法结构体和实现:
- # mrg 方法结构体和实现:
- struct fpga_manager_ops {
- size_t initial_header_size;
- enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
- u64 (*status)(struct fpga_manager *mgr);
- int (*write_init)(struct fpga_manager *mgr,
- struct fpga_image_info *info,
- const char *buf, size_t count);
- int (*write)(struct fpga_manager *mgr, const char *buf, size_t count);
- int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
- int (*write_complete)(struct fpga_manager *mgr,
- struct fpga_image_info *info);
- int (*read)(struct fpga_manager *mgr, struct seq_file *s);
- void (*fpga_remove)(struct fpga_manager *mgr);
- const struct attribute_group **groups;
- };
- static const struct fpga_manager_ops zynqmp_fpga_ops = {
- .state = zynqmp_fpga_ops_state,
- .status = zynqmp_fpga_ops_status,
- .write_init = zynqmp_fpga_ops_write_init,
- .write = zynqmp_fpga_ops_write,
- .write_complete = zynqmp_fpga_ops_write_complete,
- .read = zynqmp_fpga_ops_read,
- };
复制代码# 每一个方法的实现: # zynqmp_fpga_ops_state 调用 eemi_ops->fpga_get_status(&status);
# eemi_ops = zynqmp_pm_get_eemi_ops();
- static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- u32 status;
- if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_get_status)
- return FPGA_MGR_STATE_UNKNOWN;
- eemi_ops->fpga_get_status(&status);
- if (status & IXR_FPGA_DONE_MASK)
- return FPGA_MGR_STATE_OPERATING;
- return FPGA_MGR_STATE_UNKNOWN;
- }
复制代码# zynqmp_pm_get_eemi_ops 返回了 eemi_ops_tbl
- const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
- {
- if (eemi_ops_tbl)
- return eemi_ops_tbl;
- else
- return ERR_PTR(-EPROBE_DEFER);
- }
复制代码# eemi_ops_tbl 就是 firmware 的方法
# zynqmp_fpga_ops_state 调用了 firmware 的方法中的 fpga_get_status 实现的
# 最终通过 zynqmp_pm_fpga_get_status 函数实现,是 firmware 的方法,最终也是调用 smc #0 实现 # 具体内容参照上一篇文章: https://www.cirmall.com/bbs/thread-204685-1-1.html
# zynqmp_fpga_ops_status 调用 eemi_ops->fpga_read 实现,最终调用 zynqmp_pm_fpga_read ,又调用 smc #0 实现
- static u64 zynqmp_fpga_ops_status(struct fpga_manager *mgr)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- unsigned int *buf, reg_val;
- dma_addr_t dma_addr;
- u64 status = 0;
- int ret;
- if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_read)
- return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
- buf = dma_alloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
- &dma_addr, GFP_KERNEL);
- if (!buf)
- return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
- ret = eemi_ops->fpga_read(IXR_FPGA_CONFIG_STAT_OFFSET, dma_addr,
- IXR_FPGA_READ_CONFIG_TYPE, ®_val);
- if (ret) {
- status = FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
- goto free_dmabuf;
- }
- if (reg_val & IXR_FPGA_ERR_CRC_ERR)
- status |= FPGA_MGR_STATUS_CRC_ERR;
- if (reg_val & IXR_FPGA_ERR_SECURITY_ERR)
- status |= FPGA_MGR_STATUS_SECURITY_ERR;
- if (!(reg_val & IXR_FPGA_INIT_B_INTERNAL))
- status |= FPGA_MGR_STATUS_DEVICE_INIT_ERR;
- if (!(reg_val & IXR_FPGA_DONE_INTERNAL_SIGNAL))
- status |= FPGA_MGR_STATUS_SIGNAL_ERR;
- if (!(reg_val & IXR_FPGA_GST_CFG_B))
- status |= FPGA_MGR_STATUS_HIGH_Z_STATE_ERR;
- if (!(reg_val & IXR_FPGA_END_OF_STARTUP))
- status |= FPGA_MGR_STATUS_EOS_ERR;
- free_dmabuf:
- dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf, dma_addr);
- return status;
- }
复制代码# zynqmp_fpga_ops_write_init 仅修改了一个 flags
- static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
- struct fpga_image_info *info,
- const char *buf, size_t size)
- {
- struct zynqmp_fpga_priv *priv;
- priv = mgr->priv;
- priv->flags = info->flags;
- return 0;
- }
复制代码# zynqmp_fpga_ops_write 调用 eemi_ops->fpga_load(dma_addr, size, eemi_flags);/zynqmp_pm_fpga_load 实现
- static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
- const char *buf, size_t size)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- struct zynqmp_fpga_priv *priv;
- dma_addr_t dma_addr;
- u32 eemi_flags = 0;
- size_t dma_size;
- char *kbuf;
- int ret;
- if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_load)
- return -ENXIO;
- priv = mgr->priv;
- priv->size = size;
- if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM)
- dma_size = size + ENCRYPTED_KEY_LEN;
- else
- dma_size = size;
- kbuf = dma_alloc_coherent(priv->dev, dma_size, &dma_addr, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
- memcpy(kbuf, buf, size);
- if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM) {
- eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY;
- memcpy(kbuf + size, mgr->key, ENCRYPTED_KEY_LEN);
- } else if (priv->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) {
- eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY;
- }
- wmb(); /* ensure all writes are done before initiate FW call */
- if (priv->flags & FPGA_MGR_DDR_MEM_AUTH_BITSTREAM)
- eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR;
- else if (priv->flags & FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM)
- eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM;
- if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
- eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
- if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM)
- ret = eemi_ops->fpga_load(dma_addr, dma_addr + size,
- eemi_flags);
- else
- ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);
- dma_free_coherent(priv->dev, dma_size, kbuf, dma_addr);
- return ret;
- }
复制代码# zynqmp_fpga_ops_write_complete 啥也没干直接返回
- static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
- struct fpga_image_info *info)
- {
- return 0;
- }
复制代码# zynqmp_fpga_ops_read 调用 zynqmp_fpga_read_cfgdata 和 zynqmp_fpga_read_cfgreg 实现
# zynqmp_fpga_read_cfgdata 和 zynqmp_fpga_read_cfgreg 中调用了 eemi_ops->fpga_read / zynqmp_pm_fpga_read 实现
- static int zynqmp_fpga_ops_read(struct fpga_manager *mgr, struct seq_file *s)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- int ret;
- if (!eemi_ops || !eemi_ops->fpga_read)
- return -ENXIO;
- if (readback_type)
- ret = zynqmp_fpga_read_cfgdata(mgr, s);
- else
- ret = zynqmp_fpga_read_cfgreg(mgr, s);
- return ret;
- }
- static int zynqmp_fpga_read_cfgdata(struct fpga_manager *mgr,
- struct seq_file *s)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- struct zynqmp_fpga_priv *priv;
- int ret, data_offset;
- unsigned int *buf;
- dma_addr_t dma_addr;
- size_t size;
- priv = mgr->priv;
- size = priv->size + READ_DMA_SIZE + DUMMY_FRAMES_SIZE;
- buf = dma_alloc_coherent(mgr->dev.parent, size, &dma_addr,
- GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- seq_puts(s, "zynqMP FPGA Configuration data contents are\n");
- ret = eemi_ops->fpga_read((priv->size + DUMMY_FRAMES_SIZE) / 4,
- dma_addr, readback_type, &data_offset);
- if (ret)
- goto free_dmabuf;
- seq_write(s, &buf[data_offset], priv->size);
- free_dmabuf:
- dma_free_coherent(mgr->dev.parent, size, buf, dma_addr);
- return ret;
- }
- static int zynqmp_fpga_read_cfgreg(struct fpga_manager *mgr,
- struct seq_file *s)
- {
- const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
- int ret, val;
- unsigned int *buf;
- dma_addr_t dma_addr;
- struct zynqmp_configreg *p = cfgreg;
- buf = dma_alloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
- &dma_addr, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- seq_puts(s, "zynqMP FPGA Configuration register contents are\n");
- while (p->reg) {
- ret = eemi_ops->fpga_read(p->offset, dma_addr, readback_type,
- &val);
- if (ret)
- goto free_dmabuf;
- seq_printf(s, "%s --> \t %x \t\r\n", p->reg, val);
- p++;
- }
- free_dmabuf:
- dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf,
- dma_addr);
- return ret;
- }
复制代码能看懂 C 语言不重要,重要的是代码要表达的意思,看总结
# 总结: 1,pcap 主要实现 fpga 管理功能 2,这些功能的实现最终调用 firmware 实现
|