Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: fsl-dpaa2/eth: Extra headroom in RX buffers

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@nxp.com>
Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Bogdan Purcareata and committed by
Greg Kroah-Hartman
4b2d9fe8 8a4fd877

+76 -48
+50 -35
drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
··· 135 135 136 136 ch->buf_count--; 137 137 138 - skb = build_skb(fd_vaddr, DPAA2_ETH_RX_BUF_SIZE + 139 - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); 138 + skb = build_skb(fd_vaddr, DPAA2_ETH_SKB_SIZE); 140 139 if (unlikely(!skb)) 141 140 return NULL; 142 141 ··· 177 178 178 179 if (i == 0) { 179 180 /* We build the skb around the first data buffer */ 180 - skb = build_skb(sg_vaddr, DPAA2_ETH_RX_BUF_SIZE + 181 - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); 181 + skb = build_skb(sg_vaddr, DPAA2_ETH_SKB_SIZE); 182 182 if (unlikely(!skb)) { 183 183 /* Free the first SG entry now, since we already 184 184 * unmapped it and obtained the virtual address ··· 571 573 percpu_stats = this_cpu_ptr(priv->percpu_stats); 572 574 percpu_extras = this_cpu_ptr(priv->percpu_extras); 573 575 574 - if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) { 576 + if (unlikely(skb_headroom(skb) < dpaa2_eth_needed_headroom(priv))) { 575 577 struct sk_buff *ns; 576 578 577 - ns = skb_realloc_headroom(skb, DPAA2_ETH_NEEDED_HEADROOM(priv)); 579 + ns = skb_realloc_headroom(skb, dpaa2_eth_needed_headroom(priv)); 578 580 if (unlikely(!ns)) { 579 581 percpu_stats->tx_dropped++; 580 582 goto err_alloc_headroom; ··· 1790 1792 else 1791 1793 priv->rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN; 1792 1794 1793 - /* rx buffer */ 1794 - buf_layout.pass_parser_result = true; 1795 + /* tx buffer */ 1795 1796 buf_layout.pass_frame_status = true; 1796 1797 buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE; 1797 - buf_layout.data_align = priv->rx_buf_align; 1798 - buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | 1799 - DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | 1800 - DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | 1801 - DPNI_BUF_LAYOUT_OPT_DATA_ALIGN; 1802 - err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, 1803 - DPNI_QUEUE_RX, &buf_layout); 1804 - if (err) { 1805 - dev_err(dev, "dpni_set_buffer_layout(RX) failed\n"); 1806 - return err; 1807 - } 1808 - 1809 - /* tx buffer */ 1810 1798 buf_layout.options = DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | 1811 1799 DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; 1812 1800 err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, ··· 1808 1824 DPNI_QUEUE_TX_CONFIRM, &buf_layout); 1809 1825 if (err) { 1810 1826 dev_err(dev, "dpni_set_buffer_layout(TX_CONF) failed\n"); 1827 + return err; 1828 + } 1829 + 1830 + /* Now that we've set our tx buffer layout, retrieve the minimum 1831 + * required tx data offset. 1832 + */ 1833 + err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token, 1834 + &priv->tx_data_offset); 1835 + if (err) { 1836 + dev_err(dev, "dpni_get_tx_data_offset() failed\n"); 1837 + return err; 1838 + } 1839 + 1840 + if ((priv->tx_data_offset % 64) != 0) 1841 + dev_warn(dev, "Tx data offset (%d) not a multiple of 64B\n", 1842 + priv->tx_data_offset); 1843 + 1844 + /* rx buffer */ 1845 + buf_layout.pass_parser_result = true; 1846 + buf_layout.data_align = priv->rx_buf_align; 1847 + buf_layout.data_head_room = dpaa2_eth_rx_head_room(priv); 1848 + buf_layout.private_data_size = 0; 1849 + buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | 1850 + DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | 1851 + DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | 1852 + DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM; 1853 + err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, 1854 + DPNI_QUEUE_RX, &buf_layout); 1855 + if (err) { 1856 + dev_err(dev, "dpni_set_buffer_layout(RX) failed\n"); 1811 1857 return err; 1812 1858 } 1813 1859 ··· 1882 1868 if (err) 1883 1869 goto close; 1884 1870 1885 - /* Now that we've set our tx buffer layout, retrieve the minimum 1886 - * required tx data offset. 1887 - */ 1888 - err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token, 1889 - &priv->tx_data_offset); 1890 - if (err) { 1891 - dev_err(dev, "dpni_get_tx_data_offset() failed\n"); 1892 - goto close; 1893 - } 1894 - 1895 - if ((priv->tx_data_offset % 64) != 0) 1896 - dev_warn(dev, "Tx data offset (%d) not a multiple of 64B\n", 1897 - priv->tx_data_offset); 1898 1871 1899 1872 return 0; 1900 1873 ··· 2273 2272 { 2274 2273 struct device *dev = net_dev->dev.parent; 2275 2274 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 2275 + u16 rx_headroom, req_headroom; 2276 2276 u8 bcast_addr[ETH_ALEN]; 2277 2277 u8 num_queues; 2278 2278 int err; ··· 2295 2293 /* Reserve enough space to align buffer as per hardware requirement; 2296 2294 * NOTE: priv->tx_data_offset MUST be initialized at this point. 2297 2295 */ 2298 - net_dev->needed_headroom = DPAA2_ETH_NEEDED_HEADROOM(priv); 2296 + net_dev->needed_headroom = dpaa2_eth_needed_headroom(priv); 2297 + 2298 + /* If headroom guaranteed by hardware in the Rx frame buffer is 2299 + * smaller than the Tx headroom required by the stack, issue a 2300 + * one time warning. This will most likely mean skbs forwarded to 2301 + * another DPAA2 network interface will get reallocated, with a 2302 + * significant performance impact. 2303 + */ 2304 + req_headroom = LL_RESERVED_SPACE(net_dev) - ETH_HLEN; 2305 + rx_headroom = ALIGN(DPAA2_ETH_RX_HWA_SIZE + 2306 + dpaa2_eth_rx_head_room(priv), priv->rx_buf_align); 2307 + if (req_headroom > rx_headroom) 2308 + dev_info_once(dev, "Required headroom (%d) greater than available (%d)\n", 2309 + req_headroom, rx_headroom); 2299 2310 2300 2311 /* Set MTU limits */ 2301 2312 net_dev->min_mtu = 68;
+26 -13
drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
··· 82 82 */ 83 83 #define DPAA2_ETH_BUFS_PER_CMD 7 84 84 85 - /* Hardware requires alignment for ingress/egress buffer addresses 86 - * and ingress buffer lengths. 87 - */ 88 - #define DPAA2_ETH_RX_BUF_SIZE 2048 85 + /* Hardware requires alignment for ingress/egress buffer addresses */ 89 86 #define DPAA2_ETH_TX_BUF_ALIGN 64 90 87 91 - #define DPAA2_ETH_NEEDED_HEADROOM(p_priv) \ 92 - ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN) 88 + #define DPAA2_ETH_RX_BUF_SIZE 2048 89 + #define DPAA2_ETH_SKB_SIZE \ 90 + (DPAA2_ETH_RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) 91 + 92 + /* Hardware annotation area in RX buffers */ 93 + #define DPAA2_ETH_RX_HWA_SIZE 64 93 94 94 95 /* Due to a limitation in WRIOP 1.0.0, the RX buffer data must be aligned 95 96 * to 256B. For newer revisions, the requirement is only for 64B alignment ··· 134 133 DPAA2_FD_CTRL_FAERR) 135 134 136 135 /* Annotation bits in FD CTRL */ 137 - #define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128 */ 136 + #define DPAA2_FD_CTRL_ASAL 0x00010000 /* ASAL = 64 */ 138 137 #define DPAA2_FD_CTRL_PTA 0x00800000 139 138 #define DPAA2_FD_CTRL_PTV1 0x00400000 140 139 ··· 354 353 extern const struct ethtool_ops dpaa2_ethtool_ops; 355 354 extern const char dpaa2_eth_drv_version[]; 356 355 357 - /* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but we need to allocate ingress 358 - * buffers large enough to allow building an skb around them and also account 359 - * for alignment restrictions 356 + /* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around 357 + * the buffer also needs space for its shared info struct, and we need 358 + * to allocate enough to accommodate hardware alignment restrictions 360 359 */ 361 360 static inline unsigned int dpaa2_eth_buf_raw_size(struct dpaa2_eth_priv *priv) 362 361 { 363 - return DPAA2_ETH_RX_BUF_SIZE + 364 - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + 365 - priv->rx_buf_align; 362 + return DPAA2_ETH_SKB_SIZE + priv->rx_buf_align; 363 + } 364 + 365 + static inline 366 + unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv) 367 + { 368 + return priv->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN - HH_DATA_MOD; 369 + } 370 + 371 + /* Extra headroom space requested to hardware, in order to make sure there's 372 + * no realloc'ing in forwarding scenarios 373 + */ 374 + static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv) 375 + { 376 + return dpaa2_eth_needed_headroom(priv) - DPAA2_ETH_RX_HWA_SIZE; 366 377 } 367 378 368 379 static int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv)