Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux DMA 平台驅動架構解析:以 Samsung PL330 控制器為例

編輯:Linux 教學

Linux 內核 DMA 引擎框架採用 Platform Device/Driver 模式,將 DMA 控制器抽象為平台設備,通過 dmaengine 子系統統一管理通道分配、傳輸提交、中斷處理。本文以 Samsung S5P 系列 SoC 集成的 ARM PL330 DMA 控制器驅動(s3c-pl330.c)為例,剖析平台層數據結構、資源管理、通道綁定與傳輸流程。

一、 核心數據結構設計

1. DMAC 管理結構 s3c_pl330_dmac

struct s3c_pl330_dmac {
    struct pl330_info *pi;              // PL330 核心驅動上下文
    unsigned busy_chan;                 // 忙碌通道計數
    struct list_head node;              // 全局 DMAC 鏈表節點
    enum dma_ch *peri;                  // 支持的外設 ID 列表
    struct kmem_cache *kmcache;         // 傳輸描述符 slab 緩存
};

2. 通道結構 s3c_pl330_chan

struct s3c_pl330_chan {
    enum dma_ch id;                     // 外設 ID(請求線)
    struct list_head node;              // 全局通道鏈表
    struct pl330_req *lrq;              // 最後提交的請求
    struct list_head xfer_list;         // 排隊傳輸鏈表
    struct s3c_pl330_xfer *xfer_head;   // 隊首傳輸
    struct s3c_pl330_dmac *dmac;        // 所屬 DMAC(NULL=空閒)
    void *pl330_chan_id;                // PL330 硬件線程 ID
    struct pl330_req req[2];            // 雙缓衝請求(雙緩衝)
    struct s3c2410_dma_client *client;  // 老版客戶端接口兼容
    s3c2410_dma_cbfn_t callback_fn;     // 完成回調
    unsigned int options;               // 通道選項
    struct pl330_reqcfg rqcfg;          // 請求配置
    unsigned long sdaddr;               // 設備地址(s3c2410_dma_devconfig)
};

3. 傳輸描述符 s3c_pl330_xfer

struct s3c_pl330_xfer {
    struct list_head node;              // 掛載於通道 xfer_list
    struct s3c_pl330_chan *chan;        // 反向指針
    void *token;                        // 客戶端標識
    struct pl330_xfer px;               // PL330 核心傳輸描述符
};

二、 全局資源管理

static LIST_HEAD(dmac_list);    // 所有 DMAC
static LIST_HEAD(chan_list);    // 所有通道
static DEFINE_SPINLOCK(res_lock); // 並發保護鎖

通道查找與分配

// 根據外設 ID 查找通道
static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id) {
    struct s3c_pl330_chan *ch;
    list_for_each_entry(ch, &chan_list, node)
        if (ch->id == id) return ch;
    return NULL;
}

// 動態添加通道(平台初始化調用)
static void chan_add(const enum dma_ch id) {
    if (id_to_chan(id)) return;  // 已存在
    struct s3c_pl330_chan *ch = kmalloc(sizeof(*ch), GFP_KERNEL);
    if (!ch) return;
    ch->id = id;
    ch->dmac = NULL;             // 標記空閒
    list_add_tail(&ch->node, &chan_list);
}

// 判斷通道是否空閒
static bool chan_free(struct s3c_pl330_chan *ch) {
    return ch && !ch->dmac;      // dmac 為 NULL 表示未被獲取
}

三、 平台設備註冊流程

機器初始化代碼(arch/arm/mach-s5pv210/dma.c)調用 platform_add_devices() 註冊多個 DMAC 設備:

static struct platform_device *s5pc110_dmacs[] __initdata = {
    &s5pc11x_device_mdma,   // 內存到內存 DMAC
    &s5pc11x_device_pdma0,  // 外設 DMAC 0
    &s5pc11x_device_pdma1,  // 外設 DMAC 1
};

static int __init s5pv210_dma_init(void) {
    platform_add_devices(s5pc110_dmacs, ARRAY_SIZE(s5pc110_dmacs));
    return 0;
}
arch_initcall(s5pv210_dma_init);

每個 platform_device 對應一個 DMAC 實例,probe 階段驅動創建 s3c_pl330_dmac、掃描硬件通道、調用 chan_add() 填充全局通道池。

四、 客戶端接口兼容層

為兼容舊版 S3C2410/6410 DMA API,驅動實現 s3c2410_dma_client 回調接口:

  • s3c2410_dma_request():請求通道 → 內部調用 dmaengine 申請。
  • s3c2410_dma_enqueue():提交傳輸 → 構建 s3c_pl330_xfer 入隊。
  • s3c2410_dma_ctrl():START/STOP/PAUSE/FLUSH → 映射到 dmaengine 控制命令。
  • s3c2410_dma_devconfig():配置設備地址/傳輸方向 → 填充 sdaddr、rqcfg。

五、 關鍵設計亮點

  1. 雙層抽象:Platform 驅動管理硬件資源(DMAC/通道),dmaengine 提供統一 API 給上層驅動。
  2. 動態通道綁定:通道不固定屬於某 DMAC,運行時根據外設請求線動態分配(chan->dmac 指針)。
  3. Slab 緩存加速:kmcache 專用於 s3c_pl330_xfer 分配,減少內存碎片與分配延遲。
  4. 自旋鎖保護全局鏈表:res_lock 確保多核下通道查找/添加/刪除原子性。
  5. 雙緩衝請求:req[2] 支持鏈式傳輸,硬件處理第一個請求時 CPU 準備下一個,實現零拷貝流水線。
Copyright © Windows教程網 All Rights Reserved