Commit c406700c authored by Jarod Wilson's avatar Jarod Wilson Committed by David S. Miller

ethernet/atheros/alx: sanitize buffer sizing and padding

This is based on the work done by Przemek Rudy in bug 70761 at
bugzilla.kernel.org, but with some work done to disentagle and clarify
things a bit.

Similar to Przemek's work and other drivers, we're adding a padding of 16
here, but we're also disentangling mtu size calculations from max buffer
size calculations a bit, and adding ETH_HLEN to the value written into
ALX_MTU. Hopefully, with a bit more consistency and clarity, things behave
better here. Sadly, I can only test in my alx-driven E2200, which worked
just fine before this patch.

In comment #58 of bug 70761, Eugene A. Shatokhin reports that this patch
does help considerably for a ROSA Linux user of his with an AR8162 network
adapter when patched into a 4.1.x-based kernel, with several days of
normal operation where wired network previously wasn't usable without
setting MTU to 9000 as a work-around.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761
CC: "Eugene A. Shatokhin" <eugene.shatokhin@rosalab.ru>
CC: Przemek Rudy <prudy1@o2.pl>
CC: Jay Cliburn <jcliburn@gmail.com>
CC: Chris Snook <chris.snook@gmail.com>
CC: netdev@vger.kernel.org
Signed-off-by: default avatarJarod Wilson <jarod@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f637941b
...@@ -958,13 +958,13 @@ void alx_configure_basic(struct alx_hw *hw) ...@@ -958,13 +958,13 @@ void alx_configure_basic(struct alx_hw *hw)
alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd); alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd);
alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt); alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt);
raw_mtu = hw->mtu + ETH_HLEN; raw_mtu = ALX_RAW_MTU(hw->mtu);
alx_write_mem32(hw, ALX_MTU, raw_mtu + 8); alx_write_mem32(hw, ALX_MTU, raw_mtu);
if (raw_mtu > ALX_MTU_JUMBO_TH) if (raw_mtu > (ALX_MTU_JUMBO_TH + ETH_FCS_LEN + VLAN_HLEN))
hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE; hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE;
if ((raw_mtu + 8) < ALX_TXQ1_JUMBO_TSO_TH) if (raw_mtu < ALX_TXQ1_JUMBO_TSO_TH)
val = (raw_mtu + 8 + 7) >> 3; val = (raw_mtu + 7) >> 3;
else else
val = ALX_TXQ1_JUMBO_TSO_TH >> 3; val = ALX_TXQ1_JUMBO_TSO_TH >> 3;
alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN); alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/mdio.h> #include <linux/mdio.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/if_vlan.h>
#include "reg.h" #include "reg.h"
/* Transmit Packet Descriptor, contains 4 32-bit words. /* Transmit Packet Descriptor, contains 4 32-bit words.
...@@ -343,12 +344,14 @@ struct alx_rrd { ...@@ -343,12 +344,14 @@ struct alx_rrd {
ALX_RSS_HASH_TYPE_IPV4_TCP | \ ALX_RSS_HASH_TYPE_IPV4_TCP | \
ALX_RSS_HASH_TYPE_IPV6 | \ ALX_RSS_HASH_TYPE_IPV6 | \
ALX_RSS_HASH_TYPE_IPV6_TCP) ALX_RSS_HASH_TYPE_IPV6_TCP)
#define ALX_DEF_RXBUF_SIZE 1536 #define ALX_FRAME_PAD 16
#define ALX_RAW_MTU(_mtu) (_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
#define ALX_MAX_FRAME_LEN(_mtu) (ALIGN((ALX_RAW_MTU(_mtu) + ALX_FRAME_PAD), 8))
#define ALX_DEF_RXBUF_SIZE ALX_MAX_FRAME_LEN(1500)
#define ALX_MAX_JUMBO_PKT_SIZE (9*1024) #define ALX_MAX_JUMBO_PKT_SIZE (9*1024)
#define ALX_MAX_TSO_PKT_SIZE (7*1024) #define ALX_MAX_TSO_PKT_SIZE (7*1024)
#define ALX_MAX_FRAME_SIZE ALX_MAX_JUMBO_PKT_SIZE #define ALX_MAX_FRAME_SIZE ALX_MAX_JUMBO_PKT_SIZE
#define ALX_MIN_FRAME_SIZE 68 #define ALX_MIN_FRAME_SIZE (ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN)
#define ALX_RAW_MTU(_mtu) (_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
#define ALX_MAX_RX_QUEUES 8 #define ALX_MAX_RX_QUEUES 8
#define ALX_MAX_TX_QUEUES 4 #define ALX_MAX_TX_QUEUES 4
......
...@@ -704,7 +704,7 @@ static int alx_init_sw(struct alx_priv *alx) ...@@ -704,7 +704,7 @@ static int alx_init_sw(struct alx_priv *alx)
hw->smb_timer = 400; hw->smb_timer = 400;
hw->mtu = alx->dev->mtu; hw->mtu = alx->dev->mtu;
alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8); alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu);
alx->tx_ringsz = 256; alx->tx_ringsz = 256;
alx->rx_ringsz = 512; alx->rx_ringsz = 512;
hw->imt = 200; hw->imt = 200;
...@@ -805,7 +805,7 @@ static void alx_reinit(struct alx_priv *alx) ...@@ -805,7 +805,7 @@ static void alx_reinit(struct alx_priv *alx)
static int alx_change_mtu(struct net_device *netdev, int mtu) static int alx_change_mtu(struct net_device *netdev, int mtu)
{ {
struct alx_priv *alx = netdev_priv(netdev); struct alx_priv *alx = netdev_priv(netdev);
int max_frame = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; int max_frame = ALX_MAX_FRAME_LEN(mtu);
if ((max_frame < ALX_MIN_FRAME_SIZE) || if ((max_frame < ALX_MIN_FRAME_SIZE) ||
(max_frame > ALX_MAX_FRAME_SIZE)) (max_frame > ALX_MAX_FRAME_SIZE))
...@@ -816,8 +816,7 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) ...@@ -816,8 +816,7 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
netdev->mtu = mtu; netdev->mtu = mtu;
alx->hw.mtu = mtu; alx->hw.mtu = mtu;
alx->rxbuf_size = mtu > ALX_DEF_RXBUF_SIZE ? alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE);
ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE;
netdev_update_features(netdev); netdev_update_features(netdev);
if (netif_running(netdev)) if (netif_running(netdev))
alx_reinit(alx); alx_reinit(alx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment