回答

收藏

[评测分享] 【百度大脑AI计算盒FZ5C】firmware pcap 驱动代码分析

#板卡评测 #板卡评测 1889 人阅读 | 0 人回复 | 2021-04-14

【百度大脑AI计算盒FZ5C】firmware pcap 驱动代码分析

# 设备树:
  1. zynqmp_pcap: pcap {
  2.         compatible = "xlnx,zynqmp-pcap-fpga";
  3.         clock-names = "ref_clk";
  4. };
复制代码
# pcap 驱动 match table
  1. static const struct of_device_id zynqmp_fpga_of_match[] = {
  2.         { .compatible = "xlnx,zynqmp-pcap-fpga", },
  3.         {},
  4. };

  5. MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
复制代码
# platform_driver 驱动
  1. static struct platform_driver zynqmp_fpga_driver = {
  2.         .probe = zynqmp_fpga_probe,
  3.         .remove = zynqmp_fpga_remove,
  4.         .driver = {
  5.                 .name = "zynqmp_fpga_manager",
  6.                 .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
  7.         },
  8. };

  9. module_platform_driver(zynqmp_fpga_driver);
复制代码
# probe:创建 mgr,注册 mgr
  1. static int zynqmp_fpga_probe(struct platform_device *pdev)
  2. {
  3.         struct device *dev = &pdev->dev;
  4.         struct zynqmp_fpga_priv *priv;
  5.         struct fpga_manager *mgr;
  6.         int ret;

  7.         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  8.         if (!priv)
  9.                 return -ENOMEM;

  10.         priv->dev = dev;

  11.         mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
  12.                                    &zynqmp_fpga_ops, priv);
  13.         if (!mgr)
  14.                 return -ENOMEM;

  15.         platform_set_drvdata(pdev, mgr);

  16.         ret = fpga_mgr_register(mgr);
  17.         if (ret) {
  18.                 dev_err(dev, "unable to register FPGA manager");
  19.                 return ret;
  20.         }

  21.         return 0;
  22. }
复制代码
# mrg 方法结构体和实现:
  1. # mrg 方法结构体和实现:
  2. struct fpga_manager_ops {
  3.         size_t initial_header_size;
  4.         enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
  5.         u64 (*status)(struct fpga_manager *mgr);
  6.         int (*write_init)(struct fpga_manager *mgr,
  7.                           struct fpga_image_info *info,
  8.                           const char *buf, size_t count);
  9.         int (*write)(struct fpga_manager *mgr, const char *buf, size_t count);
  10.         int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
  11.         int (*write_complete)(struct fpga_manager *mgr,
  12.                               struct fpga_image_info *info);
  13.         int (*read)(struct fpga_manager *mgr, struct seq_file *s);
  14.         void (*fpga_remove)(struct fpga_manager *mgr);
  15.         const struct attribute_group **groups;
  16. };

  17. static const struct fpga_manager_ops zynqmp_fpga_ops = {
  18.         .state = zynqmp_fpga_ops_state,
  19.         .status = zynqmp_fpga_ops_status,
  20.         .write_init = zynqmp_fpga_ops_write_init,
  21.         .write = zynqmp_fpga_ops_write,
  22.         .write_complete = zynqmp_fpga_ops_write_complete,
  23.         .read = zynqmp_fpga_ops_read,
  24. };
复制代码
# 每一个方法的实现:
# zynqmp_fpga_ops_state 调用 eemi_ops->fpga_get_status(&status);
# eemi_ops = zynqmp_pm_get_eemi_ops();
  1. static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
  2. {
  3.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  4.         u32 status;

  5.         if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_get_status)
  6.                 return FPGA_MGR_STATE_UNKNOWN;

  7.         eemi_ops->fpga_get_status(&status);
  8.         if (status & IXR_FPGA_DONE_MASK)
  9.                 return FPGA_MGR_STATE_OPERATING;

  10.         return FPGA_MGR_STATE_UNKNOWN;
  11. }
复制代码
# zynqmp_pm_get_eemi_ops 返回了 eemi_ops_tbl
  1. const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
  2. {
  3.         if (eemi_ops_tbl)
  4.                 return eemi_ops_tbl;
  5.         else
  6.                 return ERR_PTR(-EPROBE_DEFER);

  7. }
复制代码
# 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 实现
  1. static u64 zynqmp_fpga_ops_status(struct fpga_manager *mgr)
  2. {
  3.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  4.         unsigned int *buf, reg_val;
  5.         dma_addr_t dma_addr;
  6.         u64 status = 0;
  7.         int ret;

  8.         if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_read)
  9.                 return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;

  10.         buf = dma_alloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
  11.                                  &dma_addr, GFP_KERNEL);
  12.         if (!buf)
  13.                 return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;

  14.         ret = eemi_ops->fpga_read(IXR_FPGA_CONFIG_STAT_OFFSET, dma_addr,
  15.                                   IXR_FPGA_READ_CONFIG_TYPE, ?_val);
  16.         if (ret) {
  17.                 status = FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
  18.                 goto free_dmabuf;
  19.         }

  20.         if (reg_val & IXR_FPGA_ERR_CRC_ERR)
  21.                 status |= FPGA_MGR_STATUS_CRC_ERR;
  22.         if (reg_val & IXR_FPGA_ERR_SECURITY_ERR)
  23.                 status |= FPGA_MGR_STATUS_SECURITY_ERR;
  24.         if (!(reg_val & IXR_FPGA_INIT_B_INTERNAL))
  25.                 status |= FPGA_MGR_STATUS_DEVICE_INIT_ERR;
  26.         if (!(reg_val & IXR_FPGA_DONE_INTERNAL_SIGNAL))
  27.                 status |= FPGA_MGR_STATUS_SIGNAL_ERR;
  28.         if (!(reg_val & IXR_FPGA_GST_CFG_B))
  29.                 status |= FPGA_MGR_STATUS_HIGH_Z_STATE_ERR;
  30.         if (!(reg_val & IXR_FPGA_END_OF_STARTUP))
  31.                 status |= FPGA_MGR_STATUS_EOS_ERR;

  32. free_dmabuf:
  33.         dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf, dma_addr);

  34.         return status;
  35. }
复制代码
# zynqmp_fpga_ops_write_init 仅修改了一个 flags
  1. static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
  2.                                       struct fpga_image_info *info,
  3.                                       const char *buf, size_t size)
  4. {
  5.         struct zynqmp_fpga_priv *priv;

  6.         priv = mgr->priv;
  7.         priv->flags = info->flags;

  8.         return 0;
  9. }
复制代码
# zynqmp_fpga_ops_write 调用 eemi_ops->fpga_load(dma_addr, size, eemi_flags);/zynqmp_pm_fpga_load 实现
  1. static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
  2.                                  const char *buf, size_t size)
  3. {
  4.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  5.         struct zynqmp_fpga_priv *priv;
  6.         dma_addr_t dma_addr;
  7.         u32 eemi_flags = 0;
  8.         size_t dma_size;
  9.         char *kbuf;
  10.         int ret;

  11.         if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_load)
  12.                 return -ENXIO;

  13.         priv = mgr->priv;
  14.         priv->size = size;

  15.         if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM)
  16.                 dma_size = size + ENCRYPTED_KEY_LEN;
  17.         else
  18.                 dma_size = size;

  19.         kbuf = dma_alloc_coherent(priv->dev, dma_size, &dma_addr, GFP_KERNEL);
  20.         if (!kbuf)
  21.                 return -ENOMEM;

  22.         memcpy(kbuf, buf, size);

  23.         if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM) {
  24.                 eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY;
  25.                 memcpy(kbuf + size, mgr->key, ENCRYPTED_KEY_LEN);
  26.         } else if (priv->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) {
  27.                 eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY;
  28.         }

  29.         wmb(); /* ensure all writes are done before initiate FW call */

  30.         if (priv->flags & FPGA_MGR_DDR_MEM_AUTH_BITSTREAM)
  31.                 eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR;
  32.         else if (priv->flags & FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM)
  33.                 eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM;

  34.         if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
  35.                 eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;

  36.         if (priv->flags & FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM)
  37.                 ret = eemi_ops->fpga_load(dma_addr, dma_addr + size,
  38.                                           eemi_flags);
  39.         else
  40.                 ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);

  41.         dma_free_coherent(priv->dev, dma_size, kbuf, dma_addr);

  42.         return ret;
  43. }
复制代码
# zynqmp_fpga_ops_write_complete 啥也没干直接返回
  1. static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
  2.                                           struct fpga_image_info *info)
  3. {
  4.         return 0;
  5. }
复制代码
# 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 实现
  1. static int zynqmp_fpga_ops_read(struct fpga_manager *mgr, struct seq_file *s)
  2. {
  3.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  4.         int ret;

  5.         if (!eemi_ops || !eemi_ops->fpga_read)
  6.                 return -ENXIO;

  7.         if (readback_type)
  8.                 ret = zynqmp_fpga_read_cfgdata(mgr, s);
  9.         else
  10.                 ret = zynqmp_fpga_read_cfgreg(mgr, s);

  11.         return ret;
  12. }

  13. static int zynqmp_fpga_read_cfgdata(struct fpga_manager *mgr,
  14.                                     struct seq_file *s)
  15. {
  16.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  17.         struct zynqmp_fpga_priv *priv;
  18.         int ret, data_offset;
  19.         unsigned int *buf;
  20.         dma_addr_t dma_addr;
  21.         size_t size;

  22.         priv = mgr->priv;
  23.         size = priv->size + READ_DMA_SIZE + DUMMY_FRAMES_SIZE;

  24.         buf = dma_alloc_coherent(mgr->dev.parent, size, &dma_addr,
  25.                                  GFP_KERNEL);
  26.         if (!buf)
  27.                 return -ENOMEM;

  28.         seq_puts(s, "zynqMP FPGA Configuration data contents are\n");
  29.         ret = eemi_ops->fpga_read((priv->size + DUMMY_FRAMES_SIZE) / 4,
  30.                                   dma_addr, readback_type, &data_offset);
  31.         if (ret)
  32.                 goto free_dmabuf;

  33.         seq_write(s, &buf[data_offset], priv->size);

  34. free_dmabuf:
  35.         dma_free_coherent(mgr->dev.parent, size, buf, dma_addr);

  36.         return ret;
  37. }

  38. static int zynqmp_fpga_read_cfgreg(struct fpga_manager *mgr,
  39.                                    struct seq_file *s)
  40. {
  41.         const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  42.         int ret, val;
  43.         unsigned int *buf;
  44.         dma_addr_t dma_addr;
  45.         struct zynqmp_configreg *p = cfgreg;

  46.         buf = dma_alloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
  47.                                  &dma_addr, GFP_KERNEL);
  48.         if (!buf)
  49.                 return -ENOMEM;

  50.         seq_puts(s, "zynqMP FPGA Configuration register contents are\n");

  51.         while (p->reg) {
  52.                 ret = eemi_ops->fpga_read(p->offset, dma_addr, readback_type,
  53.                                           &val);
  54.                 if (ret)
  55.                         goto free_dmabuf;
  56.                 seq_printf(s, "%s --> \t %x \t\r\n", p->reg, val);
  57.                 p++;
  58.         }

  59. free_dmabuf:
  60.         dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf,
  61.                           dma_addr);

  62.         return ret;
  63. }
复制代码
能看懂 C 语言不重要,重要的是代码要表达的意思,看总结
# 总结:
1,pcap 主要实现 fpga 管理功能
2,这些功能的实现最终调用 firmware 实现



分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条