[PATCH] skge: check length from PHY
authorStephen Hemminger <shemminger@osdl.org>
Mon, 19 Sep 2005 22:37:16 +0000 (15:37 -0700)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 22 Sep 2005 02:32:50 +0000 (22:32 -0400)
Cleanup receive buffer allocation and management,
Add more error handling checks from PHY and bump version.
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
drivers/net/skge.c
drivers/net/skge.h

index 62e2ae0eb8581364ed7dd906a9bf45bad452b982..ae1996a3bc5cc8868d2baae7644a5ffcc1d9da3e 100644 (file)
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "1.0"
+#define DRV_VERSION            "1.1"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
@@ -762,17 +762,6 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
        return 0;
 }
 
-static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
-{
-       struct sk_buff *skb = dev_alloc_skb(size);
-
-       if (likely(skb)) {
-               skb->dev = dev;
-               skb_reserve(skb, NET_IP_ALIGN);
-       }
-       return skb;
-}
-
 /* Allocate and setup a new buffer for receiving */
 static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
                          struct sk_buff *skb, unsigned int bufsize)
@@ -845,16 +834,17 @@ static int skge_rx_fill(struct skge_port *skge)
 {
        struct skge_ring *ring = &skge->rx_ring;
        struct skge_element *e;
-       unsigned int bufsize = skge->rx_buf_size;
 
        e = ring->start;
        do {
-               struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
+               struct sk_buff *skb;
 
+               skb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN);
                if (!skb)
                        return -ENOMEM;
 
-               skge_rx_setup(skge, e, skb, bufsize);
+               skb_reserve(skb, NET_IP_ALIGN);
+               skge_rx_setup(skge, e, skb, skge->rx_buf_size);
        } while ( (e = e->next) != ring->start);
 
        ring->to_clean = ring->start;
@@ -2429,6 +2419,14 @@ static void yukon_set_multicast(struct net_device *dev)
        gma_write16(hw, port, GM_RX_CTRL, reg);
 }
 
+static inline u16 phy_length(const struct skge_hw *hw, u32 status)
+{
+       if (hw->chip_id == CHIP_ID_GENESIS)
+               return status >> XMR_FS_LEN_SHIFT;
+       else
+               return status >> GMR_FS_LEN_SHIFT;
+}
+
 static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
 {
        if (hw->chip_id == CHIP_ID_GENESIS)
@@ -2438,80 +2436,99 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
                        (status & GMR_FS_RX_OK) == 0;
 }
 
-static void skge_rx_error(struct skge_port *skge, int slot,
-                         u32 control, u32 status)
-{
-       if (netif_msg_rx_err(skge))
-               printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
-                      skge->netdev->name, slot, control, status);
-
-       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
-               skge->net_stats.rx_length_errors++;
-       else if (skge->hw->chip_id == CHIP_ID_GENESIS) {
-               if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
-                       skge->net_stats.rx_length_errors++;
-               if (status & XMR_FS_FRA_ERR)
-                       skge->net_stats.rx_frame_errors++;
-               if (status & XMR_FS_FCS_ERR)
-                       skge->net_stats.rx_crc_errors++;
-       } else {
-               if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
-                       skge->net_stats.rx_length_errors++;
-               if (status & GMR_FS_FRAGMENT)
-                       skge->net_stats.rx_frame_errors++;
-               if (status & GMR_FS_CRC_ERR)
-                       skge->net_stats.rx_crc_errors++;
-       }
-}
 
 /* Get receive buffer from descriptor.
  * Handles copy of small buffers and reallocation failures
  */
 static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
                                          struct skge_element *e,
-                                         unsigned int len)
+                                         u32 control, u32 status, u16 csum)
 {
-       struct sk_buff *nskb, *skb;
+       struct sk_buff *skb;
+       u16 len = control & BMU_BBC;
+
+       if (unlikely(netif_msg_rx_status(skge)))
+               printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
+                      skge->netdev->name, e - skge->rx_ring.start,
+                      status, len);
+
+       if (len > skge->rx_buf_size)
+               goto error;
+
+       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
+               goto error;
+
+       if (bad_phy_status(skge->hw, status))
+               goto error;
+
+       if (phy_length(skge->hw, status) != len)
+               goto error;
 
        if (len < RX_COPY_THRESHOLD) {
-               nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
-               if (unlikely(!nskb))
-                       return NULL;
+               skb = dev_alloc_skb(len + 2);
+               if (!skb)
+                       goto resubmit;
 
+               skb_reserve(skb, 2);
                pci_dma_sync_single_for_cpu(skge->hw->pdev,
                                            pci_unmap_addr(e, mapaddr),
                                            len, PCI_DMA_FROMDEVICE);
-               memcpy(nskb->data, e->skb->data, len);
+               memcpy(skb->data, e->skb->data, len);
                pci_dma_sync_single_for_device(skge->hw->pdev,
                                               pci_unmap_addr(e, mapaddr),
                                               len, PCI_DMA_FROMDEVICE);
-
-               if (skge->rx_csum) {
-                       struct skge_rx_desc *rd = e->desc;
-                       nskb->csum = le16_to_cpu(rd->csum2);
-                       nskb->ip_summed = CHECKSUM_HW;
-               }
                skge_rx_reuse(e, skge->rx_buf_size);
-               return nskb;
        } else {
-               nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size);
-               if (unlikely(!nskb))
-                       return NULL;
+               struct sk_buff *nskb;
+               nskb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN);
+               if (!nskb)
+                       goto resubmit;
 
                pci_unmap_single(skge->hw->pdev,
                                 pci_unmap_addr(e, mapaddr),
                                 pci_unmap_len(e, maplen),
                                 PCI_DMA_FROMDEVICE);
                skb = e->skb;
-               if (skge->rx_csum) {
-                       struct skge_rx_desc *rd = e->desc;
-                       skb->csum = le16_to_cpu(rd->csum2);
-                       skb->ip_summed = CHECKSUM_HW;
-               }
-
+               prefetch(skb->data);
                skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
-               return skb;
        }
+
+       skb_put(skb, len);
+       skb->dev = skge->netdev;
+       if (skge->rx_csum) {
+               skb->csum = csum;
+               skb->ip_summed = CHECKSUM_HW;
+       }
+
+       skb->protocol = eth_type_trans(skb, skge->netdev);
+
+       return skb;
+error:
+
+       if (netif_msg_rx_err(skge))
+               printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n",
+                      skge->netdev->name, e - skge->rx_ring.start,
+                      control, status);
+
+       if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+               if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+                       skge->net_stats.rx_length_errors++;
+               if (status & XMR_FS_FRA_ERR)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & XMR_FS_FCS_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       } else {
+               if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+                       skge->net_stats.rx_length_errors++;
+               if (status & GMR_FS_FRAGMENT)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & GMR_FS_CRC_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       }
+
+resubmit:
+       skge_rx_reuse(e, skge->rx_buf_size);
+       return NULL;
 }
 
 
@@ -2527,32 +2544,16 @@ static int skge_poll(struct net_device *dev, int *budget)
        for (e = ring->to_clean; work_done < to_do; e = e->next) {
                struct skge_rx_desc *rd = e->desc;
                struct sk_buff *skb;
-               u32 control, len, status;
+               u32 control;
 
                rmb();
                control = rd->control;
                if (control & BMU_OWN)
                        break;
 
-               len = control & BMU_BBC;
-               status = rd->status;
-
-               if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
-                            || bad_phy_status(hw, status))) {
-                       skge_rx_error(skge, e - ring->start, control, status);
-                       skge_rx_reuse(e, skge->rx_buf_size);
-                       continue;
-               }
-
-               if (netif_msg_rx_status(skge))
-                   printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
-                          dev->name, e - ring->start, rd->status, len);
-
-               skb = skge_rx_get(skge, e, len);
+               skb = skge_rx_get(skge, e, control, rd->status,
+                                 le16_to_cpu(rd->csum2));
                if (likely(skb)) {
-                       skb_put(skb, len);
-                       skb->protocol = eth_type_trans(skb, dev);
-
                        dev->last_rx = jiffies;
                        netif_receive_skb(skb);
 
index efbf98c675d2d5823acaf26fc9021e9de551b3f4..72c175b87a5a26d8aeb15bfb286712cebb5ef364 100644 (file)
@@ -953,6 +953,7 @@ enum {
  */
 enum {
        XMR_FS_LEN      = 0x3fff<<18,   /* Bit 31..18:  Rx Frame Length */
+       XMR_FS_LEN_SHIFT = 18,
        XMR_FS_2L_VLAN  = 1<<17, /* Bit 17:     tagged wh 2Lev VLAN ID*/
        XMR_FS_1_VLAN   = 1<<16, /* Bit 16:     tagged wh 1ev VLAN ID*/
        XMR_FS_BC       = 1<<15, /* Bit 15:     Broadcast Frame */
@@ -1868,6 +1869,7 @@ enum {
 /* Receive Frame Status Encoding */
 enum {
        GMR_FS_LEN      = 0xffff<<16, /* Bit 31..16:    Rx Frame Length */
+       GMR_FS_LEN_SHIFT = 16,
        GMR_FS_VLAN     = 1<<13, /* Bit 13:     VLAN Packet */
        GMR_FS_JABBER   = 1<<12, /* Bit 12:     Jabber Packet */
        GMR_FS_UN_SIZE  = 1<<11, /* Bit 11:     Undersize Packet */