1. 初始化UniPro协议栈

初始化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 中的轮询属性 ID 0x1001 对应 PA 层状态,真实平台需按芯片手册调整。
  • 资源分配仅包含收发缓冲区,未涉及中断、DMA 描述符等工程细节——这些属于平台相关层,不影响协议栈初始化流程本身的验证。
  • 链路速率 1248 表示 12.48 Gbps(HS-G3 每通道),与 UFS 3.0+ 的 UniPro 速率档位对应。