ch->buf_count--;
 
-       skb = build_skb(fd_vaddr, DPAA2_ETH_RX_BUF_SIZE +
-                       SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+       skb = build_skb(fd_vaddr, DPAA2_ETH_SKB_SIZE);
        if (unlikely(!skb))
                return NULL;
 
 
                if (i == 0) {
                        /* We build the skb around the first data buffer */
-                       skb = build_skb(sg_vaddr, DPAA2_ETH_RX_BUF_SIZE +
-                               SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+                       skb = build_skb(sg_vaddr, DPAA2_ETH_SKB_SIZE);
                        if (unlikely(!skb)) {
                                /* Free the first SG entry now, since we already
                                 * unmapped it and obtained the virtual address
        percpu_stats = this_cpu_ptr(priv->percpu_stats);
        percpu_extras = this_cpu_ptr(priv->percpu_extras);
 
-       if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) {
+       if (unlikely(skb_headroom(skb) < dpaa2_eth_needed_headroom(priv))) {
                struct sk_buff *ns;
 
-               ns = skb_realloc_headroom(skb, DPAA2_ETH_NEEDED_HEADROOM(priv));
+               ns = skb_realloc_headroom(skb, dpaa2_eth_needed_headroom(priv));
                if (unlikely(!ns)) {
                        percpu_stats->tx_dropped++;
                        goto err_alloc_headroom;
        else
                priv->rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN;
 
-       /* rx buffer */
-       buf_layout.pass_parser_result = true;
+       /* tx buffer */
        buf_layout.pass_frame_status = true;
        buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE;
-       buf_layout.data_align = priv->rx_buf_align;
-       buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
-                            DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
-                            DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE |
-                            DPNI_BUF_LAYOUT_OPT_DATA_ALIGN;
-       err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token,
-                                    DPNI_QUEUE_RX, &buf_layout);
-       if (err) {
-               dev_err(dev, "dpni_set_buffer_layout(RX) failed\n");
-               return err;
-       }
-
-       /* tx buffer */
        buf_layout.options = DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
                             DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
        err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token,
                return err;
        }
 
+       /* Now that we've set our tx buffer layout, retrieve the minimum
+        * required tx data offset.
+        */
+       err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token,
+                                     &priv->tx_data_offset);
+       if (err) {
+               dev_err(dev, "dpni_get_tx_data_offset() failed\n");
+               return err;
+       }
+
+       if ((priv->tx_data_offset % 64) != 0)
+               dev_warn(dev, "Tx data offset (%d) not a multiple of 64B\n",
+                        priv->tx_data_offset);
+
+       /* rx buffer */
+       buf_layout.pass_parser_result = true;
+       buf_layout.data_align = priv->rx_buf_align;
+       buf_layout.data_head_room = dpaa2_eth_rx_head_room(priv);
+       buf_layout.private_data_size = 0;
+       buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
+                            DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
+                            DPNI_BUF_LAYOUT_OPT_DATA_ALIGN |
+                            DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM;
+       err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token,
+                                    DPNI_QUEUE_RX, &buf_layout);
+       if (err) {
+               dev_err(dev, "dpni_set_buffer_layout(RX) failed\n");
+               return err;
+       }
+
        return 0;
 }
 
        if (err)
                goto close;
 
-       /* Now that we've set our tx buffer layout, retrieve the minimum
-        * required tx data offset.
-        */
-       err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token,
-                                     &priv->tx_data_offset);
-       if (err) {
-               dev_err(dev, "dpni_get_tx_data_offset() failed\n");
-               goto close;
-       }
-
-       if ((priv->tx_data_offset % 64) != 0)
-               dev_warn(dev, "Tx data offset (%d) not a multiple of 64B\n",
-                        priv->tx_data_offset);
 
        return 0;
 
 {
        struct device *dev = net_dev->dev.parent;
        struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+       u16 rx_headroom, req_headroom;
        u8 bcast_addr[ETH_ALEN];
        u8 num_queues;
        int err;
        /* Reserve enough space to align buffer as per hardware requirement;
         * NOTE: priv->tx_data_offset MUST be initialized at this point.
         */
-       net_dev->needed_headroom = DPAA2_ETH_NEEDED_HEADROOM(priv);
+       net_dev->needed_headroom = dpaa2_eth_needed_headroom(priv);
+
+       /* If headroom guaranteed by hardware in the Rx frame buffer is
+        * smaller than the Tx headroom required by the stack, issue a
+        * one time warning. This will most likely mean skbs forwarded to
+        * another DPAA2 network interface will get reallocated, with a
+        * significant performance impact.
+        */
+       req_headroom = LL_RESERVED_SPACE(net_dev) - ETH_HLEN;
+       rx_headroom = ALIGN(DPAA2_ETH_RX_HWA_SIZE +
+                           dpaa2_eth_rx_head_room(priv), priv->rx_buf_align);
+       if (req_headroom > rx_headroom)
+               dev_info_once(dev, "Required headroom (%d) greater than available (%d)\n",
+                             req_headroom, rx_headroom);
 
        /* Set MTU limits */
        net_dev->min_mtu = 68;
 
  */
 #define DPAA2_ETH_BUFS_PER_CMD         7
 
-/* Hardware requires alignment for ingress/egress buffer addresses
- * and ingress buffer lengths.
- */
-#define DPAA2_ETH_RX_BUF_SIZE          2048
+/* Hardware requires alignment for ingress/egress buffer addresses */
 #define DPAA2_ETH_TX_BUF_ALIGN         64
 
-#define DPAA2_ETH_NEEDED_HEADROOM(p_priv) \
-       ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN)
+#define DPAA2_ETH_RX_BUF_SIZE          2048
+#define DPAA2_ETH_SKB_SIZE \
+       (DPAA2_ETH_RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
+/* Hardware annotation area in RX  buffers */
+#define DPAA2_ETH_RX_HWA_SIZE          64
 
 /* Due to a limitation in WRIOP 1.0.0, the RX buffer data must be aligned
  * to 256B. For newer revisions, the requirement is only for 64B alignment
                                         DPAA2_FD_CTRL_FAERR)
 
 /* Annotation bits in FD CTRL */
-#define DPAA2_FD_CTRL_ASAL             0x00020000      /* ASAL = 128 */
+#define DPAA2_FD_CTRL_ASAL             0x00010000      /* ASAL = 64 */
 #define DPAA2_FD_CTRL_PTA              0x00800000
 #define DPAA2_FD_CTRL_PTV1             0x00400000
 
 extern const struct ethtool_ops dpaa2_ethtool_ops;
 extern const char dpaa2_eth_drv_version[];
 
-/* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but we need to allocate ingress
- * buffers large enough to allow building an skb around them and also account
- * for alignment restrictions
+/* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around
+ * the buffer also needs space for its shared info struct, and we need
+ * to allocate enough to accommodate hardware alignment restrictions
  */
 static inline unsigned int dpaa2_eth_buf_raw_size(struct dpaa2_eth_priv *priv)
 {
-       return DPAA2_ETH_RX_BUF_SIZE +
-              SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
-              priv->rx_buf_align;
+       return DPAA2_ETH_SKB_SIZE + priv->rx_buf_align;
+}
+
+static inline
+unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv)
+{
+       return priv->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN - HH_DATA_MOD;
+}
+
+/* Extra headroom space requested to hardware, in order to make sure there's
+ * no realloc'ing in forwarding scenarios
+ */
+static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv)
+{
+       return dpaa2_eth_needed_headroom(priv) - DPAA2_ETH_RX_HWA_SIZE;
 }
 
 static int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv)