[PATCH] 2.4.0-test11 - drivers/net/epic100.c - use of DMA mapping

From: Francois ROMIEU (romieu@cogenit.fr)
Date: Sun Nov 26 2000 - 13:22:23 EST


Hello,

  the following updates the epic100.c driver to the DMA mapping api.
It compiles. It survives ping flood (small/big sizes), insmod/rmmod and seems
to work as it should on an intel machine. Big-endian testers welcome.

--- linux-2.4.0-test11.orig/drivers/net/epic100.c Sun Nov 26 11:41:47 2000
+++ linux-2.4.0-test11/drivers/net/epic100.c Sun Nov 26 13:57:01 2000
@@ -73,6 +73,8 @@
 #define TX_RING_SIZE 16
 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
 #define RX_RING_SIZE 32
+#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc)
+#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc)
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -172,8 +174,6 @@
 #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
 #endif
 
-#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-
 typedef enum {
         SMSC_83C170_0,
         SMSC_83C170,
@@ -276,14 +276,16 @@
 
 
 struct epic_private {
- /* Tx and Rx rings first so that they remain paragraph aligned. */
- struct epic_rx_desc rx_ring[RX_RING_SIZE];
- struct epic_tx_desc tx_ring[TX_RING_SIZE];
+ struct epic_rx_desc *rx_ring;
+ struct epic_tx_desc *tx_ring;
         /* The saved address of a sent-in-place packet/buffer, for skfree(). */
         struct sk_buff* tx_skbuff[TX_RING_SIZE];
         /* The addresses of receive-in-place skbuffs. */
         struct sk_buff* rx_skbuff[RX_RING_SIZE];
 
+ dma_addr_t tx_ring_dma;
+ dma_addr_t rx_ring_dma;
+
         /* Ring pointers. */
         spinlock_t lock; /* Group with Tx control cache line. */
         unsigned int cur_tx, dirty_tx;
@@ -342,6 +344,8 @@
         struct epic_chip_info *ci = &epic_chip_info[ent->driver_data];
         long ioaddr;
         int chip_idx = (int) ent->driver_data;
+ void *ring_space;
+ dma_addr_t ring_dma;
 
         card_idx++;
         
@@ -392,6 +396,21 @@
         }
 #endif
 
+ pdev->driver_data = dev;
+ ep = dev->priv;
+
+ ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+ if (!ring_space)
+ goto err_out_iounmap;
+ ep->tx_ring = (struct epic_tx_desc *)ring_space;
+ ep->tx_ring_dma = ring_dma;
+
+ ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+ if (!ring_space)
+ goto err_out_unmap_tx;
+ ep->rx_ring = (struct epic_rx_desc *)ring_space;
+ ep->rx_ring_dma = ring_dma;
+
         if (dev->mem_start) {
                 option = dev->mem_start;
                 duplex = (dev->mem_start & 16) ? 1 : 0;
@@ -402,12 +421,10 @@
                         duplex = full_duplex[card_idx];
         }
 
- pdev->driver_data = dev;
 
         dev->base_addr = ioaddr;
         dev->irq = pdev->irq;
 
- ep = dev->priv;
         ep->pci_dev = pdev;
         ep->chip_flags = ci->drv_flags;
         spin_lock_init (&ep->lock);
@@ -493,14 +510,18 @@
 
         return 0;
 
-#ifndef USE_IO_OPS
-err_out_free_mmio:
- release_mem_region (pci_resource_start (pdev, 1),
- pci_resource_len (pdev, 1));
+err_out_unmap_tx:
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+err_out_iounmap:
+#ifdef USE_IO_OPS
+ iounmap(ioaddr);
 #endif
+err_out_free_mmio:
+ release_mem_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
 err_out_free_pio:
- release_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0));
+ release_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
 err_out_free_netdev:
         unregister_netdev(dev);
         kfree(dev);
@@ -668,8 +689,8 @@
         }
 
         outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
- outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR);
- outl(virt_to_bus(ep->tx_ring), ioaddr + PTxCDAR);
+ outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
+ outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
 
         /* Start the chip's Rx process. */
         set_rx_mode(dev);
@@ -755,9 +776,10 @@
         ep->tx_threshold = TX_FIFO_THRESH;
         outl(ep->tx_threshold, ioaddr + TxThresh);
         outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
- outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR);
- outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]),
- ioaddr + PTxCDAR);
+ outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
+ sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
+ outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
+ sizeof(struct epic_tx_desc), ioaddr + PTxCDAR);
 
         /* Start the chip's Rx process. */
         set_rx_mode(dev);
@@ -852,11 +874,12 @@
         for (i = 0; i < RX_RING_SIZE; i++) {
                 ep->rx_ring[i].rxstatus = 0;
                 ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz);
- ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]);
+ ep->rx_ring[i].next = ep->rx_ring_dma +
+ (i+1)*sizeof(struct epic_rx_desc);
                 ep->rx_skbuff[i] = 0;
         }
         /* Mark the last entry as wrapping the ring. */
- ep->rx_ring[i-1].next = virt_to_le32desc(&ep->rx_ring[0]);
+ ep->rx_ring[i-1].next = ep->rx_ring_dma;
 
         /* Fill in the Rx buffers. Handle allocation failure gracefully. */
         for (i = 0; i < RX_RING_SIZE; i++) {
@@ -866,7 +889,8 @@
                         break;
                 skb->dev = dev; /* Mark as being used by this device. */
                 skb_reserve(skb, 2); /* 16 byte align the IP header. */
- ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail);
+ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
+ skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                 ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
         }
         ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -876,9 +900,10 @@
         for (i = 0; i < TX_RING_SIZE; i++) {
                 ep->tx_skbuff[i] = 0;
                 ep->tx_ring[i].txstatus = 0x0000;
- ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]);
+ ep->tx_ring[i].next = ep->tx_ring_dma +
+ (i+1)*sizeof(struct epic_tx_desc);
         }
- ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]);
+ ep->tx_ring[i-1].next = ep->tx_ring_dma;
         return;
 }
 
@@ -897,8 +922,8 @@
         entry = ep->cur_tx % TX_RING_SIZE;
 
         ep->tx_skbuff[entry] = skb;
- ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data);
-
+ ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
         if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
                 ctrl_word = cpu_to_le32(0x100000); /* No interrupt */
         } else if (free_count == TX_QUEUE_LEN/2) {
@@ -970,6 +995,7 @@
                         cur_tx = ep->cur_tx;
                         dirty_tx = ep->dirty_tx;
                         for (; cur_tx - dirty_tx > 0; dirty_tx++) {
+ struct sk_buff *skb;
                                 int entry = dirty_tx % TX_RING_SIZE;
                                 int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
 
@@ -1001,7 +1027,10 @@
                                 }
 
                                 /* Free the original skb. */
- dev_kfree_skb_irq(ep->tx_skbuff[entry]);
+ skb = ep->tx_skbuff[entry];
+ pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
                                 ep->tx_skbuff[entry] = 0;
                         }
 
@@ -1103,6 +1132,10 @@
                         short pkt_len = (status >> 16) - 4;
                         struct sk_buff *skb;
 
+ pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr,
+ ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr,
+ ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                         if (pkt_len > PKT_BUF_SZ - 4) {
                                 printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
                                            "%d bytes.\n",
@@ -1145,7 +1178,8 @@
                                 break;
                         skb->dev = dev; /* Mark as being used by this device. */
                         skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail);
+ ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
+ skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                         work_done++;
                 }
                 ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);
@@ -1157,6 +1191,7 @@
 {
         long ioaddr = dev->base_addr;
         struct epic_private *ep = (struct epic_private *)dev->priv;
+ struct sk_buff *skb;
         int i;
 
         netif_stop_queue(dev);
@@ -1171,19 +1206,25 @@
 
         /* Free all the skbuffs in the Rx queue. */
         for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = ep->rx_skbuff[i];
+ skb = ep->rx_skbuff[i];
                 ep->rx_skbuff[i] = 0;
                 ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */
                 ep->rx_ring[i].buflength = 0;
- ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
                 if (skb) {
+ pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr,
+ ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                         dev_kfree_skb(skb);
                 }
+ ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
         }
         for (i = 0; i < TX_RING_SIZE; i++) {
- if (ep->tx_skbuff[i])
- dev_kfree_skb(ep->tx_skbuff[i]);
+ skb = ep->tx_skbuff[i];
                 ep->tx_skbuff[i] = 0;
+ if (!skb)
+ continue;
+ pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
         }
 
         /* Green! Leave the chip in low-power mode. */
@@ -1319,15 +1360,18 @@
 static void __devexit epic_remove_one (struct pci_dev *pdev)
 {
         struct net_device *dev = pdev->driver_data;
+ struct epic_private *ep = dev->priv;
         
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
         unregister_netdev(dev);
 #ifndef USE_IO_OPS
- iounmap ((void*) dev->base_addr);
+ iounmap((void*) dev->base_addr);
 #endif
- release_mem_region (pci_resource_start (pdev, 1),
- pci_resource_len (pdev, 1));
- release_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0));
+ release_mem_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+ release_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
         kfree(dev);
 }
 

-- 
Ueimor
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Nov 30 2000 - 21:00:15 EST