E1000网卡:
1.e1000_hw.h
#define E1000_IMS 0x000D0
/* Interrupt Mask Set - RW */
#define E1000_IMC 0x000D8
/* Interrupt Mask Clear - WO */
2.
e1000_request_irq()
static int e1000_request_irq(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
irq_handler_t handler = e1000_intr;
int irq_flags = IRQF_SHARED;
int err;
//adapter->pdev->irq = 13
err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,netdev);
if (err) {
e_err(probe, "Unable to allocate interrupt Error: %d\n", err);
}
return err;
}
3.
e1000_intr()
/**
* e1000_intr - Interrupt Handler
* @irq: interrupt number
* @data: pointer to a network interface device structure
**/
static irqreturn_t e1000_intr(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 icr = er32(ICR);
if (unlikely((!icr)))
return IRQ_NONE;
/* Not our interrupt */
/* we might have caused the interrupt, but the above
* read cleared it, and just in case the driver is
* down there is nothing to do so return handled
*/
if (unlikely(test_bit(__E1000_DOWN, &adapter->flags)))
return IRQ_HANDLED;
if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
hw->get_link_status = 1;
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->flags))
schedule_delayed_work(&adapter->watchdog_task, 1);
}
/* disable interrupts, without the synchronize_irq bit */
ew32(IMC, ~0);
E1000_WRITE_FLUSH();
if (likely(napi_schedule_prep(&adapter->napi))) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
//netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
//void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
// int (*poll)(struct napi_struct *, int), int weight)
__napi_schedule(&adapter->napi);
} else {
/* this really should not happen! if it does it is basically a
* bug, but not a hard error, so enable ints and continue
*/
if (!test_bit(__E1000_DOWN, &adapter->flags))
e1000_irq_enable(adapter);
}
return IRQ_HANDLED;
}
4.
e1000_clean()
/**
* e1000_clean - NAPI Rx polling callback
* @adapter: board private structure
**/
static int e1000_clean(struct napi_struct *napi,
int budget)
{
struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter,
napi);
int tx_clean_complete = 0, work_done = 0;
tx_clean_complete = e1000_clean_tx_irq(adapter, &adapter->tx_ring[0]);
//adapter->clean_rx = e1000_clean_rx_irq;
adapter->clean_rx(adapter, &adapter->rx_ring[0], &work_done,
budget);
if (!tx_clean_complete)
work_done = budget;
/* If budget not fully consumed, exit the polling mode */
if (work_done < budget) {
if (likely(adapter->itr_setting & 3))
e1000_set_itr(adapter);
napi_complete(napi);
if (!test_bit(__E1000_DOWN, &adapter->flags))
e1000_irq_enable(adapter);
}
return work_done;
}
4.
e1000_clean_rx_irq()
/**
* e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure
* @rx_ring: ring to clean
* @work_done: amount of napi work completed this call
* @work_to_do: max amount of work allowed for this call to do
*/
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done,
int work_to_do)
{
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc, *next_rxd;
struct e1000_buffer *buffer_info, *next_buffer;
unsigned long flags;
u32 length;
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
unsigned int total_rx_bytes=0, total_rx_packets=0;
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
//DMA ring,还没搞得太懂 =-=
while (rx_desc->status & E1000_RXD_STAT_DD) {
struct sk_buff *skb;
u8 status;
if (*work_done >= work_to_do)
break;
(*work_done)++;
......
e1000_receive_skb(adapter, status, rx_desc->special, skb);
}
......
return cleaned;
}
5.
e1000_irq_disable()
/**
* e1000_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
**/
static void e1000_irq_disable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
ew32(IMC, ~0);
E1000_WRITE_FLUSH();
synchronize_irq(adapter->pdev->irq);
}
6.
e1000_irq_enable()
/**
* e1000_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
**/
static void e1000_irq_enable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
ew32(IMS, IMS_ENABLE_MASK);
E1000_WRITE_FLUSH();
}
7.
e1000_netpoll() //没搞懂这个干嘛的=-=
#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
* the interrupt routine is executing.
*/
static void e1000_netpoll(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev);
enable_irq(adapter->pdev->irq);
}
#endif
----------------------------------------------------------------------------
使用 NAPI 先决条件:
驱动可以继续使用老的 2.4
内核的网络驱动程序接口,NAPI
的加入并不会导致向前兼容性的丧失,但是
NAPI 的使用至少要得到下面的保证:
A. 要使用
DMA 的环形输入队列(也就是
ring_dma,这个在
2.4 驱动中关于
Ethernet 的部分有详细的介绍),或者是有足够的内存空间缓存驱动获得的包。
B. 在发送/接收数据包产生中断的时候有能力关断
NIC 中断的事件处理,并且在关断
NIC 以后,并不影响数据包接收到网络设备的环形缓冲区(以下简称
rx-ring)处理队列中。
----------------------------------------------------------------------------
以太网数据在 TSEC<-->DDR
PCI_Controller<-->DDR 之间的流动,CPU的core是不需要介入的只有在数据流动结束时(接收完、发送完),DMA
Engine才会以外部中断的方式告诉CPU的core
----------------------------------------------------------------------------
study总结:
1.NAPI:中断到扫描(硬中断到软中断)
e1000_intr()---->e1000_clean_rx_irq()(NAPI:net_rx_action()-->work =
n->poll(n, weight);)
----------------------------------------------------------------------------
from:
http://blog.chinaunix.net/uid-23366077-id-4767542.html
二、NAPI方法
NAPI的特点是进一次中断,可以处理多个包,所以设备要想使用NAPI,必须满足两个条件:
(1)设备必须能够保留多个RX分组,例如RX DMA环形缓冲区。
(2)设备必须能够禁用用于分组接受的IRQ。