为什么使用 cpu_to_le32 作为 DMA 地址而不是长度? (在书中的示例代码中)
why use cpu_to_le32 for the DMA address but not for length? (in an example code in a book)
我正在阅读 Essential Linux Device Driver 一书(作者 Sreekrishnan Venkateswaran)和第 10 章 清单 10.5。设置 DMA 描述符和缓冲区,我明白了
/* Device-specific data structure for the Ethernet Function */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the receive descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the receive descriptor */
void *dma_buffer_tx; /* Kernel virtual address of the transmit descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit descriptor */
/* ... */
spin_lock_t device_lock; /* Serialize */
} *mydev_data;
/* On-card registers related to DMA */
#define DMA_RX_REGISTER_OFFSET 0x0 /* Offset of the register holding the bus address of the RX descriptor */
#define DMA_TX_REGISTER_OFFSET 0x4 /* Offset of the register holding the bus address of the TX descriptor */
#define CONTROL_REGISTER 0x8 /* Offset of the control register */
/* Control Register Defines */
#define INITIATE_XMIT 0x1
/* Descriptor control word definitions */
#define FREE_FLAG 0x1 /* Free Descriptor */
#define INTERRUPT_FLAG 0x2 /* Assert interrupt after DMA */
/* Invoked from Listing 10.3 */
static void dma_descriptor_setup(struct pci_dev *pdev)
{
/* Allocate receive DMA descriptors and buffers */
mydev_data->dma_buffer_rx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_rx);
/* Fill the two receive descriptors as shown in Figure 10.2 */
/* RX descriptor 1 */
mydev_data->dma_buffer_rx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 24)); /* Buffer address */
mydev_data->dma_buffer_rx[1] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[2] = FREE_FLAG; /* Descriptor is free */
/* RX descriptor 2 */
mydev_data->dma_buffer_rx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 1560)); /* Buffer address */
mydev_data->dma_buffer_rx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[5] = FREE_FLAG; /* Descriptor is free */
wmb(); /* Write Memory Barrier */
/* Write the address of the receive descriptor to the appropriate register in the card. The I/O base address, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_rx), ioaddr + DMA_RX_REGISTER_OFFSET);
/* Allocate transmit DMA descriptors and buffers */
mydev_data->dma_buffer_tx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_tx);
/* Fill the two transmit descriptors as shown in Figure 10.2 */
/* TX descriptor 1 */
mydev_data->dma_buffer_tx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 24)); /* Buffer address */ <---- line A
mydev_data->dma_buffer_tx[1] = 1536; /* Buffer length */ <---- line B
/* Valid descriptor. Generate an interrupt after completing the DMA */
mydev_data->dma_buffer_tx[2] = (FREE_FLAG | INTERRUPT_FLAG);
/* TX descriptor 2 */
mydev_data->dma_buffer_tx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 1560)); /* Buffer address */
mydev_data->dma_buffer_tx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_tx[5] = (FREE_FLAG | INTERRUPT_FLAG);
wmb(); /* Write Memory Barrier */
/* Write the address of the transmit descriptor to the appropriate register in the card. The I/O base, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_tx), ioaddr + DMA_TX_REGISTER_OFFSET);
}
/* Invoked from Listing 10.3 */
static void dma_descriptor_release(struct pci_dev *pdev)
{
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_tx);
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_rx);
}
在代码中,驱动程序使用 pci_alloc_consistent()
为 DMA 描述符和 DMA 缓冲区准备缓冲区并设置它们并将缓冲区地址(总线地址)传递给硬件,确保它是小端格式使用 cpu_to_le32()
。所以我理解 H/W 看到缓冲区描述符。但是在描述符中,为什么它使用 cpu_to_le32()
作为描述符地址(上面的 A 行)而不是下面的缓冲区长度(上面的 B 行)? H/W 是否只看到缓冲区地址而不看到大小?还是书上有误?顺便说一下,这是一个虚构的 PCI 以太网芯片驱动程序。
在实践中,这种做法看起来确实是一个错误。但从理论上讲,无论如何,一个字段 (address
) 可能总是小端,而另一个 (length
) 处于本机模式。如今,在FPGA的帮助下,我想人们甚至可以尝试实现这一理论案例。
因此,在给定的上下文中,特别是考虑到您所说的这是针对 一个虚构的 PCI 以太网芯片,很难说出作者的意图是什么.
我正在阅读 Essential Linux Device Driver 一书(作者 Sreekrishnan Venkateswaran)和第 10 章 清单 10.5。设置 DMA 描述符和缓冲区,我明白了
/* Device-specific data structure for the Ethernet Function */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the receive descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the receive descriptor */
void *dma_buffer_tx; /* Kernel virtual address of the transmit descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit descriptor */
/* ... */
spin_lock_t device_lock; /* Serialize */
} *mydev_data;
/* On-card registers related to DMA */
#define DMA_RX_REGISTER_OFFSET 0x0 /* Offset of the register holding the bus address of the RX descriptor */
#define DMA_TX_REGISTER_OFFSET 0x4 /* Offset of the register holding the bus address of the TX descriptor */
#define CONTROL_REGISTER 0x8 /* Offset of the control register */
/* Control Register Defines */
#define INITIATE_XMIT 0x1
/* Descriptor control word definitions */
#define FREE_FLAG 0x1 /* Free Descriptor */
#define INTERRUPT_FLAG 0x2 /* Assert interrupt after DMA */
/* Invoked from Listing 10.3 */
static void dma_descriptor_setup(struct pci_dev *pdev)
{
/* Allocate receive DMA descriptors and buffers */
mydev_data->dma_buffer_rx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_rx);
/* Fill the two receive descriptors as shown in Figure 10.2 */
/* RX descriptor 1 */
mydev_data->dma_buffer_rx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 24)); /* Buffer address */
mydev_data->dma_buffer_rx[1] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[2] = FREE_FLAG; /* Descriptor is free */
/* RX descriptor 2 */
mydev_data->dma_buffer_rx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 1560)); /* Buffer address */
mydev_data->dma_buffer_rx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[5] = FREE_FLAG; /* Descriptor is free */
wmb(); /* Write Memory Barrier */
/* Write the address of the receive descriptor to the appropriate register in the card. The I/O base address, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_rx), ioaddr + DMA_RX_REGISTER_OFFSET);
/* Allocate transmit DMA descriptors and buffers */
mydev_data->dma_buffer_tx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_tx);
/* Fill the two transmit descriptors as shown in Figure 10.2 */
/* TX descriptor 1 */
mydev_data->dma_buffer_tx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 24)); /* Buffer address */ <---- line A
mydev_data->dma_buffer_tx[1] = 1536; /* Buffer length */ <---- line B
/* Valid descriptor. Generate an interrupt after completing the DMA */
mydev_data->dma_buffer_tx[2] = (FREE_FLAG | INTERRUPT_FLAG);
/* TX descriptor 2 */
mydev_data->dma_buffer_tx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 1560)); /* Buffer address */
mydev_data->dma_buffer_tx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_tx[5] = (FREE_FLAG | INTERRUPT_FLAG);
wmb(); /* Write Memory Barrier */
/* Write the address of the transmit descriptor to the appropriate register in the card. The I/O base, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_tx), ioaddr + DMA_TX_REGISTER_OFFSET);
}
/* Invoked from Listing 10.3 */
static void dma_descriptor_release(struct pci_dev *pdev)
{
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_tx);
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_rx);
}
在代码中,驱动程序使用 pci_alloc_consistent()
为 DMA 描述符和 DMA 缓冲区准备缓冲区并设置它们并将缓冲区地址(总线地址)传递给硬件,确保它是小端格式使用 cpu_to_le32()
。所以我理解 H/W 看到缓冲区描述符。但是在描述符中,为什么它使用 cpu_to_le32()
作为描述符地址(上面的 A 行)而不是下面的缓冲区长度(上面的 B 行)? H/W 是否只看到缓冲区地址而不看到大小?还是书上有误?顺便说一下,这是一个虚构的 PCI 以太网芯片驱动程序。
在实践中,这种做法看起来确实是一个错误。但从理论上讲,无论如何,一个字段 (address
) 可能总是小端,而另一个 (length
) 处于本机模式。如今,在FPGA的帮助下,我想人们甚至可以尝试实现这一理论案例。
因此,在给定的上下文中,特别是考虑到您所说的这是针对 一个虚构的 PCI 以太网芯片,很难说出作者的意图是什么.