The copyleft of this document return to Wwwlkk all, using the GPL release, you can freely copy, reprint, reprint, please keep the integrity of the document, is strictly prohibited for any commercial purposes.
e-mail: wwwlkk@126.com
source :http://passport.baidu.com/?business&aid=6&un=wwwlkk#7
(1) Single CPU hard interrupt 1
(2) e1000 network card hardware Interrupt handler 1
(3) Single CPU soft interrupt 2
(4) Net_rx_softirq soft Interrupt Service Routine 3
(5) e1000 soft Interrupt Service Routine 4
(6) Multi-CPU E1000 network card packet receiving process 5
(7) RPS Implementation Analysis 6
(8) Prevent the CPU cache frequent Refresh 7
(9) Receiveflow Steering (RFS) Analysis 9 (1) Single CPU hard interrupt
Execution Process:
Irqi : Enter the interrupt number is I hard Interrupt handler. The first instruction to execute is to save the contents of the current register on the kernel stack.
Iret : Returns from a hard interrupt, and finally restores the contents of the register.
interrupts can be nested for execution:
Irqi
IRQJ
Iret
Iret
Note: Interrupt signal ( instruction ) it is possible to nest execution, but each interrupt handler is different, it is possible to turn off interrupts in an interrupt handler, or use a spin lock to prevent interrupted nesting execution.
The above content is in the Linux break Analysis has a more detailed analysis. (2) e1000 network card hardware interrupt handler
The following analysis e1000 the hard interrupt handler for the type of NIC.
Register and assign an interrupt number:
E1000_open (Structnet_device *netdev)
Err= E1000_REQUEST_IRQ (adapter);
REQUEST_IRQ (Adapter->pdev->irq,handler, Irq_flags, Netdev->name, Netdev);
Interrupt Handler:
1e1000_intr ()
2 Ew32 (imc,~0); turn off the NIC interrupt
3 Napi_schedule_prep (&ADAPTER->NAPI) test napi is running
4!test_and_set_bit (napi_state_sched,&n->state) test and set NAPI Run bit
5 if NAPI is not running
6 __napi_schedule (&ADAPTER->NAPI); Join this CPU the soft interrupt processing queue
7 if NAPI is already running
8 Direct return
in the 1-2 May produce multiple interrupt signals between the sections of the program, which may occur as follows:
Irqei // receive first interrupt signal
E1000_intr ()
Run between 1-2
Irqei // receive a second interrupt signal
E1000_intr ()
Ew32 (imc,~0); turn off the NIC interrupt
Executive Napi_schedule_prep (&ADAPTER->NAPI)
!test_and_set_bit (napi_state_sched,&n->state) set NAPI run bit
__napi_schedule (&ADAPTER->NAPI);
Iret
The first interrupt service routine continues to run
!test_and_set_bit (napi_state_sched,&n->state) test NAPI run bit
Napi has run
return directly // the interrupt processing routine that the first interrupt signal triggers will be returned directly
Iret
the conclusion drawn from here:
multiple network card interrupts may have been generated prior to shutting down the interrupt, but eventually only one of the interrupt processing routines is executed __napi_schedule (&ADAPTER->NAPI) .
Conclusions 1 also applies to multiple CPU . (3) Single CPU soft interrupt
the entry point for soft interrupts is Do_softirq () , more than one point in the kernel code will enter Do_softirq () :
1.local_bh_enable ()
2.irq_exit ()
3.ksoftirq/n when the kernel thread is awakened
above 3 is the most important entry point.
1do_softirq (void)
2 if (In_interrupt ())
3 return if it is already in a hard interrupt or soft interrupt, go straight back.
4 Local_irq_save (flags); Save if flag and block programmable interrupts
5 __do_softirq ();
5.1 pending= local_softirq_pending ();
6 __local_bh_disable () soft interrupt counter plus 1
6.1 set_softirq_pending (0);
7 local_irq_enable (); open Local CPU programmable interrupt
8 local_irq_disable (); masking local CPU programmable interrupts
9 _local_bh_enable () soft interrupt counter minus 1
Local_irq_restore (flags); Open local CPU programmable interrupt and restore if flag
from this code, you can be sure that:
If a kernel path is already in the 6-9 Execution of this code (soft interrupt counter has been added 1 at this point, the other kernel path executes to the 2 will be returned directly.
because the interrupt context (including a soft interrupt) is a process-disabled switch, 2 a kernel path into Do_softirq () , the latter must be entered in a hard interrupt handler Do_softirq () , and because 4-7 The shield is a hard interrupt, so this code is not interrupted by a hard interrupt, that is, it will not be preempted by other kernel paths.
4-7 preemption (including process preemption and hard interrupts) does not occur between, and this code executes a __local_bh_disable () Soft interrupt counter plus 1 , in 7-9 In this code, no process preemption occurs, but a hard interrupt may occur, after which a hard interrupt service program may enter Do_softirq () , it's time to judge In_interrupt () must return 1 , it can be concluded that in 7-9 The hard interrupt service that executes within this code enters the Do_softirq () will be returned immediately. That is, There will not be two kernel paths in one CPU executing code between 4-9.
Well, the analysis is so much to draw a key conclusion: in a CPU , the soft interrupt service routine must be serial execution ( The routines here refer to h->action (h)) .
Note: The analysis here is 4-9 This piece of code, however, for the specific h->action (h) The interior has concrete implementation. (4) NET_RX_SOFTIRQ soft interrupt Service Routines
The following analysis of a specific action-------Net_rx_softirq
Soft Interrupt Routine registration process:
Net_dev_init (void)
OPEN_SOFTIRQ (net_rx_softirq,net_rx_action);
net_rx_action Internal process:
Net_rx_action (structsoftirq_action *h)
Structsoftnet_data *sd = &__get_cpu_var (softnet_data)
Local_irq_disable ();
while (!list_empty (&sd->poll_list)) {
Structnapi_struct *n;
Local_irq_enable ();
N= list_first_entry (&sd->poll_list, struct napi_struct,poll_list);
Work= n->poll (n, weight);
}
A key data structure appears on the key code-- per CPU variable &__get_cpu_var (softnet_data)
every CPU Assignment of variables:
define_per_cpu_aligned (Structsoftnet_data, softnet_data);
where the second argument is the array name
Structsoftnet_data {
Structqdisc *output_queue;
Structqdisc **output_queue_tailp;
structlist_head poll_list; struct napi_struct structure linked list
Structsk_buff *completion_queue;
Structsk_buff_head Process_queue;
/*stats *
Unsignedint processed;
Unsignedint Time_squeeze;
Unsignedint cpu_collision;
Unsignedint Received_rps;
#ifdefCONFIG_RPS
Structsoftnet_data *rps_ipi_list;
/*elements below can be accessed between CPUs for RPS * *
Structcall_single_data CSD ____CACHELINE_ALIGNED_IN_SMP;
Structsoftnet_data *rps_ipi_next;
Unsignedint CPU;
Unsignedint Input_queue_head;
Unsignedint Input_queue_tail;
#endif
unsigned dropped;
Structsk_buff_head Input_pkt_queue;
structnapi_struct Backlog;
};
structnapi_struct {
Structlist_head poll_list; Connection structnapi_struct structure linked list
Unsignedlong State;
int weight;
Int (*poll) (structnapi_struct *, int); execution Function
#ifdefCONFIG_NETPOLL
spinlock_t Poll_lock;
int Poll_owner;
#endif
Unsignedint Gro_count;
Structnet_device *dev;
Structlist_head dev_list;
Structsk_buff *gro_list;
Structsk_buff *SKB;
};
net_rx_action The internal process is the execution of the hook poll_list linked List of structnapi_struct the callback function in Poll . (5) e1000 soft interrupt Service Routines
The following analysis of the network card e1000 how the driver receives the packet. ( using NAPI)
The hard interrupt from the top has been analyzed, e1000 hard Interrupt handler function final execution __napi_schedule (ADAPTER->NAPI)
__napi_schedule (structnapi_struct *n)
____napi_schedule (&__get_cpu_var (Softnet_data), n);
List_add_tail (&napi->poll_list,&sd->poll_list); Join Poll Queue
__raise_softirq_irqoff (NET_RX_SOFTIRQ); triggering Rx Soft Interrupt
This function is very simple, which is to structnapi_struct add to every CPU variable Softnet_data of the poll_list , and Wake NET_RX_SOFTIRQ soft interrupt.
so structnapi_struct in the Poll what function to point to.
Poll function Registration process:
E1000_probe (Structpci_dev *pdev, const struct PCI_DEVICE_ID *ent)
Netif_napi_add (netdev,&adapter->napi,E1000_clean, 64);
Now you know Poll Point to E1000_clean ()
E1000_clean (structnapi_struct *napi, int budget)
Adapter->clean_rx (Adapter,&adapter->rx_ring[0], &work_done, budget);
according to the different circumstances Clean_rx point to a different function, register the process:
E1000_configure_rx (Structe1000_adapter *adapter)
if (Adapter->netdev->mtu > Eth_data_len) {
rdlen= Adapter->rx_ring[0].count *
sizeof (struct E1000_RX_DESC);
adapter->clean_rx= E1000_clean_jumbo_rx_irq;
Adapter->alloc_rx_buf= e1000_alloc_jumbo_rx_buffers;
}else {
rdlen= Adapter->rx_ring[0].count *
sizeof (struct E1000_RX_DESC);
adapter->clean_rx= E1000_clean_rx_irq;
Adapter->alloc_rx_buf= e1000_alloc_rx_buffers;
}
is normally called E1000_clean_rx_irq ()
E1000_CLEAN_RX_IRQ ()
skb= Buffer_info->skb;
buffer_info->skb= null;<