麻省大学排名:e1000中DMA传输的问题

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 06:57:25
看看pci_map_single和pci_unmap_single分别是怎么实现的:
---------------------------------------------------------------------------
linux/include/asm-generic/pci-dma-compact.h
static inline dma_addr_t
pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
    return dma_map_single(hwdev == NULL ? NULL : &hwdev->dev, ptr, size, (enum dma_data_direction)direction);
}

/linux/include/asm-i386/dma-mapping.h
------------------------------------------------------------
static inline dma_addr_t
dma_map_single(struct device *dev, void *ptr, size_t size,
           enum dma_data_direction direction)
{
    BUG_ON(direction == DMA_NONE);
    flush_write_buffers();
    return virt_to_phys(ptr);
}

static inline dma_addr_t
dma_map_single(struct device *dev, void *ptr, size_t size,
           enum dma_data_direction direction)
{
    BUG_ON(direction == DMA_NONE);
    flush_write_buffers();
    return virt_to_phys(ptr);
}

static inline void
dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
         enum dma_data_direction direction)
{
    BUG_ON(direction == DMA_NONE);
}

dma_map_single返回ptr的物理地址,dma_unmap_single正好相反,执行这个之后,就可以操作DMA缓存区的 数据。
因为外设在访问内存的时候需要的是物理地址,所以driver才需要做用函数pci_map_single将虚地址转成物理地址。这段地址是由CPU和外设共享的。一般情况下CPU只做读操作,写入是由外设完成的。

现在的网卡大多数都是采用主动DMA的方式。也就是当网卡从网线上接收到数据之后,就会自己启动dma将数据从网卡内部的FIFO传送到配置寄存器指定的内存地址。当一个数据包接收完成之后,产生一个中断通知driver进行处理。整个过程不需要cpu进行干涉。当driver接收到中断的时候,数据已经在内存里存放好了。

对linux系统来说,大多数网卡driver为了提高处理效率,都会将skb->data指向这块共享内存中,这样可以减少一次内存拷贝操作。
在e1000_clean_rx_irq函数里在调用 netif_rx 之前直接访问skb->data就可以了...这就是收到的数据包。

如果真的要自己指定地址,修改 alloc_rx_buf 里面的实现代码就好了