Linux網路驅動程式編寫(四)(轉)

worldblog發表於2007-08-10
Linux網路驅動程式編寫(四)(轉)[@more@]

  三.編寫Linux網路驅動程式中需要注意的問題

  3.1 中斷共享

  Linux系統執行幾個裝置共享同一個中斷。需要共享的話,在申請的時候指明共享方式。系統提供的request_irq()呼叫的定義:

    int request_irq(unsigned int irq,

          void (*handler)(int irq, void *dev_id, struct pt_regs *regs),

          unsigned long irqflags,

          const char * devname,

          void *dev_id);

  如果共享中斷,irqflags設定SA_SHIRQ屬性,這樣就允許別的裝置申請同一個中斷。需要注意所有用到這個中斷的裝置在呼叫request_irq()都必須設定這個屬性。系統在回撥每個中斷處理程式時,可以用dev_id這個引數找到相應的裝置。系統在回撥每個中斷處理程式時,可以用dev_id這個引數找到相應的裝置。一般dev_id就設為device結構本身。系統處理共享中斷是用各自的dev_id引數依次呼叫每一箇中斷處理程式。

  3.2 硬體傳送忙時的處理

  主CPU的處理能力一般比網路傳送要快,所以經常會遇到系統有資料要發,但上一包資料網路裝置還沒傳送完。因為在Linux裡網路裝置驅動程式一般不做資料快取,不能傳送的資料都是通知系統傳送不成功,所以必須要有一個機制在硬體不忙時及時通知系統接著傳送下面的資料。

  一般對傳送忙的處理在前面裝置的傳送方法(hard_start_xmit)裡已經描述過,即如果傳送忙,置tbusy為1。處理完傳送資料後,在傳送結束中斷裡清tbusy,同時用mark_bh()呼叫通知系統繼續傳送。

  但在具體實現我的驅動程式時發現,這樣的處理系統好象並不能及時地知道硬體已經空閒了,即在mark_bh()以後,系統要等一段時間才會接著傳送。造成傳送效率很低。2M線路只有10%不到的使用率。核心版本為2.0.35。

  我最後的實現是不把tbusy置1,讓系統始終認為硬體空閒,但是報告傳送不成功。系統會一直嘗試重發。這樣處理就執行正常了。但是遍循核心原始碼中的網路驅動程式,似乎沒有這樣處理的。不知道癥結在哪裡。

  3.3 流量控制(flow control)

  網路資料的傳送和接收都需要流量控制。這些控制是在系統裡實現的,不需要驅動程式做工作。每個裝置資料結構裡都有一個引數dev->tx_queue_len,這個引數標明傳送時最多快取的資料包。在Linux系統裡乙太網裝置(10/100Mbps)標明傳送時最多快取的資料包。在Linux系統裡乙太網裝置(10/100Mbps)tx_queue_len一般設定為100,序列線路(非同步串列埠)為10。實際上如果看原始碼可以知道,設定了dev->tx_queue_len並不是為快取這些資料申請了空間。這個引數只是在收到協議層的資料包時判斷髮送佇列裡的資料是不是到了tx_queue_len的限度,以決定這一包資料加不加進傳送佇列。傳送時另一個方面的流控是更高層協議的傳送視窗(TCP協議裡就有傳送視窗)。達到了視窗大小,高層協議就不會再傳送資料。

  接收流控也分兩個層次。netif_rx()快取的資料包有限制。另外高層協議也會有一個最大的等待處理的資料量。

  傳送和接收流控處理在net/core/dev.c的do_dev_queue_xmit()和netif_rx()中。

  3.4 除錯

  很多Linux的驅動程式都是編譯進核心的,形成一個大的核心檔案。但對除錯來說,這是相當麻煩的。除錯驅動程式可以用module方式載入。支援模組方式的驅動程式必須提供兩個函式:int init_module(void)和void cleanup_module(void)。init_module()在載入此模組時呼叫,在這個函式里可以register_netdev()註冊裝置。init_module()返回0表示成功,返回負表示失敗。cleanup_module()在驅動程式被解除安裝時呼叫,清除佔用的資源,呼叫unregister_netdev()。

  模組可以動態地載入、解除安裝。在2.0.xx版本里,還有kerneld自動載入模組,但是2.2.xx中已經取消了kerneld。手工載入使用insmod命令,解除安裝用rmmod命令,看核心中的模組用lsmod命令。

  編譯驅動程式用gcc,主要命令列引數-DKERNEL -DMODULE。並且作為模組載入的驅動程式,只編譯成obj形式(加-c引數)。編譯好的目標文放/lib/modules/2.x.xx/misc下,在啟動檔案裡用insmod載入。

  四.進一步的閱讀

  Linux程式設計資料可以從網上獲得。這就是開放原始碼的好處。並且沒有什麼“未公開的秘密”。我編寫驅動程式時參閱的主要資料包括:

  Linux核心原始碼

  《The Linux Kernel Hacker's Guide》by Michael K. Johnson

  《Linux Kernel Module Programming Guide》by Ori Pomerantz

  《Linux下的裝置驅動程》by olly in BBS水木清華站

  可以選擇一個模板作為開始,核心原始碼裡有一個網路驅動程式的模板,drivers/net/skeleton.c。裡面包含了驅動程式的基本內容。但這個模板是以乙太網裝置為物件的,乙太網的處理在Linux系統裡有特殊“待遇”,所以如果不是乙太網裝置,有些細節上要注意,主要在初始化程式裡。

  最後,多參照別人寫的程式,聽聽其他開發者的經驗之談大概是最有效的幫助了。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-940213/,如需轉載,請註明出處,否則將追究法律責任。

相關文章