Linux下如何筛选指定DMA通道(基于设备树compatible属性)
筛选指定DMA通道:获取通道compatible属性的实现方法
在设备驱动开发中,需要调用dma_request_channel并传入筛选函数,选中设备树中指定的DMA通道(即dma-channel@48000000节点,其compatible为xlnx,axi-dma-mm2s-channel)。
参考设备树片段
srio_hier0_srio_hier0_AXI_DMA_SGDMA0: dma@48000000 { #dma-cells = <1>; clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk"; clocks = <&clkc 15>, <&clkc 16>, <&clkc 16>, <&clkc 16>; compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a"; interrupt-names = "mm2s_introut", "s2mm_introut"; interrupt-parent = <&intc>; interrupts = <0 30 4 0 29 4>; reg = <0x48000000 0x10000>; xlnx,addrwidth = <0x20>; xlnx,include-sg ; xlnx,sg-include-stscntrl-strm ; xlnx,sg-length-width = <0x17>; dma-channel@48000000 { compatible = "xlnx,axi-dma-mm2s-channel"; // 目标DMA通道 dma-channels = <0x1>; interrupts = <0 30 4>; xlnx,datawidth = <0x40>; xlnx,device-id = <0x0>; xlnx,include-dre ; }; dma-channel@48000030 { compatible = "xlnx,axi-dma-s2mm-channel"; dma-channels = <0x1>; interrupts = <0 29 4>; xlnx,datawidth = <0x40>; xlnx,device-id = <0x0>; xlnx,include-dre ; }; };
现有调用代码
dma_cap_mask_t dma_cap_mask; dma_cap_zero(dma_cap_mask); dma_cap_set(DMA_SLAVE, dma_cap_mask); slave_dma_chan = dma_request_channel(dma_cap_mask, dma_filter_function, ptrToMyData);
待完善的筛选函数
static bool dma_filter_function (struct dma_chan *chan, void *filter_param) { struct MyData* myData = (struct MyData*) filter_param; struct device* dev = chan->device->dev; struct device_node* device_tree_node = dev->of_node; if (0 != strcmp(device_tree_node->full_name, "dma@48000000")) return false; // 求助:如何编写get_compatible函数,获取当前通道的compatible属性值? return (NULL != strstr( "axi-dma-mm2s-channel", get_compatible(chan))); }
解决方案:无需自定义get_compatible函数
内核提供了现成的OF设备树操作API,直接利用这些API即可获取DMA通道对应的设备树节点并检查compatible属性。需要注意的是:原代码中chan->device->dev->of_node指向的是DMA控制器的父节点,而非具体的通道子节点,正确的做法是直接使用chan->of_node(Xilinx AXI DMA驱动会将每个通道的of_node字段关联到对应的设备树子节点)。
完整的筛选函数实现
#include <linux/of.h> #include <linux/dmaengine.h> static bool dma_filter_function(struct dma_chan *chan, void *filter_param) { // 首先检查通道是否关联了设备树节点 if (!chan->of_node) return false; // 检查当前通道节点的compatible是否匹配目标值 if (of_device_is_compatible(chan->of_node, "xlnx,axi-dma-mm2s-channel")) { // 可选:如果需要额外匹配DMA控制器父节点的地址,可添加以下检查 struct device_node *parent_node = of_get_parent(chan->of_node); bool parent_match = false; if (parent_node) { parent_match = !strcmp(parent_node->full_name, "dma@48000000"); of_node_put(parent_node); } return parent_match; } return false; }
代码说明
- 检查通道的设备树节点:先判断
chan->of_node是否有效,避免空指针访问。 - 匹配compatible属性:使用
of_device_is_compatible函数,该函数会自动遍历节点的compatible列表,检查是否包含指定字符串,比手动调用strstr更可靠。 - 可选的父节点匹配:如果需要确保选中的通道属于特定的DMA控制器,可以额外获取父节点并检查其名称,完成后记得调用
of_node_put释放节点引用。
内容的提问来源于stack exchange,提问作者Pax to You
相关产品推荐
相关产品推荐

