Chinaunix首页 | 论坛 | 博客
  • 博客访问: 397666
  • 博文数量: 124
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 872
  • 用 户 组: 普通用户
  • 注册时间: 2018-03-29 14:38
个人简介

默默的一块石头

文章分类

全部博文(124)

文章存档

2022年(26)

2021年(10)

2020年(28)

2019年(60)

我的朋友

分类: LINUX

2020-02-27 10:00:03

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 之间的流动,CPUcore是不需要介入的只有在数据流动结束时(接收完、发送完),DMA Engine才会以外部中断的方式告诉CPUcore
----------------------------------------------------------------------------
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。

阅读(2365) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~