diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index d65950d7f06b..0d8ed002adcb 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -135,8 +135,7 @@ static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv, 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; @@ -178,8 +177,7 @@ static struct sk_buff *build_frag_skb(struct dpaa2_eth_priv *priv, 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 @@ -573,10 +571,10 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) 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; @@ -1792,23 +1790,9 @@ static int set_buffer_layout(struct dpaa2_eth_priv *priv) 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, @@ -1827,6 +1811,36 @@ static int set_buffer_layout(struct dpaa2_eth_priv *priv) 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; } @@ -1868,19 +1882,6 @@ static int setup_dpni(struct fsl_mc_device *ls_dev) 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; @@ -2272,6 +2273,7 @@ static int netdev_init(struct net_device *net_dev) { 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; @@ -2293,7 +2295,20 @@ static int netdev_init(struct net_device *net_dev) /* 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; diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index 749bd6be39c1..5b3ab9f62d5e 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -82,14 +82,15 @@ */ #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 @@ -133,7 +134,7 @@ struct dpaa2_eth_swa { 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 @@ -353,15 +354,27 @@ struct dpaa2_eth_priv { 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)