Commit 9a9ba2a4 authored by Doug Berger's avatar Doug Berger Committed by David S. Miller

net: bcmgenet: always enable status blocks

The hardware offloading of the NETIF_F_HW_CSUM and NETIF_F_RXCSUM
features requires the use of Transmit Status Blocks before transmit
frame data and Receive Status Blocks before receive frame data to
carry the checksum information.

Unfortunately, these status blocks are currently only enabled when
the NETIF_F_HW_CSUM feature is enabled. As a result NETIF_F_RXCSUM
will not actually be offloaded to the hardware unless both it and
NETIF_F_HW_CSUM are enabled. Fortunately, that is the default
configuration.

This commit addresses this issue by always enabling the use of
status blocks on both transmit and receive frames. Further, it
replaces the use of a dedicated flag within the driver private
data structure with direct use of the netdev features flags.

Fixes: 81015539 ("net: bcmgenet: use CHECKSUM_COMPLETE for NETIF_F_RXCSUM")
Signed-off-by: default avatarDoug Berger <opendmb@gmail.com>
Acked-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 749f6f68
...@@ -94,12 +94,6 @@ static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, ...@@ -94,12 +94,6 @@ static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,
bcmgenet_writel(value, d + DMA_DESC_LENGTH_STATUS); bcmgenet_writel(value, d + DMA_DESC_LENGTH_STATUS);
} }
static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv,
void __iomem *d)
{
return bcmgenet_readl(d + DMA_DESC_LENGTH_STATUS);
}
static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
void __iomem *d, void __iomem *d,
dma_addr_t addr) dma_addr_t addr)
...@@ -508,61 +502,6 @@ static int bcmgenet_set_link_ksettings(struct net_device *dev, ...@@ -508,61 +502,6 @@ static int bcmgenet_set_link_ksettings(struct net_device *dev,
return phy_ethtool_ksettings_set(dev->phydev, cmd); return phy_ethtool_ksettings_set(dev->phydev, cmd);
} }
static void bcmgenet_set_rx_csum(struct net_device *dev,
netdev_features_t wanted)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
u32 rbuf_chk_ctrl;
bool rx_csum_en;
rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
/* enable rx checksumming */
if (rx_csum_en)
rbuf_chk_ctrl |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS;
else
rbuf_chk_ctrl &= ~RBUF_RXCHK_EN;
priv->desc_rxchk_en = rx_csum_en;
/* If UniMAC forwards CRC, we need to skip over it to get
* a valid CHK bit to be set in the per-packet status word
*/
if (rx_csum_en && priv->crc_fwd_en)
rbuf_chk_ctrl |= RBUF_SKIP_FCS;
else
rbuf_chk_ctrl &= ~RBUF_SKIP_FCS;
bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL);
}
static void bcmgenet_set_tx_csum(struct net_device *dev,
netdev_features_t wanted)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
bool desc_64b_en;
u32 tbuf_ctrl, rbuf_ctrl;
tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv);
rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
desc_64b_en = !!(wanted & NETIF_F_HW_CSUM);
/* enable 64 bytes descriptor in both directions (RBUF and TBUF) */
if (desc_64b_en) {
tbuf_ctrl |= RBUF_64B_EN;
rbuf_ctrl |= RBUF_64B_EN;
} else {
tbuf_ctrl &= ~RBUF_64B_EN;
rbuf_ctrl &= ~RBUF_64B_EN;
}
priv->desc_64b_en = desc_64b_en;
bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl);
bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL);
}
static int bcmgenet_set_features(struct net_device *dev, static int bcmgenet_set_features(struct net_device *dev,
netdev_features_t features) netdev_features_t features)
{ {
...@@ -578,9 +517,6 @@ static int bcmgenet_set_features(struct net_device *dev, ...@@ -578,9 +517,6 @@ static int bcmgenet_set_features(struct net_device *dev,
reg = bcmgenet_umac_readl(priv, UMAC_CMD); reg = bcmgenet_umac_readl(priv, UMAC_CMD);
priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
bcmgenet_set_tx_csum(dev, features);
bcmgenet_set_rx_csum(dev, features);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
return ret; return ret;
...@@ -1475,7 +1411,7 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) ...@@ -1475,7 +1411,7 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev)
/* Reallocate the SKB to put enough headroom in front of it and insert /* Reallocate the SKB to put enough headroom in front of it and insert
* the transmit checksum offsets in the descriptors * the transmit checksum offsets in the descriptors
*/ */
static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev, static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
...@@ -1590,14 +1526,12 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1590,14 +1526,12 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
*/ */
GENET_CB(skb)->bytes_sent = skb->len; GENET_CB(skb)->bytes_sent = skb->len;
/* set the SKB transmit checksum */ /* add the Transmit Status Block */
if (priv->desc_64b_en) { skb = bcmgenet_add_tsb(dev, skb);
skb = bcmgenet_put_tx_csum(dev, skb);
if (!skb) { if (!skb) {
ret = NETDEV_TX_OK; ret = NETDEV_TX_OK;
goto out; goto out;
} }
}
for (i = 0; i <= nr_frags; i++) { for (i = 0; i <= nr_frags; i++) {
tx_cb_ptr = bcmgenet_get_txcb(priv, ring); tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
...@@ -1775,6 +1709,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, ...@@ -1775,6 +1709,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
while ((rxpktprocessed < rxpkttoprocess) && while ((rxpktprocessed < rxpkttoprocess) &&
(rxpktprocessed < budget)) { (rxpktprocessed < budget)) {
struct status_64 *status;
__be16 rx_csum;
cb = &priv->rx_cbs[ring->read_ptr]; cb = &priv->rx_cbs[ring->read_ptr];
skb = bcmgenet_rx_refill(priv, cb); skb = bcmgenet_rx_refill(priv, cb);
...@@ -1783,21 +1720,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, ...@@ -1783,21 +1720,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
goto next; goto next;
} }
if (!priv->desc_64b_en) {
dma_length_status =
dmadesc_get_length_status(priv, cb->bd_addr);
} else {
struct status_64 *status;
__be16 rx_csum;
status = (struct status_64 *)skb->data; status = (struct status_64 *)skb->data;
dma_length_status = status->length_status; dma_length_status = status->length_status;
if (dev->features & NETIF_F_RXCSUM) {
rx_csum = (__force __be16)(status->rx_csum & 0xffff); rx_csum = (__force __be16)(status->rx_csum & 0xffff);
if (priv->desc_rxchk_en) {
skb->csum = (__force __wsum)ntohs(rx_csum); skb->csum = (__force __wsum)ntohs(rx_csum);
skb->ip_summed = CHECKSUM_COMPLETE; skb->ip_summed = CHECKSUM_COMPLETE;
} }
}
/* DMA flags and length are still valid no matter how /* DMA flags and length are still valid no matter how
* we got the Receive Status Vector (64B RSB or register) * we got the Receive Status Vector (64B RSB or register)
...@@ -1840,14 +1769,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, ...@@ -1840,14 +1769,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
} /* error packet */ } /* error packet */
skb_put(skb, len); skb_put(skb, len);
if (priv->desc_64b_en) {
skb_pull(skb, 64);
len -= 64;
}
/* remove hardware 2bytes added for IP alignment */ /* remove RSB and hardware 2bytes added for IP alignment */
skb_pull(skb, 2); skb_pull(skb, 66);
len -= 2; len -= 66;
if (priv->crc_fwd_en) { if (priv->crc_fwd_en) {
skb_trim(skb, len - ETH_FCS_LEN); skb_trim(skb, len - ETH_FCS_LEN);
...@@ -2038,11 +1963,28 @@ static void init_umac(struct bcmgenet_priv *priv) ...@@ -2038,11 +1963,28 @@ static void init_umac(struct bcmgenet_priv *priv)
bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
/* init rx registers, enable ip header optimization */ /* init tx registers, enable TSB */
reg = bcmgenet_tbuf_ctrl_get(priv);
reg |= TBUF_64B_EN;
bcmgenet_tbuf_ctrl_set(priv, reg);
/* init rx registers, enable ip header optimization and RSB */
reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL); reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
reg |= RBUF_ALIGN_2B; reg |= RBUF_ALIGN_2B | RBUF_64B_EN;
bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL); bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL);
/* enable rx checksumming */
reg = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
reg |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS;
/* If UniMAC forwards CRC, we need to skip over it to get
* a valid CHK bit to be set in the per-packet status word
*/
if (priv->crc_fwd_en)
reg |= RBUF_SKIP_FCS;
else
reg &= ~RBUF_SKIP_FCS;
bcmgenet_rbuf_writel(priv, reg, RBUF_CHK_CTRL);
if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv))
bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL);
......
...@@ -273,6 +273,7 @@ struct bcmgenet_mib_counters { ...@@ -273,6 +273,7 @@ struct bcmgenet_mib_counters {
#define RBUF_FLTR_LEN_SHIFT 8 #define RBUF_FLTR_LEN_SHIFT 8
#define TBUF_CTRL 0x00 #define TBUF_CTRL 0x00
#define TBUF_64B_EN (1 << 0)
#define TBUF_BP_MC 0x0C #define TBUF_BP_MC 0x0C
#define TBUF_ENERGY_CTRL 0x14 #define TBUF_ENERGY_CTRL 0x14
#define TBUF_EEE_EN (1 << 0) #define TBUF_EEE_EN (1 << 0)
...@@ -662,8 +663,6 @@ struct bcmgenet_priv { ...@@ -662,8 +663,6 @@ struct bcmgenet_priv {
unsigned int irq0_stat; unsigned int irq0_stat;
/* HW descriptors/checksum variables */ /* HW descriptors/checksum variables */
bool desc_64b_en;
bool desc_rxchk_en;
bool crc_fwd_en; bool crc_fwd_en;
u32 dma_max_burst_length; u32 dma_max_burst_length;
......
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