}
 
 /**
- * i40e_max_xdp_frame_size - returns the maximum allowed frame size for XDP
+ * i40e_calculate_vsi_rx_buf_len - Calculates buffer length
+ *
+ * @vsi: VSI to calculate rx_buf_len from
+ */
+static u16 i40e_calculate_vsi_rx_buf_len(struct i40e_vsi *vsi)
+{
+       if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX))
+               return I40E_RXBUFFER_2048;
+
+       return PAGE_SIZE < 8192 ? I40E_RXBUFFER_3072 : I40E_RXBUFFER_2048;
+}
+
+/**
+ * i40e_max_vsi_frame_size - returns the maximum allowed frame size for VSI
  * @vsi: the vsi
+ * @xdp_prog: XDP program
  **/
-static int i40e_max_xdp_frame_size(struct i40e_vsi *vsi)
+static int i40e_max_vsi_frame_size(struct i40e_vsi *vsi,
+                                  struct bpf_prog *xdp_prog)
 {
-       if (PAGE_SIZE >= 8192 || (vsi->back->flags & I40E_FLAG_LEGACY_RX))
-               return I40E_RXBUFFER_2048;
+       u16 rx_buf_len = i40e_calculate_vsi_rx_buf_len(vsi);
+       u16 chain_len;
+
+       if (xdp_prog)
+               chain_len = 1;
        else
-               return I40E_RXBUFFER_3072;
+               chain_len = I40E_MAX_CHAINED_RX_BUFFERS;
+
+       return min_t(u16, rx_buf_len * chain_len, I40E_MAX_RXBUFFER);
 }
 
 /**
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
+       int frame_size;
 
-       if (i40e_enabled_xdp_vsi(vsi)) {
-               int frame_size = new_mtu + I40E_PACKET_HDR_PAD;
-
-               if (frame_size > i40e_max_xdp_frame_size(vsi))
-                       return -EINVAL;
+       frame_size = i40e_max_vsi_frame_size(vsi, vsi->xdp_prog);
+       if (new_mtu > frame_size - I40E_PACKET_HDR_PAD) {
+               netdev_err(netdev, "Error changing mtu to %d, Max is %d\n",
+                          new_mtu, frame_size - I40E_PACKET_HDR_PAD);
+               return -EINVAL;
        }
 
        netdev_dbg(netdev, "changing MTU from %d to %d\n",
        return err;
 }
 
-/**
- * i40e_calculate_vsi_rx_buf_len - Calculates buffer length
- *
- * @vsi: VSI to calculate rx_buf_len from
- */
-static u16 i40e_calculate_vsi_rx_buf_len(struct i40e_vsi *vsi)
-{
-       if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX))
-               return I40E_RXBUFFER_2048;
-
-#if (PAGE_SIZE < 8192)
-       if (!I40E_2K_TOO_SMALL_WITH_PADDING && vsi->netdev->mtu <= ETH_DATA_LEN)
-               return I40E_RXBUFFER_1536 - NET_IP_ALIGN;
-#endif
-
-       return PAGE_SIZE < 8192 ? I40E_RXBUFFER_3072 : I40E_RXBUFFER_2048;
-}
-
 /**
  * i40e_vsi_configure_rx - Configure the VSI for Rx
  * @vsi: the VSI being configured
        int err = 0;
        u16 i;
 
-       vsi->max_frame = I40E_MAX_RXBUFFER;
+       vsi->max_frame = i40e_max_vsi_frame_size(vsi, vsi->xdp_prog);
        vsi->rx_buf_len = i40e_calculate_vsi_rx_buf_len(vsi);
 
 #if (PAGE_SIZE < 8192)
        if (vsi->netdev && !I40E_2K_TOO_SMALL_WITH_PADDING &&
-           vsi->netdev->mtu <= ETH_DATA_LEN)
-               vsi->max_frame = I40E_RXBUFFER_1536 - NET_IP_ALIGN;
+           vsi->netdev->mtu <= ETH_DATA_LEN) {
+               vsi->rx_buf_len = I40E_RXBUFFER_1536 - NET_IP_ALIGN;
+               vsi->max_frame = vsi->rx_buf_len;
+       }
 #endif
 
        /* set up individual rings */
 static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog,
                          struct netlink_ext_ack *extack)
 {
-       int frame_size = vsi->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+       int frame_size = i40e_max_vsi_frame_size(vsi, prog);
        struct i40e_pf *pf = vsi->back;
        struct bpf_prog *old_prog;
        bool need_reset;
        int i;
 
        /* Don't allow frames that span over multiple buffers */
-       if (frame_size > i40e_calculate_vsi_rx_buf_len(vsi)) {
+       if (vsi->netdev->mtu > frame_size - I40E_PACKET_HDR_PAD) {
                NL_SET_ERR_MSG_MOD(extack, "MTU too large to enable XDP");
                return -EINVAL;
        }