查看: 1280|回复: 0

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

[复制链接]
  • TA的每日心情
    开心
    3 天前
  • 签到天数: 597 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2021-4-14 00:39:02 | 显示全部楼层 |阅读模式
    分享到:
    【百度大脑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 实现



    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-11-23 13:02 , Processed in 0.117281 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.