FPGA 管理器

概述

FPGA 管理器核心匯出了一組用於使用映像程式設計 FPGA 的函式。該 API 與製造商無關。 所有制造商的特殊性都隱藏在底層驅動程式中,該驅動程式向核心註冊一組操作。 FPGA 映像資料本身非常特定於製造商,但就我們的目的而言,它只是二進位制資料。 FPGA 管理器核心不會解析它。

要程式設計的 FPGA 映像可以在散佈/聚集列表中、單個連續緩衝區中或韌體檔案中。 因為應避免為緩衝區分配連續的核心記憶體,因此建議使用者儘可能改用散佈/聚集列表。

程式設計映像的詳細資訊顯示在一個結構體 (struct fpga_image_info) 中。 此結構體包含諸如指向 FPGA 映像的指標以及映像特定的詳細資訊(例如映像是為完全還是部分重新配置而構建的)之類的引數。

如何支援新的 FPGA 裝置

要新增另一個 FPGA 管理器,請編寫一個實現一組操作的驅動程式。 probe 函式呼叫 fpga_mgr_register()fpga_mgr_register_full(),例如

static const struct fpga_manager_ops socfpga_fpga_ops = {
        .write_init = socfpga_fpga_ops_configure_init,
        .write = socfpga_fpga_ops_configure_write,
        .write_complete = socfpga_fpga_ops_configure_complete,
        .state = socfpga_fpga_ops_state,
};

static int socfpga_fpga_probe(struct platform_device *pdev)
{
        struct device *dev = &pdev->dev;
        struct socfpga_fpga_priv *priv;
        struct fpga_manager *mgr;
        int ret;

        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;

        /*
         * do ioremaps, get interrupts, etc. and save
         * them in priv
         */

        mgr = fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
                                &socfpga_fpga_ops, priv);
        if (IS_ERR(mgr))
                return PTR_ERR(mgr);

        platform_set_drvdata(pdev, mgr);

        return 0;
}

static int socfpga_fpga_remove(struct platform_device *pdev)
{
        struct fpga_manager *mgr = platform_get_drvdata(pdev);

        fpga_mgr_unregister(mgr);

        return 0;
}

或者,probe 函式可以呼叫資源管理的註冊函式之一 devm_fpga_mgr_register()devm_fpga_mgr_register_full()。 使用這些函式時,引數語法相同,但應刪除對 fpga_mgr_unregister() 的呼叫。 在上面的示例中,不需要 socfpga_fpga_remove() 函式。

這些操作將實現所需的任何裝置特定暫存器寫入,以執行此特定 FPGA 的程式設計序列。 這些操作成功時返回 0,否則返回負錯誤程式碼。

程式設計序列為:
  1. .parse_header(可選,可以呼叫一次或多次)

  2. .write_init

  3. .write 或 .write_sg(可以呼叫一次或多次)

  4. .write_complete

.parse_header 函式會將 header_size 和 data_size 設定為 struct fpga_image_info。 在 parse_header 呼叫之前,header_size 會使用 initial_header_size 初始化。 如果 fpga_manager_ops 的標誌 skip_header 為 true,則 .write 函式將獲取從頭 header_size 偏移量開始的映像緩衝區。 如果設定了 data_size,則 .write 函式將獲取映像緩衝區的 data_size 個位元組,否則 .write 將獲取資料直到映像緩衝區的末尾。 這不會影響 .write_sg,.write_sg 仍將以 sg_table 形式獲取整個映像。 如果 FPGA 映像已對映為單個連續緩衝區,則整個緩衝區將傳遞到 .parse_header。 如果映像採用散佈-聚集形式,則核心程式碼將在第一次呼叫 .parse_header 之前緩衝至少 .initial_header_size,如果這不夠,則 .parse_header 應將所需大小設定為 info->header_size 並返回 -EAGAIN,然後將再次使用輸入端上的較大映像緩衝區呼叫它。

.write_init 函式將準備 FPGA 以接收映像資料。 傳遞到 .write_init 的緩衝區將至少為 info->header_size 位元組長;如果整個位元流不可立即使用,則核心程式碼將在啟動之前緩衝至少這麼多。

.write 函式將緩衝區寫入 FPGA。 該緩衝區可能包含整個 FPGA 映像,也可能包含 FPGA 映像的較小塊。 在後一種情況下,會為連續塊多次呼叫此函式。 此介面適用於使用 PIO 的驅動程式。

.write_sg 版本的行為與 .write 相同,只是輸入是 sg_table 散佈列表。 此介面適用於使用 DMA 的驅動程式。

.write_complete 函式在所有映像都已寫入後呼叫,以使 FPGA 進入執行模式。

這些操作包括一個 .state 函式,該函式將確定 FPGA 所處的狀態,並返回 enum fpga_mgr_states 型別的程式碼。 它不會導致狀態更改。

用於實現新的 FPGA 管理器驅動程式的 API

輔助宏 fpga_mgr_register_full()fpga_mgr_register()devm_fpga_mgr_register_full()devm_fpga_mgr_register() 可用於簡化註冊。

enum fpga_mgr_states

fpga 框架狀態

常量

FPGA_MGR_STATE_UNKNOWN

無法確定狀態

FPGA_MGR_STATE_POWER_OFF

FPGA 電源已關閉

FPGA_MGR_STATE_POWER_UP

FPGA 報告電源已開啟

FPGA_MGR_STATE_RESET

FPGA 處於復位狀態

FPGA_MGR_STATE_FIRMWARE_REQ

韌體請求正在進行中

FPGA_MGR_STATE_FIRMWARE_REQ_ERR

韌體請求失敗

FPGA_MGR_STATE_PARSE_HEADER

解析 FPGA 映像標頭

FPGA_MGR_STATE_PARSE_HEADER_ERR

PARSE_HEADER 階段期間出錯

FPGA_MGR_STATE_WRITE_INIT

準備 FPGA 進行程式設計

FPGA_MGR_STATE_WRITE_INIT_ERR

WRITE_INIT 階段期間出錯

FPGA_MGR_STATE_WRITE

將映像寫入 FPGA

FPGA_MGR_STATE_WRITE_ERR

寫入 FPGA 時出錯

FPGA_MGR_STATE_WRITE_COMPLETE

執行程式設計後步驟

FPGA_MGR_STATE_WRITE_COMPLETE_ERR

WRITE_COMPLETE 期間出錯

FPGA_MGR_STATE_OPERATING

FPGA 已程式設計並正在執行

struct fpga_manager

fpga 管理器結構體

定義:

struct fpga_manager {
    const char *name;
    struct device dev;
    struct mutex ref_mutex;
    enum fpga_mgr_states state;
    struct fpga_compat_id *compat_id;
    const struct fpga_manager_ops *mops;
    struct module *mops_owner;
    void *priv;
};

成員

name

底層 fpga 管理器的名稱

dev

fpga 管理器裝置

ref_mutex

僅允許對 fpga 管理器的一個引用

state

fpga 管理器的狀態

compat_id

用於相容性檢查的 FPGA 管理器 ID。

mops

指向 fpga 管理器操作結構體的指標

mops_owner

包含 mops 的模組

priv

底層驅動程式私有日期

struct fpga_manager_ops

底層 fpga 管理器驅動程式的操作

定義:

struct fpga_manager_ops {
    size_t initial_header_size;
    bool skip_header;
    enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
    u64 (*status)(struct fpga_manager *mgr);
    int (*parse_header)(struct fpga_manager *mgr,struct fpga_image_info *info, const char *buf, size_t count);
    int (*write_init)(struct fpga_manager *mgr,struct fpga_image_info *info, const char *buf, size_t count);
    int (*write)(struct fpga_manager *mgr, const char *buf, size_t count);
    int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
    int (*write_complete)(struct fpga_manager *mgr, struct fpga_image_info *info);
    void (*fpga_remove)(struct fpga_manager *mgr);
    const struct attribute_group **groups;
};

成員

initial_header_size

應傳遞到 parse_header 和 write_init 的最小位元組數。

skip_header

bool 標誌,用於告訴 fpga-mgr 核心在呼叫寫入回撥時是否應跳過映像開頭的 info->header_size 部分。

state

返回 FPGA 狀態的列舉值

status

返回 FPGA 的狀態,包括重新配置錯誤程式碼

parse_header

解析 FPGA 映像標頭以設定 info->header_size 和 info->data_size。 如果輸入緩衝區不夠大,請將所需大小設定為 info->header_size 並返回 -EAGAIN。

write_init

準備 FPGA 以接收配置資料

write

將 count 個位元組的配置資料寫入 FPGA

write_sg

將配置資料的散佈列表寫入 FPGA

write_complete

寫入完成後,將 FPGA 設定為執行狀態

fpga_remove

可選:在驅動程式移除期間將 FPGA 設定為特定狀態

groups

可選的屬性組。

描述

fpga_manager_ops 是由特定的 fpga 管理器驅動程式實現的底層函式。 可選的函式在呼叫之前會測試是否為 NULL,因此省略它們是可以的。

struct fpga_manager_info

FPGA 管理器的引數集合

定義:

struct fpga_manager_info {
    const char *name;
    struct fpga_compat_id *compat_id;
    const struct fpga_manager_ops *mops;
    void *priv;
};

成員

name

fpga 管理器名稱

compat_id

用於相容性檢查的 FPGA 管理器 ID。

mops

指向 fpga 管理器操作結構體的指標

priv

fpga 管理器私有資料

描述

fpga_manager_info 包含 register_full 函式的引數。 這些引數被分成一個 info 結構體,因為它們中的一些是可選的,而其他的可能會在將來被新增。 info 結構體有助於維護穩定的 API。

struct fpga_manager *__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, struct module *owner)

建立並註冊 FPGA 管理器裝置

引數

struct device *parent

來自 pdev 的 fpga 管理器裝置

const struct fpga_manager_info *info

fpga 管理器的引數

struct module *owner

包含操作的 owner 模組

描述

此函式的呼叫者負責呼叫 fpga_mgr_unregister()。 建議改用 devm_fpga_mgr_register_full()。

返回

指向 struct fpga_manager 指標的指標,或者 ERR_PTR()

struct fpga_manager *__fpga_mgr_register(struct device *parent, const char *name, const struct fpga_manager_ops *mops, void *priv, struct module *owner)

建立並註冊 FPGA 管理器裝置

引數

struct device *parent

來自 pdev 的 fpga 管理器裝置

const char *name

fpga 管理器名稱

const struct fpga_manager_ops *mops

指向 fpga 管理器操作結構體的指標

void *priv

fpga 管理器私有資料

struct module *owner

包含操作的 owner 模組

描述

此函式的呼叫者負責呼叫 fpga_mgr_unregister()。 建議改用 devm_fpga_mgr_register()。 此簡單版本的註冊函式應足以滿足大多數使用者的需求。 fpga_mgr_register_full() 函式可用於需要傳遞其他可選引數的使用者。

返回

指向 struct fpga_manager 指標的指標,或者 ERR_PTR()

struct fpga_manager *__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, struct module *owner)

fpga_mgr_register() 的資源管理變體

引數

struct device *parent

來自 pdev 的 fpga 管理器裝置

const struct fpga_manager_info *info

fpga 管理器的引數

struct module *owner

包含操作的 owner 模組

返回

成功時返回 FPGA 管理器指標,否則返回負的錯誤程式碼。

描述

這是 fpga_mgr_register_full() 的 devres 變體,當管理裝置分離時,將自動呼叫登出函式。

struct fpga_manager *__devm_fpga_mgr_register(struct device *parent, const char *name, const struct fpga_manager_ops *mops, void *priv, struct module *owner)

fpga_mgr_register() 的資源管理變體

引數

struct device *parent

來自 pdev 的 fpga 管理器裝置

const char *name

fpga 管理器名稱

const struct fpga_manager_ops *mops

指向 fpga 管理器操作結構體的指標

void *priv

fpga 管理器私有資料

struct module *owner

包含操作的 owner 模組

返回

成功時返回 FPGA 管理器指標,否則返回負的錯誤程式碼。

描述

這是 fpga_mgr_register() 的 devres 變體,當管理裝置分離時,將自動呼叫登出函式。

void fpga_mgr_unregister(struct fpga_manager *mgr)

登出一個 FPGA 管理器

引數

struct fpga_manager *mgr

FPGA 管理器結構體

描述

此函式旨在用於 FPGA 管理器驅動程式的 remove 函式中。