ChangeSet 1.1548.1.7, 2005/02/24 00:41:00-05:00, [EMAIL PROTECTED]

        [PATCH] e1000: Checks for desc ring/rx data
        
        7 Add checks for desc ring/rx data bufs spanning 64k address boundary
        Signed-off-by: Mallikarjuna R Chilakala <[EMAIL PROTECTED]>
        Signed-off-by: Ganesh Venkatesan <[EMAIL PROTECTED]>
        Signed-off-by: John Ronciak <[EMAIL PROTECTED]>
        Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>



 e1000_main.c |  136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 133 insertions(+), 3 deletions(-)


diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c    2005-03-04 12:03:01 -08:00
+++ b/drivers/net/e1000/e1000_main.c    2005-03-04 12:03:01 -08:00
@@ -810,6 +810,31 @@
 }
 
 /**
+ * e1000_check_64k_bound - check that memory doesn't cross 64kB boundary
+ * @adapter: address of board private structure
+ * @begin: address of beginning of memory
+ * @end: address of end of memory
+ **/
+static inline boolean_t
+e1000_check_64k_bound(struct e1000_adapter *adapter,
+                     void *start, unsigned long len)
+{
+       unsigned long begin = (unsigned long) start;
+       unsigned long end = begin + len;
+
+       /* first rev 82545 and 82546 need to not allow any memory
+        * write location to cross a 64k boundary due to errata 23 */
+       if (adapter->hw.mac_type == e1000_82545 ||
+           adapter->hw.mac_type == e1000_82546 ) {
+
+               /* check buffer doesn't cross 64kB */
+               return ((begin ^ (end - 1)) >> 16) != 0 ? FALSE : TRUE;
+       }
+
+       return TRUE;
+}
+
+/**
  * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
  * @adapter: board private structure
  *
@@ -839,11 +864,42 @@
 
        txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
        if(!txdr->desc) {
+setup_tx_desc_die:
                DPRINTK(PROBE, ERR, 
                "Unable to Allocate Memory for the Transmit descriptor ring\n");
                vfree(txdr->buffer_info);
                return -ENOMEM;
        }
+
+       /* fix for errata 23, cant cross 64kB boundary */
+       if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
+               void *olddesc = txdr->desc;
+               dma_addr_t olddma = txdr->dma;
+               DPRINTK(TX_ERR,ERR,"txdr align check failed: %u bytes at %p\n",
+                       txdr->size, txdr->desc);
+               /* try again, without freeing the previous */
+               txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+               /* failed allocation, critial failure */
+               if(!txdr->desc) {
+                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+                       goto setup_tx_desc_die;
+               }
+
+               if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
+                       /* give up */
+                       pci_free_consistent(pdev, txdr->size,
+                            txdr->desc, txdr->dma);
+                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+                       DPRINTK(PROBE, ERR,
+                        "Unable to Allocate aligned Memory for the Transmit"
+                        " descriptor ring\n");
+                       vfree(txdr->buffer_info);
+                       return -ENOMEM;
+               } else {
+                       /* free old, move on with the new one since its okay */
+                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+               }
+       }
        memset(txdr->desc, 0, txdr->size);
 
        txdr->next_to_use = 0;
@@ -961,11 +1017,43 @@
        rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
        if(!rxdr->desc) {
+setup_rx_desc_die:
                DPRINTK(PROBE, ERR, 
                "Unable to Allocate Memory for the Recieve descriptor ring\n");
                vfree(rxdr->buffer_info);
                return -ENOMEM;
        }
+
+       /* fix for errata 23, cant cross 64kB boundary */
+       if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
+               void *olddesc = rxdr->desc;
+               dma_addr_t olddma = rxdr->dma;
+               DPRINTK(RX_ERR,ERR,
+                       "rxdr align check failed: %u bytes at %p\n",
+                       rxdr->size, rxdr->desc);
+               /* try again, without freeing the previous */
+               rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+               /* failed allocation, critial failure */
+               if(!rxdr->desc) {
+                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+                       goto setup_rx_desc_die;
+               }
+
+               if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
+                       /* give up */
+                       pci_free_consistent(pdev, rxdr->size,
+                            rxdr->desc, rxdr->dma);
+                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+                       DPRINTK(PROBE, ERR, 
+                               "Unable to Allocate aligned Memory for the"
+                               " Receive descriptor ring\n");
+                       vfree(rxdr->buffer_info);
+                       return -ENOMEM;
+               } else {
+                       /* free old, move on with the new one since its okay */
+                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+               }
+       }
        memset(rxdr->desc, 0, rxdr->size);
 
        rxdr->next_to_clean = 0;
@@ -2451,20 +2539,43 @@
        struct e1000_buffer *buffer_info;
        struct sk_buff *skb;
        int reserve_len = 2;
-       unsigned int i;
+       unsigned int i, bufsz;
 
        i = rx_ring->next_to_use;
        buffer_info = &rx_ring->buffer_info[i];
 
        while(!buffer_info->skb) {
+               bufsz = adapter->rx_buffer_len + reserve_len;
 
-               skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
-
+               skb = dev_alloc_skb(bufsz);
                if(unlikely(!skb)) {
                        /* Better luck next round */
                        break;
                }
 
+               /* fix for errata 23, cant cross 64kB boundary */
+               if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+                       struct sk_buff *oldskb = skb;
+                       DPRINTK(RX_ERR,ERR,
+                               "skb align check failed: %u bytes at %p\n",
+                               bufsz, skb->data);
+                       /* try again, without freeing the previous */
+                       skb = dev_alloc_skb(bufsz);
+                       if (!skb) {
+                               dev_kfree_skb(oldskb);
+                               break;
+                       }
+                       if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+                               /* give up */
+                               dev_kfree_skb(skb);
+                               dev_kfree_skb(oldskb);
+                               break; /* while !buffer_info->skb */
+                       } else {
+                               /* move on with the new one */
+                               dev_kfree_skb(oldskb);
+                       }
+               }
+
                /* Make buffer alignment 2 beyond a 16 byte boundary
                 * this will result in a 16 byte aligned IP header after
                 * the 14 byte MAC header is removed
@@ -2479,6 +2590,25 @@
                                                  skb->data,
                                                  adapter->rx_buffer_len,
                                                  PCI_DMA_FROMDEVICE);
+
+               /* fix for errata 23, cant cross 64kB boundary */
+               if(!e1000_check_64k_bound(adapter,
+                                              (void *)(unsigned 
long)buffer_info->dma,
+                                              adapter->rx_buffer_len)) {
+                       DPRINTK(RX_ERR,ERR,
+                               "dma align check failed: %u bytes at %ld\n",
+                               adapter->rx_buffer_len, (unsigned 
long)buffer_info->dma);
+
+                       dev_kfree_skb(skb);
+                       buffer_info->skb = NULL;
+
+                       pci_unmap_single(pdev,
+                                        buffer_info->dma,
+                                        adapter->rx_buffer_len,
+                                        PCI_DMA_FROMDEVICE);
+
+                       break; /* while !buffer_info->skb */
+               }
 
                rx_desc = E1000_RX_DESC(*rx_ring, i);
                rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-24" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to