зачем использовать cpu_to_le32 для адреса DMA, а не для длины? (в примере кода в книге) - PullRequest
0 голосов
/ 08 мая 2020

Я читал книгу 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);
}

В коде драйвер подготавливает буфер для дескрипторов DMA и буферов DMA, используя pci_alloc_consistent(), устанавливает их и передает адрес буфера (адрес шины) к оборудованию, убедившись, что он в формате с прямым порядком байтов, используя cpu_to_le32(). Итак, я понял, что H / W видит дескриптор буфера. Но почему в дескрипторе используется cpu_to_le32() для адреса дескриптора (строка A выше), а не для следующей длины буфера (строка B выше)? H / W видит только адрес буфера, а не размер? Или это ошибка в книге? Кстати, это для фиктивного драйвера микросхемы PCI ethe rnet.

1 Ответ

0 голосов
/ 19 мая 2020

На практике такой подход действительно выглядит ошибкой. Но теоретически возможно, что одно поле (address) всегда имеет обратный порядок байтов, а другое (length) находится в основном режиме. В настоящее время, с помощью FPGA, я думаю, можно даже попытаться реализовать этот теоретический случай.

Итак, в данном контексте, особенно с учетом вашего замечания, что это фиктивный PCI ethe rnet чип , сложно сказать, что было задумано автором здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...