日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

5.4. Interaction Between Devices and Kernel 设备与内核的交互

發布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 5.4. Interaction Between Devices and Kernel 设备与内核的交互 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄:http://www.cnblogs.com/WuCountry/archive/2008/11/15/1333960.html
?
[不提供插圖,讀者最好從網上下載源書]
????
5.4. Interaction Between Devices and Kernel 設備與內核的交互
Nearly all devices (including NICs) interact with the kernel in one of two ways:
幾乎所有的設備(包括NIC)有2種方式與內核交互:

Polling 輪詢

Driven on the kernel side. The kernel checks the device status at regular intervals to see if it has anything to say.
內核驅動模式,由內核有規則的主動檢測設備的狀態,看設備是否有內容要輸出。

Interrupt

Driven on the device side. The device sends a hardware signal (by generating an interrupt) to the kernel when it needs the kernel's attention.
設備驅動模式,在設備須要內核關注時,由設備主動發送一個硬件信號(通常是通過一個中斷)給內核。

In Chapter 9, you can find a detailed discussion of NIC driver design alternatives as well as software interrupts. You will also see how Linux can use a combination of polling and interrupts to increase performance. In this chapter, we will look only at the interrupt-based case.
在第9章,你可以看到詳細的討論,關于NIC驅動可以選擇性的設計成很好的軟件中斷模式。你同樣可以看到Linux是如何合并使用輪詢和中斷來提高性能的。在這一章,我只講基于中斷的情況。

I won't go into detail on how interrupts are reported by the hardware, the difference between hardware exceptions and device interrupts, how the driver and bus kernel infrastructures are designed, etc.; you can refer to Linux Device Drivers and Understanding the Linux Kernel for those topics. But I'll give a brief overview on interrupts to help you understand how device drivers initialize and register the devices they are responsible for, with special attention to the networking aspect.
我不會詳細的說明中斷是如何從硬件上報給內核的,硬件異常和設備中斷的區別,驅動和內核總線的底層是怎樣設計的,等等。關于這些內容你可以參考:Linux Device Drivers 和 Understanding the Linux Kernel。但我會簡單的說明一下中斷,以幫助你理解設備驅動的初始化和讓設備回應的注冊,而這些都只關注于網絡特性。

5.4.1. Hardware Interrupts 使用中斷
You do not need to know the low-level background about how hardware interrupts are handled. However, there are details worth mentioning because they can make it easier to understand how NIC device drivers are written, and therefore how they interact with the upper networking layers.
你須要知道一些關于硬件底層中斷處理的背景知識。顯然,它們的細節是值得被關注的,因為這會讓你更加容易的理解NIC設備驅動應該怎樣寫,而且知道它們是怎樣與網絡層交互的。

Every interrupt runs a function called an interrupt handler, which must be tailored to the device and therefore is installed by the device driver. Typically, when a device driver registers an NIC, it requests and assigns an IRQ. It then registers and (if the driver is unloaded) unregisters a handler for a given IRQ with the following two architecture-dependent functions. They are defined in kernel/irq/manage.c and are overridden by architecture-specific functions in arch/XXX/kernel/irq.c, where XXX is the architecture-specific directory:
每一個中斷是以一個被稱為中斷處理的函數調用來運行的,這些必須可以通過安裝的設備驅動程序,根據設備被裁剪。代表性的,當一個設備驅動注冊成一個NIC,它要請求分配一個IRQ。然后它就通過以下兩個基于系統體系結構的函數來注冊和反注冊(如果設備在卸載時)IRQ。這兩個函數定義在kernel/irq/manage.c中,而且它們被不同的體系結構在arch/XXX/kernel/irq.c中重載,其中的XXX是指定的體系結構目錄:

int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs*), unsigned long irqflags, const char * devname, void *dev_id)


This function registers a handler, first making sure that the requested interrupt is a valid one, and that it is not already allocated to another device unless both devices understand shared IRQs (see the later section "Interrupt sharing").
這個函數注冊一個句柄,首先確保請求的中斷是一個有效的中斷號,而且它還沒有分配給另一個設備,除非兩個設備都明確的使用共享IRQ(參見后面的一節“Interrupt sharing”)。

void free_irq(unsigned_int irq, void *dev_id)

Given the device identified by dev_id, this function removes the handler and disables the IRQ line if no more devices are registered for that IRQ. Note that to identify the handler, the kernel needs both the IRQ number and the device identifier. This is especially important with shared IRQs, as explained in the later section "Interrupt sharing."
dev_id給出了設備唯一標識,如果一個IRQ上已經沒有了注冊的設備,這個函數就用于刪除處理句柄并禁用IRQ總線。注意,為了標識處理句柄,內核同時須要IRQ號和設備ID。對于共享IRQ來說,這更加重要,在后面的章節“共享中斷”中有解釋。

When the kernel receives an interrupt notification, it uses the IRQ number to find out the driver's handler and then executes this handler. To find handlers, the kernel stores the associations between IRQ numbers and function handlers in a global table. The association can be either one-to-one or one-to-many, because the Linux kernel allows multiple devices to use the same IRQ, a feature described in the later section "Interrupt sharing."
當內核收到一個中斷通知時,它就使用IRQ號來找到設備的句柄,然后執行它。為了找到處理句柄,內核將IRQ號和函數句柄以關聯的形式存儲在一個全局表中。這個關聯可以是一對一的,也可以是一對多的,因為Linux內核充許多設備使用同一個IRQ,相關特性在后面的“共享中斷”中有描述

In the following sections, you will see common examples of the information exchanged between devices and drivers by means of interrupts, and how an IRQ can be shared by multiple devices under some conditions.
在下面的章節中,就會看到一些在名義上稱為中斷的,關于設備與驅動之間信息交換的通用示例,以及一個IRQ是如何在一些條件下,在多個設備之間共享的。

5.4.1.1. Interrupt types 中斷類型
With an interrupt, an NIC can tell its driver several different things. Among them are:
在一個中斷上,一個NIC可以特性它的驅動一些不同的事。這些有:

Reception of a frame 收到一個幀

This is the most common and standard situation. 這是最常見和標準的情況。

Transmission failure 轉送失敗

This kind of notification is generated on Ethernet devices only after a feature called exponential binary backoff has failed (this feature is implemented at the hardware level by the NIC). Note that the driver will not relay this notification to higher network layers; they will come to know about the failure by other means (timer timeouts, negative ACKs, etc.).
這種通知只在以太設備上,當一個稱為(exponential binary backoff)失敗以后才發生。(這一特性是在NIC的硬件層上實現的)。注意,驅動在更高層的網絡層上將不再對這個通知轉發;它們以另一種形式來獲知這個失敗(計時器超時,拒絕的確認幀等)。


DMA transfer has completed successfully DMA傳送已經成功的完成

Given a frame to send, the buffer that holds it is released by the driver once the frame has been uploaded into the NIC's memory for transmission on the medium. With synchronous transmissions (no DMA), the driver knows right away when the frame has been uploaded on the NIC. But with DMA, which uses asynchronous transmissions, the device driver needs to wait for an explicit interrupt from the NIC. You can find an example of each case at points where dev_kfree_skb[*] is called within the driver code drivers/net/3c59x.c (DMA) and drivers/net/3c509.c (non-DMA).
給一個發送幀,在介質上傳送該幀時,一但幀已經上傳到NIC的內存以后,該幀的緩存會被驅動釋放。在同步傳輸時(非DMA),設備可以正確的知道在什么時候幀已經上傳到NIC設備中。但在DMA中,也就是用戶使用異步傳送模式,設備驅動須要等待NIC一個清楚的中斷。你可以在drivers/net/3c59x.c和drivers/net/3c509.c中分別找到調用dev_kfree_skb的示例。

[*] Chapter 11 describes this function in detail. 該函數在第11章中有詳細說明。


Device has enough memory to handle a new transmission 設備已經有足夠的內存來處理新的傳輸

It is common for an NIC device driver to disable transmissions by stopping the egress queue when that queue does not have sufficient free space to hold a frame of maximum size (e.g., 1,536 bytes for an Ethernet NIC). The queue is then re-enabled when memory becomes available. The rest of this section goes into this case in more detail.
對于NIC設備驅動來說,當隊列沒有足夠的空閑空間來存儲一個最大字節的幀(例如,在以太NIC上是1536字節)時,通過停止出口隊列來禁止傳輸是很常見的情況。而當隊列上有了足夠的內存時就會重新使能該設備。這一節后面的內容會詳細討論這一問題。

The final case in the previous list covers a sophisticated way of throttling transmissions in a manner that can improve efficiency if done properly. In this system, a device driver disables transmissions for lack of queuing space, asks the NIC to issue an interrupt when the available memory is bigger than a given amount (typically the device's Maximum Transmission Unit, or MTU), and then re-enables transmissions when the interrupt comes.
前面列出的最后一個情況,包括了一個如果處理正確的話,可以提高效率的成熟的方法;在這個系統里,一個設備驅動在缺少空間的隊列上禁用數據傳輸,詢問該NIC以確認一個中斷,當有大于給定數量的內存空間(通常就是設備的最大傳輸單元,或者MTU),然后當中斷到來時重新使能數據傳輸。

A device driver can also disable the egress queue before a transmission (to prevent the kernel from generating another transmission request on the device), and re-enable it only if there is enough free memory on the NIC; if not, the device asks for an interrupt that allows it to resume transmission at a later time. Here is an example of this logic, taken from the el3_start_xmit routine, which the drivers/net/3c509.c driver installs as its hard_start_xmit function in its net_device structure:
一個設備驅動同樣可以禁用出口隊列的數據傳輸(用于防止內核在該設備上產生另一個傳輸請示),而只在NIC有足夠的內存時才重新使能;否則,該設備請求一個中斷,該中斷充許它在后面某個時刻恢復數據傳輸。關于這一邏輯,這里有一個從drivers/net/3c509.c里取得的一個el3_start_xmit的示例,設備驅動用類似hard_start_mit的函數放在它的設備數據結構里:

?The hard_start_xmit virtual function is described in Chapter 11.
hard_start_xmit虛函數在第11章里討論

static int
el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
??? ... ... ...
??? netif_stop_queue (dev);
??? ... ... ...
??? if (inw(ioaddr + TX_FREE) > 1536)
??????? netif_start_queue(dev);
??? else
??????? outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
??? ... ... ...
}


The driver stops the device queue with netif_stop_queue, thus inhibiting the kernel from submitting further transmission requests. The driver then checks whether the device's memory has enough free space for a packet of 1,536 bytes. If so, the driver starts the queue to allow the kernel once again to submit transmission requests; otherwise, it instructs the device (by writing to a configuration register with an outw call) to generate an interrupt when that condition will be met. An interrupt handler will then re-enable the device queue with netif_start_queue so that the kernel can restart transmissions.
該驅動用netif_stop_queue來停止設備隊列,這樣就抑制內核后期的傳輸請求。然后驅動檢測設備是否有足夠的內存空間來存放一個1536字節的數據包。如果是這樣的,設備啟動隊列,用以再次讓內核可以提交數據傳輸請求。否則,它就指示設備(通過寫一個outw調用來寫一個配置寄存器)在這個條件滿足時產生一個中斷。然后一個中斷句柄用netif_start_queue來重新使能設備隊列,這樣內核就可以重新啟動數據傳輸。

The netif_xxx_queue routines are described in the section "Enabling and Disabling Transmissions" in Chapter 11.
netif_xxx_queue函數會在第11章的“傳輸的使能與去使能”中描述。

5.4.1.2. Interrupt sharing 共享中斷
IRQ lines are a limited resource. A simple way to increase the number of devices a system can host is to allow multiple devices to share a common IRQ. Normally, each driver registers its own handler to the kernel for that IRQ. Instead of having the kernel receive the interrupt notification, find the right device, and invoke its handler, the kernel simply invokes all the handlers of those devices that registered for the same shared IRQ. It is up to the handlers to filter spurious invocations, such as by reading a registry on their devices.
IRQ線是有限的資源。一個簡單的方法可以增加該系統可以提供的設備數目,就是充許多個設備共享一個通用的IRQ。原來內核是收到一個中斷通知以后,查找到正確的設備,然后調用它的句柄;共享IRQ以后,內核取而代之的就是簡單的調用這些設備注冊在同一個IRQ上的所有句柄。這就等于讓句柄去過濾欺騙的行為,例如在他們的設備上讀一個寄存器。

For a group of devices to share an IRQ line, all of them must have device drivers capable of handling shared IRQs. In other words, each time a device registers for an IRQ line, it needs to explicitly say whether it supports interrupt sharing. For example, the first device that registers for one IRQ, saying something like "assign me IRQ n and use this routine fn as the handler," must also specify whether it is willing to share the IRQ with other devices. When another device driver tries to register the same IRQ number, it is refused if either it, or the driver to which the IRQ is currently assigned, is incapable of sharing IRQs.
為了讓一組設備可以共享一個IRQ線,所有設備都必須有一個在共享IRQ上可以處理的句柄。也就是說,每次在注冊一個IRQ時,它必須顯示的說明它是否支持共享中斷。例如,第一個設備在注冊一個IRQ時,像這樣申明:“分配給我一個IRQ n,而且用這個句柄來做為我的調用函數”,同時還必須指定它是否要與其它設備共享這個中斷號。當另一個設備來注冊同一個中斷號是時,如果該設備不使用共享,那么它會被拒絕,或者說,已經注冊了該中斷號的設備也是無法共享該中斷號的。

5.4.1.3. Organization of IRQs to handler mappings IRQ句柄的映射組織
The mapping of IRQs to handlers is stored in a vector of lists, one list of handlers for each IRQ (see Figure 5-2). A list includes more than one element only when multiple devices share the same IRQ. The size of the vector (i.e., the number of possible IRQ numbers) is architecture dependent and can vary from 15 (on an x86) to more than 200. With the introduction of interrupt sharing, even more devices can be supported on a system at once.
映射IRQ的句柄是存儲在一個向量鏈表中,每一個IRQ(參見圖5-2)有一個句柄鏈表。一個鏈表只有在多個設備共享同一個IRQ時才會包含更多的元素。向量的大小(例如:IRQ的可用數量)是與體系結構相關的,而且是可以從15(在x86的體系結構上)到多于200的范圍上變化的。和中斷共享所介紹的一樣,可能更多的設備可以一次在一個系統是被支持。

The section "Hardware Interrupts" already introduced the two functions provided by the kernel to register and unregister a handler, respectively. Let's now see the data structure used to store the mappings.
在硬件中斷一節中已經介紹了內核所提供的兩個函數,用于注冊和反注冊一個句柄。接下來讓我們看看關于映射的數據結構的存儲。

Mappings are defined with irqaction data structures. The request_irq function introduced in the earlier section "Hardware Interrupts" is a wrapper around setup_irq, which takes an irqaction structure as input and inserts it into the global irq_desc vector. irq_desc is defined in kernel/irq/handler.c and can be overridden in the per-architecture files arch/XXX/kernel/irq.c. setup_irq is defined in kernel/irq/manage.c and can be overridden in the per-architecture files arch/XXX/kernel/irq.c.
映射和中斷動作(irqaction)數據結構定義在一起。request_irq函數已經在前面的“硬件中斷”一節中介紹過,它被封裝成setup_irq,這個函數用一個中斷動作數據結構做為一個輸入參數,而且將它插入到一個全局的irq_desc向量中。irq_des在kernel/irq/handler.c中有定義,而且它可在以每個不同的體系結構中被重載,這些體系結構文件在arch/xxx/kernel/irq.c中。setup_irq被定義在kernel/irq/manage.c中,而且可以被arch/xxx/kernle/irq.c中不同的體系結構所重載。

The kernel function that handles interrupts and passes them to drivers is architecture dependent. It is called handle_IRQ_event on most architectures.
內核用于處理句柄并將它們傳給設備的函數是與體系結構相關的。它們在很多體系結構中都被稱為handle_IRQ_event。

Figure 5-2 shows how irqaction instances are stored: there is an instance of irq_desc for each possible IRQ and an instance of irqaction for each successfully registered IRQ handler. The vector of irq_desc instances is called irq_desc as well, and its size is given by the architecture-dependent symbol NR_IRQS.
圖5-2展示了中斷動作實例是如何存儲的:這里,在每一個可能的IRQ上有一個irq_desc的實例,而且每中斷動作的實例已經成功的注冊了IRQ處理句柄。irq_desc向量的實例可以就稱為irq_desc,而且它的大小是由給定的與體系結構相關的NR_IRQS所決定的。

Note that when you have more than one irqaction instance for a given IRQ number (that is, for a given element of the irq_desc vector), interrupt sharing is required (each structure must have the SA_SHIRQ flag set).
應該注意,當你在一個給定的IRQ數上使多個IRQ動作時(也就是在一個給定的irq_desc向量元素上),中斷共享是必須的(每個結構必須同時擁有SA_SHIRQ標志位)。

Figure 5-2. Organization of IRQ handlers
圖5-2,IRQ句柄組織


Let's see now what information is stored about IRQ handlers in the fields of an irqaction data structure:
現在讓我們來看看關于IRQ句柄的信息在一個中斷動作的數據結構中是如何存儲的:


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

Function provided by the device driver to handle notifications of interrupts: whenever the kernel receives an interrupt on line irq, it invokes handler. Here are the function's input parameters:
該函數由設備驅動提供,用于處理中斷通知:不管什么時候,只要內核在IRQ線上收到一個中斷,它就調用這個句柄。這里是函數的輸入參數:


int irq

IRQ number that generated the notification. Most of the time it is not used by the NICs' device drivers to accomplish their job; the device ID is sufficient.
IRQ號,用于合成(中斷)通知。多數時候,它只并不被NIC設備驅動所使用去完成它們的任務,設備ID已經足夠了。

void *dev_id

Device identifier. The same driver can be responsible for different devices at the same time, so it needs the device ID to process the notification correctly.
設備ID,同一個設備驅動可以同時對不同的設備負責,所以它須要設備ID用于處理正確的中斷通知。


struct pt_regs *regs

Structure used to save the content of the processor's registers at the moment the interrupt interrupted the current process. It is normally not used by the interrupt handler.
該結構用于在中斷正中斷了當前進程時,用于保存當前處理器的寄存器內容。通常它不被中斷句柄所使用。

unsigned long flags

Set of flags. The possible values SA_XXX are defined in include/asm-XXX/signal.h. Here are the main ones from the x86 architecture file:
標志位,它的可能值在include/asm-XXX/signal.h中以SA_XXX的形式定義,這里是幾個x86體系結構的主要值:


SA_SHIRQ

When set, the device driver can handle shared IRQs.
設置它時,設備驅動可以處理共享IRQ


SA_SAMPLE_RANDOM

When set, the device is making itself available as a source of random events. This can be useful to help the kernel generate random numbers for internal use, and is called contributing to system entropy. This is further described in the later section "Initializing the Device Handling Layer: net_dev_init."
設置它時,設備就讓它自己可成為一個隨機事件的源。這可以用于幫助內核產生一些內部使用的隨機數,而且它被稱為給內核貢獻的熵值。這個會在后面的“初始化設備句柄層:net_dev_init”章節中描述。

SA_INTERRUPT

When set, the handler runs with interrupts disabled on the local processor. This should be specified only for handlers that can get done very quickly. See one of the handle_IRQ_event instances for an example (for instance, /kernel/irq/handle.c).
當它被設置時,句柄就在本地處理器上以可中斷的形式運行。這只有在句柄可以很快的處理完時指定??梢詤⒁娨粋€handle_IRQ_event的實例(/kernel/irq/handle.c)。

There are other values, but they are either obsolete or used only by particular architectures.
這里有另一個值,但它們并沒有被丟棄,也沒有被特殊的體系結構所使用。

void *dev_id

Pointer to the net_device data structure associated with the device. The reason it is declared void * is that NICs are not the only devices to use IRQs. Because various device types use different data structures to identify and represent device instances, a generic type declaration is used.
用于指向一個與設備相關的數據結構net_device,使用void *的理由是NIC并不是唯一使用IRQ的設備。

struct irqaction *next

All the devices sharing the same IRQ number are linked together in a list with this pointer.
所有的共享同一個IRQ數的設備被一個鏈表所關聯在一起,這個指針指向這個鏈表。

const char *name

Device name. You can read it by dumping the contents of /proc/interrupts.
設備名,你可以通過導出/proc/interrupts中的信息來讀取它。

轉載于:https://www.cnblogs.com/WuCountry/archive/2009/02/01/1382106.html

總結

以上是生活随笔為你收集整理的5.4. Interaction Between Devices and Kernel 设备与内核的交互的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。