skb->protocol = eth_type_trans(skb, bp->dev);
                skb_checksum_none_assert(skb);
+               if (bp->dev->features & NETIF_F_RXCSUM &&
+                   !(bp->dev->flags & IFF_PROMISC) &&
+                   GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                bp->stats.rx_packets++;
                bp->stats.rx_bytes += skb->len;
        config |= MACB_BIT(BIG);                /* Receive oversized frames */
        if (bp->dev->flags & IFF_PROMISC)
                config |= MACB_BIT(CAF);        /* Copy All Frames */
+       else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM)
+               config |= GEM_BIT(RXCOEN);
        if (!(bp->dev->flags & IFF_BROADCAST))
                config |= MACB_BIT(NBC);        /* No BroadCast */
        config |= macb_dbw(bp);
 
        cfg = macb_readl(bp, NCFGR);
 
-       if (dev->flags & IFF_PROMISC)
+       if (dev->flags & IFF_PROMISC) {
                /* Enable promiscuous mode */
                cfg |= MACB_BIT(CAF);
-       else if (dev->flags & (~IFF_PROMISC))
-                /* Disable promiscuous mode */
+
+               /* Disable RX checksum offload */
+               if (macb_is_gem(bp))
+                       cfg &= ~GEM_BIT(RXCOEN);
+       } else {
+               /* Disable promiscuous mode */
                cfg &= ~MACB_BIT(CAF);
 
+               /* Enable RX checksum offload only if requested */
+               if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM)
+                       cfg |= GEM_BIT(RXCOEN);
+       }
+
        if (dev->flags & IFF_ALLMULTI) {
                /* Enable all multicast mode */
                macb_or_gem_writel(bp, HRB, -1);
                gem_writel(bp, DMACFG, dmacfg);
        }
 
+       /* RX checksum offload */
+       if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) {
+               u32 netcfg;
+
+               netcfg = gem_readl(bp, NCFGR);
+               if (features & NETIF_F_RXCSUM &&
+                   !(netdev->flags & IFF_PROMISC))
+                       netcfg |= GEM_BIT(RXCOEN);
+               else
+                       netcfg &= ~GEM_BIT(RXCOEN);
+               gem_writel(bp, NCFGR, netcfg);
+       }
+
        return 0;
 }
 
        dev->hw_features = NETIF_F_SG;
        /* Checksum offload is only available on gem with packet buffer */
        if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE))
-               dev->hw_features |= NETIF_F_HW_CSUM;
+               dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
        if (bp->caps & MACB_CAPS_SG_DISABLED)
                dev->hw_features &= ~NETIF_F_SG;
        dev->features = dev->hw_features;
 
 #define GEM_CLK_SIZE                           3
 #define GEM_DBW_OFFSET                         21
 #define GEM_DBW_SIZE                           2
+#define GEM_RXCOEN_OFFSET                      24
+#define GEM_RXCOEN_SIZE                                1
 
 /* Constants for data bus width. */
 #define GEM_DBW32                              0
 #define MACB_RX_BROADCAST_OFFSET               31
 #define MACB_RX_BROADCAST_SIZE                 1
 
+/* RX checksum offload disabled: bit 24 clear in NCFGR */
+#define GEM_RX_TYPEID_MATCH_OFFSET             22
+#define GEM_RX_TYPEID_MATCH_SIZE               2
+
+/* RX checksum offload enabled: bit 24 set in NCFGR */
+#define GEM_RX_CSUM_OFFSET                     22
+#define GEM_RX_CSUM_SIZE                       2
+
 #define MACB_TX_FRMLEN_OFFSET                  0
 #define MACB_TX_FRMLEN_SIZE                    11
 #define MACB_TX_LAST_OFFSET                    15
 #define GEM_TX_FRMLEN_OFFSET                   0
 #define GEM_TX_FRMLEN_SIZE                     14
 
+/* Buffer descriptor constants */
+#define GEM_RX_CSUM_NONE                       0
+#define GEM_RX_CSUM_IP_ONLY                    1
+#define GEM_RX_CSUM_IP_TCP                     2
+#define GEM_RX_CSUM_IP_UDP                     3
+
+/* limit RX checksum offload to TCP and UDP packets */
+#define GEM_RX_CSUM_CHECKED_MASK               2
+
 /**
  * struct macb_tx_skb - data about an skb which is being transmitted
  * @skb: skb currently being transmitted, only set for the last buffer