CTU CAN FD 驅動程式

作者:Martin Jerabek <martin.jerabek01@gmail.com>

關於 CTU CAN FD IP 核

CTU CAN FD 是用 VHDL 編寫的開源軟核。它起源於 2015 年,是 Ondrej Ille 在 測量系FEECTU 的專案。

基於 Xilinx Zynq SoC 的 MicroZed 板的 SocketCAN 驅動程式 Vivado 整合 和基於 Intel Cyclone V 5CSEMA4U23C6 的 DE0-Nano-SoC Terasic 板的 QSys 整合 已經開發出來,並且支援該核心的 PCIe 整合

對於 Zynq,該核心透過 APB 系統匯流排連線,該匯流排不支援列舉,並且必須在裝置樹中指定該裝置。這種裝置在核心中稱為平臺裝置,並由平臺裝置驅動程式處理。

CTU CAN FD 外設的基本功能模型已被 QEMU 主線接受。請參閱 QEMU CAN 模擬支援,瞭解 CAN FD 匯流排、主機連線和 CTU CAN FD 核心模擬。模擬支援的開發版本可以從 QEMU 本地開發的 ctu-canfd 分支中克隆 倉庫

關於 SocketCAN

SocketCAN 是 Linux 核心中 CAN 裝置的標準通用介面。顧名思義,該匯流排透過套接字訪問,類似於常見的網路裝置。其背後的原因在 Linux SocketCAN 中進行了深入描述。簡而言之,它提供了一種自然的方式來實現和處理 CAN 上的更高層協議,就像乙太網上面的 UDP/IP 一樣。

裝置探測

在詳細介紹 CAN 匯流排裝置驅動程式的結構之前,讓我們重申一下核心是如何得知該裝置的。一些匯流排(如 PCI 或 PCIe)支援裝置列舉。也就是說,當系統啟動時,它會發現總線上的所有裝置並讀取它們的配置。核心透過其供應商 ID 和裝置 ID 來識別裝置,並且如果為該識別符號組合註冊了驅動程式,則會呼叫其探測方法來填充給定硬體的驅動程式例項。USB 的情況類似,只是它允許裝置熱插拔。

對於直接嵌入到 SoC 中並連線到內部系統匯流排(AXI、APB、Avalon 等)的外設,情況有所不同。這些匯流排不支援列舉,因此核心必須從其他地方瞭解這些裝置。這正是裝置樹的用途。

裝置樹

裝置樹中的一個條目宣告系統中存在一個裝置,它的可訪問方式(它位於哪個總線上)以及它的配置——暫存器地址、中斷等等。此類裝置樹的示例如下。

/ {
    /* ... */
    amba: amba {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";

        CTU_CAN_FD_0: CTU_CAN_FD@43c30000 {
            compatible = "ctu,ctucanfd";
            interrupt-parent = <&intc>;
            interrupts = <0 30 4>;
            clocks = <&clkc 15>;
            reg = <0x43c30000 0x10000>;
        };
    };
};

驅動程式結構

驅動程式可以分為兩個部分——平臺相關的裝置發現和設定,以及平臺無關的 CAN 網路裝置實現。

平臺裝置驅動程式

對於 Zynq,該核心透過 AXI 系統匯流排連線,該匯流排不支援列舉,並且必須在裝置樹中指定該裝置。這種裝置在核心中稱為平臺裝置,並由平臺裝置驅動程式處理 [1]

平臺裝置驅動程式提供以下內容

  • 一個探測函式

  • 一個移除函式

  • 一個驅動程式可以處理的相容裝置表

當裝置出現時(或驅動程式被載入時,以較晚者為準),探測函式只會被呼叫一次。如果同一驅動程式處理多個裝置,則會為每個裝置呼叫探測函式。它的作用是分配和初始化處理裝置所需的資源,以及為平臺無關層設定底層函式,例如 read_regwrite_reg。之後,驅動程式將設備註冊到更高的層,在本例中為網路裝置

當裝置消失時,或者驅動程式即將解除安裝時,將呼叫移除函式。它的作用是釋放在探測中分配的資源,並將裝置從更高的層中登出。

最後,相容裝置表宣告驅動程式可以處理哪些裝置。裝置樹條目 compatible 與所有平臺驅動程式的表進行匹配。

/* Match table for OF platform binding */
static const struct of_device_id ctucan_of_match[] = {
    { .compatible = "ctu,canfd-2", },
    { .compatible = "ctu,ctucanfd", },
    { /* end of list */ },
};
MODULE_DEVICE_TABLE(of, ctucan_of_match);

static int ctucan_probe(struct platform_device *pdev);
static int ctucan_remove(struct platform_device *pdev);

static struct platform_driver ctucanfd_driver = {
    .probe  = ctucan_probe,
    .remove = ctucan_remove,
    .driver = {
        .name = DRIVER_NAME,
        .of_match_table = ctucan_of_match,
    },
};
module_platform_driver(ctucanfd_driver);

網路裝置驅動程式

每個網路裝置必須至少支援以下操作

  • 啟動裝置:ndo_open

  • 關閉裝置:ndo_close

  • 將 TX 幀提交到裝置:ndo_start_xmit

  • 向網路子系統發出 TX 完成和錯誤訊號:ISR

  • 將 RX 幀提交到網路子系統:ISR 和 NAPI

有兩種可能的事件源:裝置和網路子系統。裝置事件通常透過中斷髮出訊號,並在中斷服務例程 (ISR) 中處理。然後,在 struct net_device_ops 中指定網路子系統中發生的事件的處理程式。

當裝置啟動時,例如透過呼叫 ip link set can0 up,將呼叫驅動程式的函式 ndo_open。它應該驗證介面配置並配置和啟用裝置。與此相反的是 ndo_close,當裝置被關閉時呼叫,無論是顯式地還是隱式地。

當系統應該傳輸一個幀時,它會透過呼叫 ndo_start_xmit 來完成,該函式將幀排隊到裝置中。如果裝置 HW 佇列(FIFO、郵箱或任何實現)已滿,則 ndo_start_xmit 實現會通知網路子系統,它應該停止 TX 佇列(透過 netif_stop_queue)。然後在 ISR 中再次重新啟用它,當裝置有可用空間並且能夠再次將另一個幀排隊時。

所有裝置事件都在 ISR 中處理,即

  1. TX 完成。當裝置成功完成幀的傳輸時,該幀會在本地回顯。如果發生錯誤,則會向網路子系統傳送一個資訊錯誤幀 [2]。在這兩種情況下,都會恢復軟體 TX 佇列,以便可以傳送更多幀。

  2. 錯誤條件。如果出現問題(例如,裝置進入匯流排關閉狀態或發生 RX 溢位),則會更新錯誤計數器,並將資訊錯誤幀排隊到 SW RX 佇列。

  3. RX 緩衝區不為空。在這種情況下,讀取 RX 幀並將它們排隊到 SW RX 佇列。通常使用 NAPI 作為中間層(請參閱)。

NAPI

傳入幀的頻率可能很高,並且為每個幀呼叫中斷服務例程的開銷可能會導致顯著的系統負載。Linux 核心中有多種機制可以處理這種情況。它們是在 Linux 核心開發和增強的多年中演變而來的。對於網路裝置,當前的標準是 NAPI——New API。它類似於經典的上半部/下半部中斷處理,因為它只在 ISR 中確認中斷,併發出訊號表示其餘處理應在 softirq 上下文中完成。最重要的是,它提供了輪詢一段時間新幀的可能性。這有可能避免代價高昂的啟用中斷、在 ISR 中處理傳入 IRQ、重新啟用 softirq 和將上下文切換回 softirq 的過程。

有關更多資訊,請參閱 Documentation/networking/napi.rst

將核心整合到 Xilinx Zynq

該核心與 Avalon(搜尋 Intel Avalon Interface Specifications)匯流排的一個簡單子集介面,因為它最初是在 Alterra FPGA 晶片上使用的,但 Xilinx 原生與 AXI 介面(搜尋 ARM AMBA AXI and ACE Protocol Specification AXI3, AXI4, and AXI4-Lite, ACE and ACE-Lite)。最明顯的解決方案是使用 Avalon/AXI 橋接器或實現一些簡單的轉換實體。然而,該核心的介面是半雙工的,沒有握手信令,而 AXI 是全雙工的,具有雙向信令。此外,即使是 AXI-Lite 從介面也相當消耗資源,並且 CAN 核心不需要 AXI 的靈活性和速度。

因此,選擇了一個更簡單的匯流排——APB(Advanced Peripheral Bus)(搜尋 ARM AMBA APB Protocol Specification)。APB-AXI 橋接器直接在 Xilinx Vivado 中可用,並且介面介面卡實體只是一些簡單的組合賦值。

最後,為了能夠將該核心作為自定義 IP 包含在框圖中,該核心與 APB 介面一起被打包為 Vivado 元件。

CTU CAN FD 驅動程式設計

CAN 裝置驅動程式的一般結構已在 中進行了檢查。接下來的段落將提供有關 CTU CAN FD 核心驅動程式的更詳細描述。

底層驅動程式

該核心並非僅供 SocketCAN 使用,因此需要有一個與作業系統無關的底層驅動程式。然後,此底層驅動程式可以用於作業系統驅動程式的實現,或者直接用於裸機或使用者空間應用程式。另一個優點是,如果硬體略有變化,則只需要修改底層驅動程式。

程式碼 [3] 部分是自動生成的,部分是由核心作者手動編寫的,並由論文作者貢獻。底層驅動程式支援諸如以下操作:設定位時序、設定控制器模式、啟用/停用、讀取 RX 幀、寫入 TX 幀等等。

配置位時序

在 CAN 上,每個位分為四個段:SYNC、PROP、PHASE1 和 PHASE2。它們的持續時間以時間量子 (Time Quantum) 的倍數表示(詳情請參見 CAN Specification, Version 2.0,第 8 章)。配置位元率時,必須從位元率和取樣點計算所有段(和時間量子)的持續時間。對於 CAN FD,這是獨立於標稱位元率和資料位元率執行的。

SocketCAN 非常靈活,可以透過手動設定所有段持續時間來實現高度自定義配置,或者透過僅設定位元率和取樣點來實現方便的配置(即使未指定,也可以按照 Bosch 建議自動選擇)。但是,每個 CAN 控制器可能具有不同的基本時鐘頻率和不同的段持續時間暫存器寬度。因此,該演算法需要持續時間的最小值和最大值(以及時鐘預分頻器),並嘗試最佳化數字以適應約束和請求的引數。

struct can_bittiming_const {
    char name[16];      /* Name of the CAN controller hardware */
    __u32 tseg1_min;    /* Time segment 1 = prop_seg + phase_seg1 */
    __u32 tseg1_max;
    __u32 tseg2_min;    /* Time segment 2 = phase_seg2 */
    __u32 tseg2_max;
    __u32 sjw_max;      /* Synchronisation jump width */
    __u32 brp_min;      /* Bit-rate prescaler */
    __u32 brp_max;
    __u32 brp_inc;
};

[lst:can_bittiming_const]

好奇的讀者會注意到,段 PROP_SEG 和 PHASE_SEG1 的持續時間不是單獨確定的,而是組合在一起,然後預設情況下,生成的 TSEG1 在 PROP_SEG 和 PHASE_SEG1 之間均勻分配。實際上,這幾乎沒有後果,因為取樣點在 PHASE_SEG1 和 PHASE_SEG2 之間。但是,在 CTU CAN FD 中,持續時間暫存器 PROPPH1 具有不同的寬度(分別為 6 位和 7 位),因此自動計算的值可能會溢位較短的暫存器,因此必須在兩個之間重新分配 [4]

處理 RX

幀接收在 NAPI 佇列中處理,當設定 RXNE(RX FIFO 不為空)位時,從 ISR 啟用該佇列。逐個讀取幀,直到 RX FIFO 中沒有剩餘幀或達到 NAPI 輪詢執行的最大工作配額(請參閱)。然後將每個幀傳遞到網路介面 RX 佇列。

傳入幀可以是 CAN 2.0 幀或 CAN FD 幀。在核心中區分這兩者的方法是分配 struct can_framestruct canfd_frame,兩者具有不同的大小。在控制器中,有關幀型別的資訊儲存在 RX FIFO 的第一個字中。

這給我們帶來了一個先有雞還是先有蛋的問題:我們想要為幀分配 skb,只有在成功的情況下才從 FIFO 獲取幀;否則將其保留在那裡以供以後使用。但是為了能夠分配正確的 skb,我們必須獲取 FIFO 的第一個字。有幾種可能的解決方案

  1. 讀取該字,然後分配。如果失敗,則丟棄幀的其餘部分。當系統記憶體不足時,情況無論如何都很糟糕。

  2. 始終預先分配足夠大的 skb 以用於 FD 幀。然後調整 skb 的內部結構,使其看起來像是為較小的 CAN 2.0 幀分配的。

  3. 新增選項以窺視 FIFO 而不是消耗該字。

  4. 如果分配失敗,則將讀取的字儲存到驅動程式的資料中。在下一次嘗試時,使用儲存的字而不是再次讀取它。

選項 1 足夠簡單,但如果我們做得更好,就不會那麼令人滿意。選項 2 是不可接受的,因為它需要修改完整核心結構的私有狀態。稍微更高的記憶體消耗只是“蛋糕”上的虛擬櫻桃。選項 3 需要非平凡的 HW 更改,並且從 HW 的角度來看並不理想。

選項 4 似乎是一個很好的折衷方案,它的缺點是部分幀可能會在 FIFO 中停留很長時間。儘管如此,可能只有一個 RX FIFO 的所有者,因此沒有人應該看到部分幀(忽略一些特殊的除錯場景)。此外,驅動程式會在初始化時重置核心,因此部分幀也不能被“採用”。最終,選擇了選項 4 [5]

時間戳 RX 幀

CTU CAN FD 核心報告接收到幀時的確切時間戳。預設情況下,時間戳是在 EOF 的最後一位的取樣點捕獲的,但可以配置為在 SOF 位捕獲。時間戳源在核心外部,最大寬度可達 64 位。在編寫本文時,尚未實現將時間戳從核心傳遞到使用者空間,但計劃在將來實現。

處理 TX

CTU CAN FD 核心具有 4 個獨立的 TX 緩衝區,每個緩衝區都有自己的狀態和優先順序。當核心想要傳輸時,將選擇處於 Ready 狀態且優先順序最高的 TX 緩衝區。

優先順序是暫存器 TX_PRIORITY 中的 3 位數字(位元組對齊)。這對於大多數用例來說應該足夠靈活。但是,SocketCAN 僅支援一個用於傳出幀的 FIFO 佇列 [6]。可以透過為每個緩衝區分配一個不同的優先順序並在幀傳輸完成後旋轉優先順序來使用緩衝區優先順序來模擬 FIFO 行為。

除了優先順序旋轉之外,軟體還必須維護由 TX 緩衝區形成的 FIFO 中的頭指標和尾指標,以便能夠確定哪個緩衝區應該用於下一個幀 (txb_head) 以及哪個應該是第一個完成的緩衝區 (txb_tail)。實際的緩衝區索引(顯然)是模 4(TX 緩衝區的數量),但指標必須至少寬一位,才能區分 FIFO 已滿和 FIFO 為空——在這種情況下,txb\_head \equiv txb\_tail\ (\textrm{mod}\ 4)。如何在維護 FIFO 的同時進行優先順序旋轉的示例,請參見


TXB#

0

1

2

3

Seq

A

B

C

Prio

7

6

5

4

T

H


TXB#

0

1

2

3

Seq

B

C

Prio

4

7

6

5

T

H


TXB#

0

1

2

3

0’

Seq

E

B

C

D

Prio

4

7

6

5

T

H


../../../../_images/fsm_txt_buffer_user.svg

TX 緩衝區狀態以及可能的轉換

時間戳 TX 幀

當將幀提交到 TX 緩衝區時,可以指定應該傳輸幀的時間戳。幀傳輸可能會稍後開始,但不會更早。請注意,時間戳不參與緩衝區優先順序排序——這完全由上述機制決定。

對基於時間的包傳輸的支援最近已合併到 Linux v4.19 中 基於時間的包傳輸,但仍有待研究此功能是否對 CAN 實用。

同樣,與檢索 RX 幀的時間戳類似,核心支援檢索 TX 幀的時間戳——這是成功傳遞幀的時間。細節與時間戳 RX 幀非常相似,並在 中進行了描述。

處理 RX 緩衝區溢位

當接收到的幀不再完全適合硬體 RX FIFO 時,會設定 RX FIFO 溢位標誌 (STATUS[DOR]) 並觸發資料溢位中斷 (DOI)。在處理中斷時,必須首先清除 DOR 標誌(透過 COMMAND[CDO]),然後清除 DOI 中斷標誌。否則,中斷將立即 [7] 重新啟用。

注意:在開發過程中,有人討論了內部 HW 流水線是否會中斷此清除序列,以及在清除標誌和中斷之間是否需要額外的虛擬週期。在 Avalon 介面上,情況確實如此,但 APB 是安全的,因為它使用 2 個週期的事務。基本上,DOR 標誌將被清除,但當 DOI 清除請求也將被應用時(透過將暫存器的 Reset 輸入設定為高電平),DOI 暫存器的 Preset 輸入仍然很高。由於 Set 的優先順序高於 Reset,因此 DOI 標誌不會被重置。這已經透過交換 Set/Reset 優先順序來解決(請參閱問題 #187)。

報告錯誤被動和匯流排關閉條件

可能需要報告節點何時達到錯誤被動錯誤警告匯流排關閉條件。驅動程式透過中斷(EPI、EWLI)通知錯誤狀態更改,然後透過讀取其錯誤計數器來確定核心的錯誤狀態。

但是,這裡存在一個輕微的競爭條件——在狀態轉換髮生(並且觸發中斷)和讀取錯誤計數器之間存在延遲。當收到 EPI 時,節點可能處於錯誤被動匯流排關閉狀態。如果節點進入匯流排關閉狀態,則顯然會保持該狀態直到重置。否則,該節點處於或曾經處於錯誤被動狀態。但是,可能會發生讀取狀態為錯誤警告甚至錯誤活動狀態。在那種情況下,可能不清楚是否以及究竟要報告什麼,但我個人認為應該仍然報告過去的錯誤條件。同樣,當收到 EWLI 但後來檢測到狀態為錯誤被動時,應報告錯誤被動狀態。

CTU CAN FD 驅動程式原始碼參考

int ctucan_probe_common(struct device *dev, void __iomem *addr, int irq, unsigned int ntxbufs, unsigned long can_clk_rate, int pm_enable_call, void (*set_drvdata_fnc)(struct device *dev, struct net_device *ndev))

裝置型別無關注冊呼叫

引數

struct device *dev

通用裝置結構的控制代碼

void __iomem *addr

CTU CAN FD 核心地址的基地址

int irq

中斷號

unsigned int ntxbufs

已實現的 Tx 緩衝區的數量

unsigned long can_clk_rate

時鐘速率,如果為 0,則從裝置節點獲取時鐘

int pm_enable_call

是否應該呼叫 pm_runtime_enable

void (*set_drvdata_fnc)(struct device *dev, struct net_device *ndev)

用於設定物理裝置的網路驅動程式資料的函式

描述

此函式執行 CAN 裝置的所有記憶體分配和註冊。

返回值

成功時返回 0,錯誤時返回失敗值

const char *ctucan_state_to_str(enum can_state state)

將 CAN 控制器狀態程式碼轉換為相應的文字

引數

enum can_state state

CAN 控制器狀態程式碼

返回值

指向錯誤狀態字串表示形式的指標

int ctucan_reset(struct net_device *ndev)

向 CTU CAN FD 發出軟體重置請求

引數

struct net_device *ndev

指向 net_device 結構的指標

返回值

成功時返回 0,如果 CAN 控制器未離開重置狀態,則返回 -ETIMEDOUT

int ctucan_set_btr(struct net_device *ndev, struct can_bittiming *bt, bool nominal)

在 CTU CAN FD 中設定 CAN 匯流排位時序

引數

struct net_device *ndev

指向 net_device 結構的指標

struct can_bittiming *bt

指向位時序結構的指標

bool nominal

True - 標稱位時序,False - 資料位時序

返回值

0 - OK,如果控制器已啟用,則返回 -EPERM

int ctucan_set_bittiming(struct net_device *ndev)

CAN 設定標稱位時序例程

引數

struct net_device *ndev

指向 net_device 結構的指標

返回值

成功時返回 0,錯誤時返回 -EPERM

int ctucan_set_data_bittiming(struct net_device *ndev)

CAN 設定資料位時序例程

引數

struct net_device *ndev

指向 net_device 結構的指標

返回值

成功時返回 0,錯誤時返回 -EPERM

int ctucan_set_secondary_sample_point(struct net_device *ndev)

在 CTU CAN FD 中設定輔助取樣點

引數

struct net_device *ndev

指向 net_device 結構的指標

返回值

成功返回 0,如果控制器已啟用,則返回 -EPERM

void ctucan_set_mode(struct ctucan_priv *priv, const struct can_ctrlmode *mode)

設定 CTU CAN FD 的模式

引數

struct ctucan_priv *priv

指向私有資料的指標

const struct can_ctrlmode *mode

指向要設定的控制器模式的指標

int ctucan_chip_start(struct net_device *ndev)

此例程啟動驅動程式

引數

struct net_device *ndev

指向 net_device 結構的指標

描述

例程期望晶片處於重置狀態。它為 FIFO 優先順序設定初始 Tx 緩衝區,設定位時序,啟用中斷,將核心切換到操作模式,並將控制器狀態更改為 CAN_STATE_STOPPED

返回值

成功時返回 0,錯誤時返回失敗值

int ctucan_do_set_mode(struct net_device *ndev, enum can_mode mode)

設定驅動程式的模式

引數

struct net_device *ndev

指向 net_device 結構的指標

enum can_mode mode

告知驅動程式的模式

描述

這檢查驅動程式的狀態並呼叫相應的模式進行設定。

返回值

成功時返回 0,錯誤時返回失敗值

enum ctucan_txtb_status ctucan_get_tx_status(struct ctucan_priv *priv, u8 buf)

獲取 TXT 緩衝區的狀態

引數

struct ctucan_priv *priv

指向私有資料的指標

u8 buf

緩衝區索引(從 0 開始)

返回值

TXT 緩衝區的狀態

bool ctucan_is_txt_buf_writable(struct ctucan_priv *priv, u8 buf)

檢查是否可以將幀插入到 TXT 緩衝區

引數

struct ctucan_priv *priv

指向私有資料的指標

u8 buf

緩衝區索引(從 0 開始)

返回值

True - 可以將幀插入到 TXT 緩衝區,False - 如果嘗試,幀將不會被

插入到 TXT 緩衝區

bool ctucan_insert_frame(struct ctucan_priv *priv, const struct canfd_frame *cf, u8 buf, bool isfdf)

將幀插入到 TXT 緩衝區

引數

struct ctucan_priv *priv

指向私有資料的指標

const struct canfd_frame *cf

指向要插入的 CAN 幀的指標

u8 buf

幀插入到的 TXT 緩衝區索引(從 0 開始)

bool isfdf

True - CAN FD 幀,False - CAN 2.0 幀

返回值

True - 幀插入成功
False - 由於以下原因之一,幀未插入
  1. TXT 緩衝區不可寫(處於錯誤狀態)

  2. 無效的 TXT 緩衝區索引

  3. 無效的幀長度

void ctucan_give_txtb_cmd(struct ctucan_priv *priv, enum ctucan_txtb_command cmd, u8 buf)

將命令應用於 TXT 緩衝區

引數

struct ctucan_priv *priv

指向私有資料的指標

enum ctucan_txtb_command cmd

要給出的命令

u8 buf

緩衝區索引(從 0 開始)

netdev_tx_t ctucan_start_xmit(struct sk_buff *skb, struct net_device *ndev)

開始傳輸

引數

struct sk_buff *skb

sk_buff 指標,包含要 Tx 的資料

struct net_device *ndev

指向 net_device 結構的指標

描述

從上層呼叫以啟動傳輸。使用下一個可用的空閒 TXT 緩衝區並填充其欄位以啟動傳輸。

返回值

成功時返回 NETDEV_TX_OK,當沒有可用的空閒 TXT 緩衝區時返回 NETDEV_TX_BUSY

負返回值保留用於錯誤情況

void ctucan_read_rx_frame(struct ctucan_priv *priv, struct canfd_frame *cf, u32 ffw)

從 RX FIFO 讀取幀

引數

struct ctucan_priv *priv

指向 CTU CAN FD 的私有資料的指標

struct canfd_frame *cf

指向 CAN 幀結構的指標

u32 ffw

先前讀取的幀格式字

注意

幀格式字必須單獨讀取並在“ffw”中提供。

int ctucan_rx(struct net_device *ndev)

從 CAN ISR 呼叫以完成接收幀處理

引數

struct net_device *ndev

指向 net_device 結構的指標

描述

此函式從 CAN isr(poll) 呼叫以處理 Rx 幀。它進行最小處理並呼叫“netif_receive_skb”以完成進一步處理。

返回值

當幀傳遞到網路層時返回 1,當讀取第一個幀字時返回 0 但

系統暫時沒有可用的 SKB,並留下程式碼稍後解決 SKB 分配問題,在 Rx FIFO 為空的情況下返回 -EAGAIN

enum can_state ctucan_read_fault_state(struct ctucan_priv *priv)

讀取 CTU CAN FD 的故障限制狀態。

引數

struct ctucan_priv *priv

指向私有資料的指標

返回值

控制器的故障限制狀態

void ctucan_get_rec_tec(struct ctucan_priv *priv, struct can_berr_counter *bec)

從控制器讀取 REC/TEC 計數器值

引數

struct ctucan_priv *priv

指向私有資料的指標

struct can_berr_counter *bec

指向錯誤計數器結構的指標

void ctucan_err_interrupt(struct net_device *ndev, u32 isr)

錯誤幀 ISR

引數

struct net_device *ndev

net_device 指標

u32 isr

中斷狀態暫存器值

描述

這是 CAN 錯誤中斷,它將檢查錯誤型別並將錯誤幀轉發到上層。

int ctucan_rx_poll(struct napi_struct *napi, int quota)

rx 資料包的輪詢例程 (NAPI)

引數

struct napi_struct *napi

NAPI 結構指標

int quota

要處理的最大 rx 資料包數。

描述

這是 rx 部分的輪詢例程。它將處理最大配額值的資料包。

返回值

收到的資料包數

void ctucan_rotate_txb_prio(struct net_device *ndev)

旋轉 TXT 緩衝區的優先順序

引數

struct net_device *ndev

net_device 指標

void ctucan_tx_interrupt(struct net_device *ndev)

Tx 完成 Isr

引數

struct net_device *ndev

net_device 指標

irqreturn_t ctucan_interrupt(int irq, void *dev_id)

CAN Isr

引數

int irq

irq 編號

void *dev_id

裝置 id 指標

描述

這是 CTU CAN FD ISR。它檢查中斷型別並呼叫相應的 ISR。

返回值

IRQ_NONE - 如果 CAN 裝置處於睡眠模式,否則為 IRQ_HANDLED

void ctucan_chip_stop(struct net_device *ndev)

驅動程式停止例程

引數

struct net_device *ndev

指向 net_device 結構的指標

描述

這是驅動程式的停止例程。它將停用中斷並停用控制器。

int ctucan_open(struct net_device *ndev)

驅動程式開啟例程

引數

struct net_device *ndev

指向 net_device 結構的指標

描述

這是驅動程式開啟例程。

返回值

成功時返回 0,錯誤時返回失敗值

int ctucan_close(struct net_device *ndev)

驅動程式關閉例程

引數

struct net_device *ndev

指向 net_device 結構的指標

返回值

始終為 0

int ctucan_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec)

錯誤計數器例程

引數

const struct net_device *ndev

指向 net_device 結構的指標

struct can_berr_counter *bec

指向 can_berr_counter 結構的指標

描述

這是驅動程式錯誤計數器例程。

返回值

成功時返回 0,錯誤時返回失敗值

int ctucan_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

PCI 註冊呼叫

引數

struct pci_dev *pdev

PCI 裝置結構的控制代碼

const struct pci_device_id *ent

指向 ctucan_pci_tbl 中的條目的指標

描述

此函式執行 CAN 裝置的所有記憶體分配和註冊。

返回值

成功時返回 0,錯誤時返回失敗值

void ctucan_pci_remove(struct pci_dev *pdev)

釋放資源後登出裝置

引數

struct pci_dev *pdev

PCI 裝置結構的控制代碼

描述

此函式釋放分配給裝置的所有資源。

返回值

始終為 0

int ctucan_platform_probe(struct platform_device *pdev)

平臺註冊呼叫

引數

struct platform_device *pdev

平臺裝置結構的控制代碼

描述

此函式執行 CAN 裝置的所有記憶體分配和註冊。

返回值

成功時返回 0,錯誤時返回失敗值

void ctucan_platform_remove(struct platform_device *pdev)

釋放資源後登出裝置

引數

struct platform_device *pdev

平臺裝置結構的控制代碼

描述

此函式釋放分配給裝置的所有資源。

返回值

始終為 0

CTU CAN FD IP 核和驅動程式開發感謝

  • Intel SoC 的系統整合、核心和驅動程式測試和更新

  • 提供了 OSADL 專業知識來討論 IP 核許可

  • 指出了 LGPL 和 CAN 匯流排可能的專利案例可能出現的死鎖,這導致將 IP 核設計重新許可為類似 BSD 的許可證

  • 提供了建議和幫助,以告知社群有關該專案的資訊,並邀請我們參加專注於 CAN 匯流排未來發展方向的活動

  • Jan Charvat

  • 為 QEMU 實現了 CTU CAN FD 功能模型,該模型已整合到 QEMU 主線中 (docs/system/devices/can.rst)

  • 學士論文 QEMU 模擬器的 CAN FD 通訊控制器模型

註釋