互连总线是具有可配置参数的硬件,可以根据从各种驱动程序接收到的请求在数据路径上设置这些参数。互连总线的一个例子是芯片组中各种组件或功能块之间的互连。一个 SoC 上可以有多个互连,这些互连可以是多层的。
互连子系统的设计
互连子系统用以下几个概念抽象硬件的实现。
Interconnect provider
以软件的方式定义互连硬件模块,比如上图中的 M NoC、S NoC、C NoC、P NoC 和 Mem NoC。
struct icc_provider { //注册互连供应商名单 struct list_head provider_list; //互连供应商节点的内部列表 struct list_head nodes; //指向设备特定设置操作函数的指针 int (*set)(struct icc_node *src, struct icc_node *dst);
//指向设备特定聚合操作函数的指针 int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
//指向在聚合开始之前调用的特定于设备的函数的指针 void (*pre_aggregate)(struct icc_node *node);
//指向设备特定函数的指针以获取当前带宽 int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
//用于从 phandle 参数映射节点的特定于提供程序的回调 struct icc_node* (*xlate)(struct of_phandle_args *spec, void *data); //用于从 phandle 参数映射节点数据的供应商特定回调 struct icc_node_data* (*xlate_extended)(struct of_phandle_args *spec, void *data); //此互连提供程序所属的设备 struct device *dev; //活跃用户数 int users;
//是否将使用set配置提供商间对 bool inter_set;
//指向私有数据的指针 void *data;
};
struct icc_onecell_data { /此设备中的节点数
unsigned int num_nodes;
//指向此设备中节点的指针数组 struct icc_node *nodes[]; };
Interconnect provider 提供的相关 API 如下所示:
//#include <linux/interconnect-provider.h> int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak); struct icc_node *icc_node_create(int id); void icc_node_destroy(int id); int icc_link_create(struct icc_node *node, const int dst_id); int icc_link_destroy(struct icc_node *src, struct icc_node *dst); void icc_node_add(struct icc_node *node, struct icc_provider *provider); void icc_node_del(struct icc_node *node); int icc_nodes_remove(struct icc_provider *provider); int icc_provider_add(struct icc_provider *provider); int icc_provider_del(struct icc_provider *provider); struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec); void icc_sync_state(struct device *dev);
Interconnect node
互连节点定义这些互连硬件的端口。比如图中 CPU 连接到内存的点称为互连节点,属于 Mem NoC 模块。
struct icc_node { //平台特定的节点 ID int id;
//debugfs 中使用的节点名称 const char *name;
//指向我们在遍历时下一步可以去哪里的目标列表 struct icc_node **links; //到其他互连节点的链接数 size_t num_links;
//指向此节点的互连供应商 struct icc_provider *provider; //父提供者的“节点”列表中的列表条目 struct list_head node_list; //遍历节点图时使用的列表 struct list_head search_list; //遍历节点图时指向前一个节点的指针 struct icc_node *reverse; //遍历节点图时使用的标志 u8 is_traversed:1;
//与此节点关联的 QoS 约束请求列表 struct hlist_head req_list; //来自所有消费者的平均带宽请求的总和 u32 avg_bw;
//来自所有消费者的峰值带宽请求的总和 u32 peak_bw;
//在初始化期间从硬件读取的平均带宽值 u32 init_avg;
//在初始化期间从硬件读取的峰值带宽值 u32 init_peak;
//指向私有数据的指针 void *data;
};
Interconnect endpoints
互连端点是路径的第一个或最后一个元素。每个端点都是一个节点,但并非每个节点都是一个端点。
Interconnect path
互连路径是两个端点之间的一切,包括从源节点到达目标节点必须遍历的所有节点。
struct icc_path { const char *name;
size_t num_nodes;
struct icc_req reqs[]; };
Interconnect consumers
向 provider 发送请求,请求各种吞吐量、延迟和优先级。通常是设备驱动程序,根据他们的需要发送请求。
Interconnect consumers 提供的相关 API 如下所示:
//include/linux/interconnect.h struct icc_path *icc_get(struct device *dev, const int src_id,
const int dst_id); struct icc_path *of_icc_get(struct device *dev, const char *name); struct icc_path *devm_of_icc_get(struct device *dev, const char *name); struct icc_path *of_icc_get_by_index(struct device *dev, int idx); void icc_put(struct icc_path *path); int icc_enable(struct icc_path *path); int icc_disable(struct icc_path *path); int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw); void icc_set_tag(struct icc_path *path, u32 tag); const char *icc_get_name(struct icc_path *path);
互连子系统的 debugfs 接口
在用户态可以通过 debugfs 的接口去调试互联子系统的信息。
-
/sys/kernel/debug/interconnect/interconnect_graph
-
/sys/kernel/debug/interconnect/interconnect_summary
结果如下所示:
我有话说: