This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] PRU-ICSS-INDUSTRIAL-SW:来自 PRU 的驱动器控制

Guru**** 2553450 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/908046/pru-icss-industrial-sw-driver-control-from-pru

器件型号:PRU-ICSS-INDUSTRIAL-SW

我已经很久没能回到这个问题、 但我相信我有一种工作方法可以通过 sysfs 从 Remoteproc 导出分割信息、这样它将在 Remoteproc 目录中创建分割目录、并在 PRU 启动时导出分割地址、并在关闭时将其删除。 如果 Nick Saulnier 或 Suman 有任何批评、比如在启动和关断期间、哪些引用是安全的、以及我是否应该以不同的方式获取某些引用以尊重参考计数注意事项、我对此感兴趣。 我还想知道他们是否有任何关于处理 PRU 和应用处理器之间高带宽数据交换的新建议。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

module_license ("GPL");
module_Author ("Bill Merryman");
module_description ("a Simple module to access information from the PRU rproc.");
module_version ("0.01");

//
/sys/class/remoteproc/remoteproc1
是
/sys/devices/platform/ocp/4a326004.pruss-soc-bus/4a300000.pruss/4a334000.pru/remoteproc/remoteproc1

/sys/class/remoteproc/remoteproc2的符号链接
是
/sys/devices/platform/ocp/4a326004.pruss-soc-bus/4a300000.pruss/4a338000.pru/remoteproc/remoteproc2的符号链接

*/

struct rproc * rproc_rproc_struct;
struct kpt_subtrust_device_remote_remote_subtrade_static;
*


static ssize_t carveout_show (struct kobject *kobj、struct kobj_attribute *属性、
char *buf)
{
struct resource_table *table = rproc_ptr->table_ptr;
struct fw_rsc_carveout *c;
int i;

if (!table){
return 0;
}

for (i = 0;i < table->num;i++){
int offset = table->offset[i];
struct sizrdr*
=* void *(ddr_dr)*= void *+* void *!
if (HDR->type == RSC_CARVEOUT) c = RSC;
}

返回 sprintf (buf、"%x\n"、(c)? c->pA:0);
}

静态结构 kobj_attribute carveout_attribute =_attr (carveout_address、0440、carveout_show、NULL);

int rproc_access_driver_probe (struct rproc_subdev * subdev)
{




int error = 0;carveout_dir_kobj_show、NULL);"curveout_file_remote_remote_remote_out_en_dete_remote_remote_out"(a
);"cart_remote_remote_remote_remote_remote_remote_out_en_file"(r = carved_debug_out_profile";"cart_remote_remote_remote_remote_remote_remote_out_out_en_file"(r);"cart_remote_remote_remote_remote_remote_remote_out_enote_remote_remote_out_subdirectory (
返回错误;
}

void rproc_access_driver_remove (struct rproc_subdev * subdev)
{
if (carveout_dir_kobj_ptr)
{
kobject_put (carveout_dir_kobj_ptr);
carveout_dir_kobj_ptr = NULL;
printk (kern_info "curveout_dir_kobj_ptr}"pru_subdirectory


(n_shutdown);carveout_n_info on "prue_null_down" subdirectory (pruetooth_pru_
curveout 子目录未删除\n");
}


static int __init rproc_access_driver_init (void)
{
struct device_node *PRU_device_node;
struct platform_device *PRU_platform_device_ptr;
struct device *remoteEV_DEVICE_ptr;

pru_DEVICE_NODE_ptr = of "pru_platform_device *PRU_init_n_device_ptr;"pru_device_out_out_init_n_device"/ocp/pruss_soc_bus




(not
be acu_ent_out_out_ent_ent_ent_init_ent_ent_out_out_init_ent/r);struct@@@"pru_out_out_init_device"(pru_out_out_out_out_out_out_ent_ent_ent_init_ent_ent_ent full_name:%s\n"、PRU_DEVICE_NODE_PTR->full_name);
PRU_platform_DEVICE_ptr = of _find_device_BY_node (PRU_DEVICE_NODE_ptr);
of _NODE_Put (PRU_DEVICE_NODE_ptr);

if (!PRU_platform_DEVICE_DEVICE_PTR

)(PRU_DEVICE-PRU_PRU_PRU_DEVICE-PRU_DEVICE-PRU&PRU_DEVICE-PRU_PRECT_PRECT_PRECT_PRECTr);PRU_PRODEVICE-PRU_PRU_PRU_DEVICE-PRU_DEVICE-PRU&PRU_DEVICE-PRECT_PRECT_PRECT_PRU_DEVICE-PRECTr);PRU_PROTOP= PRU_PROTOP_





rproc_ptr = platform_get_drvdata (PRU_platform_device_ptr);
pt_device (&PRU_platform_device_ptr->dev);
if (!rproc_ptr) return -EPROBE_DERAD;

printk (Kern_info "rproc 在 init 处获取。 名称:%s\n"、rproc_ptr->name);

//我可能应该在这里使用 get_device,但我现在会危险地生活...
remoteproc_device_ptr =&rproc_ptr->dev;
remoteproc_device_kobj_ptr =&remoteproc_device_ptr->kobj;
printk (kproc_info "remoteproc kobj name:%s\n"、remoteproc_device_kobj->name);

rsizproc_subproc_dev_subreturn (rspr_subspr_spr_spr_sum_spru&r);


rproc_add_subdev (rproc_ptr、rproc_subdev、rproc_access_driver_probe、rproc_access_driver_remove);

返回0;
}

static void __exit rproc_access_driver_exit (void)
{
//*
在这里,我们必须考虑到在
删除驱动程序时有可能已经删除了 rproc *。
*所以我们需要检查它的存在情况、如果它存在、请移除
*我们为车辆创建的子设备。 如果
相关 PRU 正在运行、我们还必须*考虑、在这种情况
下、我们必须*在主退出逻辑之前执行完整的拆卸。
//
struct device_node *PRU_DEVICE_NODE_PTR;
struct platform_device * PRU_platform_device_ptr;
struct rproc * rptr_ptr;

PRU_DEVICE_NODE_ptr = of _find_node_by_path ("/ocp/pruss_soc_bus@4a326004/pruss@0/PRU@34000");

如果
在 PRU_DEVICE_NODE_BY_PATH (PRU_END)获取)。 full_name:%s\n"、PRU_DEVICE_NODE_PTR->full_name);
PRU_platform_DEVICE_ptr = of _find_device_BY_node (PRU_DEVICE_NODE_ptr);
of _NODE_Put (PRU_DEVICE_NODE_ptr);

if (PRU_platform_DEVICE_ptr



)



= PRU_DEVICE_PRU_ptr (PRU_DEVICE_PROT_PRU_DEVICE_PRU_DEVICE_ptr)(PRU_PROT_PRU_DEVICE_PRU_PROT = PRU_PROT_PRU_PROT);PRU_PROT_PRU_PROTOP= PRU_PRU_PROT (PRU_PROTOP= PRU_PROT_PRU_PRU_PROTOP= PRU_PRU_PRU_PRU_PROT (PRU_PROTOP= PRU_PRU_PRU_PROTOP= PRU_PRU_PRU_PROT) PRU_PRU_PROT (PRU_PRU_PRO 名称:%s\n"、rproc_ptr->name);
rproc_remove_subdev (rproc_ptr、rproc_subdev);
}

否则
{
put 设备(&pru_platform_device_ptr->dev);
}


}printk (kern_info "释放 curveout 子设备内存\n"); rproc_access_module_out_init_driver
(rproc


);rproc_remove
)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bill、

    很高兴再次聊天!

    对于未来的读者、这将继续文章中开始的讨论 从 userspace 访问 PRU remoteproc 分割的最佳方式是什么? 和 PRU 的驱动器控制。

    这是您用例的适当总结吗? 您是否还会添加其他内容以阐明上述帖子?
    目标:将3MB/秒的数据从 PRU 移动到非根 Linux 用户空间。
    解决方案概述:您决定创建一个驱动程序,以便将 PRU 内存暴露给用户空间。 您的用例不需要驱动程序在 PRU 和 Linux 之间启用中断。 您希望在初始化 PRU 固件时探测驱动程序、并在 PRU 停止时移除驱动程序。 上述驱动程序使用 rproc_add_subdev 来添加 rproc 子设备。

    您目前使用的是哪种版本的 Linux?

    此致、

    Nick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Nick、

    很高兴再次听到您的声音。 您的总结非常完美。 我在 BeagleBone (绿色)上使用 Debian 9.5。

    我的项目是 BeagleBone 的机器人项目。 这个特定部件是、我有一个廉价摄像头模块(OV7675)、它以每秒15帧的速度通过8位总线将320 x 240 RGB565 (SO 16位颜色信息)视频流传输到 PRU。 PRU 将 RGB565重新编码为24位 RGB、并将其泵入 Remoteproc 分割缓冲区。 因此(320 x 240 x 3字节 RGB x 15帧/秒)=从 PRU 到主存储器每秒约3MB。

    RPMsg 稳健耐用、但看起来不能实时适应数据速度。 我会考虑任何其他选项、以可用视频格式将数据从 PRU 实时传输到用户空间。 迄今为止、使用车辆的功能足以满足我的需求、但车辆不会暴露在用户空间中。 我能够将其映射到过程空间、这很简单、但分割线的地址只能通过结构不好的 DebugFS 进行公开。 我正在处理的 LKM 将通过 sysfs 以每文件一个值的格式显示分割信息。 我目前的粗略草稿显示了一个车辆的起始地址(如果存在)。 我最终可能会通过此驱动程序引入将分割中包含的数据(与分割相关元数据相反)移动到用户空间的功能。

    再次感谢您的任何评论和建议!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    整合一些更实质性的东西。

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    module_license ("GPL");
    module_Author ("Bill Merryman");
    module_description ("a Simple module to access caveout information from the PRU rproc.");
    module_version ("0.01");
    
    //
    /sys/class/remoteproc/remoteproc1
    是
    /sys/devices/platform/ocp/4a326004.pruss-soc-bus/4a300000.pruss/4a334000.pru/remoteproc/remoteproc1
    
    /sys/class/remoteproc/remoteproc2的符号链接
    是
    /sys/devices/platform/ocp/4a326004.pruss-soc-bus/4a300000.pruss/4a338000.pru/remoteproc/remoteproc2
    的符号链接*/
    
    struct caveout_kobject
    {
    carveout_kout_object
    entry};// carveout_out_object directory in 资源目录中的符号链接//在资源表的 caveout
    结构的偏移数组中的位置 fw_RSC_carveout * caveout;//在 caveout 资源
    结构 list_head 节点的资源表中输入;//在 rproc_subproc_container
    中添加链接的 caveouts 列表(caveout_directories);
    
    struct rproc_subsurvedev_device_substructure
    ;//
    
    //rproc 此分割监视器是
    struct kobject *carveouts_dir_kobj_ptr 的子设备;//每个分割信息目录将添加到
    struct list_head curveout_directories 的'carveouts_kobject'目录;//类型列表 caveout_kobject,每个分割
    区一个};
    
    //执行该子设备的监控器。 最终可能会进行修改以枚举所有 Remoteproc 实例。
    
    静态结构 rproc_subdev_container * rproc_subdev_container;
    
    //与每个分割关联的文件属性:物理地址(pA)、长度(len)和名称(name)
    
    //显示分割
    静态 ssize_t pa_show (struct kobject *)*kobj、struct kobj_attributes (name)的物理地址(name)*carveout、carveout_object
    
    = carveout_carveout *、carveout *、carveout_object_structure
    = carveout *
    返回 sprintf (buf、"%x"、carveout->pA);
    }
    
    //显示分割的长度/大小
    static ssize_t len_show (struct kobject *kobj,struct kobj_attribute *attr,char *buf)
    {
    struct carveout_kobject *carveout_kobject = container_of(kobj,struct carveout_kobject,kobj );
    struct fw_Rsc_carveout *carveout *carveout_kobject = carven_kobject
    (kobj);struct carveout->carveout_carveout_carveout_carveout->curveout_kout_kout_kout_k
    
    
    
    static ssize_t name_show (struct kobject *kobj、struct kobj_attribute *attr、char *buf)
    {
    struct carveout_kobject * carveout_kobject = container_of(kobj、struct carveout_kOBJ);
    struct fw_rsc_carveout *属性=_ carveout_attr_kattle_at_kattribute
    
    
    
    
    
    =_ carveout_kout_kout_kobj;static 属性= carveout_carveout_kobj = kout_carveout_static 属性= cart_kout_kout_kobj = kobj = kout_kout_carveout_carveout_kout_static 属性= kobj;carveout_kout_kout_carveout_static 属性= kout_kout_kout_kout_kout
    
    struct 属性*carveout_atttrs[]={
    caveout_pa_kobj_attribute.attr、
    caveout_len_kobj_attribute.attr、
    caveout_name_kobj_attribute.attr、
    null、
    };
    
    //结束:与每个分割关联的文件属性:物理地址(PA)、长度(len)和名称(name)
    
    //自定义发布方法和 kobject 容器的 kobj_type (表示每个分割子目录的 kobject
    void obj_release (struct kobject *kobj)
    {
    struct carveout_kobject * carveout_kobject = container_of (kobj、struct carveout_kobject、kobj);
    printk (kern_info "释放%s curveout_kobject\n"、kobject_name (&caveout_kobject->kobj));
    kfree (carveout_kobject);
    }
    
    静态结构 kobj_type carveout_kobj_ktype ={
    .release= obj_release、
    .sysfs_ops=&kobj_sysfs_ops、
    };
    
    int rproc_access_driver_probe (struct rproc_subdev * subdev)
    {
    //get the subdevice container to get the rproc、which is used to get the resource table、
    //也 to get the device which we get the kobject
    for the remoteproc directory,in my case:
    ///sys/devices/platform/ocp/4a326004.pruss-soc-bus/4a300000.pruss/4a334000.pru/remoteproc/remoteproc1
    //也来自
    ///sys/class/remoteproc/remoteproc1 //
    我可能应该将 get_device 用于此处的设备,但我现在将危险地生活...
    struct rproc_subdev_container * rproc_subdev_container = container_of (subdev、struct rproc_subdev_container、rproc_subdev);
    struct rproc * rproc = rproc_subdev_container->rproc;
    struct device * dev =&rproc_subdev->obj;
    struct kobject * kobj = rproc
    
    
    
    
    
    1、source_outs *和 rproc outs *(如果是)、则为 rproc、则为 rproc_remote_remote_outs (开
    箱:);strategote_remote_remote_outs = rproc = rproc;
    if (!rproc_subdev_container->carveouts_dir_kobj_ptr) return -ENOMEM;
    printk (Kern_info "%s directory created on probe \n"、kobject_name (rproc_subdev_container->carveouts_dir_kobj_ptr));
    
    //为每个分割创建一个目录。
    //我们将其命名为'carveout_{n}',其中{n}是资源表中的分割索引
    (resource_counter = 0;resource_counter < table->num;resource_counter++){
    int offset = table->offset[resource_counter];
    struct fw_RSC_thizHDR =(*)
    * void + dr *;* void * eHDR =(* void *)*!
    if (hdr->type =RSC_CARVEOUT)
    {
    char carveout_folder_name[12];
    sprintf (carveout_folder_name、"carveout_%d"、resource_counter);
    struct carveout_kobject *carveout_kobject = kzalloc (sizeof (carveof)、"curveout_kinfo_kernel_kout"
    
    、"curveout_kinfot_kobject"、"curveout_kout_kobject"、"curveout_kout_kobject"、"curveout_kout_k 正在跳过...\n"、caveout_folder_name);
    继续;
    }
    caveout_kobject->resource_entry_number = resource_counter;
    caveout_kobject->caveout =(struct fw_RSC_carveout *) rSC;
    if (kobject_init_and_add (caveout_kobject->cart_kout_kout_subdirectory->cr、curveout_prob_kout_kout_subdirectory
    
    )、%kout_prob_kout_kout_prob_kout_kout_cr、curveout_prob_kout_kout_subdirect_kout_subdirectory->cr 正在跳过...\n"、kobject_name (&carveout_kobject->kobj);
    kfree (carveout_kobject);
    继续;
    }
    if (sysfs_create_files (&carveout_kobject->kobj、 (const struct attribute **) carveout_atttrs)
    {
    printk (Kern_info "在探测器上为%s 创建属性文件失败。 正在跳过...\n"、kobject_name (&carveout_kobject->kobj);
    kobject_put (&carveout_kobject->kobj);
    继续;
    }
    list_add_tail (&carveout_kobject->node、 rproc_subdev_container->carveout_directories);
    printk (kern_info "%s 子目录在 probe 上创建\n"、kobject_name (&carveout_kobject->kobj));
    }
    
    
    
    
    
    
    
    proc return 0;}void rproc_access_driver_remove (struct rproc_subdev * subobject){*)、scrstruct substruct_subcontainer;rproc_substruct_subcontainer = rulp_ subsumple_subcontainer;rulp_ subscand_deout *
    
    
    //从 caveouts 目录
    list_for_each_entry_safe (caveout_kobject、tmp、&rproc_subdev_container->caveout_directories、node){
    list_del (&caveout_kobject->node);
    kobject_put (&caveout_kobject->obj
    )中删除所有 caveout 子目录
    
    //删除 caveouts 目录
    kobject_put (rproc_subdev_container->caveouts_dir_kobj_ptr);
    rproc_subdev_container->caveouts_dir_kobj_ptr = NULL;
    printk (kern_info 在 remove\n"上删除 curveouts 目录);
    }
    
    static inout_subdev_nt_union _ n_device_out_init
    
    
    /ocp/pruss_soc_bus
    
    
    
    
    
    (n_union = n_union@@@n_devices/union (如果在设备节点上未获取)/unt n_union (n_unt)/union (n_union (n_unt)/union (n_devices/unt)/union (n_union (n_unt)/union (n_unt)/union (n_union (n_device_n_unt)/union (n_unt)/union (n_unt)/en %s)在 init\n"、device_node->full_name 中获取;
    
    //get the platform device
    struct platform_device * platform_device = of _find_device_BY_node (device_node);
    of _node_put (device_node);//如果
    (!platform_device)
    = of _find_device_init_device (
    kern_device
    
    
    ),则释放设备节点;{PRn_init_device-n_name\init_device-n_device",但无法在"platform_init_device"中获取(platform_name"(init_device-n_name";/////pruelt <n_device",在"platform_device"中获取设备名称:
    
    //如果
    (!strstr (dev_name (&platform_device->dev)、"pru")&!strstr (dev_name (&platform_device->dev)、"rt")
    、则确保我们获得的器件为 PRU (可能在此处并不是真正必要的);
    
    返回
    
    
    proc (dev_device-platform_device-vproc
    )
    、"rtue";rplatform_device-platform_get&rproc (rproc = rplatform_device-platform/rproc (+rproc);
    如果(!rproc)
    {
    printk(kern_info "rproc could not be acquired at init\n");
    返回-EPROBE_Defer;
    }
    printk(kern_info "rproc (name:%s) acquired at init\n",rproc->name;
    
    //创建一个子设备容器(包含 rproc rproc rproc (name:%s);rproc
    
    )
    
    ;rproc n_subproc_enp_ subcontainer = ren_en_en_en_en_en_container;ren_en_en_en_en_en_subcontainer (ren_en_en_en_en_en_subcontainer);ren_en_en_en_en_en_en_en_en_en_en_subcontainer (rproc = rproc);
    
    //添加子设备
    rproc_add_subdev (rproc、&rproc_subdev_container->rproc_subdev、rproc_access_driver_probe、rproc_access_driver_remove);
    
    返回0;
    
    //我是否需要在 rproc 上执行'get'? 如果是、我应该在_exit 函数中执行匹配的"Put"调用
    ?}
    
    静态空__exit rproc_access_driver_exit (void)
    {
    if (rproc_subdev_container->carveouts_dir_kobj_ptr) rinit_access_driver_remove (&rproc_subdev_container->rproc_subdev);rproc_remove_subout_subdev_rproc_access_container->rproc_subproc_subproc_driver
    (rproc
    
    );rproc_subproc_access_subproc_en_en_subtren_subdev_container->rproc_<rproc_subproc_driver;rproc_access_subproc_en_subproc_subproc_en_en_en_module->rpro
    
    
    MODULE_EXIT (rproc_access_driver_exit);