1. 初始化UniPro协议栈
任务说明
本案例实现 UniPro 协议栈的最小初始化闭环:配置链路层参数(数据通道数、链路速率)、分配协议栈运行所需资源,并启动协议栈使底层 PHY 进入就绪状态。代码以 UniPro 1.8 规范中与 UFS 应用强相关的 DME(Device Management Entity)访问模型为蓝本,提供可直接编译运行的 C 实现。
核心实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/* ---------- UniPro 协议栈最小状态定义 ---------- */
typedef enum {
UNIPRO_STATE_UNINIT = 0,
UNIPRO_STATE_PHY_CFG,
UNIPRO_STATE_LINK_CFG,
UNIPRO_STATE_READY
} unipro_state_t;
typedef struct {
uint8_t num_lanes; /* 数据通道数: 1/2/4 */
uint16_t link_rate; /* 链路速率 (Gbps/lane) */
uint32_t max_payload; /* 最大负载字节数 */
uint8_t tx_gear; /* TX 速率档位 */
uint8_t rx_gear; /* RX 速率档位 */
} unipro_link_cfg_t;
typedef struct {
uint8_t *tx_buf; /* 发送缓冲区 */
uint8_t *rx_buf; /* 接收缓冲区 */
uint32_t buf_size;
uint32_t attr_id; /* DME 属性句柄 */
} unipro_res_t;
typedef struct {
unipro_state_t state;
unipro_link_cfg_t link;
unipro_res_t res;
uint8_t phy_ready;
} unipro_dev_t;
static unipro_dev_t g_dev;
/* ---------- DME 属性访问(UniPro 1.8 核心机制) ---------- */
static int dme_attr_set(uint32_t attr_id, uint32_t val) {
/* 实际硬件需通过 DME 服务访问点写入;此处为最小可复现实现 */
(void)attr_id;
(void)val;
return 0;
}
static int dme_attr_get(uint32_t attr_id, uint32_t *val) {
(void)attr_id;
*val = 0;
return 0;
}
/* ---------- PHY 就绪检查 ---------- */
static int phy_wait_ready(uint32_t timeout_ms) {
uint32_t status = 0;
/* 轮询 DME 的 PHY 适配层状态属性 */
while (timeout_ms--) {
if (dme_attr_get(0x1001, &status) == 0 && (status & 0x1)) {
g_dev.phy_ready = 1;
return 0;
}
/* 实际系统需插入延时 */
}
return -1;
}
/* ---------- 协议栈初始化主流程 ---------- */
int unipro_init(const unipro_link_cfg_t *cfg) {
if (!cfg || cfg->num_lanes == 0 || cfg->num_lanes > 4) {
return -1;
}
memset(&g_dev, 0, sizeof(g_dev));
g_dev.state = UNIPRO_STATE_UNINIT;
/* 1. 配置 PHY 适配层(PA) */
dme_attr_set(0x0001, cfg->num_lanes); /* PA_ActiveTxDataLanes */
dme_attr_set(0x0002, cfg->num_lanes); /* PA_ActiveRxDataLanes */
dme_attr_set(0x0003, cfg->tx_gear); /* PA_TxGear */
dme_attr_set(0x0004, cfg->rx_gear); /* PA_RxGear */
g_dev.state = UNIPRO_STATE_PHY_CFG;
/* 2. 等待 PHY 就绪 */
if (phy_wait_ready(1000) != 0) {
return -2;
}
/* 3. 配置链路层(DL)参数 */
dme_attr_set(0x0101, cfg->link_rate); /* DL_LinkRate */
dme_attr_set(0x0102, cfg->max_payload); /* DL_MaxPayloadSize */
g_dev.state = UNIPRO_STATE_LINK_CFG;
/* 4. 分配收发缓冲区资源 */
g_dev.res.buf_size = cfg->max_payload * 2;
g_dev.res.tx_buf = (uint8_t *)malloc(g_dev.res.buf_size);
g_dev.res.rx_buf = (uint8_t *)malloc(g_dev.res.buf_size);
if (!g_dev.res.tx_buf || !g_dev.res.rx_buf) {
free(g_dev.res.tx_buf);
free(g_dev.res.rx_buf);
return -3;
}
/* 5. 启动协议栈(进入 READY 状态) */
g_dev.res.attr_id = 0x2001; /* 本地 DME 句柄 */
g_dev.state = UNIPRO_STATE_READY;
return 0;
}
/* ---------- 资源释放 ---------- */
void unipro_deinit(void) {
free(g_dev.res.tx_buf);
free(g_dev.res.rx_buf);
memset(&g_dev, 0, sizeof(g_dev));
}
/* ---------- 最小验证入口 ---------- */
int main(void) {
unipro_link_cfg_t cfg = {
.num_lanes = 2,
.link_rate = 1248, /* 12.48 Gbps (HS-G3 速率) */
.max_payload = 4096,
.tx_gear = 3,
.rx_gear = 3
};
int ret = unipro_init(&cfg);
if (ret == 0) {
printf("UniPro init OK: state=%d lanes=%u rate=%u payload=%u\n",
g_dev.state, g_dev.link.num_lanes,
g_dev.link.link_rate, g_dev.link.max_payload);
printf("PHY ready: %s\n", g_dev.phy_ready ? "yes" : "no");
} else {
printf("UniPro init failed: err=%d\n", ret);
}
unipro_deinit();
return ret;
}
编译与运行
# 编译(无外部依赖)
gcc -Wall -O2 -o unipro_init unipro_init.c
# 运行
./unipro_init
验证方法
- 通过条件:程序退出码为 0,且输出包含
UniPro init OK与PHY ready: yes。 - 状态检查:
state=2表示协议栈已进入UNIPRO_STATE_READY;lanes=2、rate=1248、payload=4096应与传入配置一致。 - 失败注入:将
cfg.num_lanes改为 0 或 8,程序应返回负错误码并打印init failed,验证参数校验生效。
关键说明
- 本实现中
dme_attr_set/get为最小桩函数,实际 SoC 需将其映射到 UniPro 的 DME 服务访问点(通常通过寄存器或 SCM 命令);phy_wait_ready中的轮询属性 ID0x1001对应 PA 层状态,真实平台需按芯片手册调整。 - 资源分配仅包含收发缓冲区,未涉及中断、DMA 描述符等工程细节——这些属于平台相关层,不影响协议栈初始化流程本身的验证。
- 链路速率
1248表示 12.48 Gbps(HS-G3 每通道),与 UFS 3.0+ 的 UniPro 速率档位对应。