设备驱动开发指南
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_card | NCSI over MCTP, IMU | 网迅、华为海思等 |
| PCIe GPU | awm_m11p_card | MCTP | 全志元芯等 |
| 通用访问器 | accessor | 标准PCIe | 通用 |
| 总线设备 | bus_i2c, bus_hisport, bus_i2c_mux | I2C, Hisport | 通用 |
| 芯片设备 | chip_pca9545, chip_lm75, chip_eeprom | I2C协议 | 通用芯片 |
| 扫描器 | scanner | 设备扫描 | 通用 |
| 复合器件 | complex | 多协议组合 | 通用 |
1.3 设备对象系统
Component Drivers采用基于MC_OBJECT宏的设备对象模型,实现设备的层次化管理:
1.3.1 设备对象定义
设备对象通过MC_OBJECT宏定义其核心特征:
// 以华为海思 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 dev1.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 |
接口组合示例:
// 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实现属性的编译期反射和运行时动态访问:
// 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_STATUS | 0x0A | 获取链路状态 | 监控链路UP/DOWN |
| SET_MAC_ADDRESS | 0x0E | 设置MAC地址 | 配置网卡MAC |
| ENABLE_VLAN | 0x0C | 启用VLAN | 配置VLAN过滤 |
| GET_CAPABILITIES | 0x16 | 获取能力 | 查询控制器功能 |
| OEM_COMMAND | 0x50 | 厂商命令 | 厂商扩展功能 |
使用示例:
// 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绑定
使用示例:
// 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命令:
架构优势:
| 特性 | NCSI | MCTP | NCSI over MCTP |
|---|---|---|---|
| 传输方式 | Socket | PCIe/I2C | MCTP传输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 能力与发送 | 链路发现 |
使用示例:
// 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设备信息:
使用示例:
// 创建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中:
// 设备驱动描述结构
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_base或chip_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: 需求分析和设计
- 确定设备类型:PCIe设备、I2C设备、传感器等
- 选择基类:继承相应的基类(
PCIeCard,bus_base,chip_base等) - 协议选择:确定需要的通信协议(NCSI, MCTP, IMU等)
- 接口设计:定义需要暴露的属性和方法
步骤2: 设备树接口定义
在gen/include/device_tree/interface/中定义设备接口:
// 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: 内部器件对象实现
实现具体的硬件操作逻辑:
// 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// 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: 接口类实现
创建接口类,连接设备树接口和内部实现:
// 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: 设备对象实现
实现主设备对象,管理整个设备的生命周期:
// 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接口:
// 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构建配置:
# 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网卡为例:
接口组合架构
| 接口类别 | 接口名称 | 成员变量 | 功能说明 | 是否必需 |
|---|---|---|---|---|
| 基础接口 | PCIeDevice | m_pcie_device | PCIe设备基本信息(VID/DID) | ✅ 必需 |
| 基础接口 | PCIeDevice_PCIeFunction | m_pcie_device_pcie_function | PCIe功能信息(BDF、链路能力) | ✅ 必需 |
| 基础接口 | PCIeCard | m_pcie_card | PCIe卡片信息(插槽、链路状态) | ✅ 必需 |
| 基础接口 | Board | m_board | 板卡信息(序列号、制造商) | ⭕ 可选 |
| 功能接口 | NetworkAdapter | m_network_adapter | 网络适配器功能(MAC地址、速率) | ✅ 网卡必需 |
| 扩展接口 | NetworkAdapter_FaultStatus | m_network_adapter_fault_status | 故障状态监控 | ⭕ 可选 |
| 扩展接口 | Cooling | m_cooling | 冷却和温度管理(bmc.dev.Cooling) | ⭕ 可选 |
| 扩展接口 | PCIeDevice_Bandwidth | m_pcie_device_bandwidth | PCIe带宽监控 | ⭕ 可选 |
| 扩展接口 | NetworkAdapter_LogCollection | m_network_adapter_log_collection | 日志收集功能 | ⭕ 可选 |
| 扩展接口 | NetworkAdapter_Oem | m_network_adapter_oem | 厂商扩展功能 | ⭕ 可选 |
协议栈集成
| 协议类型 | 成员变量 | 协议作用 | 应用场景 |
|---|---|---|---|
| NCSI over MCTP | m_ncsi_over_mctp_huawei | 华为扩展的NCSI协议 | 网卡状态查询、配置管理、OEM命令 |
| IMU | m_imu_obj | 设备管理单元协议 | 通过IPMI获取设备信息、固件版本 |
| SMBUS | m_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设备管理 |
类定义示例
// 华为海思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板卡设计模式
// 英诺硅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板卡通常需要集成多种通信协议,每种协议有独立的生命周期:
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;
}
};协议集成规范:
- 协议隔离:每种协议使用独立的智能指针管理
- 统一初始化:在
start_protocol()中统一管理协议启动 - 接口绑定:将协议实例绑定到相关接口对象
- 错误处理:协议初始化失败时进行适当的错误处理和资源清理
- 定时任务:使用统一的定时间隔管理协议更新
4.4.2 协议差异化处理
不同厂商的板卡支持不同的协议组合:
// 华为海思 - 支持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()方法动态发现和管理子设备:
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) {
// 光模块设备处理
}
}
}子设备管理规范:
- 类型识别:通过对象名前缀或特征字符串识别子设备类型
- 类型转换:使用
dynamic_cast将基类指针转换为具体子设备类型,并必须校验空指针(禁止使用static_cast向下转换) - 集合管理:使用
std::vector管理同类型子设备集合 - 生命周期同步:主设备的启动/停止时同步管理所有子设备
4.5.2 子设备生命周期管理
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接口:
// 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实现规范:
- 设备分离:主设备和子设备分别实现独立的ABI函数
- 统一命名:函数名格式
{action}_{vendor}_{model}_{device_type} - 设备表管理:使用数组管理多个设备驱动结构
- 错误处理:每个ABI函数都要进行参数验证和异常处理
4.7 构建系统集成
4.7.1 分层构建配置
# 主目录 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构建配置规范:
- 协议依赖:明确声明所有使用的协议库依赖
- 路径管理:正确配置include路径,包括芯片和内部实现路径
- 双库构建:同时提供静态库(测试用)和动态库(部署用)
- 条件编译:支持测试模式和部署模式的条件编译
4.8 设备树配置规范
4.8.1 DDS设备描述文件
{
"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" // 诊断扩展接口
]
}
}
}设备树配置规范:
- 层次结构:主设备作为根,子设备通过
:Parent引用父设备 - 接口组合:每个设备明确列出支持的所有接口
- 路径约定:遵循BMC设备路径标准,支持动态参数替换
- 扩展接口:使用点号分隔的命名空间表示扩展接口
5. 板卡驱动开发最佳实践
5.1 开发流程规范
5.2 代码质量规范
5.2.1 架构设计原则
单一职责原则:
- 主设备对象:负责接口组合和协议管理
- 子设备对象:负责具体功能实现
- 接口类:负责配置加载和协议绑定
开闭原则:
- 通过继承扩展新厂商支持
- 通过接口组合扩展新功能
- 避免修改现有稳定代码
依赖倒置原则:
- 依赖抽象接口而非具体实现
- 使用智能指针管理协议依赖
- 通过依赖注入管理对象关系
5.2.2 内存管理规范
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();
}
};内存管理规范:
- 智能指针为主:协议对象、定时器等动态资源统一使用
mc::shared_ptr或std::shared_ptr管理,禁止手动delete原始指针 - 明确所有权:MCTP底层对象使用
mc::shared_ptr(框架对象),协议上层使用std::shared_ptr - 回调注销:析构/停止时先注销回调,避免悬空指针
5.2.3 异常安全保证
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网卡 | 华为海思 | Hi182x | NCSI+IMU+SMBUS | 温度监控、故障诊断、日志收集 | NicPort, OpticalModule |
| PCIe网卡 | 华为海思 | Hi1822_Fc | NCSI+IMU+SMBUS | FC网络功能支持 | NicPort, OpticalModule |
| PCIe网卡 | 网迅 | RP1000 | NCSI+IMU | 四元组更新、电源状态检测 | NicPort |
| PCIe GPU | 英诺硅 | AWM-M11P | 基础PCIe | GPU监控、内存管理 | Gpu, Memory |
5.3.2 差异化实现策略
// === 基础接口统一,实现差异化 ===
// 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 日志记录规范
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 常见问题诊断
协议初始化失败:
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;
}子设备管理失败:
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 单元测试
// 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 集成测试
// 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 内存管理
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 异步操作
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 错误处理策略
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 调试工具
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原则
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 线程安全
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 编译问题
问题:找不到头文件
fatal error: 'device_tree/interface/MyDevice.h' file not found解决方案:
- 确保在
gen/device_tree/interface/中定义了接口 - 检查include路径配置
- 运行代码生成:
meson compile -C builddir
问题:链接错误
undefined reference to 'register_device_driver'解决方案:
- 确保ABI函数正确导出
- 检查
extern "C"包装 - 验证meson.build配置
9.2 运行时问题
问题:设备初始化失败
诊断步骤:
- 检查日志输出
- 验证配置参数
- 确认硬件连接
- 检查权限设置
问题:协议通信失败
诊断步骤:
- 验证协议配置
- 检查网络连接
- 分析协议日志
- 使用协议调试工具
9.3 性能问题
问题:设备响应慢
优化策略:
- 使用异步操作
- 实现缓冲和批处理
- 优化锁粒度
- 使用内存池
10. 参考资料
10.1 相关文档
- 项目概览
- 总线芯片驱动开发指南
- Component Drivers API文档
- Meson构建系统文档
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项目中设备驱动开发的完整流程,从架构设计到具体实现,再到测试和优化。遵循本指南中的最佳实践,可以开发出高质量、可维护的设备驱动程序。
在开发过程中,建议:
- 先理解再实现:深入理解项目架构和设计理念
- 参考现有实现:学习已有驱动的实现模式
- 逐步迭代:从简单功能开始,逐步完善
- 充分测试:确保驱动的稳定性和可靠性
- 文档同步:及时更新相关文档
如有疑问,请参考现有代码实现或联系项目维护者。