MEN 變色龍匯流排¶
簡介¶
本文件描述了 MEN 變色龍匯流排(在本文件中始終稱為 MCB)的架構和實現。
本文件的範圍¶
本文件旨在簡要概述當前的實現,絕不描述基於 MCB 的裝置的完整可能性。
當前實現的限制¶
當前實現僅限於使用單個記憶體資源並共享 PCI 傳統 IRQ 的基於 PCI 和 PCIe 的載體裝置。未實現的是
多資源 MCB 裝置,例如 VME 控制器或 M-Module 載體。
需要另一個 MCB 裝置的 MCB 裝置,例如用於 DMA 控制器的緩衝區描述符的 SRAM 或影片控制器的影片記憶體。
每個載體裝置的每個載體 IRQ 域,這些載體裝置每個 MCB 裝置具有一個(或多個)IRQ,例如具有 MSI 或 MSI-X 支援的基於 PCIe 的載體。
架構¶
MCB 分為 3 個功能塊
MEN 變色龍匯流排本身,
MCB 載體裝置的驅動程式和
變色龍表的解析器。
MEN 變色龍匯流排¶
MEN 變色龍匯流排是一種人工匯流排系統,它連線到 MEN Mikro Elektronik GmbH 生產的某些硬體上找到的所謂變色龍 FPGA 裝置。這些裝置是在單個 FPGA 中實現的多功能裝置,通常透過某種 PCI 或 PCIe 鏈路連線。每個 FPGA 包含一個頭部部分,用於描述 FPGA 的內容。頭部列出了裝置 ID、PCI BAR、距 PCI BAR 起始的偏移量、FPGA 中的大小、中斷號以及 MCB 實現當前未處理的其他一些屬性。
載體裝置¶
載體裝置只是變色龍 FPGA 連線到的真實物理匯流排的抽象。某些 IP Core 驅動程式可能需要與載體裝置的屬性進行互動(例如,查詢 PCI 裝置的 IRQ 號)。為了提供與真實硬體匯流排的抽象,MCB 載體裝置提供了回撥方法,用於將驅動程式的 MCB 函式呼叫轉換為與硬體相關的函式呼叫。例如,載體裝置可以實現 get_irq() 方法,該方法可以轉換為硬體匯流排查詢,以獲取裝置應使用的 IRQ 號。
解析器¶
解析器讀取變色龍裝置的前 512 個位元組並解析變色龍表。當前,解析器僅支援變色龍表的 Chameleon v2 變體,但可以輕鬆地採用它來支援較舊或可能的未來變體。在解析表的條目時,會分配新的 MCB 裝置,並根據變色龍表中的資源分配分配其資源。資源分配完成後,MCB 裝置會在 MCB 上註冊,從而在 Linux 核心的驅動程式核心上註冊。
資源處理¶
當前實現為每個 MCB 裝置分配一個記憶體和一個 IRQ 資源。但這很可能在將來會發生變化。
記憶體資源¶
每個 MCB 裝置只有一個記憶體資源,可以從 MCB 匯流排請求。此記憶體資源是 MCB 裝置在載體內部的物理地址,旨在傳遞給 ioremap() 及其朋友。它已經透過呼叫 request_mem_region() 從核心請求。
IRQ¶
每個 MCB 裝置只有一個 IRQ 資源,可以從 MCB 匯流排請求。如果載體裝置驅動程式實現了 ->get_irq() 回撥方法,則將返回載體裝置分配的 IRQ 號,否則將返回變色龍表中的 IRQ 號。此號碼適合傳遞給 request_irq()。
編寫 MCB 驅動程式¶
驅動程式結構¶
每個 MCB 驅動程式都有一個結構來標識裝置驅動程式以及標識 FPGA 內部 IP Core 的裝置 ID。驅動程式結構還包含回撥方法,這些方法在驅動程式探測和從系統中移除時執行
static const struct mcb_device_id foo_ids[] = {
{ .device = 0x123 },
{ }
};
MODULE_DEVICE_TABLE(mcb, foo_ids);
static struct mcb_driver foo_driver = {
driver = {
.name = "foo-bar",
.owner = THIS_MODULE,
},
.probe = foo_probe,
.remove = foo_remove,
.id_table = foo_ids,
};
探測和連線¶
當載入驅動程式並找到其服務的 MCB 裝置時,MCB 核心將呼叫驅動程式的探測回撥方法。從系統中移除驅動程式時,MCB 核心將呼叫驅動程式的移除回撥方法
static init foo_probe(struct mcb_device *mdev, const struct mcb_device_id *id);
static void foo_remove(struct mcb_device *mdev);
初始化驅動程式¶
當核心啟動或插入 foo 驅動程式模組時,您必須執行驅動程式初始化。通常,在 MCB 核心註冊您的驅動程式模組就足夠了
static int __init foo_init(void)
{
return mcb_register_driver(&foo_driver);
}
module_init(foo_init);
static void __exit foo_exit(void)
{
mcb_unregister_driver(&foo_driver);
}
module_exit(foo_exit);
module_mcb_driver() 宏可用於減少上述程式碼
module_mcb_driver(foo_driver);
使用 DMA¶
要使用核心 DMA-API 的函式,您需要使用載體裝置的 'struct device'。幸運的是,'struct mcb_device' 嵌入了一個指向載體裝置的指標 (->dma_dev),用於 DMA 目的
ret = dma_set_mask_and_coherent(&mdev->dma_dev, DMA_BIT_MASK(dma_bits));
if (rc)
/* Handle errors */