[PATCH 5/5] staging: fsl-dpaa2/eth: Extra headroom in RX buffers

From: Bogdan Purcareata
Date: Fri Oct 27 2017 - 10:12:30 EST


The needed headroom that we ask the stack to reserve for us in TX
skbs is larger than the headroom available in RX frames, which
leads to skb reallocations in forwarding scenarios involving two
DPNI interfaces.

Configure the hardware to reserve some extra space in the RX
frame headroom to avoid this situation. The value is chosen based
on the Tx frame data offset, the Rx buffer alignment value and the
netdevice required headroom.

The network stack will take care to reserve space for HH_DATA_MOD when
building the skb, so there's no need to account for it in the netdevice
needed headroom.

Signed-off-by: Bogdan Purcareata <bogdan.purcareata@xxxxxxx>
Signed-off-by: Ioana Radulescu <ruxandra.radulescu@xxxxxxx>
---
drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 79 +++++++++++++++-----------
drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h | 32 +++++++----
2 files changed, 67 insertions(+), 44 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
index 29b4928..636beac 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
@@ -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;
@@ -2295,6 +2297,19 @@ static int netdev_init(struct net_device *net_dev)
*/
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;
net_dev->max_mtu = DPAA2_ETH_MAX_MTU;
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
index 374a99a..234d612 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
@@ -82,10 +82,7 @@
*/
#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
/* 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
@@ -94,16 +91,20 @@
#define DPAA2_ETH_RX_BUF_ALIGN 64

#define DPAA2_ETH_NEEDED_HEADROOM(p_priv) \
- ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN)
+ ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN - HH_DATA_MOD)

-/* 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
*/
+#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)))
#define DPAA2_ETH_BUF_RAW_SIZE(priv) \
- (DPAA2_ETH_RX_BUF_SIZE + \
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + \
- (priv)->rx_buf_align)
+ (DPAA2_ETH_SKB_SIZE + (priv)->rx_buf_align)
+
+/* Hardware annotation area in RX buffers */
+#define DPAA2_ETH_RX_HWA_SIZE 64

/* We are accommodating a skb backpointer and some S/G info
* in the frame's software annotation. The hardware
@@ -111,6 +112,13 @@
*/
#define DPAA2_ETH_SWA_SIZE 64

+/* Extra headroom space requested to hardware, in order to make sure there's
+ * no realloc'ing in forwarding scenarios
+ */
+#define DPAA2_ETH_RX_HEAD_ROOM(priv) \
+ (DPAA2_ETH_NEEDED_HEADROOM(priv) - \
+ DPAA2_ETH_RX_HWA_SIZE)
+
/* Must keep this struct smaller than DPAA2_ETH_SWA_SIZE */
struct dpaa2_eth_swa {
struct sk_buff *skb;
@@ -141,7 +149,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

--
2.7.4