设备驱动开发指南

1. 概述

本指南面向Component Drivers项目的设备驱动开发者,提供从设计到实现的完整开发流程。Component Drivers是一个基于C++17的硬件组件驱动程序框架,采用分层架构设计,支持多种设备类型和通信协议。

1.1 项目特点

  • 分层架构:设备树对象层 + 内部器件对象层 + 协议通信层
  • 多设备支持:PCIe网卡、GPU、传感器、总线设备、访问器等
  • 协议集成:NCSI over MCTP、IMU、MCTP、多厂商协议支持
  • 配置驱动:基于设备树的配置管理和反射机制
  • 标准化ABI:统一的驱动注册和生命周期管理
  • 统一管理:采用device_manager单例模式管理所有设备对象
  • 智能指针:使用shared_ptr自动管理设备生命周期

1.2 支持的设备类型

设备类型实现示例协议支持厂商支持
PCIe网卡rp1000_card, hi182x_card, hi1822_fc_cardNCSI over MCTP, IMU网迅、华为海思等
PCIe GPUawm_m11p_cardMCTP全志元芯等
通用访问器accessor标准PCIe通用
总线设备bus_i2c, bus_hisport, bus_i2c_muxI2C, Hisport通用
芯片设备chip_pca9545, chip_lm75, chip_eepromI2C协议通用芯片
扫描器scanner设备扫描通用
复合器件complex多协议组合通用

1.3 设备对象系统

Component Drivers采用基于MC_OBJECT宏的设备对象模型,实现设备的层次化管理:

1.3.1 设备对象定义

设备对象通过MC_OBJECT宏定义其核心特征:

cpp
// 以华为海思 hi182x 网卡为例(完整定义见 drivers/pcie_nic_card/hisi/hi182x/hi182x_card.h)
namespace dev {
// 协议智能指针类型别名(与库中定义一致)
using ncsi_over_mctp_hw_ptr = std::shared_ptr<ncsi_over_mctp_huawei>;
using smbus_obj_ptr         = mc::shared_ptr<smbus>;
using imu_ptr               = std::shared_ptr<imu>;

class hi182x_card : public mc::engine::object<hi182x_card> {
public:
    MC_OBJECT(
        hi182x_card, "PCIeNicCard", "/bmc/dev/Systems/1/PCIeNicCard/${object_name}",
        (PCIeDevice)(PCIeDevice_PCIeFunction)(PCIeDevice_Oem)(PCIeDevice_Status)(PCIeCard)(PCIeCard_Oem)
        (PCIeCard_Metrics)(NetworkAdapter)(NetworkAdapter_FaultStatus)(Cooling)(NetworkAdapter_Oem)(Board)
        (PCIeDevice_Bandwidth)(NetworkAdapter_LogCollection)(Fru))

    // 接口实例 - 组合多个接口实现复杂功能(类型即接口名,与 MC_OBJECT 中声明一致)
    PCIeDevice                   m_pcie_device;
    PCIeDevice_PCIeFunction      m_pcie_device_pcie_function;
    NetworkAdapter               m_network_adapter;
    PCIeCard                     m_pcie_card;
    Board                        m_board;
    Cooling                      m_cooling;
    NetworkAdapter_FaultStatus   m_network_adapter_fault_status;
    PCIeDevice_Bandwidth         m_pcie_device_bandwidth;
    NetworkAdapter_LogCollection m_network_adapter_log_collection;

    // 子设备集合(原始指针由框架通过 get_children() 管理,驱动只做类型转换)
    std::vector<hi182x_port*> m_network_ports;

    // 协议实例(MCTP 使用 mc::shared_ptr,其余使用 std::shared_ptr)
    ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;
    imu_ptr               m_imu_obj;
    smbus_obj_ptr         m_smbus_obj;
    mc::shared_ptr<mctp>  m_mctp_object;

    // 生命周期方法(实际签名)
    bool init(mc::mutable_dict& csr_object, const mc::dict& connector);
    bool start();
    bool stop();
};
} // namespace dev

1.3.2 设备对象层次结构

设备对象形成树状层次结构:

/bmc/dev/                                    # 根节点
└── Systems/                                 # 系统节点
    └── 1/                                   # 系统ID
        └── PCIeNicCard/                     # 设备类型
            └── {object_name}/               # 设备实例(由 ${object_name} 替换)
                ├── [PCIeDevice]             # 接口:PCIe设备信息
                ├── [NetworkAdapter]         # 接口:网络适配器
                ├── [PCIeCard]               # 接口:PCIe卡信息
                ├── [Board]                  # 接口:板卡信息
                └── NicPort/                 # 子设备
                    ├── 0/                   # 端口0
                    │   ├── [NetworkPort]    # 接口:网络端口
                    │   └── OpticalTransceiver/ # 光模块
                    │       └── [OpticalModule]
                    └── 1/                   # 端口1
                        ├── [NetworkPort]
                        └── OpticalTransceiver/
                            └── [OpticalModule]

1.3.3 接口系统

接口采用"自动生成 + 手动实现"的模式:

命名空间来源职责示例
gen::代码生成接口基类定义gen::PCIeDevice
dev::手工编写厂商接口实现dev::PCIeDevice
子接口手工编写功能细分接口NetworkPort_LinkInfo

接口组合示例

cpp
// PCIe网卡组合了多个接口
class hi182x_card {
    PCIeDevice                   m_pcie_device;               // PCIe设备接口
    PCIeDevice_PCIeFunction      m_pcie_device_pcie_function; // PCIe功能接口(BDF/VID/DID)
    NetworkAdapter               m_network_adapter;           // 网络适配器接口
    PCIeCard                     m_pcie_card;                 // PCIe卡接口
    Board                        m_board;                     // 板卡信息接口
    Cooling                      m_cooling;                   // 散热子接口(bmc.dev.Cooling)
    NetworkAdapter_FaultStatus   m_network_adapter_fault_status; // 故障状态子接口
    NetworkAdapter_LogCollection m_network_adapter_log_collection; // 日志收集子接口
    PCIeDevice_Bandwidth         m_pcie_device_bandwidth;     // 带宽监控子接口
};

1.3.4 MC_REFLECT反射机制

MC_REFLECT实现属性的编译期反射和运行时动态访问:

cpp
// 1. 接口类继承 mc::engine::interface 并关联的 gen:: 基类
class PCIeDevice : public mc::engine::interface<PCIeDevice, gen::PCIeDevice> {
public:
    std::string DeviceName;
    std::string VendorId;
    std::string DeviceId;
    uint8_t Bus, Device, Function;
};

// 2. 设备对象注册反射信息:将成员与 D-Bus 接口名关联(与 hi182x_card.cpp 一致)
MC_REFLECT(dev::hi182x_card,
           ((m_system_id, "SystemId"))((m_pcie_device, "bmc.dev.PCIeDevice"))
           ((m_pcie_device_pcie_function, "bmc.dev.PCIeDevice.PCIeFunction"))
           ((m_pcie_device_oem, "bmc.dev.PCIeDevice.Oem"))
           ((m_pcie_device_status, "bmc.dev.PCIeDevice.Status"))
           ((m_pcie_card, "bmc.dev.PCIeCard"))((m_pcie_card_oem, "bmc.dev.PCIeCard.Oem"))
           ((m_pcie_card_metrics, "bmc.dev.PCIeCard.Metrics"))
           ((m_network_adapter, "bmc.dev.NetworkAdapter"))
           ((m_network_adapter_fault_status, "bmc.dev.NetworkAdapter.FaultStatus"))
           ((m_cooling, "bmc.dev.Cooling"))((m_network_adapter_oem, "bmc.dev.NetworkAdapter.Oem"))
           ((m_board, "bmc.dev.Board"))((m_pcie_device_bandwidth, "bmc.dev.PCIeDevice.Bandwidth"))
           ((m_fru, "bmc.dev.Fru"))
           ((m_network_adapter_log_collection, "bmc.dev.NetworkAdapter.LogCollection")))

// 3. 运行时使用
mc::dict properties;
mc::reflect::to_variant(card->m_pcie_device, properties);   // 对象 -> JSON
card->m_pcie_device.DeviceName = "NewCard";                // 直接访问属性

1.4 协议库系统

Component Drivers集成了多种通信协议,为设备驱动提供底层通信能力:

1.4.1 协议架构

1.4.2 NCSI协议

NCSI (Network Controller Sideband Interface) 是DMTF标准的网卡带外管理协议:

核心命令

命令代码功能用途
GET_LINK_STATUS0x0A获取链路状态监控链路UP/DOWN
SET_MAC_ADDRESS0x0E设置MAC地址配置网卡MAC
ENABLE_VLAN0x0C启用VLAN配置VLAN过滤
GET_CAPABILITIES0x16获取能力查询控制器功能
OEM_COMMAND0x50厂商命令厂商扩展功能

使用示例

cpp
// NCSI 标准命令通过 ncsi_over_mctp_standard 提供,需基于 MCTP 对象构造
mc::shared_ptr<mctp> mctp_obj =
    mc::make_shared<mctp>(this, mctp::init_phy_addr(0x01, 0x00, 0x00),
                          MCTP_MESSAGE_TYPE::MCTP_MESSAGE_TYPE_NCSI, "");
ncsi_over_mctp_standard ncsi(mctp_obj);

// 获取链路状态
ncsi_link_status_info_t link_status;
if (ncsi.get_link_status(DEFAULT_PACKAGE_ID, DEFAULT_CHANNEL_ID, &link_status)) {
    ilog("Link: ${status}, Speed: ${speed} Mbps",
         ("status", link_status.link_status ? "UP" : "DOWN")("speed", link_status.speed_mbps));
}

// 获取能力信息
ncsi_capabilities_info_t capability;
ncsi.get_capabilities(DEFAULT_PACKAGE_ID, DEFAULT_CHANNEL_ID, &capability);

1.4.3 MCTP协议

MCTP (Management Component Transport Protocol) 是DMTF标准的管理组件传输协议:

消息类型

  • MCTP_MESSAGE_TYPE_MCTP_CTRL (0x00) - MCTP控制消息
  • MCTP_MESSAGE_TYPE_PLDM (0x01) - PLDM消息
  • MCTP_MESSAGE_TYPE_NCSI (0x02) - NCSI消息
  • MCTP_MESSAGE_TYPE_NVME (0x04) - NVMe管理消息
  • MCTP_MESSAGE_TYPE_VDPCI (0x7E) - PCIe厂商定义消息

物理媒介

  • PHY_MEDIUM_PCI (0x0F) - PCIe绑定
  • PHY_MEDIUM_SMBUS (0x02) - SMBus绑定
  • PHY_MEDIUM_SMBUS_OEM (0x80) - SMBus OEM绑定

使用示例

cpp
// MCTP 对象无默认构造函数,需传入父对象、物理地址、消息类型和位置
uint16_t phy_addr = mctp::init_phy_addr(bus, device, function); // 静态方法计算物理地址
mc::shared_ptr<mctp> mctp_obj =
    mc::make_shared<mctp>(this, phy_addr, MCTP_MESSAGE_TYPE::MCTP_MESSAGE_TYPE_NCSI, "");

// 创建传输对象和端点对象,端点和传输就绪后回调初始化业务任务
mctp_obj->create_transport_and_endpoint(std::string(get_object_name()), [this]() {
    // 端点就绪后,启动 NCSI 等上层协议任务
});

// 发送请求(request 返回 bool,响应保存在 rsp 字符串中)
mc::dict ctx = {{"timeout", 1000}};
std::vector<uint8_t> request_data = {...};  // 填充请求数据
std::string rsp;
if (mctp_obj->request(ctx, request_data, 1000, rsp)) {
    // 处理响应...
}

1.4.4 NCSI over MCTP协议

NCSI over MCTP 是华为扩展的混合协议,通过MCTP传输层发送NCSI命令:

架构优势

特性NCSIMCTPNCSI over MCTP
传输方式SocketPCIe/I2CMCTP传输NCSI
OEM扩展有限丰富丰富OEM命令
性能中等高性能
适用场景标准网卡通用管理华为网卡

协议栈实现

ncsi_over_mctp_huawei (华为OEM命令实现)

ncsi_over_mctp_standard (标准NCSI命令实现)

ncsi_over_mctp (基础封装)

mctp (MCTP传输层)

华为OEM命令

命令功能用途
get_bdf获取 BDF 信息获取网卡所在总线/设备/功能号
get_mac_addr / get_default_mac_addr获取 MAC 地址MAC 地址管理
get_chip_temp / get_om_temp获取芯片/光模块温度温度监控
get_link_ability / get_link_info获取链路能力/信息链路状态查询
get_dcbx_status获取 DCBX 状态数据中心桥接配置
get_fault_state_code获取故障状态码故障诊断
get_optical_module_info获取光模块信息光模块管理
collect_logs_by_ncsi / collect_logs_by_new_cmd收集日志故障诊断
LLDP 系列(enable/disable/get_lldp_*管理 LLDP 能力与发送链路发现

使用示例

cpp
// 1. 创建 MCTP 对象(NCSI over MCTP 基于 MCTP 传输层)
uint16_t phy_addr =
    mctp::init_phy_addr(m_pcie_device_pcie_function.BusNumber,
                        m_pcie_device_pcie_function.DeviceNumber,
                        m_pcie_device_pcie_function.FunctionNumber);
mc::shared_ptr<mctp> mctp_obj =
    mc::make_shared<mctp>(this, phy_addr, MCTP_MESSAGE_TYPE::MCTP_MESSAGE_TYPE_NCSI, "");

// 2. 通过 MCTP 对象构造华为扩展协议实例
ncsi_over_mctp_hw_ptr nom_hw = std::make_shared<ncsi_over_mctp_huawei>(mctp_obj);

// 3. 获取链路信息(package_id/channel_id 为入参,信息写入出参指针)
ncsi_link_info_t link_info;
if (nom_hw->get_link_info(DEFAULT_PACKAGE_ID, DEFAULT_CHANNEL_ID, &link_info)) {
    ilog("Link width: ${width}, speed: ${speed}",
         ("width", link_info.link_width)("speed", link_info.link_speed));
}

// 4. 获取芯片温度
uint16_t chip_temp = 0;
if (nom_hw->get_chip_temp(DEFAULT_PACKAGE_ID, DEFAULT_CHANNEL_ID, &chip_temp)) {
    ilog("Chip temperature: ${temp}", ("temp", chip_temp));
}

// 5. 在设备对象中,通常通过 mctp->create_transport_and_endpoint 回调中创建并绑定任务:
mctp_obj->create_transport_and_endpoint(std::string(get_object_name()), [this, mctp_obj]() {
    m_ncsi_over_mctp_huawei = std::make_shared<ncsi_over_mctp_huawei>(mctp_obj);
    m_network_adapter.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, m_interval);
});

1.4.5 IMU协议

IMU (Inertial Measurement Unit) 协议用于通过IPMI获取PCIe设备信息:

使用示例

cpp
// 创建IMU对象(无默认构造函数,需传入服务指针)
imu_ptr m_imu_obj = std::make_shared<imu>(get_service());

// 准备请求
imu_pcie_device_req_t req = {
    .system_id        = m_system_id,
    .socket_id        = m_pcie_device.SocketId,
    .bus              = m_pcie_device_pcie_function.BusNumber,
    .device           = m_pcie_device_pcie_function.DeviceNumber,
    .function         = m_pcie_device_pcie_function.FunctionNumber,
    .pci_info_address = VID_DID_ADDRESS, // VendorID + DeviceID
    .rlen             = 4,
};

// 获取设备信息(返回 std::optional<std::vector<uint8_t>>,小端序 VID/DID)
auto info = m_imu_obj->get_info_from_imu(true, req);
if (info && info->size() >= 4) {
    uint16_t device_id = (static_cast<uint16_t>((*info)[3]) << 8) | (*info)[2];
    uint16_t vendor_id = (static_cast<uint16_t>((*info)[1]) << 8) | (*info)[0];
    ilog("VID=0x${vid:04x}, DID=0x${did:04x}", ("vid", vendor_id)("did", device_id));
}

1.5 驱动ABI接口

驱动通过标准的C风格ABI接口与devmon框架交互。ABI定义在include/devmon/driver_abi.h中:

cpp
// 设备驱动描述结构
struct device_driver {
    const char*        device_name; // 设备名称(如 "PCIeNicCard")
    const driver_ctor  ctor;        // 创建函数
    const driver_init  init;        // 初始化函数
    const driver_start start;       // 启动函数
    const driver_stop  stop;        // 停止函数
    driver_dump        dump = nullptr; // 可选:设备状态转储
};
typedef struct device_driver device_driver_t;

// 驱动SO导出的注册函数:返回驱动数组及其数量
status_t register_device_driver(device_driver_t** device_driver, uint8_t* count);

驱动SO导出的是register_device_driver符号(而非get_device_driver),实现方式见 4.6 节示例。

2. 架构设计

2.1 分层架构概览

2.2 设备树对象与内部器件对象关系

2.2.1 职责分工

设备树对象

  • 负责设备树配置管理和对外ABI接口
  • 继承自mc::engine::object,支持设备树配置
  • 包含接口类成员,用于属性管理和配置加载
  • 实现init(), start(), stop()等生命周期方法

内部器件对象

  • 负责具体的硬件操作和业务逻辑实现
  • 继承自bus_basechip_base基类
  • 实现具体的读写、初始化、硬件自检等功能
  • 管理底层驱动实例和硬件资源

3. 开发流程

3.1 开发准备

3.1.1 环境要求

  • 操作系统:Linux (推荐Ubuntu 18.04+)
  • 编译器:支持C++17的GCC 7.0+或Clang 5.0+
  • 构建系统:Meson 0.50+
  • 依赖库:libmcpp (自动管理)

3.1.2 源码结构

component_drivers/
├── drivers/                    # 驱动实现
│   ├── [device_type]/         # 设备类型目录
│   │   ├── [vendor]/          # 厂商实现目录
│   │   └── interface/         # 接口实现
│   └── internal/              # 内部器件对象
├── gen/device_tree/interface/ # 生成的设备树接口
├── libraries/                 # 协议通信库
├── include/devmon/            # 公共头文件
└── tests/                     # 测试代码

3.2 新驱动开发步骤

步骤1: 需求分析和设计

  1. 确定设备类型:PCIe设备、I2C设备、传感器等
  2. 选择基类:继承相应的基类(PCIeCard, bus_base, chip_base等)
  3. 协议选择:确定需要的通信协议(NCSI, MCTP, IMU等)
  4. 接口设计:定义需要暴露的属性和方法

步骤2: 设备树接口定义

gen/include/device_tree/interface/中定义设备接口:

cpp
// gen/include/device_tree/interface/MyDevice.h
#ifndef GEN_MY_DEVICE_INTERFACE_H
#define GEN_MY_DEVICE_INTERFACE_H

#include <device_tree/base.h>

namespace dev::gen {

class MC_API MyDevice : public mc::engine::interface<MyDevice> {
public:
    MC_INTERFACE("bmc.dev.MyDevice")

    // 设备属性定义
    property<std::string> DeviceName;
    property<uint8_t>     DeviceId;
    property<std::string> Version;
    property<bool>        IsEnabled;

    // 虚函数接口(如需要)
    virtual bool Initialize();
    virtual bool GetStatus();
    virtual void SetEnabled(bool enabled);
};

} // namespace dev::gen

#endif // GEN_MY_DEVICE_INTERFACE_H

注意:

  • 现在使用dev::gen命名空间
  • 无需手动编写反射宏,框架自动处理
  • 属性使用property<T>模板定义
  • 虚函数可以有默认实现

步骤3: 内部器件对象实现

实现具体的硬件操作逻辑:

cpp
// drivers/internal/my_device/my_device_internal.h
#ifndef MY_DEVICE_INTERNAL_H
#define MY_DEVICE_INTERNAL_H

#include <memory>
#include <vector>
#include <mc/dict.h>

class MyDeviceInternal {
public:
    MyDeviceInternal() = default;
    ~MyDeviceInternal() = default;

    bool init(const mc::dict& config);
    bool start();
    bool stop();

    // 硬件操作接口
    bool read_register(uint32_t offset, uint32_t& value);
    bool write_register(uint32_t offset, uint32_t value);
    bool get_device_status();

private:
    std::string m_device_name;
    uint8_t m_device_id;
    bool m_initialized = false;

    // 硬件资源管理
    void* m_hardware_handle = nullptr;
};

#endif // MY_DEVICE_INTERNAL_H
cpp
// drivers/internal/my_device/my_device_internal.cpp
#include "my_device_internal.h"
#include <mc/log.h>

bool MyDeviceInternal::init(const mc::dict& config) {
    try {
        m_device_name = config["DeviceName"].as<std::string>();
        m_device_id = config["DeviceId"].as<uint8_t>();

        // 硬件初始化逻辑
        // m_hardware_handle = open_hardware_device(m_device_id);

        m_initialized = true;
        ilog("MyDevice initialized: ${name} (ID: ${id})",
             ("name", m_device_name)("id", m_device_id));
        return true;
    } catch (const std::exception& e) {
        elog("Failed to initialize MyDevice: ${error}", ("error", e.what()));
        return false;
    }
}

bool MyDeviceInternal::read_register(uint32_t offset, uint32_t& value) {
    if (!m_initialized) {
        elog("Device not initialized");
        return false;
    }

    // 实现具体的寄存器读取逻辑
    // value = hardware_read(m_hardware_handle, offset);

    return true;
}

步骤4: 接口类实现

创建接口类,连接设备树接口和内部实现:

cpp
// drivers/my_device/interface/i_my_device.h
#ifndef I_MY_DEVICE_H
#define I_MY_DEVICE_H

#include <device_tree/interface/MyDevice.h>
#include "../internal/my_device_internal.h"

namespace dev {

// MyDevice 默认值常量
constexpr uint8_t     MY_DEVICE_DEFAULT_ID      = 0;
constexpr bool        MY_DEVICE_DEFAULT_ENABLED = false;
constexpr const char* MY_DEVICE_DEFAULT_VERSION = "1.0";

class IMyDevice : public mc::engine::interface<IMyDevice, gen::MyDevice> {
public:
    IMyDevice() {
        // 使用默认值初始化成员变量
        DeviceId  = MY_DEVICE_DEFAULT_ID;
        IsEnabled = MY_DEVICE_DEFAULT_ENABLED;
        Version   = MY_DEVICE_DEFAULT_VERSION;
    }
    ~IMyDevice() = default;

    // 实现设备树接口的虚函数
    bool Initialize() override;
    bool GetStatus() override;
    void SetEnabled(bool enabled) override;

    // 从variant中加载配置到基类属性
    void from_variant(mc::mutable_dict& csr_object);

private:
    std::unique_ptr<MyDeviceInternal> m_internal;
};

} // namespace dev

#endif // I_MY_DEVICE_H

步骤5: 设备对象实现

实现主设备对象,管理整个设备的生命周期:

cpp
// drivers/my_device/my_device.h
#ifndef MY_DEVICE_H
#define MY_DEVICE_H

#include <mc/engine.h>
#include "interface/i_my_device.h"

namespace dev {

class MyDevice : public mc::engine::object<MyDevice> {
public:
    MC_OBJECT(MyDevice, "MyDevice", "/bmc/dev/MyDevice/${DeviceName}", (IMyDevice))

    MyDevice() = default;
    ~MyDevice() = default;

    // 生命周期管理
    bool init(mc::mutable_dict& csr_object, const mc::dict& connector);
    bool start();
    bool stop();

    // 设备接口实例
    IMyDevice i_my_device;

private:
    bool m_started = false;
};

} // namespace dev

MC_REFLECT(dev::MyDevice, ((i_my_device, "bmc.dev.MyDevice")))

#endif // MY_DEVICE_H

步骤6: ABI接口实现

实现驱动注册和生命周期管理的ABI接口:

cpp
// drivers/my_device/my_device_abi.cpp
#include <devmon/driver_abi.h>
#include <mc/log.h>
#include "my_device.h"

using namespace dev;

extern "C" {

driver_handle_t create_my_device(void* service, const char* name) {
    try {
        if (service == nullptr || name == nullptr) {
            elog("Error creating MyDevice: invalid parameters");
            return nullptr;
        }

        MyDevice* device = new MyDevice();
        device->set_service(static_cast<mc::engine::service*>(service));
        device->set_object_name(name);
        return (void*)device;
    } catch (const std::exception& e) {
        elog("Error creating MyDevice: ${error}", ("error", e.what()));
        return nullptr;
    }
}

status_t init_my_device(driver_handle_t device, void* csr_object, void* connector) {
    if (device == nullptr || csr_object == nullptr || connector == nullptr) {
        elog("Error initializing MyDevice: invalid parameters");
        return STATUS_ERROR;
    }

    MyDevice* device_object = static_cast<MyDevice*>(device);
    mc::mutable_dict* csr_object_ptr = static_cast<mc::mutable_dict*>(csr_object);
    mc::dict* connector_ptr = static_cast<mc::dict*>(connector);

    bool ret = device_object->init(*csr_object_ptr, *connector_ptr);
    return ret ? STATUS_OK : STATUS_ERROR;
}

status_t start_my_device(driver_handle_t device) {
    if (device == nullptr) {
        elog("Error starting MyDevice: device is null");
        return STATUS_ERROR;
    }
    MyDevice* device_object = static_cast<MyDevice*>(device);
    bool ret = device_object->start();
    return ret ? STATUS_OK : STATUS_ERROR;
}

status_t stop_my_device(driver_handle_t device) {
    if (device == nullptr) {
        elog("Error stopping MyDevice: device is null");
        return STATUS_ERROR;
    }
    MyDevice* device_object = static_cast<MyDevice*>(device);
    bool ret = device_object->stop();
    return ret ? STATUS_OK : STATUS_ERROR;
}

// 设备驱动信息
device_driver_t my_device_driver = {
    .device_name = "MyDevice",
    .ctor = create_my_device,
    .init = init_my_device,
    .start = start_my_device,
    .stop = stop_my_device
};

} // extern "C"

步骤7: 构建配置

创建Meson构建配置:

meson
# drivers/my_device/meson.build
my_device_sources = [
    'my_device.cpp',
    'my_device_abi.cpp',
    'interface/i_my_device.cpp',
    'internal/my_device_internal.cpp',
]

my_device_lib = shared_library(
    'MyDevice',
    my_device_sources,
    include_directories: [
        include_directories('.'),
        include_directories('interface'),
        gen_inc,
        internal_inc
    ],
    dependencies: [mcpp_dep, internal_dep],
    install: true,
    install_dir: drivers_install_dir,
)

my_device_dep = declare_dependency(
    link_with: my_device_lib,
    include_directories: include_directories('.')
)

4. PCIe板卡驱动开发规范

4.1 板卡驱动架构设计

PCIe板卡驱动采用分层架构,支持多厂商、多型号的复杂板卡设备:

4.2 板卡驱动文件组织规范

4.2.1 目录结构标准

drivers/pcie_{card_type}_card/           # 板卡类型根目录
├── {vendor}/                           # 厂商实现目录
│   ├── {model}/                        # 型号具体实现
│   │   ├── {model}_card.h              # 主板卡对象定义
│   │   ├── {model}_card.cpp            # 主板卡对象实现
│   │   ├── {model}_abi.cpp             # ABI导出实现
│   │   ├── {model}_{sub_device}.h      # 子设备对象定义
│   │   ├── {model}_{sub_device}.cpp    # 子设备对象实现
│   │   └── meson.build                 # 构建配置
│   ├── csr/                            # 设备树配置
│   │   ├── *.dds                       # 设备描述文件
│   │   └── *.sr                        # 自描述记录文件
│   └── interface/                      # 厂商专用接口
│       ├── {interface}.h               # 接口定义
│       ├── {interface}.cpp             # 接口实现
│       └── {interface}/                # 子接口目录
└── meson.build                         # 根构建配置

实际目录示例

  • pcie_nic_card/hisi/hi182x/ - 华为海思Hi182x网卡
  • pcie_nic_card/wangxun/rp1000/ - 网迅RP1000网卡
  • pcie_gpu_card/innosilicon/awm_m11p/ - 英诺硅AWM-M11P GPU

4.2.2 命名规范

主对象命名

  • 类名:{vendor}_{model}_card(如hi182x_card, wx_card
  • 文件名:{vendor}_{model}_card.{h|cpp}
  • ABI函数:create_{vendor}_{model}_card

子设备命名

  • 类名:{vendor}_{model}_{sub_type}(如hi182x_port, awm_m11p_gpu
  • 设备类型:NicPort, OpticalTransceiver, Gpu, Memory

4.3 板卡主对象设计模式

4.3.1 多接口组合模式

板卡驱动的核心特征是组合多个标准接口,形成完整的设备功能。以华为海思Hi182x网卡为例:

接口组合架构
接口类别接口名称成员变量功能说明是否必需
基础接口PCIeDevicem_pcie_devicePCIe设备基本信息(VID/DID)✅ 必需
基础接口PCIeDevice_PCIeFunctionm_pcie_device_pcie_functionPCIe功能信息(BDF、链路能力)✅ 必需
基础接口PCIeCardm_pcie_cardPCIe卡片信息(插槽、链路状态)✅ 必需
基础接口Boardm_board板卡信息(序列号、制造商)⭕ 可选
功能接口NetworkAdapterm_network_adapter网络适配器功能(MAC地址、速率)✅ 网卡必需
扩展接口NetworkAdapter_FaultStatusm_network_adapter_fault_status故障状态监控⭕ 可选
扩展接口Coolingm_cooling冷却和温度管理(bmc.dev.Cooling)⭕ 可选
扩展接口PCIeDevice_Bandwidthm_pcie_device_bandwidthPCIe带宽监控⭕ 可选
扩展接口NetworkAdapter_LogCollectionm_network_adapter_log_collection日志收集功能⭕ 可选
扩展接口NetworkAdapter_Oemm_network_adapter_oem厂商扩展功能⭕ 可选
协议栈集成
协议类型成员变量协议作用应用场景
NCSI over MCTPm_ncsi_over_mctp_huawei华为扩展的NCSI协议网卡状态查询、配置管理、OEM命令
IMUm_imu_obj设备管理单元协议通过IPMI获取设备信息、固件版本
SMBUSm_smbus_obj系统管理总线协议温度监控、电源管理、芯片通信
子设备管理
子设备类型容器类型说明生命周期管理
网络端口std::vector<hi182x_port*>管理多个物理网络端口父设备启动时初始化,停止时清理
光模块由端口对象管理每个端口可包含光模块随端口生命周期管理
生命周期方法
方法类型方法名称调用时机主要职责
公有方法init()设备创建后加载CSR配置、初始化成员变量
公有方法start()初始化完成后启动协议、初始化子设备、注册回调
公有方法stop()设备停止时停止协议、清理子设备、释放资源
私有方法init_network_ports()start()阶段发现和初始化网络端口
私有方法start_ncsi_protocol()start()阶段启动NCSI协议并绑定接口
私有方法start_smbus_protocol()start()阶段启动SMBUS协议通信
私有方法init_imu_protocol()start()阶段初始化IMU设备管理
类定义示例
cpp
// 华为海思Hi182x网卡示例
class hi182x_card : public mc::engine::object<hi182x_card> {
public:
    MC_OBJECT(
        hi182x_card, "PCIeNicCard", "/bmc/dev/Systems/1/PCIeNicCard/${object_name}",
        (PCIeDevice)(PCIeDevice_PCIeFunction)(PCIeDevice_Oem)(PCIeDevice_Status)(PCIeCard)(PCIeCard_Oem)
        (PCIeCard_Metrics)(NetworkAdapter)(NetworkAdapter_FaultStatus)(Cooling)(NetworkAdapter_Oem)(Board)
        (PCIeDevice_Bandwidth)(NetworkAdapter_LogCollection)(Fru))

    // === 接口对象组合 ===
    NetworkAdapter_Oem           m_network_adapter_oem;           // 网络适配器OEM扩展
    PCIeDevice                   m_pcie_device;                   // PCIe设备信息
    PCIeDevice_PCIeFunction      m_pcie_device_pcie_function;     // PCIe功能信息
    PCIeDevice_Oem               m_pcie_device_oem;               // PCIe设备OEM扩展
    PCIeDevice_Status            m_pcie_device_status;            // PCIe设备状态
    PCIeCard                     m_pcie_card;                     // PCIe卡片信息
    PCIeCard_Oem                 m_pcie_card_oem;                 // PCIe卡片OEM扩展
    PCIeCard_Metrics             m_pcie_card_metrics;             // 卡片运行态指标
    Cooling                      m_cooling;                       // 冷却管理
    NetworkAdapter               m_network_adapter;               // 网络适配器
    NetworkAdapter_FaultStatus   m_network_adapter_fault_status;  // 故障状态
    Board                        m_board;                         // 板卡信息
    PCIeDevice_Bandwidth         m_pcie_device_bandwidth;         // 带宽监控
    NetworkAdapter_LogCollection m_network_adapter_log_collection; // 日志收集
    Fru                          m_fru;                           // FRU信息
    uint8_t                      m_system_id;                     // 系统ID

    // === 生命周期管理 ===
    bool start();
    bool stop();
    bool init(mc::mutable_dict& csr_object, const mc::dict& connector);

private:
    // === 子设备管理 ===
    std::vector<hi182x_port*> m_network_ports;      // 网络端口集合

    // === 协议支持 ===
    ref_chip_ptr          m_ref_chip;               // 参考芯片对象
    smbus_obj_ptr         m_smbus_obj;              // SMBUS通信
    imu_ptr               m_imu_obj;                // IMU设备管理
    ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;  // 华为NCSI over MCTP协议
    mc::milliseconds      m_interval       = mc::milliseconds(5000); // NCSI更新间隔5s
    mc::milliseconds      m_smbus_interval = mc::milliseconds(5000); // SMBUS更新间隔5s
    mc::shared_ptr<mctp>  m_mctp_object;            // MCTP底层协议

    // === 协议生命周期管理 ===
    void init_network_ports();     // 初始化网络端口
    bool start_ncsi_protocol();    // 启动NCSI协议
    bool start_smbus_protocol();   // 启动SMBUS协议
    bool init_imu_protocol();      // 初始化IMU协议
    bool start_protocol();         // 启动NCSI over MCTP协议
};
接口组合设计原则
原则说明示例
必需接口优先基础接口(PCIeDevice/PCIeCard/Board)必须实现所有PCIe设备都需要
功能接口明确根据设备类型选择功能接口网卡选NetworkAdapter,GPU选Gpu
扩展接口可选根据硬件能力添加扩展接口支持温度监控则添加Cooling
接口命名规范使用下划线连接主接口和子接口NetworkAdapter_FaultStatus
接口分组排列MC_OBJECT宏中按功能分组基础接口→功能接口→扩展接口

4.3.2 GPU板卡设计模式

cpp
// 英诺硅AWM-M11P GPU卡示例
class awm_m11p_card : public mc::engine::object<awm_m11p_card> {
public:
    MC_OBJECT(awm_m11p_card, "PCIeGpuCard",
              "/bmc/dev/Systems/1/PCIeGpuCard/${object_name}",
              (PCIeDevice)(PCIeDevice_Oem)(PCIeDevice_Status)(PCIeDevice_PCIeFunction)(PCIeCard)(PCIeCard_Oem))

    PCIeDevice              m_pcie_device;              // PCIe设备信息
    PCIeDevice_Oem          m_pcie_device_oem;          // PCIe设备OEM信息
    PCIeDevice_Status       m_pcie_device_status;       // PCIe设备状态
    PCIeDevice_PCIeFunction m_pcie_device_pcie_function; // PCIe功能信息
    PCIeCard                m_pcie_card;                // PCIe卡片信息
    PCIeCard_Oem            m_pcie_card_oem;            // PCIe卡片OEM信息
    uint8_t                 SystemId;                   // 系统ID

    bool start();
    bool stop();
    bool init(mc::mutable_dict& csr_object, const mc::dict& connector);
};

4.4 协议集成管理

4.4.1 多协议并行管理

PCIe板卡通常需要集成多种通信协议,每种协议有独立的生命周期:

cpp
class hi182x_card : public mc::engine::object<hi182x_card> {
private:
    // === 协议对象管理 ===
    ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;  // 华为NCSI over MCTP
    imu_ptr               m_imu_obj;                // IMU设备管理协议
    smbus_obj_ptr         m_smbus_obj;              // SMBUS系统管理总线
    mc::shared_ptr<mctp>  m_mctp_object;            // MCTP底层协议对象

    // === 定时任务管理 ===
    mc::milliseconds m_interval       = mc::milliseconds(5000);  // NCSI更新间隔
    mc::milliseconds m_smbus_interval = mc::milliseconds(5000);  // SMBUS更新间隔

    // === 协议启动和管理 ===
    // 各协议独立启动,start() 中按序调用:
    //   start_protocol();        // 启动 NCSI over MCTP
    //   start_smbus_protocol();  // 启动 SMBUS
    //   init_imu_protocol();     // 初始化 IMU
    bool start_protocol() {
        return start_ncsi_protocol();
    }

    bool start_ncsi_protocol() {
        // 校验BDF已初始化
        if (m_pcie_device_pcie_function.BusNumber == 0 &&
            m_pcie_device_pcie_function.DeviceNumber == 0 &&
            m_pcie_device_pcie_function.FunctionNumber == 0) {
            elog("PCIe device BDF not initialized");
            return false;
        }

        // 1. 计算物理地址并创建 MCTP 对象
        uint16_t phy_addr =
            mctp::init_phy_addr(m_pcie_device_pcie_function.BusNumber,
                                m_pcie_device_pcie_function.DeviceNumber,
                                m_pcie_device_pcie_function.FunctionNumber);
        m_mctp_object = mc::make_shared<mctp>(this, phy_addr,
                                              MCTP_MESSAGE_TYPE::MCTP_MESSAGE_TYPE_NCSI, "");

        // 2. 在端点就绪回调中创建 NCSI over MCTP 实例并绑定各接口任务
        auto ncsi_update_task = [this]() {
            m_ncsi_over_mctp_huawei = std::make_shared<ncsi_over_mctp_huawei>(m_mctp_object);
            for (auto& port : m_network_ports) {
                port->start_ncsi_update_task(m_ncsi_over_mctp_huawei, m_interval);
                port->enable_lldp_over_mctp();   // 开启 lldp_over_mctp 透传
            }
            m_network_adapter.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, mc::milliseconds(120000));
            m_network_adapter_fault_status.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, m_interval);
            m_pcie_device_bandwidth.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, mc::milliseconds(180000));
            m_pcie_device_pcie_function.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei,
                                                                      mc::milliseconds(120000));
            m_cooling.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, m_interval);
            m_network_adapter_log_collection.init_ncsi_endpoint(m_ncsi_over_mctp_huawei);
        };
        m_mctp_object->create_transport_and_endpoint(std::string(get_object_name()), ncsi_update_task);
        return true;
    }
};

协议集成规范

  1. 协议隔离:每种协议使用独立的智能指针管理
  2. 统一初始化:在start_protocol()中统一管理协议启动
  3. 接口绑定:将协议实例绑定到相关接口对象
  4. 错误处理:协议初始化失败时进行适当的错误处理和资源清理
  5. 定时任务:使用统一的定时间隔管理协议更新

4.4.2 协议差异化处理

不同厂商的板卡支持不同的协议组合:

cpp
// 华为海思 - 支持NCSI+IMU+SMBUS
class hi182x_card {
    ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei; // 华为专用NCSI
    imu_ptr               m_imu_obj;                // IMU协议
    smbus_obj_ptr         m_smbus_obj;              // SMBUS协议
};

// 网迅 - 支持NCSI+IMU,附加四元组更新
class rp1000_card {
    ncsi_over_mctp_wx_ptr          m_ncsi_over_mctp_wx;          // 网迅专用NCSI over MCTP
    imu_ptr                        m_imu_obj;                    // IMU协议
    mc::shared_ptr<mctp>           m_mctp_object        = nullptr; // MCTP底层协议
    mc::milliseconds               m_interval           = mc::milliseconds(5000);   // NCSI更新间隔5s
    mc::milliseconds               m_quadruple_interval = mc::milliseconds(10000);  // 四元组更新间隔10s
    mc::shared_ptr<mc::timer>      m_quadruple_timer;           // 四元组更新定时器
    bool                           m_first_quadruple_update;    // 是否首次四元组更新
};

// 英诺硅GPU - 简化协议支持
class awm_m11p_card {
    // GPU卡通常协议需求较简单,主要依赖PCIe标准接口
};

4.5 子设备管理模式

4.5.1 动态子设备发现

板卡驱动通过框架提供的get_children()方法动态发现和管理子设备:

cpp
void hi182x_card::init_network_ports() {
    auto objects = get_children();  // 获取所有子对象
    if (objects.empty()) {
        elog("Error: No network ports found");
        return;
    }

    for (auto& object : objects) {
        auto object_name = object->get_name();

        // 通过对象名前缀识别设备类型
        if (object_name.substr(0, object_name.find_first_of("_")) == "NicPort") {
            // 使用 dynamic_cast 并校验空指针,避免向下转换失败
            auto* port = dynamic_cast<hi182x_port*>(object.get());
            if (port == nullptr) {
                elog("hi182x_card child ${name} is not hi182x_port, skip", ("name", object_name));
                continue;
            }
            ilog("hi182x_card init network port ${name}", ("name", object_name));
            m_network_ports.push_back(port);
        }
        // 可以添加其他子设备类型的识别
        else if (object_name.find("OpticalTransceiver") != std::string::npos) {
            // 光模块设备处理
        }
    }
}

子设备管理规范

  1. 类型识别:通过对象名前缀或特征字符串识别子设备类型
  2. 类型转换:使用dynamic_cast将基类指针转换为具体子设备类型,并必须校验空指针(禁止使用static_cast向下转换)
  3. 集合管理:使用std::vector管理同类型子设备集合
  4. 生命周期同步:主设备的启动/停止时同步管理所有子设备

4.5.2 子设备生命周期管理

cpp
bool hi182x_card::start() {
    // 1. 初始化子设备
    init_network_ports();

    // 2. 启动所有子设备
    for (auto& port : m_network_ports) {
        port->start();
        if (port->m_optical_module) {
            port->m_optical_module->m_optical_module_status.set_network_adapter_oem(&m_network_adapter_oem);
            port->m_optical_module->m_optical_module_temperature_celsius.set_network_adapter_oem(
                &m_network_adapter_oem);
        }
    }

    // 3. 建立主接口间的交叉引用
    m_cooling.set_network_adapter_oem(&m_network_adapter_oem);
    m_network_adapter_fault_status.set_network_adapter_oem(&m_network_adapter_oem);
    m_network_adapter_oem.set_network_adapter(&m_network_adapter);
    m_network_adapter.set_network_adapter_oem(&m_network_adapter_oem);

    // 4. 各协议独立启动
    start_protocol();       // 启动 NCSI over MCTP
    start_smbus_protocol(); // 启动 SMBUS
    setup_vdpci_lldp_listener();
    init_imu_protocol();    // 初始化 IMU

    // 5. 注册事件回调
    m_network_adapter_oem.register_os_reset_callback([this]() {
        this->handle_os_reset();
    });
    m_network_adapter_oem.register_os_off_callback([this]() {
        this->handle_os_off();
    });

    return true;
}

bool hi182x_card::stop() {
    // 1. 停止各协议更新任务
    stop_ncsi_update_task();
    m_network_adapter_log_collection.clean_ncsi_endpoint();
    for (auto& port : m_network_ports) {
        if (port != nullptr) {
            port->stop_ncsi_update_task();
        }
    }
    if (m_smbus_obj) {
        stop_smbus_update_task();
        m_network_adapter_log_collection.clean_smbus_obj();
        m_network_adapter_oem.clean_smbus_obj();
        for (auto& port : m_network_ports) {
            if (port != nullptr) {
                port->stop_smbus_update_task();
            }
        }
    }
    for (auto& port : m_network_ports) {
        if (port != nullptr) {
            port->stop_lldp_clear_timer();
        }
    }

    // 2. 注销回调并断开交叉引用
    m_network_adapter_oem.unregister_os_reset_callback();
    m_network_adapter_oem.unregister_os_off_callback();
    m_network_adapter_oem.unregister_eeprom_wp_callback();
    m_network_adapter_oem.set_network_adapter(nullptr);
    m_network_adapter.set_network_adapter_oem(nullptr);
    m_cooling.set_network_adapter_oem(nullptr);
    m_network_adapter_fault_status.set_network_adapter_oem(nullptr);

    return true;
}

4.6 ABI实现规范

4.6.1 多设备ABI导出

PCIe板卡驱动通常需要导出主设备和多个子设备的ABI接口:

cpp
// PCIe网卡ABI实现示例
extern "C" {

// === 主板卡设备ABI ===
driver_handle_t create_hi182x_card(void* service, const char* name) {
    try {
        if (service == nullptr || name == nullptr) {
            return nullptr;
        }
        hi182x_card* device = new hi182x_card();
        device->set_service(static_cast<mc::engine::service*>(service));
        device->set_object_name(name);
        return (void*)device;
    } catch (const std::exception& e) {
        elog("Error creating hi182x PCIeNicCard: ${error}", ("error", e.what()));
        return nullptr;
    }
}

status_t init_hi182x_card(driver_handle_t device, void* csr_object, void* connector) {
    if (device == nullptr || csr_object == nullptr || connector == nullptr) {
        elog("Error initializing hi182x PCIeNicCard: device is null");
        return STATUS_ERROR;
    }
    hi182x_card*      device_object  = static_cast<hi182x_card*>(device);
    mc::mutable_dict* csr_object_ptr = static_cast<mc::mutable_dict*>(csr_object);
    mc::dict*         connector_ptr  = static_cast<mc::dict*>(connector);

    bool ret = device_object->init(*csr_object_ptr, *connector_ptr);
    return ret ? STATUS_OK : STATUS_ERROR;
}

status_t start_hi182x_card(driver_handle_t device) {
    if (device == nullptr) {
        elog("Error starting hi182x PCIeNicCard: device is null");
        return STATUS_ERROR;
    }
    hi182x_card* device_object = static_cast<hi182x_card*>(device);
    device_object->start();
    return STATUS_OK;
}

status_t stop_hi182x_card(driver_handle_t device) {
    if (device == nullptr) {
        elog("Error stopping hi182x PCIeNicCard: device is null");
        return STATUS_ERROR;
    }
    hi182x_card* device_object = static_cast<hi182x_card*>(device);
    device_object->stop();
    return STATUS_OK;
}

// === 网络端口子设备ABI ===
driver_handle_t create_hi182x_port(void* service, const char* name) {
    try {
        if (service == nullptr || name == nullptr) {
            return nullptr;
        }
        hi182x_port* device = new hi182x_port();
        device->set_service(static_cast<mc::engine::service*>(service));
        device->set_object_name(name);
        return (void*)device;
    } catch (const std::exception& e) {
        elog("Error creating hi182x NicPort: ${error}", ("error", e.what()));
        return nullptr;
    }
}

// === 光模块子设备ABI ===
driver_handle_t create_hi182x_optical_module(void* service, const char* name) {
    try {
        if (service == nullptr || name == nullptr) {
            return nullptr;
        }
        hi182x_optical_module* device = new hi182x_optical_module();
        device->set_object_name(name);
        device->set_service(static_cast<mc::engine::service*>(service));
        return (void*)device;
    } catch (const std::exception& e) {
        elog("Error creating hi182x OpticalTransceiver: ${error}", ("error", e.what()));
        return nullptr;
    }
}

// === 设备驱动注册表 ===
device_driver_t hi182x_card_device_driver = {
    .device_name = "PCIeNicCard",
    .ctor        = create_hi182x_card,
    .init        = init_hi182x_card,
    .start       = start_hi182x_card,
    .stop        = stop_hi182x_card
};

device_driver_t hi182x_port_device_driver = {
    .device_name = "NicPort",
    .ctor        = create_hi182x_port,
    .init        = init_hi182x_port,
    .start       = start_hi182x_port,
    .stop        = stop_hi182x_port
};

device_driver_t hi182x_optical_module_device_driver = {
    .device_name = "OpticalTransceiver",
    .ctor        = create_hi182x_optical_module,
    .init        = init_hi182x_optical_module,
    .start       = start_hi182x_optical_module,
    .stop        = stop_hi182x_optical_module
};

// === 驱动导出 ===
device_driver_t hi182x_device_driver[] = {
    hi182x_card_device_driver,
    hi182x_port_device_driver,
    hi182x_optical_module_device_driver
};

status_t register_device_driver(device_driver_t** device_driver, uint8_t* count) {
    *device_driver = hi182x_device_driver;
    *count = sizeof(hi182x_device_driver) / sizeof(hi182x_device_driver[0]);
    return STATUS_OK;
}

} // extern "C"

ABI实现规范

  1. 设备分离:主设备和子设备分别实现独立的ABI函数
  2. 统一命名:函数名格式{action}_{vendor}_{model}_{device_type}
  3. 设备表管理:使用数组管理多个设备驱动结构
  4. 错误处理:每个ABI函数都要进行参数验证和异常处理

4.7 构建系统集成

4.7.1 分层构建配置

meson
# 主目录 drivers/pcie_nic_card/hisi/hi182x/meson.build
hisi_182x_sources = files(
  'hi182x_abi.cpp',        # ABI导出实现
  'hi182x_card.cpp',       # 主板卡对象
  'hi182x_om.cpp',         # 光模块子设备
  'hi182x_port.cpp',       # 网络端口子设备
)

include_dirs += include_directories('../../../chip')      # 芯片驱动路径
include_dirs += include_directories('../../../internal')  # 内部实现路径

# 静态库构建(用于测试)
libhisi_182x_static = static_library(
  'hisi_182x',
  hisi_182x_sources,
  include_directories: include_dirs + hisi_interface_inc,
  # 接口实现编译为独立共享库 libhisi_interface,此处仅声明依赖
  dependencies: [
    dev_deps,                # 基础开发依赖
    libhisi_interface_dep,   # 厂商接口共享库
    libncsi_over_mctp_dep,   # NCSI over MCTP协议库
    libpldm_over_mctp_dep,   # PLDM over MCTP协议库
    libmctp_dep,             # MCTP协议库
    libimu_dep,              # IMU协议库
    libsmbus_dep,            # SMBUS协议库
    liblldp_dep,             # LLDP协议库
  ],
  cpp_args: ['-Os', '-ffunction-sections', '-fdata-sections'],
  install: false,
)

# 动态库构建(用于部署)
libhisi_182x = shared_library(
  'hisi_182x',
  include_directories: include_dirs + hisi_interface_inc,
  name_prefix: 'lib',
  name_suffix: 'so',
  install: true,
  install_dir: drivers_install_dir,
  cpp_args: ['-Os', '-ffunction-sections', '-fdata-sections'],
  link_args: ['-Wl,--gc-sections', '-Wl,--strip-all', '-Wl,--as-needed'],
  link_whole: [libhisi_182x_static],  # 链接静态库
)

# 测试依赖声明
if build_tests
  hisi_182x_dep = declare_dependency(
    include_directories: include_dirs + hisi_interface_inc,
    link_with: libhisi_182x_static,
    dependencies: [
      libmcpp_deps,
      libncsi_over_mctp_dep,
      libmctp_dep,
      libimu_dep,
      libsmbus_dep,
      liblldp_dep,
    ],
  )
endif

构建配置规范

  1. 协议依赖:明确声明所有使用的协议库依赖
  2. 路径管理:正确配置include路径,包括芯片和内部实现路径
  3. 双库构建:同时提供静态库(测试用)和动态库(部署用)
  4. 条件编译:支持测试模式和部署模式的条件编译

4.8 设备树配置规范

4.8.1 DDS设备描述文件

json
{
    "Schema": "dds-v1",
    "Type": "Component",
    "DeviceCategory": "PCIeNicCard",
    "ID": "N/A",
    "Objects": {
        "PCIeNicCard": {
            "Path": "/bmc/dev/Systems/:SystemId/PCIeNicCard/:Id",
            "Interfaces": [
                "bmc.dev.PCIeDevice",                // PCIe设备基础接口
                "bmc.dev.PCIeDevice.PCIeFunction",   // PCIe功能信息接口
                "bmc.dev.PCIeDevice.Status",         // PCIe设备状态接口
                "bmc.dev.PCIeDevice.Oem",            // PCIe设备OEM扩展接口
                "bmc.dev.PCIeCard",                  // PCIe卡片信息接口
                "bmc.dev.PCIeCard.Oem",              // PCIe卡片OEM扩展接口
                "bmc.dev.PCIeCard.Metrics",          // PCIe卡片指标接口
                "bmc.dev.Board",                     // 板卡信息接口
                "bmc.dev.NetworkAdapter",            // 网络适配器接口
                "bmc.dev.PCIeDevice.Bandwidth",      // 带宽扩展接口
                "bmc.dev.Cooling",                   // 冷却扩展接口
                "bmc.dev.NetworkAdapter.FaultStatus", // 故障状态扩展接口
                "bmc.dev.NetworkAdapter.LogCollection", // 日志收集扩展接口
                "bmc.dev.NetworkAdapter.Oem"         // 网络适配器OEM扩展接口
            ]
        },
        "NicPort": {
            "Path": ":Parent/NicPort/:Id",
            "Interfaces": [
                "bmc.dev.NetworkPort",               // 网络端口基础接口
                "bmc.dev.NetworkPort.LinkInfo",      // 链路信息扩展接口
                "bmc.dev.NetworkPort.DataCenterBridging", // 数据中心桥接
                "bmc.dev.NetworkPort.LLDPReceive",   // LLDP接收扩展接口
                "bmc.dev.NetworkPort.Metrics"       // 监控指标扩展接口
            ]
        },
        "OpticalTransceiver": {
            "Path": ":Parent/OpticalTransceiver",
            "Interfaces": [
                "bmc.dev.OpticalModule",              // 光模块基础接口
                "bmc.dev.OpticalModule.Status",       // 状态扩展接口
                "bmc.dev.OpticalModule.TemperatureCelsius", // 温度扩展接口
                "bmc.dev.OpticalModule.Voltage",      // 电压扩展接口
                "bmc.dev.OpticalModule.Power",        // 功耗扩展接口
                "bmc.dev.OpticalModule.Current",      // 电流扩展接口
                "bmc.dev.OpticalModule.Diagnose"      // 诊断扩展接口
            ]
        }
    }
}

设备树配置规范

  1. 层次结构:主设备作为根,子设备通过:Parent引用父设备
  2. 接口组合:每个设备明确列出支持的所有接口
  3. 路径约定:遵循BMC设备路径标准,支持动态参数替换
  4. 扩展接口:使用点号分隔的命名空间表示扩展接口

5. 板卡驱动开发最佳实践

5.1 开发流程规范

5.2 代码质量规范

5.2.1 架构设计原则

单一职责原则

  • 主设备对象:负责接口组合和协议管理
  • 子设备对象:负责具体功能实现
  • 接口类:负责配置加载和协议绑定

开闭原则

  • 通过继承扩展新厂商支持
  • 通过接口组合扩展新功能
  • 避免修改现有稳定代码

依赖倒置原则

  • 依赖抽象接口而非具体实现
  • 使用智能指针管理协议依赖
  • 通过依赖注入管理对象关系

5.2.2 内存管理规范

cpp
class hi182x_card : public mc::engine::object<hi182x_card> {
private:
    // === 智能指针管理协议对象 ===
    mc::shared_ptr<mctp>          m_mctp_object;               // 框架智能指针管理MCTP
    std::shared_ptr<ncsi_over_mctp_huawei> m_ncsi_over_mctp_huawei; // 自动管理生命周期
    std::shared_ptr<imu>          m_imu_obj;                   // 支持多对象共享
    mc::shared_ptr<smbus>         m_smbus_obj;                 // 框架智能指针
    mc::shared_ptr<mc::timer>     m_quadruple_timer;           // 定时器使用框架智能指针

public:
    ~hi182x_card() {
        // === 取消回调注册,避免悬空指针 ===
        m_network_adapter_oem.unregister_os_reset_callback();
        m_network_adapter_oem.unregister_os_off_callback();
    }
};

内存管理规范

  1. 智能指针为主:协议对象、定时器等动态资源统一使用mc::shared_ptrstd::shared_ptr管理,禁止手动delete原始指针
  2. 明确所有权:MCTP底层对象使用mc::shared_ptr(框架对象),协议上层使用std::shared_ptr
  3. 回调注销:析构/停止时先注销回调,避免悬空指针

5.2.3 异常安全保证

cpp
bool hi182x_card::start_ncsi_protocol() {
    // === 资源获取即初始化(RAII) ===
    // MCTP对象由框架智能指针管理,端点就绪后创建 NCSI over MCTP 实例
    if (m_mctp_object == nullptr) {
        elog("mctp object is null");
        return false;
    }

    auto ncsi_update_task = [this]() {
        try {
            // 创建 NCSI over MCTP 实例(构造参数为 MCTP 智能指针)
            m_ncsi_over_mctp_huawei = std::make_shared<ncsi_over_mctp_huawei>(m_mctp_object);

            // === 批量操作的事务性处理 ===
            for (auto& port : m_network_ports) {
                port->start_ncsi_update_task(m_ncsi_over_mctp_huawei, m_interval);
            }

            // === 各接口绑定独立的更新任务 ===
            m_network_adapter.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei,
                                                            mc::milliseconds(120000));
            m_network_adapter_fault_status.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, m_interval);
            m_pcie_device_bandwidth.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei,
                                                                  mc::milliseconds(180000));
            m_pcie_device_pcie_function.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei,
                                                                      mc::milliseconds(120000));
            m_cooling.start_ncsi_update_task_huawei(m_ncsi_over_mctp_huawei, m_interval);
            m_network_adapter_log_collection.init_ncsi_endpoint(m_ncsi_over_mctp_huawei);
        } catch (const std::exception& e) {
            elog("Exception in start_ncsi_protocol: ${error}", ("error", e.what()));
            // 异常时清理已启动的任务
            stop_ncsi_update_task();
        } catch (...) {
            elog("Unknown exception in start_ncsi_protocol");
            stop_ncsi_update_task();
        }
    };

    // 创建传输层和端点,就绪后回调 ncsi_update_task
    m_mctp_object->create_transport_and_endpoint(std::string(get_object_name()), ncsi_update_task);
    return true;
}

5.3 多厂商差异化处理

5.3.1 厂商特性对比表

板卡类型厂商型号协议支持特有功能子设备
PCIe网卡华为海思Hi182xNCSI+IMU+SMBUS温度监控、故障诊断、日志收集NicPort, OpticalModule
PCIe网卡华为海思Hi1822_FcNCSI+IMU+SMBUSFC网络功能支持NicPort, OpticalModule
PCIe网卡网迅RP1000NCSI+IMU四元组更新、电源状态检测NicPort
PCIe GPU英诺硅AWM-M11P基础PCIeGPU监控、内存管理Gpu, Memory

5.3.2 差异化实现策略

cpp
// === 基础接口统一,实现差异化 ===

// 1. 协议差异 - 继承统一基类,实现厂商专用协议
class ncsi_over_mctp_huawei : public ncsi_over_mctp_base { /* 华为实现 */ };
class ncsi_over_mctp_wx : public ncsi_over_mctp_base { /* 网迅实现 */ };

// 2. 功能差异 - 通过接口组合支持不同功能集
class hi182x_card {
    NetworkAdapter_FaultStatus   m_fault_status;    // 华为特有
    NetworkAdapter_LogCollection m_log_collection;  // 华为特有
};

class wx_card {
    // 网迅不支持故障状态和日志收集接口
    mc::shared_ptr<mc::timer> m_quadruple_timer;  // 网迅特有四元组更新定时器
};

// 3. 定时任务差异 - 不同厂商使用不同更新间隔
class hi182x_card {
    mc::milliseconds m_interval       = mc::milliseconds(5000);  // 5秒NCSI更新
    mc::milliseconds m_smbus_interval = mc::milliseconds(5000);  // 5秒SMBUS更新
};

class wx_card {
    mc::milliseconds m_interval = mc::milliseconds(5000);         // 5秒NCSI更新
    mc::milliseconds m_quadruple_interval = mc::milliseconds(10000); // 10秒四元组更新
};

5.4 调试和故障排除

5.4.1 日志记录规范

cpp
class hi182x_card {
    bool start() {
        ilog("Starting hi182x_card: ${name}", ("name", get_object_name()));

        // === 关键步骤日志 ===
        ilog("Initializing network ports...");
        init_network_ports();
        ilog("Found ${count} network ports", ("count", m_network_ports.size()));

        // === 协议启动日志 ===
        ilog("Starting NCSI protocol...");
        if (!start_ncsi_protocol()) {
            elog("Failed to start NCSI protocol");
            return false;
        }
        ilog("NCSI protocol started successfully");

        // === 性能监控日志 ===
        dlog("hi182x_card started in ${time}ms", ("time", start_time));
        return true;
    }

    void update_device_status() {
        try {
            // === 调试级详细日志 ===
            dlog("Updating device status via NCSI...");

            // NCSI over MCTP 实例未创建时记录警告
            if (m_ncsi_over_mctp_huawei == nullptr) {
                wlog("NCSI over MCTP instance is null, skip update");
                return;
            }
            dlog("Device status updated: ${name}, BDF=${bus}:${dev}:${func}",
                 ("name", m_pcie_device.DeviceName.get_value().as<std::string>()),
                 ("bus", m_pcie_device_pcie_function.BusNumber),
                 ("dev", m_pcie_device_pcie_function.DeviceNumber),
                 ("func", m_pcie_device_pcie_function.FunctionNumber));
        } catch (const std::exception& e) {
            elog("Exception in update_device_status: ${error}", ("error", e.what()));
        }
    }
};

日志级别使用规范

  • elog(): 错误和异常情况
  • wlog(): 警告和非致命问题
  • ilog(): 重要信息和状态变化
  • dlog(): 调试信息和详细过程
  • tlog(): 临时调试和开发期日志

5.4.2 常见问题诊断

协议初始化失败

cpp
bool start_ncsi_protocol() {
    // 1. 验证PCIe设备BDF已初始化
    if (m_pcie_device_pcie_function.BusNumber == 0 &&
        m_pcie_device_pcie_function.DeviceNumber == 0 &&
        m_pcie_device_pcie_function.FunctionNumber == 0) {
        elog("PCIe device ${name} BDF not initialized",
             ("name", m_pcie_device.DeviceName.get_value().as<std::string>()));
        return false;
    }

    // 2. 检查网络端口子设备是否发现
    if (m_network_ports.empty()) {
        elog("No network ports found, NCSI protocol cannot start");
        return false;
    }

    // 3. 计算物理地址并创建MCTP对象
    uint16_t phy_addr =
        mctp::init_phy_addr(m_pcie_device_pcie_function.BusNumber,
                            m_pcie_device_pcie_function.DeviceNumber,
                            m_pcie_device_pcie_function.FunctionNumber);
    m_mctp_object = mc::make_shared<mctp>(this, phy_addr,
                                          MCTP_MESSAGE_TYPE::MCTP_MESSAGE_TYPE_NCSI, "");

    // 4. 创建传输层和端点,就绪后回调绑定接口任务
    m_mctp_object->create_transport_and_endpoint(std::string(get_object_name()), ncsi_update_task);
    return true;
}

子设备管理失败

cpp
void init_network_ports() {
    auto objects = get_children();

    // 1. 检查子设备数量
    if (objects.empty()) {
        wlog("No child objects found, expected network ports");
        return;
    }

    // 2. 验证子设备类型
    for (auto& object : objects) {
        if (!dynamic_cast<hi182x_port*>(object.get())) {
            wlog("Invalid child object type: ${name}", ("name", object->get_name()));
            continue;
        }
        // 添加到管理列表
    }

    // 3. 验证最终结果
    if (m_network_ports.empty()) {
        elog("No valid network ports found");
    }
}

5. 测试开发

5.1 测试策略

5.1 单元测试

cpp
// tests/my_device_test.cpp
#include <gtest/gtest.h>
#include "../drivers/my_device/my_device.h"

class MyDeviceTest : public ::testing::Test {
protected:
    void SetUp() override {
        m_device = std::make_unique<dev::MyDevice>();
    }

    void TearDown() override {
        if (m_device) {
            m_device->stop();
        }
    }

    std::unique_ptr<dev::MyDevice> m_device;
};

TEST_F(MyDeviceTest, InitializationTest) {
    mc::mutable_dict config;
    config["DeviceName"] = std::string("TestDevice");
    config["DeviceId"] = uint8_t(1);

    mc::dict connector;
    EXPECT_TRUE(m_device->init(config, connector));
}

5.2 集成测试

cpp
// tests/integration/my_device_integration_test.cpp
class MyDeviceIntegrationTest : public ::testing::Test {
protected:
    void SetUp() override {
        m_service = std::make_unique<mc::engine::service>();
    }

    std::unique_ptr<mc::engine::service> m_service;
};

TEST_F(MyDeviceIntegrationTest, ABI_Test) {
    driver_handle_t handle = create_my_device(m_service.get(), "TestDevice");
    EXPECT_NE(handle, nullptr);

    mc::mutable_dict config;
    config["DeviceName"] = std::string("TestDevice");
    mc::dict connector;

    EXPECT_EQ(init_my_device(handle, &config, &connector), STATUS_OK);
    EXPECT_EQ(start_my_device(handle), STATUS_OK);
    EXPECT_EQ(stop_my_device(handle), STATUS_OK);
}

6. 性能优化

6.1 性能优化策略

6.1 内存管理

cpp
class PerformantDevice {
private:
    // 使用对象池减少内存分配
    std::vector<std::unique_ptr<DataBuffer>> m_buffer_pool;
    std::mutex m_pool_mutex;

    static constexpr size_t BUFFER_POOL_SIZE = 64;
    static constexpr size_t BUFFER_SIZE = 4096;

public:
    void init_buffer_pool() {
        m_buffer_pool.reserve(BUFFER_POOL_SIZE);
        for (size_t i = 0; i < BUFFER_POOL_SIZE; ++i) {
            m_buffer_pool.push_back(
                std::make_unique<DataBuffer>(BUFFER_SIZE));
        }
    }

    std::unique_ptr<DataBuffer> get_buffer() {
        std::lock_guard<std::mutex> lock(m_pool_mutex);
        if (!m_buffer_pool.empty()) {
            auto buffer = std::move(m_buffer_pool.back());
            m_buffer_pool.pop_back();
            return buffer;
        }
        return std::make_unique<DataBuffer>(BUFFER_SIZE);
    }
};

6.2 异步操作

cpp
class AsyncDevice {
private:
    // 使用 mc::runtime 线程池执行异步任务
    std::shared_ptr<mc::runtime::thread_pool>        m_thread_pool;
    mc::runtime::thread_pool::executor_type          m_executor;

public:
    AsyncDevice()
        : m_thread_pool(std::make_shared<mc::runtime::thread_pool>(4, "device_pool")),
          m_executor(m_thread_pool->get_executor())
    {}

    // 提交异步任务(post 不等待返回)
    void submit_async_task(std::function<void()> task) {
        m_executor.post(std::move(task));
    }

    // 分发任务(dispatch 可在调用线程直接执行)
    void dispatch_async_task(std::function<void()> task) {
        m_executor.dispatch(std::move(task));
    }

    // 延迟执行(defer 延迟到当前任务结束后执行)
    void defer_async_task(std::function<void()> task) {
        m_executor.defer(std::move(task));
    }
};

7. 错误处理和调试

7.1 错误处理流程

7.1 错误处理策略

cpp
enum class DeviceError {
    SUCCESS = 0,
    INIT_FAILED,
    HARDWARE_ERROR,
    PROTOCOL_ERROR,
    TIMEOUT_ERROR,
    INVALID_CONFIG
};

class ErrorHandler {
public:
    static bool handle_error(DeviceError error, const std::string& context) {
        switch (error) {
            case DeviceError::INIT_FAILED:
                elog("Device initialization failed in ${context}", ("context", context));
                return retry_initialization();

            case DeviceError::HARDWARE_ERROR:
                elog("Hardware error detected in ${context}", ("context", context));
                return perform_hardware_reset();

            default:
                elog("Unknown error in ${context}", ("context", context));
                return false;
        }
    }
};

7.2 调试工具

cpp
class DebugHelper {
public:
    // 设备状态转储
    static void dump_device_state(const MyDevice& device) {
        ilog("=== Device State Dump ===");
        ilog("Name: ${name}", ("name", device.i_my_device.DeviceName.value()));
        ilog("ID: ${id}", ("id", device.i_my_device.DeviceId.value()));
        ilog("========================");
    }

    // 性能监控
    class PerformanceMonitor {
    private:
        std::chrono::high_resolution_clock::time_point m_start;
        std::string m_operation;

    public:
        PerformanceMonitor(const std::string& operation)
            : m_operation(operation), m_start(std::chrono::high_resolution_clock::now()) {}

        ~PerformanceMonitor() {
            auto end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - m_start);
            dlog("${operation} took ${duration} microseconds",
                 ("operation", m_operation)("duration", duration.count()));
        }
    };
};

8. 最佳实践

8.1 开发最佳实践

8.1 代码规范

8.1.1 命名规范

  • 类名:使用PascalCase,如MyDevice, NetworkAdapter
  • 函数名:使用snake_case,如init_device(), start_protocol()
  • 变量名:使用snake_case,成员变量添加m_前缀
  • 常量:使用UPPER_CASE,如MAX_BUFFER_SIZE

8.1.2 文件组织

drivers/my_device/
├── my_device.h                 # 主设备对象头文件
├── my_device.cpp               # 主设备对象实现
├── my_device_abi.cpp           # ABI接口实现
├── interface/                  # 接口层
│   ├── i_my_device.h
│   └── i_my_device.cpp
├── internal/                   # 内部实现
│   ├── my_device_internal.h
│   └── my_device_internal.cpp
└── meson.build                 # 构建配置

8.2 资源管理

8.2.1 RAII原则

cpp
class ResourceManager {
private:
    struct Resource {
        void* handle;
        std::function<void(void*)> deleter;

        ~Resource() {
            if (handle && deleter) {
                deleter(handle);
            }
        }
    };

    std::vector<std::unique_ptr<Resource>> m_resources;
};

8.3 线程安全

cpp
class ThreadSafeDevice {
private:
    mutable std::shared_mutex m_device_mutex;
    DeviceState m_state;

public:
    // 读操作使用共享锁
    DeviceState get_state() const {
        std::shared_lock<std::shared_mutex> lock(m_device_mutex);
        return m_state;
    }

    // 写操作使用独占锁
    void set_state(const DeviceState& state) {
        std::unique_lock<std::shared_mutex> lock(m_device_mutex);
        m_state = state;
    }
};

9. 常见问题和解决方案

9.1 问题诊断流程

9.1 编译问题

问题:找不到头文件

bash
fatal error: 'device_tree/interface/MyDevice.h' file not found

解决方案

  1. 确保在gen/device_tree/interface/中定义了接口
  2. 检查include路径配置
  3. 运行代码生成:meson compile -C builddir

问题:链接错误

bash
undefined reference to 'register_device_driver'

解决方案

  1. 确保ABI函数正确导出
  2. 检查extern "C"包装
  3. 验证meson.build配置

9.2 运行时问题

问题:设备初始化失败

诊断步骤

  1. 检查日志输出
  2. 验证配置参数
  3. 确认硬件连接
  4. 检查权限设置

问题:协议通信失败

诊断步骤

  1. 验证协议配置
  2. 检查网络连接
  3. 分析协议日志
  4. 使用协议调试工具

9.3 性能问题

问题:设备响应慢

优化策略

  1. 使用异步操作
  2. 实现缓冲和批处理
  3. 优化锁粒度
  4. 使用内存池

10. 参考资料

10.1 相关文档

10.2 示例代码

  • drivers/pcie_nic_card/wx/ - 网迅网卡驱动示例
  • drivers/pcie_nic_card/hisi/ - 华为海思网卡驱动示例
  • drivers/accessor/ - 通用访问器驱动示例
  • drivers/bus/i2c/ - I2C总线驱动示例

10.3 工具和库

  • libmcpp: 核心框架库
  • MCTP库: 管理组件传输协议
  • NCSI库: 网络控制器侧带接口协议
  • IMU库: IMU设备通信库

总结

本指南提供了Component Drivers项目中设备驱动开发的完整流程,从架构设计到具体实现,再到测试和优化。遵循本指南中的最佳实践,可以开发出高质量、可维护的设备驱动程序。

在开发过程中,建议:

  1. 先理解再实现:深入理解项目架构和设计理念
  2. 参考现有实现:学习已有驱动的实现模式
  3. 逐步迭代:从简单功能开始,逐步完善
  4. 充分测试:确保驱动的稳定性和可靠性
  5. 文档同步:及时更新相关文档

如有疑问,请参考现有代码实现或联系项目维护者。