SRIO通信总线

一、整个过程

打开设备 → 建通道 → 绑定 → 连接 → 收发 → 关闭 → 查状态

所有 .c 文件里最终都会落到这些命令,连接两块板卡 100% 用到

一、最核心:用户态直接调用的 IOCTL 接口(必背)

所有 .c 文件里最终都会落到这些命令,连接两块板卡 100% 用到

c

运行

复制代码
// 通道生命周期
RIO_CM_CHAN_CREATE        // 创建通道(必须第一个调用)
RIO_CM_CHAN_BIND          // 绑定本地板卡ID/端口
RIO_CM_CHAN_LISTEN        // 服务端:监听连接
RIO_CM_CHAN_ACCEPT        // 服务端:接受连接
RIO_CM_CHAN_CONNECT       // 客户端:主动连接
RIO_CM_CHAN_CLOSE         // 关闭通道

// 数据收发
RIO_CM_CHAN_SEND          // 发送数据
RIO_CM_CHAN_RECEIVE       // 接收数据

// 状态查询(排查问题必用)
RIO_CM_EP_GET_LIST_SIZE   // 获取板卡端点数量
RIO_CM_EP_GET_LIST        // 获取所有端点信息(ID/端口)
RIO_CM_MPORT_GET_LIST     // 获取物理端口状态
RIO_CM_CHAN_GET_STATUS    // 获取通道当前状态

这些是跨所有 .c 文件的统一入口,不管驱动代码多复杂,用户态只用这一套。


二、必须掌握的 关键结构体(填参数就靠它)

所有 .c 文件都会传递这些结构体,你写连接代码必须定义它们

c

运行

复制代码
// 1. 通道创建
struct rio_cm_chan {
    int chan_id;      // 通道ID
};

// 2. 绑定本地板卡(核心!)
struct rio_cm_bind {
    u16 local_id;     // 本地 RapidIO 地址 ID
    u8 local_port;    // 本地端口号
    u8 dev_id;        // 设备号
};

// 3. 客户端连接目标板卡(核心!)
struct rio_cm_connect {
    u16 remote_id;    // 目标板卡 ID
    u8 remote_port;   // 目标端口
    int timeout;      // 连接超时
};

// 4. 监听(服务端)
struct rio_cm_listen {
    int backlog;      // 最大等待连接数
};

// 5. 数据收发(核心!)
struct rio_cm_msg {
    void *buf;        // 数据缓冲区
    u32 len;          // 数据长度
};

记住:连接板卡 = 填这几个结构体 + 调用 IOCTL


三、内核层关键函数(所有 .c 文件都会用到)

你不用全看懂,但知道它们干嘛用,就能快速定位问题:

1. 通道相关(riocm_channel.c)

  • rio_cm_chan_create():创建通道内核对象
  • rio_cm_chan_bind():绑定硬件端口
  • rio_cm_chan_listen():启动监听
  • rio_cm_chan_accept():建立连接
  • rio_cm_chan_connect():发起连接
  • rio_cm_chan_close():关闭并释放资源

2. 数据收发(riocm_msg.c)

  • rio_cm_msg_send():发送报文
  • rio_cm_msg_receive():接收报文
  • rio_cm_msg_queue():消息队列管理

3. 硬件与拓扑查询(riocm_main.c)

  • rio_cm_get_ep_list():获取全网板卡列表
  • rio_cm_get_mport_list():获取本地物理端口
  • rio_cm_dev_init():驱动初始化

4. 底层 RapidIO 协议(rio.c)

  • rio_open() / rio_close():设备打开关闭
  • rio_read() / rio_write():底层寄存器读写
  • rio_phys_connect():物理链路建立

四、两块板卡连接的最简万能流程

不管代码在多少个 .c 文件里,真实干活就 7 步

服务端(板卡 A,被动等待)

  1. open("/dev/rio_cm")
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND(填本地 ID、端口)
  4. RIO_CM_CHAN_LISTEN
  5. RIO_CM_CHAN_ACCEPT(阻塞等客户端)
  6. SEND / RECEIVE 通信
  7. CLOSE

客户端(板卡 B,主动连接)

  1. open("/dev/rio_cm")
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND(本地 ID、端口)
  4. RIO_CM_CHAN_CONNECT(填对方 ID、端口)
  5. SEND / RECEIVE
  6. CLOSE

五、直接能上手的最小接口集

  1. open()
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND
  4. RIO_CM_CHAN_LISTEN
  5. RIO_CM_CHAN_ACCEPT
  6. RIO_CM_CHAN_CONNECT
  7. RIO_CM_CHAN_SEND
  8. RIO_CM_CHAN_RECEIVE
  9. RIO_CM_CHAN_CLOSE
  10. close()

六、可直接用的示例代码框架

客户端示例(主动连接)

复制代码
#include <stdio.h>//负责打印输入
#include <stdlib.h>//负责内存退出
#include <unistd.h>//Linux系统调用(close)等
#include <fcntl.h>//打开文件
#include <sys/ioctl.h>//和硬件通信时的核心接口
#include "rio.h" // 驱动头文件,包含IOCTL命令和结构体定义

int main() {
    int fd = open("/dev/rio_cm", O_RDWR);
    if (fd < 0) {
        perror("open failed");
        return -1;
    }

    // 1. 创建通道
    struct rio_cm_chan chan;
    if (ioctl(fd, RIO_CM_CHAN_CREATE, &chan) < 0) {
        perror("create chan failed");
        close(fd);
        return -1;
    }

    // 2. 绑定本地地址(本地RapidIO ID=0x1,端口=1)
    struct rio_cm_bind bind_info = {
        .local_id = 0x1,
        .local_port = 1,
        .dev_id = 0
    };
    if (ioctl(fd, RIO_CM_CHAN_BIND, &bind_info) < 0) {
        perror("bind failed");
        close(fd);
        return -1;
    }

    // 3. 连接服务端(服务端RapidIO ID=0x2,端口=1)
    struct rio_cm_connect connect_info = {
        .remote_id = 0x2,
        .remote_port = 1,
        .timeout = 5000 // 超时5秒
    };
    if (ioctl(fd, RIO_CM_CHAN_CONNECT, &connect_info) < 0) {
        perror("connect failed");
        close(fd);
        return -1;
    }
    printf("连接服务端成功!\n");

    // 4. 发送数据
    char send_buf[1024] = "Hello from Client!";
    struct rio_cm_msg send_msg = {
        .buf = send_buf,
        .len = strlen(send_buf)
    };
    if (ioctl(fd, RIO_CM_CHAN_SEND, &send_msg) < 0) {
        perror("send failed");
        close(fd);
        return -1;
    }

    // 5. 接收响应
    char recv_buf[1024];
    struct rio_cm_msg recv_msg = {
        .buf = recv_buf,
        .len = sizeof(recv_buf)
    };
    if (ioctl(fd, RIO_CM_CHAN_RECEIVE, &recv_msg) < 0) {
        perror("receive failed");
        close(fd);
        return -1;
    }
    printf("收到服务端响应: %s\n", recv_buf);

    // 6. 关闭连接
    close(fd);
    return 0;
}

服务端示例(被动连接)

c

运行

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "rio.h"

int main() {
    int listen_fd = open("/dev/rio_cm", O_RDWR);
    if (listen_fd < 0) {
        perror("open failed");
        return -1;
    }

    // 1. 创建监听通道
    struct rio_cm_chan chan;
    if (ioctl(listen_fd, RIO_CM_CHAN_CREATE, &chan) < 0) {
        perror("create listen chan failed");
        close(listen_fd);
        return -1;
    }

    // 2. 绑定本地地址(本地RapidIO ID=0x2,端口=1)
    struct rio_cm_bind bind_info = {
        .local_id = 0x2,
        .local_port = 1,
        .dev_id = 0
    };
    if (ioctl(listen_fd, RIO_CM_CHAN_BIND, &bind_info) < 0) {
        perror("bind failed");
        close(listen_fd);
        return -1;
    }

    // 3. 开始监听
    struct rio_cm_listen listen_info = {
        .backlog = 5 // 监听队列长度
    };
    if (ioctl(listen_fd, RIO_CM_CHAN_LISTEN, &listen_info) < 0) {
        perror("listen failed");
        close(listen_fd);
        return -1;
    }
    printf("等待客户端连接...\n");

    // 4. 接受连接(阻塞)
    int conn_fd = ioctl(listen_fd, RIO_CM_CHAN_ACCEPT, NULL);
    if (conn_fd < 0) {
        perror("accept failed");
        close(listen_fd);
        return -1;
    }
    printf("客户端连接成功!\n");

    // 5. 接收客户端数据
    char recv_buf[1024];
    struct rio_cm_msg recv_msg = {
        .buf = recv_buf,
        .len = sizeof(recv_buf)
    };·
    if (ioctl(conn_fd, RIO_CM_CHAN_RECEIVE, &recv_msg) < 0) {
        perror("receive failed");
        close(conn_fd);
        close(listen_fd);
        return -1;
    }
    printf("收到客户端消息: %s\n", recv_buf);

    // 6. 发送响应
    char send_buf[1024] = "Hello from Server!";
    struct rio_cm_msg send_msg = {
        .buf = send_buf,
        .len = strlen(send_buf)
    };
    if (ioctl(conn_fd, RIO_CM_CHAN_SEND, &send_msg) < 0) {
        perror("send failed");
        close(conn_fd);
        close(listen_fd);
        return -1;
    }

    // 7. 关闭连接
    close(conn_fd);
    close(listen_fd);
    return 0;
}
相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
qq_369224333 天前
Windows全系通用!ntdll.dll文件丢失、报错、闪退问题的完整排查与修复教程
windows·dll·dll修复·dll丢失·dll错误